simplify DirectiveArg

This commit is contained in:
Irmen de Jong 2025-02-02 04:35:20 +01:00
parent 216825b98a
commit 75ddcda5f3
11 changed files with 43 additions and 42 deletions

View File

@ -367,10 +367,10 @@ internal fun determineCompilationOptions(program: Program, compTarget: ICompilat
val toplevelModule = program.toplevelModule
val outputDirective = (toplevelModule.statements.singleOrNull { it is Directive && it.directive == "%output" } as? Directive)
val launcherDirective = (toplevelModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" } as? Directive)
val outputTypeStr = outputDirective?.args?.single()?.name?.uppercase()
val launcherTypeStr = launcherDirective?.args?.single()?.name?.uppercase()
val outputTypeStr = outputDirective?.args?.single()?.string?.uppercase()
val launcherTypeStr = launcherDirective?.args?.single()?.string?.uppercase()
val zpoption: String? = (toplevelModule.statements.singleOrNull { it is Directive && it.directive == "%zeropage" }
as? Directive)?.args?.single()?.name?.uppercase()
as? Directive)?.args?.single()?.string?.uppercase()
val allOptions = program.modules.flatMap { it.options() }.toSet()
val floatsEnabled = "enable_floats" in allOptions
var noSysInit = "no_sysinit" in allOptions

View File

@ -46,7 +46,7 @@ class ModuleImporter(private val program: Program,
fun importImplicitLibraryModule(name: String): Module? {
val import = Directive("%import", listOf(
DirectiveArg("", name, 42u, position = Position("<<<implicit-import>>>", 0, 0, 0))
DirectiveArg(name, 42u, position = Position("<<<implicit-import>>>", 0, 0, 0))
), Position("<<<implicit-import>>>", 0, 0, 0))
return executeImportDirective(import, null)
}
@ -75,9 +75,7 @@ class ModuleImporter(private val program: Program,
private fun executeImportDirective(import: Directive, importingModule: Module?): Module? {
if(import.directive!="%import" || import.args.size!=1)
throw SyntaxError("invalid import directive", import.position)
if(!import.args[0].str.isNullOrEmpty() || import.args[0].name==null)
throw SyntaxError("%import requires unquoted module name", import.position)
val moduleName = import.args[0].name!!
val moduleName = import.args[0].string!!
if("$moduleName.p8" == import.position.file)
throw SyntaxError("cannot import self", import.position)

View File

@ -955,24 +955,24 @@ internal class AstChecker(private val program: Program,
"%output" -> {
if(directive.parent !is Module)
err("this directive may only occur at module level")
if(directive.args.size!=1 || directive.args[0].name !in OutputType.entries.map {it.name.lowercase()})
if(directive.args.size!=1 || directive.args[0].string !in OutputType.entries.map {it.name.lowercase()})
err("invalid output directive type")
}
"%launcher" -> {
if(directive.parent !is Module)
err("this directive may only occur at module level")
if(directive.args.size!=1 || directive.args[0].name !in CbmPrgLauncherType.entries.map{it.name.lowercase()})
if(directive.args.size!=1 || directive.args[0].string !in CbmPrgLauncherType.entries.map{it.name.lowercase()})
err("invalid launcher directive type")
}
"%zeropage" -> {
if(directive.parent !is Module)
err("this directive may only occur at module level")
if(directive.args.size!=1 ||
directive.args[0].name != "basicsafe" &&
directive.args[0].name != "floatsafe" &&
directive.args[0].name != "kernalsafe" &&
directive.args[0].name != "dontuse" &&
directive.args[0].name != "full")
directive.args[0].string != "basicsafe" &&
directive.args[0].string != "floatsafe" &&
directive.args[0].string != "kernalsafe" &&
directive.args[0].string != "dontuse" &&
directive.args[0].string != "full")
err("invalid zp type, expected basicsafe, floatsafe, kernalsafe, dontuse, or full")
}
"%zpreserved", "%zpallowed" -> {
@ -998,9 +998,9 @@ internal class AstChecker(private val program: Program,
"%import" -> {
if(directive.parent !is Module)
err("this directive may only occur at module level")
if(directive.args.size!=1 || directive.args[0].name==null)
if(directive.args.size!=1 || directive.args[0].string==null)
err("invalid import directive, expected module name argument")
if(directive.args[0].name == (directive.parent as? Module)?.name)
if(directive.args[0].string == (directive.parent as? Module)?.name)
err("invalid import directive, cannot import itself")
}
"%breakpoint" -> {
@ -1012,44 +1012,44 @@ internal class AstChecker(private val program: Program,
"%asminclude" -> {
if(directive.parent !is INameScope || directive.parent is Module)
err("this directive can't be used here")
if(directive.args.size!=1 || directive.args[0].str==null)
if(directive.args.size!=1 || directive.args[0].string==null)
err("invalid asminclude directive, expected argument: \"filename\"")
checkFileExists(directive, directive.args[0].str!!)
checkFileExists(directive, directive.args[0].string!!)
}
"%asmbinary" -> {
if(directive.parent !is INameScope || directive.parent is Module)
err("this directive can't be used here")
val errormsg = "invalid asmbinary directive, expected arguments: \"filename\" [, offset [, length ] ]"
if(directive.args.isEmpty()) err(errormsg)
else if(directive.args[0].str==null) err(errormsg)
else if(directive.args[0].string==null) err(errormsg)
else if(directive.args.size>=2 && directive.args[1].int==null) err(errormsg)
else if(directive.args.size==3 && directive.args[2].int==null) err(errormsg)
else if(directive.args.size>3) err(errormsg)
else checkFileExists(directive, directive.args[0].str!!)
else checkFileExists(directive, directive.args[0].string!!)
}
"%option" -> {
if(directive.parent !is Block && directive.parent !is Module)
err("this directive may only occur in a block or at module level")
if(directive.args.isEmpty())
err("missing option directive argument(s)")
else if(directive.args.map{it.name in arrayOf("enable_floats", "force_output", "no_sysinit", "merge", "verafxmuls", "no_symbol_prefixing", "ignore_unused")}.any { !it })
else if(directive.args.map{it.string in arrayOf("enable_floats", "force_output", "no_sysinit", "merge", "verafxmuls", "no_symbol_prefixing", "ignore_unused")}.any { !it })
err("invalid option directive argument(s)")
if(directive.parent is Block) {
if(directive.args.any {it.name !in arrayOf("force_output", "merge", "verafxmuls", "no_symbol_prefixing", "ignore_unused")})
if(directive.args.any {it.string !in arrayOf("force_output", "merge", "verafxmuls", "no_symbol_prefixing", "ignore_unused")})
err("using an option that is not valid for blocks")
}
if(directive.parent is Module) {
if(directive.args.any {it.name !in arrayOf("enable_floats", "no_sysinit", "no_symbol_prefixing", "ignore_unused")})
if(directive.args.any {it.string !in arrayOf("enable_floats", "no_sysinit", "no_symbol_prefixing", "ignore_unused")})
err("using an option that is not valid for modules")
}
if(directive.args.any { it.name=="verafxmuls" } && compilerOptions.compTarget.name != Cx16Target.NAME)
if(directive.args.any { it.string=="verafxmuls" } && compilerOptions.compTarget.name != Cx16Target.NAME)
err("verafx option is only valid on cx16 target")
}
"%encoding" -> {
if(directive.parent !is Module)
err("this directive may only occur at module level")
val allowedEncodings = Encoding.entries.map {it.prefix}
if(directive.args.size!=1 || directive.args[0].name !in allowedEncodings)
if(directive.args.size!=1 || directive.args[0].string !in allowedEncodings)
err("invalid encoding directive, expected one of $allowedEncodings")
}
else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position)

View File

@ -201,13 +201,13 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
val directives = srcBlock.statements.filterIsInstance<Directive>()
for (directive in directives.filter { it.directive == "%option" }) {
for (arg in directive.args) {
when (arg.name) {
when (arg.string) {
"no_symbol_prefixing" -> noSymbolPrefixing = true
"ignore_unused" -> ignoreUnused = true
"force_output" -> forceOutput = true
"merge" -> { /* ignore this one */ }
"verafxmuls" -> veraFxMuls = true
else -> throw FatalAstException("weird directive option: ${arg.name}")
else -> throw FatalAstException("weird directive option: ${arg.string}")
}
}
}
@ -253,7 +253,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
PtAlign(align, directive.position)
}
"%asmbinary" -> {
val filename = directive.args[0].str!!
val filename = directive.args[0].string!!
val offset: UInt? = if(directive.args.size>=2) directive.args[1].int!! else null
val length: UInt? = if(directive.args.size>=3) directive.args[2].int!! else null
val abspath = if(File(filename).isFile) {
@ -268,7 +268,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
throw FatalAstException("included file doesn't exist")
}
"%asminclude" -> {
val result = loadAsmIncludeFile(directive.args[0].str!!, directive.definingModule.source)
val result = loadAsmIncludeFile(directive.args[0].string!!, directive.definingModule.source)
val assembly = result.getOrElse { throw it }
PtInlineAssembly(assembly.trimEnd().trimStart('\r', '\n'), false, directive.position)
}

View File

@ -17,7 +17,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
override fun after(block: Block, parent: Node): Iterable<IAstModification> {
val inheritOptions = block.definingModule.options() intersect setOf("no_symbol_prefixing", "ignore_unused") subtract block.options()
if(inheritOptions.isNotEmpty()) {
val directive = Directive("%option", inheritOptions.map{ DirectiveArg(null, it, null, block.position) }, block.position)
val directive = Directive("%option", inheritOptions.map{ DirectiveArg(it, null, block.position) }, block.position)
return listOf(IAstModification.InsertFirst(directive, block))
}

View File

@ -107,8 +107,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
for(arg in directive.args) {
when {
arg.int!=null -> output(arg.int.toString())
arg.name!=null -> output(arg.name)
arg.str!=null -> output("\"${arg.str}\"")
arg.string!=null -> output(arg.string)
}
if(arg!==directive.args.last())
output(",")

View File

@ -328,7 +328,7 @@ open class Module(final override val statements: MutableList<Statement>,
override fun toString() = "Module(name=$name, pos=$position, lib=${isLibrary})"
override fun referencesIdentifier(nameInSource: List<String>): Boolean = statements.any { it.referencesIdentifier(nameInSource) }
fun options() = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.name!!}.toSet()
fun options() = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.string!!}.toSet()
fun accept(visitor: IAstVisitor) = visitor.visit(this)
fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
@ -336,7 +336,7 @@ open class Module(final override val statements: MutableList<Statement>,
val textEncoding: Encoding by lazy {
val encoding = (statements.singleOrNull { it is Directive && it.directive == "%encoding" } as? Directive)
if(encoding!=null)
Encoding.entries.first { it.prefix==encoding.args[0].name }
Encoding.entries.first { it.prefix==encoding.args[0].string }
else
program.encoding.defaultEncoding
}

View File

@ -25,7 +25,7 @@ class Program(val name: String,
// insert a container module for all interned strings later
val internedStringsModule = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated(internedStringsModuleName))
val block = Block(internedStringsModuleName, null, mutableListOf(), true, Position.DUMMY)
val directive = Directive("%option", listOf(DirectiveArg(null,"no_symbol_prefixing", null, Position.DUMMY)), Position.DUMMY)
val directive = Directive("%option", listOf(DirectiveArg("no_symbol_prefixing", null, Position.DUMMY)), Position.DUMMY)
block.statements.add(directive)
directive.linkParents(block)
internedStringsModule.statements.add(block)

View File

@ -445,9 +445,13 @@ internal fun DirectiveContext.toAst() : Directive =
private fun DirectiveargContext.toAst() : DirectiveArg {
val str = stringliteral()
if(str?.encoding?.text!=null)
throw SyntaxError("don't use a string encoding for directive arguments", toPosition())
return DirectiveArg(str?.text?.substring(1, text.length-1), identifier()?.text, integerliteral()?.toAst()?.number?.toUInt(), toPosition())
if(str!=null) {
if (str.encoding?.text != null)
throw SyntaxError("don't use a string encoding for directive arguments", toPosition())
return DirectiveArg(str.text.substring(1, text.length-1), integerliteral()?.toAst()?.number?.toUInt(), toPosition())
}
return DirectiveArg(identifier()?.text, integerliteral()?.toAst()?.number?.toUInt(), toPosition())
}
private fun IntegerliteralContext.toAst(): NumericLiteralNode {

View File

@ -94,7 +94,7 @@ class Block(override val name: String,
override fun toString() = "Block(name=$name, address=$address, ${statements.size} statements)"
override fun referencesIdentifier(nameInSource: List<String>): Boolean = statements.any { it.referencesIdentifier(nameInSource) }
fun options() = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.name!!}.toSet()
fun options() = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.string!!}.toSet()
}
// note: a Directive is not strictly always Statement (in module scope, it's a Module Element rather)
@ -132,14 +132,14 @@ data class Directive(val directive: String, val args: List<DirectiveArg>, overri
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
}
data class DirectiveArg(val str: String?, val name: String?, val int: UInt?, override val position: Position) : Node {
data class DirectiveArg(val string: String?, val int: UInt?, override val position: Position) : Node {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent = parent
}
override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
override fun copy() = DirectiveArg(str, name, int, position)
override fun copy() = DirectiveArg(string, int, position)
override fun referencesIdentifier(nameInSource: List<String>): Boolean = false
}

View File

@ -56,7 +56,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
override fun visit(directive: Directive) {
val thisModule = directive.definingModule
if (directive.directive == "%import") {
val importedModule = program.modules.singleOrNull { it.name == directive.args[0].name } // the module may no longer exist at all due to optimizations
val importedModule = program.modules.singleOrNull { it.name == directive.args[0].string } // the module may no longer exist at all due to optimizations
if(importedModule!=null) {
imports[thisModule] = imports.getValue(thisModule) + importedModule
importedBy[importedModule] = importedBy.getValue(importedModule) + thisModule