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:
Irmen de Jong
2025-05-11 23:16:03 +02:00
37 changed files with 431 additions and 93 deletions

View File

@@ -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 {

View File

@@ -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())
}

View File

@@ -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")
}
}

View File

@@ -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)

View File

@@ -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)
}