mirror of
https://github.com/irmen/prog8.git
synced 2025-11-24 06:17:39 +00:00
Merge branch 'master' into structs
# Conflicts: # codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt # compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt # compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt # compilerAst/src/prog8/ast/AstToSourceTextConverter.kt # compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt # compilerAst/src/prog8/ast/walk/AstWalker.kt # compilerAst/src/prog8/ast/walk/IAstVisitor.kt # docs/source/todo.rst # examples/test.p8 # parser/src/main/antlr/Prog8ANTLR.g4
This commit is contained in:
@@ -532,6 +532,22 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
||||
output("alias ${alias.alias} = ${alias.target.nameInSource.joinToString(".")}")
|
||||
}
|
||||
|
||||
override fun visit(onGoto: OnGoto) {
|
||||
output(if(onGoto.isCall) "selectcall " else "selectgoto ")
|
||||
onGoto.index.accept(this)
|
||||
output(" from (")
|
||||
onGoto.labels.forEachIndexed { idx, label ->
|
||||
label.accept(this)
|
||||
if(idx!=onGoto.labels.lastIndex)
|
||||
output(", ")
|
||||
}
|
||||
outputln(")")
|
||||
if(onGoto.elsepart!=null && onGoto.elsepart.isNotEmpty()) {
|
||||
output(" else ")
|
||||
onGoto.elsepart.accept(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visit(deref: PtrDereference) {
|
||||
output("${deref.identifier.nameInSource.joinToString(".")}^^")
|
||||
deref.chain.forEach {
|
||||
|
||||
@@ -169,6 +169,9 @@ private fun StatementContext.toAst() : Statement {
|
||||
val aliasstmt = alias()?.toAst()
|
||||
if(aliasstmt!=null) return aliasstmt
|
||||
|
||||
val ongotostmt = ongoto()?.toAst()
|
||||
if(ongotostmt!=null) return ongotostmt
|
||||
|
||||
val structdecl = structdeclaration()?.toAst()
|
||||
if(structdecl!=null) return structdecl
|
||||
|
||||
@@ -176,7 +179,7 @@ private fun StatementContext.toAst() : Statement {
|
||||
}
|
||||
|
||||
private fun AsmsubroutineContext.toAst(): Subroutine {
|
||||
val inline = this.inline()!=null
|
||||
val inline = this.INLINE()!=null
|
||||
val subdecl = asmsub_decl().toAst()
|
||||
val statements = statement_block()?.toAst() ?: mutableListOf()
|
||||
return Subroutine(subdecl.name, subdecl.parameters.toMutableList(), subdecl.returntypes.toMutableList(),
|
||||
@@ -250,13 +253,17 @@ private fun Asmsub_paramsContext.toAst(): List<AsmSubroutineParameter> = asmsub_
|
||||
val identifiers = vardecl.identifierlist()?.identifier() ?: emptyList()
|
||||
if(identifiers.size>1)
|
||||
throw SyntaxError("parameter name must be singular", identifiers[0].toPosition())
|
||||
val identifiername = identifiers.single().name()
|
||||
val identifiername = getname(identifiers.single())
|
||||
AsmSubroutineParameter(identifiername, datatype, registerorpair, statusregister, toPosition())
|
||||
}
|
||||
|
||||
private fun IdentifierContext.name(): String {
|
||||
return (this.UNICODEDNAME().text ?: this.UNDERSCORENAME()?.text)!!
|
||||
}
|
||||
|
||||
private fun getname(identifier: IdentifierContext): String = identifier.children[0].text
|
||||
// return if (identifier == null) null
|
||||
// else identifier.children[0].text
|
||||
// //else (identifier.NAME() ?: identifier.UNDERSCORENAME() ?: identifier.ON() ?: identifier.CALL()).text
|
||||
//}
|
||||
|
||||
|
||||
private fun parseParamRegister(registerTok: Token?, pos: Position): Pair<RegisterOrPair?, Statusflag?> {
|
||||
if(registerTok==null)
|
||||
@@ -354,7 +361,7 @@ private fun Sub_paramsContext.toAst(): List<SubroutineParameter> =
|
||||
val identifiers = decl.identifierlist()?.identifier() ?: emptyList()
|
||||
if(identifiers.size>1)
|
||||
throw SyntaxError("parameter name must be singular", identifiers[0].toPosition())
|
||||
val identifiername = identifiers.single().name()
|
||||
val identifiername = getname(identifiers.single())
|
||||
|
||||
val (registerorpair, statusregister) = parseParamRegister(it.register, it.toPosition())
|
||||
if(statusregister!=null) {
|
||||
@@ -401,7 +408,7 @@ private fun Assign_targetContext.toAst() : AssignTarget {
|
||||
AssignTarget(null, arrayindexed, null, null, false, position = toPosition())
|
||||
}
|
||||
is VoidTargetContext -> {
|
||||
AssignTarget(null, null, null, null, true, position = void_().toPosition())
|
||||
AssignTarget(null, null, null, null, true, position = voidtarget().toPosition())
|
||||
}
|
||||
is PointerDereferenceTargetContext -> {
|
||||
val deref = this.pointerdereference().toAst()
|
||||
@@ -844,7 +851,7 @@ private fun When_choiceContext.toAst(): WhenChoice {
|
||||
private fun StructfielddeclContext.toAst(): Pair<DataType, List<String>> {
|
||||
val identifiers = identifierlist()?.identifier() ?: emptyList()
|
||||
val dt = datatype().toAst()
|
||||
return dt to identifiers.map { it.name() }
|
||||
return dt to identifiers.map { getname(it) }
|
||||
}
|
||||
|
||||
private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl {
|
||||
@@ -856,7 +863,7 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl
|
||||
}
|
||||
val zp = getZpOption(tags)
|
||||
val split = getSplitOption(tags)
|
||||
val identifiers = identifierlist().identifier().map { it.name() }
|
||||
val identifiers = identifierlist().identifier().map { getname(it) }
|
||||
val name = if(identifiers.size==1) identifiers[0] else "<multiple>"
|
||||
val isArray = ARRAYSIG() != null || arrayindex() != null
|
||||
val alignword = "@alignword" in tags
|
||||
@@ -894,3 +901,12 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl
|
||||
toPosition()
|
||||
)
|
||||
}
|
||||
|
||||
private fun OngotoContext.toAst(): Statement {
|
||||
val elseStatements = this.else_part()?.toAst()
|
||||
val elseScope = if(elseStatements==null) null else AnonymousScope(elseStatements, else_part()?.toPosition() ?: toPosition())
|
||||
val isCall = this.kind.text == "call"
|
||||
val index = this.expression().toAst()
|
||||
val labels = directivenamelist().scoped_identifier().map { it.toAst() }
|
||||
return OnGoto(isCall, index, labels, elseScope, toPosition())
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ class VarDecl(val type: VarDeclType,
|
||||
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
|
||||
var arrayDt = array.type.getOrElse { throw FatalAstException("unknown dt") }
|
||||
if(arrayDt.isSplitWordArray) {
|
||||
// autovars for array literals are NOT stored as a split word array!
|
||||
// autovars for array literals are NEVER stored as a split word array!
|
||||
when(arrayDt.sub) {
|
||||
BaseDataType.WORD -> arrayDt = DataType.arrayFor(BaseDataType.WORD, false)
|
||||
BaseDataType.UWORD -> arrayDt = DataType.arrayFor(BaseDataType.UWORD, false)
|
||||
@@ -296,6 +296,24 @@ class VarDecl(val type: VarDeclType,
|
||||
SplitWish.NOSPLIT, arraysize, autoVarName, emptyList(), array,
|
||||
sharedWithAsm = false, alignment = 0u, dirty = false, position = array.position)
|
||||
}
|
||||
|
||||
fun createAutoOptionalSplit(array: ArrayLiteral): VarDecl {
|
||||
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
|
||||
val arrayDt = array.type.getOrElse { throw FatalAstException("unknown dt") }
|
||||
val split = if(arrayDt.isSplitWordArray) SplitWish.SPLIT else if(arrayDt.isWordArray) SplitWish.NOSPLIT else SplitWish.DONTCARE
|
||||
val arraysize = ArrayIndex.forArray(array)
|
||||
return VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, arrayDt, ZeropageWish.NOT_IN_ZEROPAGE,
|
||||
split, arraysize, autoVarName, emptyList(), array,
|
||||
sharedWithAsm = false, alignment = 0u, dirty = false, position = array.position)
|
||||
}
|
||||
|
||||
fun createAuto(dt: DataType): VarDecl {
|
||||
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
|
||||
val vardecl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, dt, ZeropageWish.NOT_IN_ZEROPAGE,
|
||||
SplitWish.DONTCARE, null, autoVarName, emptyList(), null,
|
||||
sharedWithAsm = false, alignment = 0u, dirty = false, position = Position.DUMMY)
|
||||
return vardecl
|
||||
}
|
||||
}
|
||||
|
||||
val isArray: Boolean
|
||||
@@ -1304,3 +1322,29 @@ class DirectMemoryWrite(var addressExpression: Expression, override val position
|
||||
override fun copy() = DirectMemoryWrite(addressExpression.copy(), position)
|
||||
override fun referencesIdentifier(nameInSource: List<String>): Boolean = addressExpression.referencesIdentifier(nameInSource)
|
||||
}
|
||||
|
||||
class OnGoto(
|
||||
val isCall: Boolean,
|
||||
val index: Expression,
|
||||
val labels: List<IdentifierReference>,
|
||||
val elsepart: AnonymousScope?,
|
||||
override val position: Position
|
||||
) : Statement() {
|
||||
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
index.linkParents(this)
|
||||
labels.forEach { it.linkParents(this) }
|
||||
elsepart?.linkParents(this)
|
||||
}
|
||||
|
||||
override fun copy(): OnGoto = OnGoto(isCall, index.copy(), labels.map { it.copy() }, elsepart?.copy(), position)
|
||||
override fun referencesIdentifier(nameInSource: List<String>) = index.referencesIdentifier(nameInSource) || labels.any { it.referencesIdentifier(nameInSource) } || elsepart?.referencesIdentifier(nameInSource) == true
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||
throw FatalAstException("can't replace")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ abstract class AstWalker {
|
||||
open fun before(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(whenStmt: When, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(ongoto: OnGoto, parent: Node): Iterable<IAstModification> = noModifications
|
||||
|
||||
open fun after(addressOf: AddressOf, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(array: ArrayLiteral, parent: Node): Iterable<IAstModification> = noModifications
|
||||
@@ -190,6 +191,7 @@ abstract class AstWalker {
|
||||
open fun after(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(whenStmt: When, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(whileLoop: WhileLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(ongoto: OnGoto, parent: Node): Iterable<IAstModification> = noModifications
|
||||
|
||||
protected val modifications = mutableListOf<Triple<IAstModification, Node, Node>>()
|
||||
|
||||
@@ -523,6 +525,14 @@ abstract class AstWalker {
|
||||
track(after(chainedAssignment, parent), chainedAssignment, parent)
|
||||
}
|
||||
|
||||
fun visit(ongoto: OnGoto, parent: Node) {
|
||||
track(before(ongoto, parent), ongoto, parent)
|
||||
ongoto.index.accept(this, ongoto)
|
||||
ongoto.labels.forEach { it.accept(this, ongoto) }
|
||||
ongoto.elsepart?.accept(this, ongoto)
|
||||
track(after(ongoto, parent), ongoto, parent)
|
||||
}
|
||||
|
||||
fun visit(deref: PtrDereference, parent: Node) {
|
||||
track(before(deref, parent), deref, parent)
|
||||
deref.identifier.accept(this, deref)
|
||||
|
||||
@@ -208,6 +208,12 @@ interface IAstVisitor {
|
||||
chainedAssignment.nested.accept(this)
|
||||
}
|
||||
|
||||
fun visit(onGoto: OnGoto) {
|
||||
onGoto.index.accept(this)
|
||||
onGoto.labels.forEach { it.accept(this) }
|
||||
onGoto.elsepart?.accept(this)
|
||||
}
|
||||
|
||||
fun visit(deref: PtrDereference) {
|
||||
deref.identifier.accept(this)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user