From 788f6b44a60f1203cbcc49c5e90cb7c178a95f52 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 31 Mar 2024 00:20:37 +0100 Subject: [PATCH] antlr grammar now understands underscores in identifier names --- .../compiler/astprocessing/AstChecker.kt | 18 ++++++++++++++++++ .../src/prog8/ast/antlr/Antlr2Kotlin.kt | 19 +++++++++++++------ .../prog8/ast/expressions/AstExpressions.kt | 6 +++--- docs/source/todo.rst | 1 + parser/antlr/Prog8ANTLR.g4 | 6 ++++-- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index b28cba941..f79b109a8 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -52,6 +52,8 @@ internal class AstChecker(private val program: Program, override fun visit(module: Module) { super.visit(module) + if(module.name.startsWith('_')) + errors.err("module names cannot start with an underscore", module.position) val directives = module.statements.filterIsInstance().groupBy { it.directive } directives.filter { it.value.size > 1 }.forEach{ entry -> when(entry.key) { @@ -62,6 +64,10 @@ internal class AstChecker(private val program: Program, } override fun visit(identifier: IdentifierReference) { + if(identifier.nameInSource.any { it.startsWith('_') }) { + errors.err("identifiers cannot start with an underscore", identifier.position) + } + checkLongType(identifier) val stmt = identifier.targetStatement(program) if(stmt==null) @@ -266,6 +272,9 @@ internal class AstChecker(private val program: Program, } override fun visit(block: Block) { + if(block.name.startsWith('_')) + errors.err("block names cannot start with an underscore", block.position) + val addr = block.address if(addr!=null && addr>65535u) { errors.err("block memory address must be valid integer 0..\$ffff", block.position) @@ -295,6 +304,9 @@ internal class AstChecker(private val program: Program, } override fun visit(label: Label) { + if(label.name.startsWith('_')) + errors.err("labels cannot start with an underscore", label.position) + // scope check if(label.parent !is Block && label.parent !is Subroutine && label.parent !is AnonymousScope) { errors.err("Labels can only be defined in the scope of a block, a loop body, or within another subroutine", label.position) @@ -336,6 +348,9 @@ internal class AstChecker(private val program: Program, override fun visit(subroutine: Subroutine) { fun err(msg: String) = errors.err(msg, subroutine.position) + if(subroutine.name.startsWith('_')) + errors.err("subroutine names cannot start with an underscore", subroutine.position) + if(subroutine.name in BuiltinFunctions) err("cannot redefine a built-in function") @@ -474,6 +489,9 @@ internal class AstChecker(private val program: Program, // Non-string and non-ubytearray Pass-by-reference datatypes can not occur as parameters to a subroutine directly // Instead, their reference (address) should be passed (as an UWORD). for(p in subroutine.parameters) { + if(p.name.startsWith('_')) + errors.err("parameter names cannot start with an underscore", p.position) + if(p.type in PassByReferenceDatatypes && p.type !in listOf(DataType.STR, DataType.ARRAY_UB)) { errors.err("this pass-by-reference type can't be used as a parameter type. Instead, use an uword to receive the address, or access the variable from the outer scope directly.", p.position) } diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 5908ffa2e..bd8cf164e 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -246,7 +246,8 @@ private fun Asmsub_paramsContext.toAst(): List val identifiers = vardecl.identifier() if(identifiers.size>1) throw SyntaxError("parameter name must be singular", identifiers[0].toPosition()) - AsmSubroutineParameter(identifiers[0].NAME().text, datatype, registerorpair, statusregister, toPosition()) + val identifiername = identifiers[0].NAME() ?: identifiers[0].UNDERSCORENAME() ?: identifiers[0].UNDERSCOREPLACEHOLDER() + AsmSubroutineParameter(identifiername.text, datatype, registerorpair, statusregister, toPosition()) } private fun Functioncall_stmtContext.toAst(): Statement { @@ -316,7 +317,8 @@ private fun Sub_paramsContext.toAst(): List = val identifiers = it.identifier() if(identifiers.size>1) throw SyntaxError("parameter name must be singular", identifiers[0].toPosition()) - SubroutineParameter(identifiers[0].NAME().text, datatype, it.toPosition()) + val identifiername = identifiers[0].NAME() ?: identifiers[0].UNDERSCORENAME() ?: identifiers[0].UNDERSCOREPLACEHOLDER() + SubroutineParameter(identifiername.text, datatype, it.toPosition()) } private fun Assign_targetContext.toAst() : AssignTarget { @@ -556,8 +558,9 @@ private fun StringliteralContext.toAst(): StringLiteral { private fun Expression_listContext.toAst() = expression().map{ it.toAst() } -private fun Scoped_identifierContext.toAst() : IdentifierReference = - IdentifierReference(NAME().map { it.text }, toPosition()) +private fun Scoped_identifierContext.toAst() : IdentifierReference { + return IdentifierReference(identifier().map { it.text }, toPosition()) +} private fun FloatliteralContext.toAst() = text.replace("_","").toDouble() @@ -669,7 +672,8 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl else -> ZeropageWish.DONTCARE } val identifiers = identifier() - val name = if(identifiers.size==1) identifiers[0].NAME().text else "" + val identifiername = identifiers[0].NAME() ?: identifiers[0].UNDERSCORENAME() ?: identifiers[0].UNDERSCOREPLACEHOLDER() + val name = if(identifiers.size==1) identifiername.text else "" val isArray = ARRAYSIG() != null || arrayindex() != null val split = options.SPLIT().isNotEmpty() val origDt = datatype()?.toAst() ?: DataType.UNDEFINED @@ -690,7 +694,10 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl zp, arrayindex()?.toAst(), name, - if(identifiers.size==1) emptyList() else identifiers.map { it.NAME().text }, + if(identifiers.size==1) emptyList() else identifiers.map { + val idname = it.NAME() ?: it.UNDERSCORENAME() ?: it.UNDERSCOREPLACEHOLDER() + idname.text + }, value, options.SHARED().isNotEmpty(), split, diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 6ed900cd4..44c7431d3 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -906,12 +906,12 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because else if(elementType in WordDatatypes && value.all { it is NumericLiteral || it is AddressOf || it is IdentifierReference}) { val castArray = value.map { when(it) { - is AddressOf -> it as Expression - is IdentifierReference -> it as Expression + is AddressOf -> it + is IdentifierReference -> it is NumericLiteral -> { val numcast = it.cast(elementType, true) if(numcast.isValid) - numcast.valueOrZero() as Expression + numcast.valueOrZero() else return null // abort } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index e8931c636..47611f6bb 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,6 +2,7 @@ TODO ==== try to replace the variable number of assignment targets by allowing placeholder '_' target +or try to do this with 'void' instead, is more prog8-like? check souce code of examples and library, for void calls that could now be turned into multi-assign calls. diff --git a/parser/antlr/Prog8ANTLR.g4 b/parser/antlr/Prog8ANTLR.g4 index 5723a747c..e5be9c67c 100644 --- a/parser/antlr/Prog8ANTLR.g4 +++ b/parser/antlr/Prog8ANTLR.g4 @@ -25,6 +25,8 @@ WS : [ \t] -> skip ; // WS2 : '\\' EOL -> skip; VOID: 'void'; NAME : [\p{Letter}][\p{Letter}\p{Mark}\p{Digit}_]* ; // match unicode properties +UNDERSCORENAME : '_' NAME ; // match unicode properties +UNDERSCOREPLACEHOLDER: '_' ; DEC_INTEGER : DEC_DIGIT (DEC_DIGIT | '_')* ; HEX_INTEGER : '$' HEX_DIGIT (HEX_DIGIT | '_')* ; BIN_INTEGER : '%' BIN_DIGIT (BIN_DIGIT | '_')* ; @@ -220,9 +222,9 @@ breakstmt : 'break'; continuestmt: 'continue'; -identifier : NAME ; +identifier : NAME | UNDERSCORENAME | UNDERSCOREPLACEHOLDER; -scoped_identifier : NAME ('.' NAME)* ; +scoped_identifier : identifier ('.' identifier)* ; integerliteral : intpart=(DEC_INTEGER | HEX_INTEGER | BIN_INTEGER) ;