mirror of
https://github.com/irmen/prog8.git
synced 2024-06-10 20:29:33 +00:00
antlr grammar now understands underscores in identifier names
This commit is contained in:
parent
3e34a3ef72
commit
788f6b44a6
|
@ -52,6 +52,8 @@ internal class AstChecker(private val program: Program,
|
||||||
|
|
||||||
override fun visit(module: Module) {
|
override fun visit(module: Module) {
|
||||||
super.visit(module)
|
super.visit(module)
|
||||||
|
if(module.name.startsWith('_'))
|
||||||
|
errors.err("module names cannot start with an underscore", module.position)
|
||||||
val directives = module.statements.filterIsInstance<Directive>().groupBy { it.directive }
|
val directives = module.statements.filterIsInstance<Directive>().groupBy { it.directive }
|
||||||
directives.filter { it.value.size > 1 }.forEach{ entry ->
|
directives.filter { it.value.size > 1 }.forEach{ entry ->
|
||||||
when(entry.key) {
|
when(entry.key) {
|
||||||
|
@ -62,6 +64,10 @@ internal class AstChecker(private val program: Program,
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(identifier: IdentifierReference) {
|
override fun visit(identifier: IdentifierReference) {
|
||||||
|
if(identifier.nameInSource.any { it.startsWith('_') }) {
|
||||||
|
errors.err("identifiers cannot start with an underscore", identifier.position)
|
||||||
|
}
|
||||||
|
|
||||||
checkLongType(identifier)
|
checkLongType(identifier)
|
||||||
val stmt = identifier.targetStatement(program)
|
val stmt = identifier.targetStatement(program)
|
||||||
if(stmt==null)
|
if(stmt==null)
|
||||||
|
@ -266,6 +272,9 @@ internal class AstChecker(private val program: Program,
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(block: Block) {
|
override fun visit(block: Block) {
|
||||||
|
if(block.name.startsWith('_'))
|
||||||
|
errors.err("block names cannot start with an underscore", block.position)
|
||||||
|
|
||||||
val addr = block.address
|
val addr = block.address
|
||||||
if(addr!=null && addr>65535u) {
|
if(addr!=null && addr>65535u) {
|
||||||
errors.err("block memory address must be valid integer 0..\$ffff", block.position)
|
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) {
|
override fun visit(label: Label) {
|
||||||
|
if(label.name.startsWith('_'))
|
||||||
|
errors.err("labels cannot start with an underscore", label.position)
|
||||||
|
|
||||||
// scope check
|
// scope check
|
||||||
if(label.parent !is Block && label.parent !is Subroutine && label.parent !is AnonymousScope) {
|
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)
|
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) {
|
override fun visit(subroutine: Subroutine) {
|
||||||
fun err(msg: String) = errors.err(msg, subroutine.position)
|
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)
|
if(subroutine.name in BuiltinFunctions)
|
||||||
err("cannot redefine a built-in function")
|
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
|
// 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).
|
// Instead, their reference (address) should be passed (as an UWORD).
|
||||||
for(p in subroutine.parameters) {
|
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)) {
|
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)
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,8 @@ private fun Asmsub_paramsContext.toAst(): List<AsmSubroutineParameter>
|
||||||
val identifiers = vardecl.identifier()
|
val identifiers = vardecl.identifier()
|
||||||
if(identifiers.size>1)
|
if(identifiers.size>1)
|
||||||
throw SyntaxError("parameter name must be singular", identifiers[0].toPosition())
|
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 {
|
private fun Functioncall_stmtContext.toAst(): Statement {
|
||||||
|
@ -316,7 +317,8 @@ private fun Sub_paramsContext.toAst(): List<SubroutineParameter> =
|
||||||
val identifiers = it.identifier()
|
val identifiers = it.identifier()
|
||||||
if(identifiers.size>1)
|
if(identifiers.size>1)
|
||||||
throw SyntaxError("parameter name must be singular", identifiers[0].toPosition())
|
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 {
|
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 Expression_listContext.toAst() = expression().map{ it.toAst() }
|
||||||
|
|
||||||
private fun Scoped_identifierContext.toAst() : IdentifierReference =
|
private fun Scoped_identifierContext.toAst() : IdentifierReference {
|
||||||
IdentifierReference(NAME().map { it.text }, toPosition())
|
return IdentifierReference(identifier().map { it.text }, toPosition())
|
||||||
|
}
|
||||||
|
|
||||||
private fun FloatliteralContext.toAst() = text.replace("_","").toDouble()
|
private fun FloatliteralContext.toAst() = text.replace("_","").toDouble()
|
||||||
|
|
||||||
|
@ -669,7 +672,8 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl
|
||||||
else -> ZeropageWish.DONTCARE
|
else -> ZeropageWish.DONTCARE
|
||||||
}
|
}
|
||||||
val identifiers = identifier()
|
val identifiers = identifier()
|
||||||
val name = if(identifiers.size==1) identifiers[0].NAME().text else "<multiple>"
|
val identifiername = identifiers[0].NAME() ?: identifiers[0].UNDERSCORENAME() ?: identifiers[0].UNDERSCOREPLACEHOLDER()
|
||||||
|
val name = if(identifiers.size==1) identifiername.text else "<multiple>"
|
||||||
val isArray = ARRAYSIG() != null || arrayindex() != null
|
val isArray = ARRAYSIG() != null || arrayindex() != null
|
||||||
val split = options.SPLIT().isNotEmpty()
|
val split = options.SPLIT().isNotEmpty()
|
||||||
val origDt = datatype()?.toAst() ?: DataType.UNDEFINED
|
val origDt = datatype()?.toAst() ?: DataType.UNDEFINED
|
||||||
|
@ -690,7 +694,10 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl
|
||||||
zp,
|
zp,
|
||||||
arrayindex()?.toAst(),
|
arrayindex()?.toAst(),
|
||||||
name,
|
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,
|
value,
|
||||||
options.SHARED().isNotEmpty(),
|
options.SHARED().isNotEmpty(),
|
||||||
split,
|
split,
|
||||||
|
|
|
@ -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}) {
|
else if(elementType in WordDatatypes && value.all { it is NumericLiteral || it is AddressOf || it is IdentifierReference}) {
|
||||||
val castArray = value.map {
|
val castArray = value.map {
|
||||||
when(it) {
|
when(it) {
|
||||||
is AddressOf -> it as Expression
|
is AddressOf -> it
|
||||||
is IdentifierReference -> it as Expression
|
is IdentifierReference -> it
|
||||||
is NumericLiteral -> {
|
is NumericLiteral -> {
|
||||||
val numcast = it.cast(elementType, true)
|
val numcast = it.cast(elementType, true)
|
||||||
if(numcast.isValid)
|
if(numcast.isValid)
|
||||||
numcast.valueOrZero() as Expression
|
numcast.valueOrZero()
|
||||||
else
|
else
|
||||||
return null // abort
|
return null // abort
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
try to replace the variable number of assignment targets by allowing placeholder '_' target
|
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.
|
check souce code of examples and library, for void calls that could now be turned into multi-assign calls.
|
||||||
|
|
|
@ -25,6 +25,8 @@ WS : [ \t] -> skip ;
|
||||||
// WS2 : '\\' EOL -> skip;
|
// WS2 : '\\' EOL -> skip;
|
||||||
VOID: 'void';
|
VOID: 'void';
|
||||||
NAME : [\p{Letter}][\p{Letter}\p{Mark}\p{Digit}_]* ; // match unicode properties
|
NAME : [\p{Letter}][\p{Letter}\p{Mark}\p{Digit}_]* ; // match unicode properties
|
||||||
|
UNDERSCORENAME : '_' NAME ; // match unicode properties
|
||||||
|
UNDERSCOREPLACEHOLDER: '_' ;
|
||||||
DEC_INTEGER : DEC_DIGIT (DEC_DIGIT | '_')* ;
|
DEC_INTEGER : DEC_DIGIT (DEC_DIGIT | '_')* ;
|
||||||
HEX_INTEGER : '$' HEX_DIGIT (HEX_DIGIT | '_')* ;
|
HEX_INTEGER : '$' HEX_DIGIT (HEX_DIGIT | '_')* ;
|
||||||
BIN_INTEGER : '%' BIN_DIGIT (BIN_DIGIT | '_')* ;
|
BIN_INTEGER : '%' BIN_DIGIT (BIN_DIGIT | '_')* ;
|
||||||
|
@ -220,9 +222,9 @@ breakstmt : 'break';
|
||||||
|
|
||||||
continuestmt: 'continue';
|
continuestmt: 'continue';
|
||||||
|
|
||||||
identifier : NAME ;
|
identifier : NAME | UNDERSCORENAME | UNDERSCOREPLACEHOLDER;
|
||||||
|
|
||||||
scoped_identifier : NAME ('.' NAME)* ;
|
scoped_identifier : identifier ('.' identifier)* ;
|
||||||
|
|
||||||
integerliteral : intpart=(DEC_INTEGER | HEX_INTEGER | BIN_INTEGER) ;
|
integerliteral : intpart=(DEC_INTEGER | HEX_INTEGER | BIN_INTEGER) ;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user