diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 0c8688064..fe6005817 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -24,10 +24,9 @@ class IRCodeGen( internal val registers = RegisterPool() fun generate(): IRProgram { - flattenLabelNames() - flattenNestedSubroutines() - - // TODO: validateNames(program) + makeAllNodenamesScoped() + moveAllNestedSubroutinesToBlockScope() + verifyNameScoping(program, symbolTable) val irProg = IRProgram(program.name, IRSymbolTable(symbolTable), options, program.encoding) @@ -73,23 +72,37 @@ class IRCodeGen( return irProg } - private fun validateNames(node: PtNode) { - when(node) { - is PtBuiltinFunctionCall -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"} - is PtFunctionCall -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"} - is PtIdentifier -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"} - is PtAsmSub -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"} - is PtBlock -> require('.' !in node.name) { "block name should not be scoped: ${node.name}"} - is PtConstant -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"} - is PtLabel -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"} - is PtMemMapped -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"} - is PtSub -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"} - is PtVariable -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"} - is PtProgram -> require('.' !in node.name) { "program name should not be scoped: ${node.name}"} - is PtSubroutineParameter -> require('.' in node.name) { "node $node name is not scoped: ${node.name}"} - else -> { /* node has no name */ } + private fun verifyNameScoping(program: PtProgram, symbolTable: SymbolTable) { + fun verifyPtNode(node: PtNode) { + when (node) { + is PtBuiltinFunctionCall -> require('.' !in node.name) { "builtin function call name should not be scoped: ${node.name}" } + is PtFunctionCall -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" } + is PtIdentifier -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" } + is PtAsmSub -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" } + is PtBlock -> require('.' !in node.name) { "block name should not be scoped: ${node.name}" } + is PtConstant -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" } + is PtLabel -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" } + is PtMemMapped -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" } + is PtSub -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" } + is PtVariable -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" } + is PtProgram -> require('.' !in node.name) { "program name should not be scoped: ${node.name}" } + is PtSubroutineParameter -> require('.' in node.name) { "node $node name is not scoped: ${node.name}" } + else -> { /* node has no name */ + } + } + node.children.forEach { verifyPtNode(it) } } - node.children.forEach{ validateNames(it) } + + fun verifyStNode(node: StNode) { + require('.' !in node.name) { "st node name should not be scoped: ${node.name}"} + node.children.forEach { + require(it.key==it.value.name) + verifyStNode(it.value) + } + } + + verifyPtNode(program) + verifyStNode(symbolTable) } private fun ensureFirstChunkLabels(irProg: IRProgram) { @@ -176,79 +189,47 @@ class IRCodeGen( } } - private fun flattenLabelNames() { - val renameLabels = mutableListOf>() - - fun flattenRecurse(node: PtNode) { + private fun makeAllNodenamesScoped() { + val renames = mutableListOf>() + fun recurse(node: PtNode) { node.children.forEach { - if (it is PtLabel) - renameLabels += Pair(it.parent, it) - else - flattenRecurse(it) + if(it is PtNamedNode) + renames.add(it to it.scopedName) + recurse(it) } } - - flattenRecurse(program) - - renameLabels.forEach { (_, label) -> label.name = label.scopedName } + recurse(program) + renames.forEach { it.first.name = it.second } } - private fun flattenNestedSubroutines() { - // this moves all nested subroutines up to the block scope. - // also changes the name to be the fully scoped one, so it becomes unique at the top level. - val flattenedSubs = mutableListOf>() - val flattenedAsmSubs = mutableListOf>() - val removalsSubs = mutableListOf>() - val removalsAsmSubs = mutableListOf>() - val renameSubs = mutableListOf>() - val renameAsmSubs = mutableListOf>() + private fun moveAllNestedSubroutinesToBlockScope() { + val movedSubs = mutableListOf>() + val removedSubs = mutableListOf>() - fun flattenNestedAsmSub(block: PtBlock, parentSub: PtSub, asmsub: PtAsmSub) { - val flattened = PtAsmSub(asmsub.scopedName, - asmsub.address, - asmsub.clobbers, - asmsub.parameters, - asmsub.returnTypes, - asmsub.retvalRegisters, - asmsub.inline, - asmsub.position) - asmsub.children.forEach { flattened.add(it) } - flattenedAsmSubs += Pair(block, flattened) - removalsAsmSubs += Pair(parentSub, asmsub) + fun moveToBlock(block: PtBlock, parent: PtSub, asmsub: PtAsmSub) { + block.add(asmsub) + parent.children.remove(asmsub) } - fun flattenNestedSub(block: PtBlock, parentSub: PtSub, sub: PtSub) { - sub.children.filterIsInstance().forEach { subsub->flattenNestedSub(block, sub, subsub) } - sub.children.filterIsInstance().forEach { asmsubsub->flattenNestedAsmSub(block, sub, asmsubsub) } - val flattened = PtSub(sub.scopedName, - sub.parameters, - sub.returntype, - sub.inline, - sub.position) - sub.children.forEach { if(it !is PtSub) flattened.add(it) } - flattenedSubs += Pair(block, flattened) - removalsSubs += Pair(parentSub, sub) + fun moveToBlock(block: PtBlock, parent: PtSub, sub: PtSub) { + sub.children.filterIsInstance().forEach { subsub -> moveToBlock(block, sub, subsub) } + sub.children.filterIsInstance().forEach { asmsubsub -> moveToBlock(block, sub, asmsubsub) } + movedSubs += Pair(block, sub) + removedSubs += Pair(parent, sub) } program.allBlocks().forEach { block -> block.children.forEach { - if(it is PtSub) { + if (it is PtSub) { // Only regular subroutines can have nested subroutines. - it.children.filterIsInstance().forEach { subsub->flattenNestedSub(block, it, subsub)} - it.children.filterIsInstance().forEach { asmsubsub->flattenNestedAsmSub(block, it, asmsubsub)} - renameSubs += Pair(block, it) + it.children.filterIsInstance().forEach { subsub -> moveToBlock(block, it, subsub) } + it.children.filterIsInstance().forEach { asmsubsub -> moveToBlock(block, it, asmsubsub) } } - if(it is PtAsmSub) - renameAsmSubs += Pair(block, it) } } - removalsSubs.forEach { (parent, sub) -> parent.children.remove(sub) } - removalsAsmSubs.forEach { (parent, asmsub) -> parent.children.remove(asmsub) } - flattenedSubs.forEach { (block, sub) -> block.add(sub) } - flattenedAsmSubs.forEach { (block, asmsub) -> block.add(asmsub) } - renameSubs.forEach { (_, sub) -> sub.name = sub.scopedName } - renameAsmSubs.forEach { (_, sub) -> sub.name = sub.scopedName } + removedSubs.forEach { (parent, sub) -> parent.children.remove(sub) } + movedSubs.forEach { (block, sub) -> block.add(sub) } } internal fun translateNode(node: PtNode): IRCodeChunks { @@ -463,7 +444,8 @@ class IRCodeGen( } is PtIdentifier -> { val iterableVar = symbolTable.lookup(iterable.name) as StStaticVariable - val loopvarSymbol = loopvar.scopedName + require(forLoop.variable.name == loopvar.scopedName) + val loopvarSymbol = forLoop.variable.name val indexReg = registers.nextFree() val tmpReg = registers.nextFree() val loopLabel = createLabelName() @@ -526,7 +508,8 @@ class IRCodeGen( throw AssemblyError("step 0") val indexReg = registers.nextFree() val endvalueReg = registers.nextFree() - val loopvarSymbol = loopvar.scopedName + require(forLoop.variable.name == loopvar.scopedName) + val loopvarSymbol = forLoop.variable.name val loopvarDt = when(loopvar) { is StMemVar -> loopvar.dt is StStaticVariable -> loopvar.dt @@ -557,7 +540,8 @@ class IRCodeGen( private fun translateForInConstantRange(forLoop: PtForLoop, loopvar: StNode): IRCodeChunks { val loopLabel = createLabelName() - val loopvarSymbol = loopvar.scopedName + require(forLoop.variable.name == loopvar.scopedName) + val loopvarSymbol = forLoop.variable.name val indexReg = registers.nextFree() val loopvarDt = when(loopvar) { is StMemVar -> loopvar.dt @@ -1244,7 +1228,7 @@ class IRCodeGen( private fun translate(parameters: List) = parameters.map { - val flattenedName = it.definingSub()!!.scopedName + "." + it.name + val flattenedName = it.definingSub()!!.name + "." + it.name val orig = symbolTable.flat.getValue(flattenedName) as StStaticVariable IRSubroutine.IRParam(flattenedName, orig.dt) } diff --git a/examples/test.p8 b/examples/test.p8 index b1cadbd5f..c8278e132 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -12,6 +12,11 @@ main { str name="irmen" sub start() { + + for cx16.r0 in 0 to 10 { + cx16.r1++ + } + txt.print("= 10 ") txt.print_ub(zpvar) txt.nl()