mirror of
				https://github.com/irmen/prog8.git
				synced 2025-10-31 00:16:08 +00:00 
			
		
		
		
	allow struct initializers to occur in array literals
This commit is contained in:
		| @@ -5,9 +5,10 @@ import java.nio.file.Path | |||||||
| import kotlin.io.path.absolute | import kotlin.io.path.absolute | ||||||
|  |  | ||||||
|  |  | ||||||
| // the automatically generated module where all string literals are interned to: |  | ||||||
| const val INTERNED_STRINGS_MODULENAME = "prog8_interned_strings" | const val INTERNED_STRINGS_MODULENAME = "prog8_interned_strings" | ||||||
|  |  | ||||||
|  | val PROG8_CONTAINER_MODULES = arrayOf(INTERNED_STRINGS_MODULENAME)      // option to add more if needed one day | ||||||
|  |  | ||||||
| // all automatically generated labels everywhere need to have the same label name prefix: | // all automatically generated labels everywhere need to have the same label name prefix: | ||||||
| const val GENERATED_LABEL_PREFIX = "p8_label_gen_" | const val GENERATED_LABEL_PREFIX = "p8_label_gen_" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -252,6 +252,14 @@ private fun PtVariable.prefix(parent: PtNode, st: SymbolTable): PtVariable { | |||||||
|                         newValue.add(newAddr) |                         newValue.add(newAddr) | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |                 is PtBuiltinFunctionCall -> { | ||||||
|  |                     // could be a struct instance or memory slab "allocation" | ||||||
|  |                     if (elt.name != "prog8_lib_structalloc" && elt.name != "memory") | ||||||
|  |                         throw AssemblyError("weird array value element $elt") | ||||||
|  |                     else { | ||||||
|  |                         newValue.add(elt) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|                 else -> throw AssemblyError("weird array value element $elt") |                 else -> throw AssemblyError("weird array value element $elt") | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -1,5 +1,7 @@ | |||||||
| package prog8.codegen.cpu6502 | package prog8.codegen.cpu6502 | ||||||
|  |  | ||||||
|  | import prog8.code.StMemorySlabBlockName | ||||||
|  | import prog8.code.StStructInstanceBlockName | ||||||
| import prog8.code.SymbolTable | import prog8.code.SymbolTable | ||||||
| import prog8.code.ast.* | import prog8.code.ast.* | ||||||
| import prog8.code.core.* | import prog8.code.core.* | ||||||
| @@ -385,7 +387,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, | |||||||
|         val name = (fcall.args[0] as PtString).value |         val name = (fcall.args[0] as PtString).value | ||||||
|         require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name ${fcall.position}"} |         require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name ${fcall.position}"} | ||||||
|  |  | ||||||
|         val slabname = PtIdentifier("prog8_slabs.prog8_memoryslab_$name", DataType.UWORD, fcall.position) |         val slabname = PtIdentifier("$StMemorySlabBlockName.memory_$name", DataType.UWORD, fcall.position) | ||||||
|         val addressOf = PtAddressOf(DataType.pointer(BaseDataType.UBYTE), false, fcall.position) |         val addressOf = PtAddressOf(DataType.pointer(BaseDataType.UBYTE), false, fcall.position) | ||||||
|         addressOf.add(slabname) |         addressOf.add(slabname) | ||||||
|         addressOf.parent = fcall |         addressOf.parent = fcall | ||||||
| @@ -399,9 +401,10 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram, | |||||||
|         if(discardResult) |         if(discardResult) | ||||||
|             throw AssemblyError("should not discard result of struct allocation at $fcall") |             throw AssemblyError("should not discard result of struct allocation at $fcall") | ||||||
|         // ... don't need to pay attention to args here because struct instance is put together elsewhere we just have to get a pointer to it |         // ... don't need to pay attention to args here because struct instance is put together elsewhere we just have to get a pointer to it | ||||||
|         val slabname = SymbolTable.labelnameForStructInstance(fcall) |         val prefix = if(fcall.args.isEmpty()) "${StStructInstanceBlockName}_bss" else StStructInstanceBlockName | ||||||
|  |         val labelname = PtIdentifier("$prefix.${SymbolTable.labelnameForStructInstance(fcall)}", fcall.type, fcall.position) | ||||||
|         val addressOf = PtAddressOf(fcall.type, true, fcall.position) |         val addressOf = PtAddressOf(fcall.type, true, fcall.position) | ||||||
|         addressOf.add(PtIdentifier(slabname, fcall.type, fcall.position)) |         addressOf.add(labelname) | ||||||
|         addressOf.parent = fcall |         addressOf.parent = fcall | ||||||
|         val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, fcall.type, expression = addressOf) |         val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, fcall.type, expression = addressOf) | ||||||
|         val target = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen) |         val target = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen) | ||||||
|   | |||||||
| @@ -210,7 +210,7 @@ internal class ProgramAndVarsGen( | |||||||
|     private fun memorySlabs() { |     private fun memorySlabs() { | ||||||
|         if(symboltable.allMemorySlabs.isNotEmpty()) { |         if(symboltable.allMemorySlabs.isNotEmpty()) { | ||||||
|             asmgen.out("; memory slabs\n  .section BSS_SLABS") |             asmgen.out("; memory slabs\n  .section BSS_SLABS") | ||||||
|             asmgen.out("prog8_slabs\t.block") |             asmgen.out("$StMemorySlabBlockName\t.block") | ||||||
|             for (slab in symboltable.allMemorySlabs) { |             for (slab in symboltable.allMemorySlabs) { | ||||||
|                 if (slab.align > 1u) |                 if (slab.align > 1u) | ||||||
|                     asmgen.out("\t.align  ${slab.align.toHex()}") |                     asmgen.out("\t.align  ${slab.align.toHex()}") | ||||||
| @@ -434,6 +434,7 @@ internal class ProgramAndVarsGen( | |||||||
|         val (instancesNoInit, instances) = symboltable.allStructInstances.partition { it.initialValues.isEmpty() } |         val (instancesNoInit, instances) = symboltable.allStructInstances.partition { it.initialValues.isEmpty() } | ||||||
|         asmgen.out("; struct instances without initialization values, as BSS zeroed at startup\n") |         asmgen.out("; struct instances without initialization values, as BSS zeroed at startup\n") | ||||||
|         asmgen.out("    .section BSS\n") |         asmgen.out("    .section BSS\n") | ||||||
|  |         asmgen.out("${StStructInstanceBlockName}_bss  .block\n") | ||||||
|         instancesNoInit.forEach { |         instancesNoInit.forEach { | ||||||
|             val structtype: StStruct = symboltable.lookup(it.structName) as StStruct |             val structtype: StStruct = symboltable.lookup(it.structName) as StStruct | ||||||
|             val zerovalues = structtype.fields.map { field -> |             val zerovalues = structtype.fields.map { field -> | ||||||
| @@ -445,11 +446,17 @@ internal class ProgramAndVarsGen( | |||||||
|             } |             } | ||||||
|             asmgen.out("${it.name}    .dstruct  ${it.structName}, ${zerovalues.joinToString(",")}\n") |             asmgen.out("${it.name}    .dstruct  ${it.structName}, ${zerovalues.joinToString(",")}\n") | ||||||
|         } |         } | ||||||
|  |         asmgen.out("    .endblock\n") | ||||||
|         asmgen.out("    .send BSS\n") |         asmgen.out("    .send BSS\n") | ||||||
|  |  | ||||||
|         asmgen.out("; struct instances with initialization values\n") |         asmgen.out("; struct instances with initialization values\n") | ||||||
|         asmgen.out("    .section STRUCTINSTANCES\n") |         asmgen.out("    .section STRUCTINSTANCES\n") | ||||||
|         instances.forEach { asmgen.out("${it.name}    .dstruct  ${it.structName}, ${initValues(it).joinToString(",")}\n") } |         asmgen.out("$StStructInstanceBlockName  .block\n") | ||||||
|  |         instances.forEach { | ||||||
|  |             val instancename = it.name.substringAfter('.') | ||||||
|  |             asmgen.out("$instancename    .dstruct  ${it.structName}, ${initValues(it).joinToString(",")}\n") | ||||||
|  |         } | ||||||
|  |         asmgen.out("    .endblock\n") | ||||||
|         asmgen.out("    .send STRUCTINSTANCES\n") |         asmgen.out("    .send STRUCTINSTANCES\n") | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -866,7 +873,7 @@ internal class ProgramAndVarsGen( | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             dt.isSplitWordArray -> { |             dt.isSplitWordArray -> { | ||||||
|                 if(dt.elementType().isUnsignedWord) { |                 if(dt.elementType().isUnsignedWord || dt.elementType().isPointer) { | ||||||
|                     val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros) |                     val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros) | ||||||
|                     asmgen.out("_array_$varname := ${data.joinToString()}") |                     asmgen.out("_array_$varname := ${data.joinToString()}") | ||||||
|                     asmgen.out("${varname}_lsb\t.byte <_array_$varname") |                     asmgen.out("${varname}_lsb\t.byte <_array_$varname") | ||||||
| @@ -914,7 +921,7 @@ internal class ProgramAndVarsGen( | |||||||
|     private fun zeroFilledArray(numElts: Int): StArray { |     private fun zeroFilledArray(numElts: Int): StArray { | ||||||
|         val values = mutableListOf<StArrayElement>() |         val values = mutableListOf<StArrayElement>() | ||||||
|         repeat(numElts) { |         repeat(numElts) { | ||||||
|             values.add(StArrayElement(0.0, null, null)) |             values.add(StArrayElement(0.0, null, null,null,null)) | ||||||
|         } |         } | ||||||
|         return values |         return values | ||||||
|     } |     } | ||||||
| @@ -972,7 +979,7 @@ internal class ProgramAndVarsGen( | |||||||
|                     val number = it.number!!.toInt() |                     val number = it.number!!.toInt() | ||||||
|                     "$"+number.toString(16).padStart(2, '0') |                     "$"+number.toString(16).padStart(2, '0') | ||||||
|                 } |                 } | ||||||
|             dt.isArray && dt.elementType().isUnsignedWord -> array.map { |             dt.isArray && (dt.elementType().isUnsignedWord || dt.elementType().isPointer) -> array.map { | ||||||
|                 if(it.number!=null) { |                 if(it.number!=null) { | ||||||
|                     "$" + it.number!!.toInt().toString(16).padStart(4, '0') |                     "$" + it.number!!.toInt().toString(16).padStart(4, '0') | ||||||
|                 } |                 } | ||||||
| @@ -984,8 +991,15 @@ internal class ProgramAndVarsGen( | |||||||
|                     else |                     else | ||||||
|                         asmgen.asmSymbolName(addrOfSymbol) |                         asmgen.asmSymbolName(addrOfSymbol) | ||||||
|                 } |                 } | ||||||
|                 else |                 else if(it.structInstance!=null) { | ||||||
|  |                     asmgen.asmSymbolName("${StStructInstanceBlockName}.${it.structInstance!!}") | ||||||
|  |                 } | ||||||
|  |                 else if(it.structInstanceUninitialized!=null) { | ||||||
|  |                     asmgen.asmSymbolName("${StStructInstanceBlockName}_bss.${it.structInstanceUninitialized!!}") | ||||||
|  |                 } | ||||||
|  |                 else { | ||||||
|                     throw AssemblyError("weird array elt") |                     throw AssemblyError("weird array elt") | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             else -> throw AssemblyError("invalid dt") |             else -> throw AssemblyError("invalid dt") | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -1,5 +1,7 @@ | |||||||
| package prog8.codegen.intermediate | package prog8.codegen.intermediate | ||||||
|  |  | ||||||
|  | import prog8.code.StMemorySlabBlockName | ||||||
|  | import prog8.code.StStructInstanceBlockName | ||||||
| import prog8.code.SymbolTable | import prog8.code.SymbolTable | ||||||
| import prog8.code.ast.* | import prog8.code.ast.* | ||||||
| import prog8.code.core.AssemblyError | import prog8.code.core.AssemblyError | ||||||
| @@ -500,7 +502,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe | |||||||
|         val name = (call.args[0] as PtString).value |         val name = (call.args[0] as PtString).value | ||||||
|         val code = IRCodeChunk(null, null) |         val code = IRCodeChunk(null, null) | ||||||
|         val resultReg = codeGen.registers.next(IRDataType.WORD) |         val resultReg = codeGen.registers.next(IRDataType.WORD) | ||||||
|         code += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=resultReg, labelSymbol = "$StMemorySlabPrefix.prog8_memoryslab_$name") |         code += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=resultReg, labelSymbol = "$StMemorySlabBlockName.memory_$name") | ||||||
|         return ExpressionCodeResult(code, IRDataType.WORD, resultReg, -1) |         return ExpressionCodeResult(code, IRDataType.WORD, resultReg, -1) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -508,7 +510,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe | |||||||
|         val code = IRCodeChunk(null, null) |         val code = IRCodeChunk(null, null) | ||||||
|         val resultReg = codeGen.registers.next(IRDataType.WORD) |         val resultReg = codeGen.registers.next(IRDataType.WORD) | ||||||
|         val labelname = SymbolTable.labelnameForStructInstance(call) |         val labelname = SymbolTable.labelnameForStructInstance(call) | ||||||
|         code += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=resultReg, labelSymbol = labelname) |         code += IRInstruction(Opcode.LOAD, IRDataType.WORD, reg1=resultReg, labelSymbol = "${StStructInstanceBlockName}.$labelname") | ||||||
|         return ExpressionCodeResult(code, IRDataType.WORD, resultReg, -1) |         return ExpressionCodeResult(code, IRDataType.WORD, resultReg, -1) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -72,7 +72,9 @@ private fun convert(variable: StStaticVariable): IRStStaticVariable { | |||||||
|             val newArray = mutableListOf<IRStArrayElement>() |             val newArray = mutableListOf<IRStArrayElement>() | ||||||
|             array.forEach { |             array.forEach { | ||||||
|                 if(it.addressOfSymbol!=null) { |                 if(it.addressOfSymbol!=null) { | ||||||
|                     val target = variable.lookup(it.addressOfSymbol!!) ?: throw NoSuchElementException("can't find variable ${it.addressOfSymbol}") |                     println("LOOKUP ${it.addressOfSymbol}") | ||||||
|  |                     val target = variable.lookup(it.addressOfSymbol!!) ?: | ||||||
|  |                         throw NoSuchElementException("can't find variable ${it.addressOfSymbol}") | ||||||
|                     newArray.add(IRStArrayElement(null, null, target.scopedNameString)) |                     newArray.add(IRStArrayElement(null, null, target.scopedNameString)) | ||||||
|                 } else { |                 } else { | ||||||
|                     newArray.add(convertArrayElt(it)) |                     newArray.add(convertArrayElt(it)) | ||||||
| @@ -129,11 +131,11 @@ private fun convert(constant: StConstant): IRStConstant { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| private fun convert(variable: StMemorySlab): IRStMemorySlab { | private fun convert(mem: StMemorySlab): IRStMemorySlab { | ||||||
|     return if('.' in variable.name) |     return if('.' in mem.name) | ||||||
|         IRStMemorySlab(variable.name, variable.size, variable.align) |         IRStMemorySlab(mem.name, mem.size, mem.align) | ||||||
|     else |     else | ||||||
|         IRStMemorySlab("$StMemorySlabPrefix.${variable.name}", variable.size, variable.align) |         IRStMemorySlab("$StMemorySlabBlockName.${mem.name}", mem.size, mem.align) | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -142,8 +144,8 @@ private fun convert(instance: StStructInstance, fields: Iterable<Pair<DataType, | |||||||
|         val elt = convertArrayElt(value) |         val elt = convertArrayElt(value) | ||||||
|         IRStructInitValue(field.first.base, elt) |         IRStructInitValue(field.first.base, elt) | ||||||
|     } |     } | ||||||
|     return IRStStructInstance(instance.name, instance.structName, values, instance.size) |     return if('.' in instance.name) | ||||||
|  |         IRStStructInstance(instance.name, instance.structName, values, instance.size) | ||||||
|  |     else | ||||||
|  |         IRStStructInstance("${StStructInstanceBlockName}.${instance.name}", instance.structName, values, instance.size) | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| internal const val StMemorySlabPrefix = "prog8_slabs"       // TODO also add  ".prog8_memoryslab_"  ? |  | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ import prog8.ast.expressions.TypecastExpression | |||||||
| import prog8.ast.statements.* | import prog8.ast.statements.* | ||||||
| import prog8.ast.walk.AstWalker | import prog8.ast.walk.AstWalker | ||||||
| import prog8.ast.walk.IAstModification | import prog8.ast.walk.IAstModification | ||||||
| import prog8.code.INTERNED_STRINGS_MODULENAME | import prog8.code.PROG8_CONTAINER_MODULES | ||||||
| import prog8.code.core.ICompilationTarget | import prog8.code.core.ICompilationTarget | ||||||
| import prog8.code.core.IErrorReporter | import prog8.code.core.IErrorReporter | ||||||
| import prog8.compiler.CallGraph | import prog8.compiler.CallGraph | ||||||
| @@ -93,7 +93,7 @@ class UnusedCodeRemover(private val program: Program, | |||||||
|     override fun after(block: Block, parent: Node): Iterable<IAstModification> { |     override fun after(block: Block, parent: Node): Iterable<IAstModification> { | ||||||
|         if("force_output" !in block.options()) { |         if("force_output" !in block.options()) { | ||||||
|             if (block.containsNoCodeNorVars) { |             if (block.containsNoCodeNorVars) { | ||||||
|                 if (block.name != INTERNED_STRINGS_MODULENAME && "ignore_unused" !in block.options()) { |                 if (block.name !in PROG8_CONTAINER_MODULES && "ignore_unused" !in block.options()) { | ||||||
|                     if (!block.statements.any { it is Subroutine && it.hasBeenInlined }) |                     if (!block.statements.any { it is Subroutine && it.hasBeenInlined }) | ||||||
|                         errors.info("removing unused block '${block.name}'", block.position) |                         errors.info("removing unused block '${block.name}'", block.position) | ||||||
|                 } |                 } | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import prog8.ast.* | |||||||
| import prog8.ast.expressions.Expression | import prog8.ast.expressions.Expression | ||||||
| import prog8.ast.expressions.NumericLiteral | import prog8.ast.expressions.NumericLiteral | ||||||
| import prog8.ast.statements.Directive | import prog8.ast.statements.Directive | ||||||
|  | import prog8.code.SymbolTable | ||||||
| import prog8.code.SymbolTableMaker | import prog8.code.SymbolTableMaker | ||||||
| import prog8.code.ast.PtProgram | import prog8.code.ast.PtProgram | ||||||
| import prog8.code.ast.printAst | import prog8.code.ast.printAst | ||||||
| @@ -176,17 +177,21 @@ fun compileProgram(args: CompilerArguments): CompilationResult? { | |||||||
|                     println("*********** COMPILER AST END *************\n") |                     println("*********** COMPILER AST END *************\n") | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |                 var symbolTable: SymbolTable | ||||||
|  |  | ||||||
|                 val (intermediateAst, simplifiedAstDuration2) = measureTimedValue { |                 val (intermediateAst, simplifiedAstDuration2) = measureTimedValue { | ||||||
|                     val intermediateAst = SimplifiedAstMaker(program, args.errors).transform() |                     val intermediateAst = SimplifiedAstMaker(program, args.errors).transform() | ||||||
|                     val stMaker = SymbolTableMaker(intermediateAst, compilationOptions) |                     val stMaker = SymbolTableMaker(intermediateAst, compilationOptions) | ||||||
|                     val symbolTable = stMaker.make() |                     symbolTable = stMaker.make() | ||||||
|  |  | ||||||
|                     postprocessSimplifiedAst(intermediateAst, symbolTable, compilationOptions, args.errors) |                     postprocessSimplifiedAst(intermediateAst, symbolTable, compilationOptions, args.errors) | ||||||
|                     args.errors.report() |                     args.errors.report() | ||||||
|  |                     symbolTable = stMaker.make()        // need an updated ST because the postprocessing changes stuff | ||||||
|  |  | ||||||
|                     if (compilationOptions.optimize) { |                     if (compilationOptions.optimize) { | ||||||
|                         optimizeSimplifiedAst(intermediateAst, compilationOptions, symbolTable, args.errors) |                         optimizeSimplifiedAst(intermediateAst, compilationOptions, symbolTable, args.errors) | ||||||
|                         args.errors.report() |                         args.errors.report() | ||||||
|  |                         symbolTable = stMaker.make()        // need an updated ST because the optimization changes stuff | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     if (args.printAst2) { |                     if (args.printAst2) { | ||||||
| @@ -204,6 +209,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? { | |||||||
|                 createAssemblyDuration = measureTime { |                 createAssemblyDuration = measureTime { | ||||||
|                     if (!createAssemblyAndAssemble( |                     if (!createAssemblyAndAssemble( | ||||||
|                             intermediateAst, |                             intermediateAst, | ||||||
|  |                             symbolTable, | ||||||
|                             args.errors, |                             args.errors, | ||||||
|                             compilationOptions, |                             compilationOptions, | ||||||
|                             program.generatedLabelSequenceNumber |                             program.generatedLabelSequenceNumber | ||||||
| @@ -558,6 +564,7 @@ private fun postprocessAst(program: Program, errors: IErrorReporter, compilerOpt | |||||||
| } | } | ||||||
|  |  | ||||||
| private fun createAssemblyAndAssemble(program: PtProgram, | private fun createAssemblyAndAssemble(program: PtProgram, | ||||||
|  |                                       symbolTable: SymbolTable, | ||||||
|                                       errors: IErrorReporter, |                                       errors: IErrorReporter, | ||||||
|                                       compilerOptions: CompilationOptions, |                                       compilerOptions: CompilationOptions, | ||||||
|                                       lastGeneratedLabelSequenceNr: Int |                                       lastGeneratedLabelSequenceNr: Int | ||||||
| @@ -572,10 +579,6 @@ private fun createAssemblyAndAssemble(program: PtProgram, | |||||||
|     else |     else | ||||||
|         throw NotImplementedError("no code generator for cpu ${compilerOptions.compTarget.cpu}") |         throw NotImplementedError("no code generator for cpu ${compilerOptions.compTarget.cpu}") | ||||||
|  |  | ||||||
|     // need to make a new symboltable here to capture possible changes made by optimization steps performed earlier! |  | ||||||
|     val stMaker = SymbolTableMaker(program, compilerOptions) |  | ||||||
|     val symbolTable = stMaker.make() |  | ||||||
|  |  | ||||||
|     val assembly = asmgen.generate(program, symbolTable, compilerOptions, errors) |     val assembly = asmgen.generate(program, symbolTable, compilerOptions, errors) | ||||||
|     errors.report() |     errors.report() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1277,11 +1277,6 @@ internal class AstChecker(private val program: Program, | |||||||
|                 errors.err("initialization value contains non-constant elements", array.value[0].position) |                 errors.err("initialization value contains non-constant elements", array.value[0].position) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if(array.value.any { it is StaticStructInitializer }) { |  | ||||||
|                 errors.err("it is not yet possible to use struct initializations in an array, you have to do it one by one for now", array.value[0].position) |  | ||||||
|                 // TODO this is because later in the simplified AST the allocate struct variable is still missing somehow |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } else if(array.parent is ForLoop) { |         } else if(array.parent is ForLoop) { | ||||||
|             if (!array.value.all { it.constValue(program) != null }) |             if (!array.value.all { it.constValue(program) != null }) | ||||||
|                 errors.err("array literal for iteration must contain constants. Try using a separate array variable instead?", array.position) |                 errors.err("array literal for iteration must contain constants. Try using a separate array variable instead?", array.position) | ||||||
|   | |||||||
| @@ -21,6 +21,8 @@ internal fun postprocessSimplifiedAst( | |||||||
| private fun processSubtypesIntoStReferences(program: PtProgram, st: SymbolTable) { | private fun processSubtypesIntoStReferences(program: PtProgram, st: SymbolTable) { | ||||||
|  |  | ||||||
|     fun getStStruct(subType: ISubType): StStruct { |     fun getStStruct(subType: ISubType): StStruct { | ||||||
|  |         if(subType is StStruct) | ||||||
|  |             return subType | ||||||
|         val stNode = st.lookup(subType.scopedNameString) as? StStruct |         val stNode = st.lookup(subType.scopedNameString) as? StStruct | ||||||
|         if(stNode != null) |         if(stNode != null) | ||||||
|             return stNode |             return stNode | ||||||
| @@ -28,7 +30,7 @@ private fun processSubtypesIntoStReferences(program: PtProgram, st: SymbolTable) | |||||||
|             throw FatalAstException("cannot find in ST: ${subType.scopedNameString} $subType") |             throw FatalAstException("cannot find in ST: ${subType.scopedNameString} $subType") | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun fixSubtype(type: DataType) { |     fun fixSubtypeIntoStType(type: DataType) { | ||||||
|         if(type.subType!=null && type.subType !is StStruct) { |         if(type.subType!=null && type.subType !is StStruct) { | ||||||
|             type.subType = getStStruct(type.subType!!) |             type.subType = getStStruct(type.subType!!) | ||||||
|         } |         } | ||||||
| @@ -36,13 +38,21 @@ private fun processSubtypesIntoStReferences(program: PtProgram, st: SymbolTable) | |||||||
|  |  | ||||||
|     fun fixSubtypes(node: PtNode) { |     fun fixSubtypes(node: PtNode) { | ||||||
|         when(node) { |         when(node) { | ||||||
|             is IPtVariable -> fixSubtype(node.type) |             is IPtVariable -> { | ||||||
|             is PtPointerDeref -> fixSubtype(node.type) |                 fixSubtypeIntoStType(node.type) | ||||||
|             is PtStructDecl -> node.fields.forEach { fixSubtype(it.first) } |                 // if it's an array, fix the subtypes of its elements as well | ||||||
|             is PtAsmSub -> node.returns.forEach { fixSubtype(it.second) } |                 if(node.type.isArray && node is PtVariable) { | ||||||
|             is PtExpression -> fixSubtype(node.type) |                     (node.value as? PtArray)?.let {array -> | ||||||
|             is PtSubSignature -> node.returns.forEach { fixSubtype(it) } |                         array.children.forEach { fixSubtypes(it) } | ||||||
|             is PtSubroutineParameter -> fixSubtype(node.type) |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             is PtPointerDeref -> fixSubtypeIntoStType(node.type) | ||||||
|  |             is PtStructDecl -> node.fields.forEach { fixSubtypeIntoStType(it.first) } | ||||||
|  |             is PtAsmSub -> node.returns.forEach { fixSubtypeIntoStType(it.second) } | ||||||
|  |             is PtExpression -> fixSubtypeIntoStType(node.type) | ||||||
|  |             is PtSubSignature -> node.returns.forEach { fixSubtypeIntoStType(it) } | ||||||
|  |             is PtSubroutineParameter -> fixSubtypeIntoStType(node.type) | ||||||
|             else -> { /* has no datatype */ } |             else -> { /* has no datatype */ } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import io.kotest.matchers.shouldBe | |||||||
| import io.kotest.matchers.string.shouldContain | import io.kotest.matchers.string.shouldContain | ||||||
| import prog8.ast.Program | import prog8.ast.Program | ||||||
| import prog8.code.INTERNED_STRINGS_MODULENAME | import prog8.code.INTERNED_STRINGS_MODULENAME | ||||||
|  | import prog8.code.PROG8_CONTAINER_MODULES | ||||||
| import prog8.code.core.IErrorReporter | import prog8.code.core.IErrorReporter | ||||||
| import prog8.code.source.SourceCode | import prog8.code.source.SourceCode | ||||||
| import prog8.compiler.ModuleImporter | import prog8.compiler.ModuleImporter | ||||||
| @@ -49,7 +50,7 @@ class TestModuleImporter: FunSpec({ | |||||||
|                 withClue(".file should point to specified path") { |                 withClue(".file should point to specified path") { | ||||||
|                     error1.file.absolutePath shouldBe "${srcPathAbs.normalize()}" |                     error1.file.absolutePath shouldBe "${srcPathAbs.normalize()}" | ||||||
|                 } |                 } | ||||||
|                 program.modules.size shouldBe 1 |                 program.modules.size shouldBe PROG8_CONTAINER_MODULES.size | ||||||
|                 val error2 = importer.importMainModule(srcPathAbs).getErrorOrElse { error("should have import error") } |                 val error2 = importer.importMainModule(srcPathAbs).getErrorOrElse { error("should have import error") } | ||||||
|                 withClue(".file should be normalized") { |                 withClue(".file should be normalized") { | ||||||
|                     "${error2.file}" shouldBe "${error2.file.normalize()}" |                     "${error2.file}" shouldBe "${error2.file.normalize()}" | ||||||
| @@ -57,7 +58,7 @@ class TestModuleImporter: FunSpec({ | |||||||
|                 withClue(".file should point to specified path") { |                 withClue(".file should point to specified path") { | ||||||
|                     error2.file.absolutePath shouldBe "${srcPathAbs.normalize()}" |                     error2.file.absolutePath shouldBe "${srcPathAbs.normalize()}" | ||||||
|                 } |                 } | ||||||
|                 program.modules.size shouldBe 1 |                 program.modules.size shouldBe PROG8_CONTAINER_MODULES.size | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             test("testDirectory") { |             test("testDirectory") { | ||||||
| @@ -75,7 +76,7 @@ class TestModuleImporter: FunSpec({ | |||||||
|                             it.file.absolutePath shouldBe "${srcPathAbs.normalize()}" |                             it.file.absolutePath shouldBe "${srcPathAbs.normalize()}" | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 program.modules.size shouldBe 1 |                 program.modules.size shouldBe PROG8_CONTAINER_MODULES.size | ||||||
|  |  | ||||||
|                 shouldThrow<FileSystemException> { importer.importMainModule(srcPathAbs) } |                 shouldThrow<FileSystemException> { importer.importMainModule(srcPathAbs) } | ||||||
|                     .let { |                     .let { | ||||||
| @@ -86,7 +87,7 @@ class TestModuleImporter: FunSpec({ | |||||||
|                             it.file.absolutePath shouldBe "${srcPathAbs.normalize()}" |                             it.file.absolutePath shouldBe "${srcPathAbs.normalize()}" | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 program.modules.size shouldBe 1 |                 program.modules.size shouldBe PROG8_CONTAINER_MODULES.size | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -101,7 +102,7 @@ class TestModuleImporter: FunSpec({ | |||||||
|                 val path = assumeReadableFile(searchIn[0], fileName) |                 val path = assumeReadableFile(searchIn[0], fileName) | ||||||
|  |  | ||||||
|                 val module = importer.importMainModule(path.absolute()).getOrElse { throw it } |                 val module = importer.importMainModule(path.absolute()).getOrElse { throw it } | ||||||
|                 program.modules.size shouldBe 2 |                 program.modules.size shouldBe PROG8_CONTAINER_MODULES.size+1 | ||||||
|                 module shouldBeIn program.modules |                 module shouldBeIn program.modules | ||||||
|                 module.program shouldBe program |                 module.program shouldBe program | ||||||
|             } |             } | ||||||
| @@ -118,7 +119,7 @@ class TestModuleImporter: FunSpec({ | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 val module = importer.importMainModule(path).getOrElse { throw it } |                 val module = importer.importMainModule(path).getOrElse { throw it } | ||||||
|                 program.modules.size shouldBe 2 |                 program.modules.size shouldBe PROG8_CONTAINER_MODULES.size+1 | ||||||
|                 module shouldBeIn program.modules |                 module shouldBeIn program.modules | ||||||
|                 module.program shouldBe program |                 module.program shouldBe program | ||||||
|             } |             } | ||||||
| @@ -131,7 +132,7 @@ class TestModuleImporter: FunSpec({ | |||||||
|                 assumeReadableFile(searchIn, path) |                 assumeReadableFile(searchIn, path) | ||||||
|  |  | ||||||
|                 val module = importer.importMainModule(path).getOrElse { throw it } |                 val module = importer.importMainModule(path).getOrElse { throw it } | ||||||
|                 program.modules.size shouldBe 2 |                 program.modules.size shouldBe PROG8_CONTAINER_MODULES.size+1 | ||||||
|                 module shouldBeIn program.modules |                 module shouldBeIn program.modules | ||||||
|                 module.program shouldBe program |                 module.program shouldBe program | ||||||
|             } |             } | ||||||
| @@ -152,7 +153,7 @@ class TestModuleImporter: FunSpec({ | |||||||
|                                 withClue("endCol; should be 0-based") { it.position.endCol shouldBe 6 } |                                 withClue("endCol; should be 0-based") { it.position.endCol shouldBe 6 } | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                         program.modules.size shouldBe 1 |                         program.modules.size shouldBe PROG8_CONTAINER_MODULES.size | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
| @@ -170,9 +171,10 @@ class TestModuleImporter: FunSpec({ | |||||||
|                             withClue("line; should be 1-based") { it.position.line shouldBe 2 } |                             withClue("line; should be 1-based") { it.position.line shouldBe 2 } | ||||||
|                             withClue("startCol; should be 0-based") { it.position.startCol shouldBe 4 } |                             withClue("startCol; should be 0-based") { it.position.startCol shouldBe 4 } | ||||||
|                             withClue("endCol; should be 0-based") { it.position.endCol shouldBe 6 } |                             withClue("endCol; should be 0-based") { it.position.endCol shouldBe 6 } | ||||||
|  |                             } | ||||||
|                         } |                         } | ||||||
|                     } |                         withClue("imported module with error in it should not be present") { program.modules.size shouldBe PROG8_CONTAINER_MODULES.size } | ||||||
|                     withClue("imported module with error in it should not be present") { program.modules.size shouldBe 1 } |                         program.modules.size shouldBe PROG8_CONTAINER_MODULES.size | ||||||
|                         program.modules[0].name shouldBe INTERNED_STRINGS_MODULENAME |                         program.modules[0].name shouldBe INTERNED_STRINGS_MODULENAME | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @@ -203,14 +205,14 @@ class TestModuleImporter: FunSpec({ | |||||||
|                     withClue(count[n] + " call / NO .p8 extension") { errors.noErrors() shouldBe false } |                     withClue(count[n] + " call / NO .p8 extension") { errors.noErrors() shouldBe false } | ||||||
|                     errors.errors.single() shouldContain "0:0: no module found with name i_do_not_exist" |                     errors.errors.single() shouldContain "0:0: no module found with name i_do_not_exist" | ||||||
|                     errors.report() |                     errors.report() | ||||||
|                     program.modules.size shouldBe 1 |                     program.modules.size shouldBe PROG8_CONTAINER_MODULES.size | ||||||
|  |  | ||||||
|                     val result2 = importer.importImplicitLibraryModule(filenameWithExt) |                     val result2 = importer.importImplicitLibraryModule(filenameWithExt) | ||||||
|                     withClue(count[n] + " call / with .p8 extension") { result2 shouldBe null } |                     withClue(count[n] + " call / with .p8 extension") { result2 shouldBe null } | ||||||
|                     withClue(count[n] + " call / with .p8 extension") { importer.errors.noErrors() shouldBe false } |                     withClue(count[n] + " call / with .p8 extension") { importer.errors.noErrors() shouldBe false } | ||||||
|                     errors.errors.single() shouldContain "0:0: no module found with name i_do_not_exist.p8" |                     errors.errors.single() shouldContain "0:0: no module found with name i_do_not_exist.p8" | ||||||
|                     errors.report() |                     errors.report() | ||||||
|                     program.modules.size shouldBe 1 |                     program.modules.size shouldBe PROG8_CONTAINER_MODULES.size | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -232,7 +234,7 @@ class TestModuleImporter: FunSpec({ | |||||||
|                                 withClue("endCol; should be 0-based") { it.position.endCol shouldBe 6 } |                                 withClue("endCol; should be 0-based") { it.position.endCol shouldBe 6 } | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                         program.modules.size shouldBe 1 |                         program.modules.size shouldBe PROG8_CONTAINER_MODULES.size | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
| @@ -254,7 +256,7 @@ class TestModuleImporter: FunSpec({ | |||||||
|                                 withClue("endCol; should be 0-based") { it.position.endCol shouldBe 6 } |                                 withClue("endCol; should be 0-based") { it.position.endCol shouldBe 6 } | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                         withClue("imported module with error in it should not be present") { program.modules.size shouldBe 1 } |                         withClue("imported module with error in it should not be present") { program.modules.size shouldBe PROG8_CONTAINER_MODULES.size } | ||||||
|                         program.modules[0].name shouldBe INTERNED_STRINGS_MODULENAME |                         program.modules[0].name shouldBe INTERNED_STRINGS_MODULENAME | ||||||
|                         importer.errors.report() |                         importer.errors.report() | ||||||
|                     } |                     } | ||||||
|   | |||||||
| @@ -1731,6 +1731,30 @@ main { | |||||||
|         compileText(Cx16Target(), false, src, outputDir) shouldNotBe null |         compileText(Cx16Target(), false, src, outputDir) shouldNotBe null | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     test("struct initializers in array") { | ||||||
|  |         val src=""" | ||||||
|  | main { | ||||||
|  |     struct Node { | ||||||
|  |         ubyte id | ||||||
|  |         str name | ||||||
|  |         uword array | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     sub start() { | ||||||
|  |         ^^Node[] @shared nodes = [ | ||||||
|  |             ^^Node:[1,"one", 1000 ], | ||||||
|  |             ^^Node:[2,"two", 2000 ], | ||||||
|  |             ^^Node:[3,"three", 3000], | ||||||
|  |             ^^Node:[], | ||||||
|  |             ^^Node:[], | ||||||
|  |             ^^Node:[], | ||||||
|  |         ] | ||||||
|  |     } | ||||||
|  | }""" | ||||||
|  |         compileText(C64Target(), false, src, outputDir) shouldNotBe null | ||||||
|  |         compileText(VMTarget(), false, src, outputDir) shouldNotBe null | ||||||
|  |     } | ||||||
|  |  | ||||||
|     test("type error for invalid bool field initializer") { |     test("type error for invalid bool field initializer") { | ||||||
|         val src=""" |         val src=""" | ||||||
| main { | main { | ||||||
|   | |||||||
| @@ -88,8 +88,8 @@ class TestSymbolTable: FunSpec({ | |||||||
|         val stVar1 = StStaticVariable("initialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false,node) |         val stVar1 = StStaticVariable("initialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false,node) | ||||||
|         stVar1.setOnetimeInitNumeric(99.0) |         stVar1.setOnetimeInitNumeric(99.0) | ||||||
|         val stVar2 = StStaticVariable("uninitialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false, node) |         val stVar2 = StStaticVariable("uninitialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false, node) | ||||||
|         val arrayInitNonzero = listOf(StArrayElement(1.1, null, null), StArrayElement(2.2, null, null), StArrayElement(3.3, null, null)) |         val arrayInitNonzero = listOf(StArrayElement(1.1, null, null, null, null), StArrayElement(2.2, null, null, null, null), StArrayElement(3.3, null, null,null, null)) | ||||||
|         val arrayInitAllzero = listOf(StArrayElement(0.0, null, null), StArrayElement(0.0, null, null), StArrayElement(0.0, null, null)) |         val arrayInitAllzero = listOf(StArrayElement(0.0, null, null, null, null), StArrayElement(0.0, null, null,null, null), StArrayElement(0.0, null, null,null, null)) | ||||||
|         val stVar3 = StStaticVariable("initialized", DataType.arrayFor(BaseDataType.UWORD), null, arrayInitNonzero, 3u, ZeropageWish.DONTCARE, 0u, false, node) |         val stVar3 = StStaticVariable("initialized", DataType.arrayFor(BaseDataType.UWORD), null, arrayInitNonzero, 3u, ZeropageWish.DONTCARE, 0u, false, node) | ||||||
|         val stVar4 = StStaticVariable("initialized", DataType.arrayFor(BaseDataType.UWORD), null, arrayInitAllzero, 3u, ZeropageWish.DONTCARE, 0u, false, node) |         val stVar4 = StStaticVariable("initialized", DataType.arrayFor(BaseDataType.UWORD), null, arrayInitAllzero, 3u, ZeropageWish.DONTCARE, 0u, false, node) | ||||||
|         val stVar5 = StStaticVariable("uninitialized", DataType.arrayFor(BaseDataType.UWORD), null, null, 3u, ZeropageWish.DONTCARE, 0u, false, node) |         val stVar5 = StStaticVariable("uninitialized", DataType.arrayFor(BaseDataType.UWORD), null, null, 3u, ZeropageWish.DONTCARE, 0u, false, node) | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import io.kotest.matchers.string.shouldContain | |||||||
| import prog8.ast.AstToSourceTextConverter | import prog8.ast.AstToSourceTextConverter | ||||||
| import prog8.ast.Module | import prog8.ast.Module | ||||||
| import prog8.ast.Program | import prog8.ast.Program | ||||||
| import prog8.code.INTERNED_STRINGS_MODULENAME | import prog8.code.PROG8_CONTAINER_MODULES | ||||||
| import prog8.code.source.SourceCode | import prog8.code.source.SourceCode | ||||||
| import prog8.parser.ParseError | import prog8.parser.ParseError | ||||||
| import prog8.parser.Prog8Parser.parseModule | import prog8.parser.Prog8Parser.parseModule | ||||||
| @@ -38,10 +38,12 @@ class TestAstToSourceText: AnnotationSpec() { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Test |     @Test | ||||||
|     fun testMentionsInternedStringsModule() { |     fun testMentionsProg8ContainerModules() { | ||||||
|         val orig = SourceCode.Text("\n") |         val orig = SourceCode.Text("\n") | ||||||
|         val (txt, _) = roundTrip(parseModule(orig)) |         val (txt, _) = roundTrip(parseModule(orig)) | ||||||
|         txt shouldContain Regex(";.*$INTERNED_STRINGS_MODULENAME") |         PROG8_CONTAINER_MODULES.forEach { | ||||||
|  |             txt shouldContain Regex(";.*$it") | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Test |     @Test | ||||||
|   | |||||||
| @@ -13,10 +13,11 @@ import io.kotest.matchers.types.shouldBeSameInstanceAs | |||||||
| import prog8.ast.Module | import prog8.ast.Module | ||||||
| import prog8.ast.Program | import prog8.ast.Program | ||||||
| import prog8.ast.statements.Block | import prog8.ast.statements.Block | ||||||
|  | import prog8.code.INTERNED_STRINGS_MODULENAME | ||||||
|  | import prog8.code.PROG8_CONTAINER_MODULES | ||||||
| import prog8.code.ast.PtBlock | import prog8.code.ast.PtBlock | ||||||
| import prog8.code.core.Position | import prog8.code.core.Position | ||||||
| import prog8.code.source.SourceCode | import prog8.code.source.SourceCode | ||||||
| import prog8.code.INTERNED_STRINGS_MODULENAME |  | ||||||
| import prog8.code.target.C64Target | import prog8.code.target.C64Target | ||||||
| import prog8tests.helpers.DummyFunctions | import prog8tests.helpers.DummyFunctions | ||||||
| import prog8tests.helpers.DummyMemsizer | import prog8tests.helpers.DummyMemsizer | ||||||
| @@ -30,7 +31,7 @@ class TestProgram: FunSpec({ | |||||||
|     context("Constructor") { |     context("Constructor") { | ||||||
|         test("withNameBuiltinsAndMemsizer") { |         test("withNameBuiltinsAndMemsizer") { | ||||||
|             val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder) |             val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder) | ||||||
|             program.modules.size shouldBe 1 |             program.modules.size shouldBe PROG8_CONTAINER_MODULES.size | ||||||
|             program.modules[0].name shouldBe INTERNED_STRINGS_MODULENAME |             program.modules[0].name shouldBe INTERNED_STRINGS_MODULENAME | ||||||
|             program.modules[0].program shouldBeSameInstanceAs program |             program.modules[0].program shouldBeSameInstanceAs program | ||||||
|             program.modules[0].parent shouldBeSameInstanceAs program.namespace |             program.modules[0].parent shouldBeSameInstanceAs program.namespace | ||||||
| @@ -45,7 +46,7 @@ class TestProgram: FunSpec({ | |||||||
|             val retVal = program.addModule(m1) |             val retVal = program.addModule(m1) | ||||||
|  |  | ||||||
|             retVal shouldBeSameInstanceAs program |             retVal shouldBeSameInstanceAs program | ||||||
|             program.modules.size shouldBe 2 |             program.modules.size shouldBe PROG8_CONTAINER_MODULES.size + 1 | ||||||
|             m1 shouldBeIn program.modules |             m1 shouldBeIn program.modules | ||||||
|             m1.program shouldBeSameInstanceAs program |             m1.program shouldBeSameInstanceAs program | ||||||
|             m1.parent shouldBeSameInstanceAs program.namespace |             m1.parent shouldBeSameInstanceAs program.namespace | ||||||
| @@ -163,7 +164,7 @@ datablock2 ${'$'}8000 { | |||||||
|  |  | ||||||
|         val result = compileText(C64Target(), optimize=false, src, outputDir, writeAssembly=true)!! |         val result = compileText(C64Target(), optimize=false, src, outputDir, writeAssembly=true)!! | ||||||
|         result.compilerAst.allBlocks.size shouldBeGreaterThan 5 |         result.compilerAst.allBlocks.size shouldBeGreaterThan 5 | ||||||
|         result.compilerAst.modules.drop(2).all { it.isLibrary } shouldBe true |         result.compilerAst.modules.drop(PROG8_CONTAINER_MODULES.size+1).all { it.isLibrary } shouldBe true | ||||||
|         val mainMod = result.compilerAst.modules[0] |         val mainMod = result.compilerAst.modules[0] | ||||||
|         mainMod.name shouldStartWith "on_the_fly" |         mainMod.name shouldStartWith "on_the_fly" | ||||||
|         result.compilerAst.modules[1].name shouldBe "prog8_interned_strings" |         result.compilerAst.modules[1].name shouldBe "prog8_interned_strings" | ||||||
| @@ -183,7 +184,7 @@ datablock2 ${'$'}8000 { | |||||||
|         blocks[1].name shouldBe "p8_sys_startup" |         blocks[1].name shouldBe "p8_sys_startup" | ||||||
|         blocks[2].name shouldBe "p8b_otherblock1" |         blocks[2].name shouldBe "p8b_otherblock1" | ||||||
|         blocks[3].name shouldBe "p8b_otherblock2" |         blocks[3].name shouldBe "p8b_otherblock2" | ||||||
|         blocks[4].name shouldBe "prog8_interned_strings" |         blocks[4].name shouldBe INTERNED_STRINGS_MODULENAME | ||||||
|         blocks[5].name shouldBe "txt" |         blocks[5].name shouldBe "txt" | ||||||
|         blocks[5].library shouldBe true |         blocks[5].library shouldBe true | ||||||
|         blocks[13].name shouldBe "p8b_datablock2" |         blocks[13].name shouldBe "p8b_datablock2" | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import prog8.ast.statements.* | |||||||
| import prog8.ast.walk.IAstVisitor | import prog8.ast.walk.IAstVisitor | ||||||
| import prog8.code.GENERATED_LABEL_PREFIX | import prog8.code.GENERATED_LABEL_PREFIX | ||||||
| import prog8.code.INTERNED_STRINGS_MODULENAME | import prog8.code.INTERNED_STRINGS_MODULENAME | ||||||
|  | import prog8.code.PROG8_CONTAINER_MODULES | ||||||
| import prog8.code.core.* | import prog8.code.core.* | ||||||
| import prog8.code.source.SourceCode | import prog8.code.source.SourceCode | ||||||
|  |  | ||||||
| @@ -22,17 +23,19 @@ class Program(val name: String, | |||||||
|     val namespace: GlobalNamespace = GlobalNamespace(_modules) |     val namespace: GlobalNamespace = GlobalNamespace(_modules) | ||||||
|  |  | ||||||
|     init { |     init { | ||||||
|         // insert a container module for all interned strings later |         // insert container modules for all interned strings and struct instances | ||||||
|         val internedStringsModule = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated(INTERNED_STRINGS_MODULENAME)) |         PROG8_CONTAINER_MODULES.forEach { containername -> | ||||||
|         val block = Block(INTERNED_STRINGS_MODULENAME, null, mutableListOf(), true, Position.DUMMY) |             val module = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated(containername)) | ||||||
|         val directive = Directive("%option", listOf(DirectiveArg("no_symbol_prefixing", null, Position.DUMMY)), Position.DUMMY) |             val block = Block(containername, null, mutableListOf(), true, Position.DUMMY) | ||||||
|         block.statements.add(directive) |             val directive = Directive("%option", listOf(DirectiveArg("no_symbol_prefixing", null, Position.DUMMY)), Position.DUMMY) | ||||||
|         directive.linkParents(block) |             block.statements.add(directive) | ||||||
|         internedStringsModule.statements.add(block) |             directive.linkParents(block) | ||||||
|  |             module.statements.add(block) | ||||||
|  |  | ||||||
|         _modules.add(0, internedStringsModule) |             _modules.add(0, module) | ||||||
|         internedStringsModule.linkParents(namespace) |             module.linkParents(namespace) | ||||||
|         internedStringsModule.program = this |             module.program = this | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun addModule(module: Module): Program { |     fun addModule(module: Module): Program { | ||||||
| @@ -67,7 +70,7 @@ class Program(val name: String, | |||||||
|         } |         } | ||||||
|  |  | ||||||
|     val toplevelModule: Module |     val toplevelModule: Module | ||||||
|         get() = modules.first { it.name!= INTERNED_STRINGS_MODULENAME } |         get() = modules.first { it.name !in PROG8_CONTAINER_MODULES } | ||||||
|  |  | ||||||
|     private val internedStringsReferenceCounts = mutableMapOf<VarDecl, Int>() |     private val internedStringsReferenceCounts = mutableMapOf<VarDecl, Int>() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -52,10 +52,7 @@ needs_sphinx = '5.3' | |||||||
| # Add any Sphinx extension module names here, as strings. They can be | # Add any Sphinx extension module names here, as strings. They can be | ||||||
| # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | ||||||
| # ones. | # ones. | ||||||
| extensions = [ 'sphinxcontrib.jquery', 'sphinx_rtd_dark_mode'] | extensions = [ 'sphinxcontrib.jquery', 'sphinx_rtd_dark_mode', 'sphinx.ext.imgconverter'] | ||||||
|  |  | ||||||
| # user starts in light mode |  | ||||||
| default_dark_mode = False |  | ||||||
|  |  | ||||||
| # Add any paths that contain templates here, relative to this directory. | # Add any paths that contain templates here, relative to this directory. | ||||||
| templates_path = ['_templates'] | templates_path = ['_templates'] | ||||||
| @@ -177,6 +174,9 @@ texinfo_documents = [ | |||||||
|  |  | ||||||
| # -- Extension configuration ------------------------------------------------- | # -- Extension configuration ------------------------------------------------- | ||||||
|  |  | ||||||
|  | # user starts in light mode | ||||||
|  | default_dark_mode = False | ||||||
|  |  | ||||||
| # -- Options for to do extension ---------------------------------------------- | # -- Options for to do extension ---------------------------------------------- | ||||||
|  |  | ||||||
| # todo_include_todos = True | # todo_include_todos = True | ||||||
|   | |||||||
| @@ -58,7 +58,8 @@ and for example the below code omits line 5:: | |||||||
| STRUCTS and TYPED POINTERS | STRUCTS and TYPED POINTERS | ||||||
| -------------------------- | -------------------------- | ||||||
|  |  | ||||||
| - allow struct initialization syntax in an array such as [ ^^Node:[], ^^Node:[], ^^Node:[] ],  update sorting example to use list of countries like that | - can we have some syntactic sugar to avoid the struct name pointer prefix for all array elements that are a struct instance? | ||||||
|  | - fix VM so that pointers/sorting.p8 example works again (it worked when adding the struct instances in a loop, no longer now that they're static) | ||||||
| - fix code size regressions (if any left) | - fix code size regressions (if any left) | ||||||
| - optimize deref in PointerAssignmentsGen: optimize 'forceTemporary' to only use a temporary when the offset is >0 | - optimize deref in PointerAssignmentsGen: optimize 'forceTemporary' to only use a temporary when the offset is >0 | ||||||
| - update structpointers.rst docs with 6502 specific things? | - update structpointers.rst docs with 6502 specific things? | ||||||
| @@ -79,6 +80,7 @@ STRUCTS and TYPED POINTERS | |||||||
| Future Things and Ideas | Future Things and Ideas | ||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^ | ||||||
|  |  | ||||||
|  | - allow memory() to occur in array initializer | ||||||
| - %breakpoint after an assignment is parsed as part of the expression (x % breakpoint), that should not happen | - %breakpoint after an assignment is parsed as part of the expression (x % breakpoint), that should not happen | ||||||
| - when a complete block is removed because unused, suppress all info messages about everything in the block being removed | - when a complete block is removed because unused, suppress all info messages about everything in the block being removed | ||||||
| - fix the line, cols in Position, sometimes they count from 0 sometimes from 1 | - fix the line, cols in Position, sometimes they count from 0 sometimes from 1 | ||||||
|   | |||||||
| @@ -282,9 +282,10 @@ For instance ``30_000.999_999`` is a valid floating point number 30000.999999. | |||||||
|  |  | ||||||
| Arrays | Arrays | ||||||
| ^^^^^^ | ^^^^^^ | ||||||
| Arrays can be created from a list of booleans, bytes, words, floats, or addresses of other variables | Arrays can be created from a list of booleans, bytes, words, floats, addresses of other variables | ||||||
| (such as explicit address-of expressions, strings, or other array variables) - values in an array literal | (such as explicit address-of expressions, strings, or other array variables), and struct initializers. | ||||||
| always have to be constants. A trailing comma is allowed, sometimes this is easier when copying values | The values in an array literal always have to be constants. | ||||||
|  | A trailing comma is allowed, sometimes this is easier when copying values | ||||||
| or when adding more stuff to the array later. Here are some examples of arrays:: | or when adding more stuff to the array later. Here are some examples of arrays:: | ||||||
|  |  | ||||||
|     byte[10]  array                   ; array of 10 bytes, initially set to 0 |     byte[10]  array                   ; array of 10 bytes, initially set to 0 | ||||||
|   | |||||||
| @@ -11,34 +11,32 @@ main{ | |||||||
|         uword area              ; 1000 km^2 |         uword area              ; 1000 km^2 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ^^Country[100] countries        ; won't be fully filled |     ^^Country[] countries = [ | ||||||
|     ubyte num_countries |         ^^Country:["Indonesia", 285.72, 1904], | ||||||
|  |         ^^Country:["Congo", 112.83, 2344], | ||||||
|  |         ^^Country:["Vietnam", 101.60, 331], | ||||||
|  |         ^^Country:["United States", 347.28, 9372], | ||||||
|  |         ^^Country:["Iran", 92.42, 1648], | ||||||
|  |         ^^Country:["Turkey", 87.69, 783], | ||||||
|  |         ^^Country:["Brazil", 212.81, 8515], | ||||||
|  |         ^^Country:["Bangladesh", 175.69, 147], | ||||||
|  |         ^^Country:["Germany", 84.08, 357], | ||||||
|  |         ^^Country:["Japan", 123.10, 377], | ||||||
|  |         ^^Country:["India", 1463.87, 3287], | ||||||
|  |         ^^Country:["China", 1416.10, 9596], | ||||||
|  |         ^^Country:["Philippines", 116.79, 300], | ||||||
|  |         ^^Country:["Russia", 143.99, 17098], | ||||||
|  |         ^^Country:["Pakistan", 255.22, 881], | ||||||
|  |         ^^Country:["Nigeria", 237.53, 923], | ||||||
|  |         ^^Country:["Ethiopia", 135.47, 1104], | ||||||
|  |         ^^Country:["Mexico", 131.95, 1964], | ||||||
|  |         ^^Country:["Thailand", 71.62, 513], | ||||||
|  |         ^^Country:["Egypt", 118.37, 1002], | ||||||
|  |     ] | ||||||
|  |  | ||||||
|     sub start() { |     sub start() { | ||||||
|         txt.lowercase() |         txt.lowercase() | ||||||
|  |  | ||||||
|         ; because pointer array initialization is not supported yet, we have to add the countries in separate statements for now |  | ||||||
|         add(^^Country:["Indonesia", 285.72, 1904]) |  | ||||||
|         add(^^Country:["Congo", 112.83, 2344]) |  | ||||||
|         add(^^Country:["Vietnam", 101.60, 331]) |  | ||||||
|         add(^^Country:["United States", 347.28, 9372]) |  | ||||||
|         add(^^Country:["Iran", 92.42, 1648]) |  | ||||||
|         add(^^Country:["Turkey", 87.69, 783]) |  | ||||||
|         add(^^Country:["Brazil", 212.81, 8515]) |  | ||||||
|         add(^^Country:["Bangladesh", 175.69, 147]) |  | ||||||
|         add(^^Country:["Germany", 84.08, 357]) |  | ||||||
|         add(^^Country:["Japan", 123.10, 377]) |  | ||||||
|         add(^^Country:["India", 1463.87, 3287]) |  | ||||||
|         add(^^Country:["China", 1416.10, 9596]) |  | ||||||
|         add(^^Country:["Philippines", 116.79, 300]) |  | ||||||
|         add(^^Country:["Russia", 143.99, 17098]) |  | ||||||
|         add(^^Country:["Pakistan", 255.22, 881]) |  | ||||||
|         add(^^Country:["Nigeria", 237.53, 923]) |  | ||||||
|         add(^^Country:["Ethiopia", 135.47, 1104]) |  | ||||||
|         add(^^Country:["Mexico", 131.95, 1964]) |  | ||||||
|         add(^^Country:["Thailand", 71.62, 513]) |  | ||||||
|         add(^^Country:["Egypt", 118.37, 1002]) |  | ||||||
|  |  | ||||||
|         txt.print("UNSORTED:\n") |         txt.print("UNSORTED:\n") | ||||||
|         dump() |         dump() | ||||||
|  |  | ||||||
| @@ -57,7 +55,7 @@ main{ | |||||||
|  |  | ||||||
|     sub sort_by_name() { |     sub sort_by_name() { | ||||||
|         ; stupid slow bubble sort |         ; stupid slow bubble sort | ||||||
|         ubyte n = num_countries |         ubyte n = len(countries) | ||||||
|         do { |         do { | ||||||
|             ubyte newn=0 |             ubyte newn=0 | ||||||
|             ubyte i |             ubyte i | ||||||
| @@ -73,7 +71,7 @@ main{ | |||||||
|  |  | ||||||
|     sub sort_by_population() { |     sub sort_by_population() { | ||||||
|         ; stupid slow bubble sort |         ; stupid slow bubble sort | ||||||
|         ubyte n = num_countries |         ubyte n = len(countries) | ||||||
|         do { |         do { | ||||||
|             ubyte newn=0 |             ubyte newn=0 | ||||||
|             ubyte i |             ubyte i | ||||||
| @@ -89,7 +87,7 @@ main{ | |||||||
|  |  | ||||||
|     sub sort_by_area() { |     sub sort_by_area() { | ||||||
|         ; stupid slow bubble sort |         ; stupid slow bubble sort | ||||||
|         ubyte n = num_countries |         ubyte n = len(countries) | ||||||
|         do { |         do { | ||||||
|             ubyte newn=0 |             ubyte newn=0 | ||||||
|             ubyte i |             ubyte i | ||||||
| @@ -125,10 +123,5 @@ main{ | |||||||
|             txt.nl() |             txt.nl() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     sub add(^^Country c) { |  | ||||||
|         countries[num_countries] = c |  | ||||||
|         num_countries++ |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,19 +8,20 @@ main { | |||||||
|         uword array |         uword array | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ^^Node @shared @zp node = 2000 |  | ||||||
|  |  | ||||||
|     sub start() { |     sub start() { | ||||||
|         ^^Node[] nodes = [ |         ^^Node[] nodes = [ | ||||||
|             ^^Node:[1,"one", 1000 ], |             ^^Node:[1,"one", 1000 ], | ||||||
|             ^^Node:[2,"two", 2000 ], |             ^^Node:[2,"two", 2000 ], | ||||||
|             ^^Node:[3,"three", 3000] |             ^^Node:[3,"three", 3000], | ||||||
|  |             ^^Node:[], | ||||||
|  |             ^^Node:[], | ||||||
|  |             ^^Node:[], | ||||||
|         ] |         ] | ||||||
|         txt.print_uw(nodes[0]) |  | ||||||
|         txt.spc() |         for cx16.r0 in nodes { | ||||||
|         txt.print_uw(nodes[1]) |             txt.print_uw(cx16.r0) | ||||||
|         txt.spc() |             txt.spc() | ||||||
|         txt.print_uw(nodes[2]) |         } | ||||||
|         txt.nl() |         txt.nl() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| package prog8.intermediate | package prog8.intermediate | ||||||
|  |  | ||||||
| import prog8.code.INTERNED_STRINGS_MODULENAME | import prog8.code.PROG8_CONTAINER_MODULES | ||||||
| import prog8.code.core.BaseDataType | import prog8.code.core.BaseDataType | ||||||
| import prog8.code.core.DataType | import prog8.code.core.DataType | ||||||
| import prog8.code.core.Encoding | import prog8.code.core.Encoding | ||||||
| @@ -49,10 +49,9 @@ class IRSymbolTable { | |||||||
|         val prefix = "$label." |         val prefix = "$label." | ||||||
|         val vars = table.filter { it.key.startsWith(prefix) } |         val vars = table.filter { it.key.startsWith(prefix) } | ||||||
|         vars.forEach { |         vars.forEach { | ||||||
|             // check if attempt is made to delete interned strings, if so, refuse that. |             // check if attempt is made to delete fixed modules, if so, refuse that. | ||||||
|             if(!it.key.startsWith(INTERNED_STRINGS_MODULENAME)) { |             if(!PROG8_CONTAINER_MODULES.any { containername -> it.key.startsWith(containername)}) | ||||||
|                 table.remove(it.key) |                 table.remove(it.key) | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -123,7 +123,7 @@ class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GL | |||||||
|             val scopehash = call.parent.hashCode().toUInt().toString(16) |             val scopehash = call.parent.hashCode().toUInt().toString(16) | ||||||
|             val pos = "${call.position.line}_${call.position.startCol}" |             val pos = "${call.position.line}_${call.position.startCol}" | ||||||
|             val hash = call.position.file.hashCode().toUInt().toString(16) |             val hash = call.position.file.hashCode().toUInt().toString(16) | ||||||
|             return "prog8_struct_${structname.replace('.', '_')}_${hash}_${pos}_${scopehash}" |             return "${structname.replace('.', '_')}_${hash}_${pos}_${scopehash}" | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -338,13 +338,18 @@ class StExtSub(name: String, | |||||||
|  |  | ||||||
| class StSubroutineParameter(val name: String, val type: DataType, val register: RegisterOrPair?) | class StSubroutineParameter(val name: String, val type: DataType, val register: RegisterOrPair?) | ||||||
| class StExtSubParameter(val register: RegisterOrStatusflag, val type: DataType) | class StExtSubParameter(val register: RegisterOrStatusflag, val type: DataType) | ||||||
| class StArrayElement(val number: Double?, val addressOfSymbol: String?, val boolean: Boolean?) { | class StArrayElement(val number: Double?, val addressOfSymbol: String?, val structInstance: String?, val structInstanceUninitialized: String?, val boolean: Boolean?) { | ||||||
|     init { |     init { | ||||||
|         if(number!=null) require(addressOfSymbol==null && boolean==null) |         if(number!=null) require(addressOfSymbol==null && boolean==null && structInstance==null && structInstanceUninitialized==null) | ||||||
|         if(addressOfSymbol!=null) require(number==null && boolean==null) |         if(addressOfSymbol!=null) require(number==null && boolean==null && structInstance==null && structInstanceUninitialized==null) | ||||||
|         if(boolean!=null) require(addressOfSymbol==null && number==null) |         if(structInstance!=null) require(number==null && boolean==null && addressOfSymbol==null && structInstanceUninitialized==null) | ||||||
|  |         if(structInstanceUninitialized!=null) require(number==null && boolean==null && addressOfSymbol==null && structInstance==null) | ||||||
|  |         if(boolean!=null) require(addressOfSymbol==null && number==null &&structInstance==null && structInstanceUninitialized==null) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| typealias StString = Pair<String, Encoding> | typealias StString = Pair<String, Encoding> | ||||||
| typealias StArray = List<StArrayElement> | typealias StArray = List<StArrayElement> | ||||||
|  |  | ||||||
|  | const val StMemorySlabBlockName = "prog8_slabs" | ||||||
|  | const val StStructInstanceBlockName = "prog8_struct_instances" | ||||||
|   | |||||||
| @@ -82,7 +82,7 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp | |||||||
|                             numElements = (value.value.length + 1).toUInt()   // include the terminating 0-byte |                             numElements = (value.value.length + 1).toUInt()   // include the terminating 0-byte | ||||||
|                         } |                         } | ||||||
|                         is PtArray -> { |                         is PtArray -> { | ||||||
|                             initialArray = makeInitialArray(value) |                             initialArray = makeInitialArray(value, scope) | ||||||
|                             initialString = null |                             initialString = null | ||||||
|                             initialNumeric = null |                             initialNumeric = null | ||||||
|                             numElements = initialArray.size.toUInt() |                             numElements = initialArray.size.toUInt() | ||||||
| @@ -119,22 +119,12 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp | |||||||
|                     val size = (node.args[1] as PtNumber).number.toUInt() |                     val size = (node.args[1] as PtNumber).number.toUInt() | ||||||
|                     val align = (node.args[2] as PtNumber).number.toUInt() |                     val align = (node.args[2] as PtNumber).number.toUInt() | ||||||
|                     // don't add memory slabs in nested scope, just put them in the top level of the ST |                     // don't add memory slabs in nested scope, just put them in the top level of the ST | ||||||
|                     scope.first().add(StMemorySlab("prog8_memoryslab_$slabname", size, align, node)) |                     scope.first().add(StMemorySlab("memory_$slabname", size, align, node)) | ||||||
|                 } |                 } | ||||||
|                 else if(node.name=="prog8_lib_structalloc") { |                 else if(node.name=="prog8_lib_structalloc") { | ||||||
|                     val struct = node.type.subType!! |                     val instance = handleStructAllocation(node) | ||||||
|                     if(struct is StStruct) { |                     if(instance!=null) { | ||||||
|                         val label =  SymbolTable.labelnameForStructInstance(node) |                         scope.first().add(instance)  // don't add struct instances in nested scope, just put them in the top level of the ST | ||||||
|                         val initialValues = node.args.map { |  | ||||||
|                             when(it) { |  | ||||||
|                                 is PtAddressOf -> StArrayElement(null, it.identifier!!.name, null) |  | ||||||
|                                 is PtBool -> StArrayElement(null, null, it.value) |  | ||||||
|                                 is PtNumber -> StArrayElement(it.number, null, null) |  | ||||||
|                                 else -> throw AssemblyError("invalid structalloc argument type $it") |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         val scopedName = if(struct.astNode!=null) (struct.astNode as PtNamedNode).scopedName else struct.scopedNameString |  | ||||||
|                         scope.first().add(StStructInstance(label, scopedName, initialValues, struct.size, null)) |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 null |                 null | ||||||
| @@ -153,20 +143,50 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp | |||||||
|             scope.removeLast() |             scope.removeLast() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private fun makeInitialArray(value: PtArray): List<StArrayElement> { |     private fun handleStructAllocation(node: PtBuiltinFunctionCall): StStructInstance? { | ||||||
|  |         val struct = node.type.subType as? StStruct ?: return null | ||||||
|  |         val initialValues = node.args.map { | ||||||
|  |             when(it) { | ||||||
|  |                 is PtAddressOf -> StArrayElement(null, it.identifier!!.name, null, null,null) | ||||||
|  |                 is PtBool -> StArrayElement(null, null, null, null, it.value) | ||||||
|  |                 is PtNumber -> StArrayElement(it.number, null, null, null, null) | ||||||
|  |                 else -> throw AssemblyError("invalid structalloc argument type $it") | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         val label =  SymbolTable.labelnameForStructInstance(node) | ||||||
|  |         val scopedStructName = if(struct.astNode!=null) (struct.astNode as PtNamedNode).scopedName else struct.scopedNameString | ||||||
|  |         return StStructInstance(label, scopedStructName, initialValues, struct.size, null) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun makeInitialArray(value: PtArray, scope: ArrayDeque<StNode>): List<StArrayElement> { | ||||||
|         return value.children.map { |         return value.children.map { | ||||||
|             when(it) { |             when(it) { | ||||||
|                 is PtAddressOf -> { |                 is PtAddressOf -> { | ||||||
|                     when { |                     when { | ||||||
|                         it.isFromArrayElement -> TODO("address-of array element $it in initial array value") |                         it.isFromArrayElement -> TODO("address-of array element $it in initial array value") | ||||||
|                         else -> StArrayElement(null, it.identifier!!.name, null) |                         else -> StArrayElement(null, it.identifier!!.name, null, null,null) | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 is PtNumber -> StArrayElement(it.number, null, null) |                 is PtNumber -> StArrayElement(it.number, null, null,null,null) | ||||||
|                 is PtBool -> StArrayElement(null, null, it.value) |                 is PtBool -> StArrayElement(null, null, null,null,it.value) | ||||||
|                 is PtBuiltinFunctionCall -> { |                 is PtBuiltinFunctionCall -> { | ||||||
|                     val labelname = SymbolTable.labelnameForStructInstance(it) |                     if(it.name=="prog8_lib_structalloc") { | ||||||
|                     StArrayElement(null, labelname, null) |                         val instance = handleStructAllocation(it) | ||||||
|  |                         if(instance==null) { | ||||||
|  |                             val label = SymbolTable.labelnameForStructInstance(it) | ||||||
|  |                             if (it.args.isEmpty()) | ||||||
|  |                                 StArrayElement(null, null, null, label, null) | ||||||
|  |                             else | ||||||
|  |                                 StArrayElement(null, null, label, null, null) | ||||||
|  |                         } else { | ||||||
|  |                             scope.first().add(instance)  // don't add struct instances in nested scope, just put them in the top level of the ST | ||||||
|  |                             if (it.args.isEmpty()) | ||||||
|  |                                 StArrayElement(null, null, null, instance.name, null) | ||||||
|  |                             else | ||||||
|  |                                 StArrayElement(null, null, instance.name, null, null) | ||||||
|  |                         } | ||||||
|  |                     } else | ||||||
|  |                         TODO("support for initial array element via ${it.name}  ${it.position}") | ||||||
|                 } |                 } | ||||||
|                 else -> throw AssemblyError("invalid array element $it") |                 else -> throw AssemblyError("invalid array element $it") | ||||||
|             } |             } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user