mirror of
https://github.com/irmen/prog8.git
synced 2025-10-25 05:18:38 +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
|
||||
|
||||
|
||||
// the automatically generated module where all string literals are interned to:
|
||||
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:
|
||||
const val GENERATED_LABEL_PREFIX = "p8_label_gen_"
|
||||
|
||||
|
||||
@@ -252,6 +252,14 @@ private fun PtVariable.prefix(parent: PtNode, st: SymbolTable): PtVariable {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package prog8.codegen.cpu6502
|
||||
|
||||
import prog8.code.StMemorySlabBlockName
|
||||
import prog8.code.StStructInstanceBlockName
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
@@ -385,7 +387,7 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
val name = (fcall.args[0] as PtString).value
|
||||
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)
|
||||
addressOf.add(slabname)
|
||||
addressOf.parent = fcall
|
||||
@@ -399,9 +401,10 @@ internal class BuiltinFunctionsAsmGen(private val program: PtProgram,
|
||||
if(discardResult)
|
||||
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
|
||||
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)
|
||||
addressOf.add(PtIdentifier(slabname, fcall.type, fcall.position))
|
||||
addressOf.add(labelname)
|
||||
addressOf.parent = fcall
|
||||
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, fcall.type, expression = addressOf)
|
||||
val target = AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, fcall.position, null, asmgen)
|
||||
|
||||
@@ -210,7 +210,7 @@ internal class ProgramAndVarsGen(
|
||||
private fun memorySlabs() {
|
||||
if(symboltable.allMemorySlabs.isNotEmpty()) {
|
||||
asmgen.out("; memory slabs\n .section BSS_SLABS")
|
||||
asmgen.out("prog8_slabs\t.block")
|
||||
asmgen.out("$StMemorySlabBlockName\t.block")
|
||||
for (slab in symboltable.allMemorySlabs) {
|
||||
if (slab.align > 1u)
|
||||
asmgen.out("\t.align ${slab.align.toHex()}")
|
||||
@@ -434,6 +434,7 @@ internal class ProgramAndVarsGen(
|
||||
val (instancesNoInit, instances) = symboltable.allStructInstances.partition { it.initialValues.isEmpty() }
|
||||
asmgen.out("; struct instances without initialization values, as BSS zeroed at startup\n")
|
||||
asmgen.out(" .section BSS\n")
|
||||
asmgen.out("${StStructInstanceBlockName}_bss .block\n")
|
||||
instancesNoInit.forEach {
|
||||
val structtype: StStruct = symboltable.lookup(it.structName) as StStruct
|
||||
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(" .endblock\n")
|
||||
asmgen.out(" .send BSS\n")
|
||||
|
||||
asmgen.out("; struct instances with initialization values\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")
|
||||
}
|
||||
|
||||
@@ -866,7 +873,7 @@ internal class ProgramAndVarsGen(
|
||||
}
|
||||
}
|
||||
dt.isSplitWordArray -> {
|
||||
if(dt.elementType().isUnsignedWord) {
|
||||
if(dt.elementType().isUnsignedWord || dt.elementType().isPointer) {
|
||||
val data = makeArrayFillDataUnsigned(dt, value, orNumberOfZeros)
|
||||
asmgen.out("_array_$varname := ${data.joinToString()}")
|
||||
asmgen.out("${varname}_lsb\t.byte <_array_$varname")
|
||||
@@ -914,7 +921,7 @@ internal class ProgramAndVarsGen(
|
||||
private fun zeroFilledArray(numElts: Int): StArray {
|
||||
val values = mutableListOf<StArrayElement>()
|
||||
repeat(numElts) {
|
||||
values.add(StArrayElement(0.0, null, null))
|
||||
values.add(StArrayElement(0.0, null, null,null,null))
|
||||
}
|
||||
return values
|
||||
}
|
||||
@@ -972,7 +979,7 @@ internal class ProgramAndVarsGen(
|
||||
val number = it.number!!.toInt()
|
||||
"$"+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) {
|
||||
"$" + it.number!!.toInt().toString(16).padStart(4, '0')
|
||||
}
|
||||
@@ -984,8 +991,15 @@ internal class ProgramAndVarsGen(
|
||||
else
|
||||
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")
|
||||
}
|
||||
}
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package prog8.codegen.intermediate
|
||||
|
||||
import prog8.code.StMemorySlabBlockName
|
||||
import prog8.code.StStructInstanceBlockName
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.*
|
||||
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 code = IRCodeChunk(null, null)
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -508,7 +510,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
||||
val code = IRCodeChunk(null, null)
|
||||
val resultReg = codeGen.registers.next(IRDataType.WORD)
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,9 @@ private fun convert(variable: StStaticVariable): IRStStaticVariable {
|
||||
val newArray = mutableListOf<IRStArrayElement>()
|
||||
array.forEach {
|
||||
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))
|
||||
} else {
|
||||
newArray.add(convertArrayElt(it))
|
||||
@@ -129,11 +131,11 @@ private fun convert(constant: StConstant): IRStConstant {
|
||||
}
|
||||
|
||||
|
||||
private fun convert(variable: StMemorySlab): IRStMemorySlab {
|
||||
return if('.' in variable.name)
|
||||
IRStMemorySlab(variable.name, variable.size, variable.align)
|
||||
private fun convert(mem: StMemorySlab): IRStMemorySlab {
|
||||
return if('.' in mem.name)
|
||||
IRStMemorySlab(mem.name, mem.size, mem.align)
|
||||
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)
|
||||
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.walk.AstWalker
|
||||
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.IErrorReporter
|
||||
import prog8.compiler.CallGraph
|
||||
@@ -93,7 +93,7 @@ class UnusedCodeRemover(private val program: Program,
|
||||
override fun after(block: Block, parent: Node): Iterable<IAstModification> {
|
||||
if("force_output" !in block.options()) {
|
||||
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 })
|
||||
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.NumericLiteral
|
||||
import prog8.ast.statements.Directive
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.SymbolTableMaker
|
||||
import prog8.code.ast.PtProgram
|
||||
import prog8.code.ast.printAst
|
||||
@@ -176,17 +177,21 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||
println("*********** COMPILER AST END *************\n")
|
||||
}
|
||||
|
||||
var symbolTable: SymbolTable
|
||||
|
||||
val (intermediateAst, simplifiedAstDuration2) = measureTimedValue {
|
||||
val intermediateAst = SimplifiedAstMaker(program, args.errors).transform()
|
||||
val stMaker = SymbolTableMaker(intermediateAst, compilationOptions)
|
||||
val symbolTable = stMaker.make()
|
||||
symbolTable = stMaker.make()
|
||||
|
||||
postprocessSimplifiedAst(intermediateAst, symbolTable, compilationOptions, args.errors)
|
||||
args.errors.report()
|
||||
symbolTable = stMaker.make() // need an updated ST because the postprocessing changes stuff
|
||||
|
||||
if (compilationOptions.optimize) {
|
||||
optimizeSimplifiedAst(intermediateAst, compilationOptions, symbolTable, args.errors)
|
||||
args.errors.report()
|
||||
symbolTable = stMaker.make() // need an updated ST because the optimization changes stuff
|
||||
}
|
||||
|
||||
if (args.printAst2) {
|
||||
@@ -204,6 +209,7 @@ fun compileProgram(args: CompilerArguments): CompilationResult? {
|
||||
createAssemblyDuration = measureTime {
|
||||
if (!createAssemblyAndAssemble(
|
||||
intermediateAst,
|
||||
symbolTable,
|
||||
args.errors,
|
||||
compilationOptions,
|
||||
program.generatedLabelSequenceNumber
|
||||
@@ -558,6 +564,7 @@ private fun postprocessAst(program: Program, errors: IErrorReporter, compilerOpt
|
||||
}
|
||||
|
||||
private fun createAssemblyAndAssemble(program: PtProgram,
|
||||
symbolTable: SymbolTable,
|
||||
errors: IErrorReporter,
|
||||
compilerOptions: CompilationOptions,
|
||||
lastGeneratedLabelSequenceNr: Int
|
||||
@@ -572,10 +579,6 @@ private fun createAssemblyAndAssemble(program: PtProgram,
|
||||
else
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
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)
|
||||
|
||||
@@ -21,6 +21,8 @@ internal fun postprocessSimplifiedAst(
|
||||
private fun processSubtypesIntoStReferences(program: PtProgram, st: SymbolTable) {
|
||||
|
||||
fun getStStruct(subType: ISubType): StStruct {
|
||||
if(subType is StStruct)
|
||||
return subType
|
||||
val stNode = st.lookup(subType.scopedNameString) as? StStruct
|
||||
if(stNode != null)
|
||||
return stNode
|
||||
@@ -28,7 +30,7 @@ private fun processSubtypesIntoStReferences(program: PtProgram, st: SymbolTable)
|
||||
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) {
|
||||
type.subType = getStStruct(type.subType!!)
|
||||
}
|
||||
@@ -36,13 +38,21 @@ private fun processSubtypesIntoStReferences(program: PtProgram, st: SymbolTable)
|
||||
|
||||
fun fixSubtypes(node: PtNode) {
|
||||
when(node) {
|
||||
is IPtVariable -> fixSubtype(node.type)
|
||||
is PtPointerDeref -> fixSubtype(node.type)
|
||||
is PtStructDecl -> node.fields.forEach { fixSubtype(it.first) }
|
||||
is PtAsmSub -> node.returns.forEach { fixSubtype(it.second) }
|
||||
is PtExpression -> fixSubtype(node.type)
|
||||
is PtSubSignature -> node.returns.forEach { fixSubtype(it) }
|
||||
is PtSubroutineParameter -> fixSubtype(node.type)
|
||||
is IPtVariable -> {
|
||||
fixSubtypeIntoStType(node.type)
|
||||
// if it's an array, fix the subtypes of its elements as well
|
||||
if(node.type.isArray && node is PtVariable) {
|
||||
(node.value as? PtArray)?.let {array ->
|
||||
array.children.forEach { fixSubtypes(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
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 */ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import prog8.ast.Program
|
||||
import prog8.code.INTERNED_STRINGS_MODULENAME
|
||||
import prog8.code.PROG8_CONTAINER_MODULES
|
||||
import prog8.code.core.IErrorReporter
|
||||
import prog8.code.source.SourceCode
|
||||
import prog8.compiler.ModuleImporter
|
||||
@@ -49,7 +50,7 @@ class TestModuleImporter: FunSpec({
|
||||
withClue(".file should point to specified path") {
|
||||
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") }
|
||||
withClue(".file should be normalized") {
|
||||
"${error2.file}" shouldBe "${error2.file.normalize()}"
|
||||
@@ -57,7 +58,7 @@ class TestModuleImporter: FunSpec({
|
||||
withClue(".file should point to specified path") {
|
||||
error2.file.absolutePath shouldBe "${srcPathAbs.normalize()}"
|
||||
}
|
||||
program.modules.size shouldBe 1
|
||||
program.modules.size shouldBe PROG8_CONTAINER_MODULES.size
|
||||
}
|
||||
|
||||
test("testDirectory") {
|
||||
@@ -75,7 +76,7 @@ class TestModuleImporter: FunSpec({
|
||||
it.file.absolutePath shouldBe "${srcPathAbs.normalize()}"
|
||||
}
|
||||
}
|
||||
program.modules.size shouldBe 1
|
||||
program.modules.size shouldBe PROG8_CONTAINER_MODULES.size
|
||||
|
||||
shouldThrow<FileSystemException> { importer.importMainModule(srcPathAbs) }
|
||||
.let {
|
||||
@@ -86,7 +87,7 @@ class TestModuleImporter: FunSpec({
|
||||
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 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.program shouldBe program
|
||||
}
|
||||
@@ -118,7 +119,7 @@ class TestModuleImporter: FunSpec({
|
||||
}
|
||||
|
||||
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.program shouldBe program
|
||||
}
|
||||
@@ -131,7 +132,7 @@ class TestModuleImporter: FunSpec({
|
||||
assumeReadableFile(searchIn, path)
|
||||
|
||||
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.program shouldBe program
|
||||
}
|
||||
@@ -152,7 +153,7 @@ class TestModuleImporter: FunSpec({
|
||||
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("startCol; should be 0-based") { it.position.startCol shouldBe 4 }
|
||||
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.size shouldBe PROG8_CONTAINER_MODULES.size
|
||||
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 }
|
||||
errors.errors.single() shouldContain "0:0: no module found with name i_do_not_exist"
|
||||
errors.report()
|
||||
program.modules.size shouldBe 1
|
||||
program.modules.size shouldBe PROG8_CONTAINER_MODULES.size
|
||||
|
||||
val result2 = importer.importImplicitLibraryModule(filenameWithExt)
|
||||
withClue(count[n] + " call / with .p8 extension") { result2 shouldBe null }
|
||||
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.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 }
|
||||
}
|
||||
}
|
||||
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("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
|
||||
importer.errors.report()
|
||||
}
|
||||
|
||||
@@ -1731,6 +1731,30 @@ main {
|
||||
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") {
|
||||
val src="""
|
||||
main {
|
||||
|
||||
@@ -88,8 +88,8 @@ class TestSymbolTable: FunSpec({
|
||||
val stVar1 = StStaticVariable("initialized", DataType.UBYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false,node)
|
||||
stVar1.setOnetimeInitNumeric(99.0)
|
||||
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 arrayInitAllzero = listOf(StArrayElement(0.0, null, null), StArrayElement(0.0, null, null), StArrayElement(0.0, 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, 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 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)
|
||||
|
||||
@@ -5,7 +5,7 @@ import io.kotest.matchers.string.shouldContain
|
||||
import prog8.ast.AstToSourceTextConverter
|
||||
import prog8.ast.Module
|
||||
import prog8.ast.Program
|
||||
import prog8.code.INTERNED_STRINGS_MODULENAME
|
||||
import prog8.code.PROG8_CONTAINER_MODULES
|
||||
import prog8.code.source.SourceCode
|
||||
import prog8.parser.ParseError
|
||||
import prog8.parser.Prog8Parser.parseModule
|
||||
@@ -38,10 +38,12 @@ class TestAstToSourceText: AnnotationSpec() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMentionsInternedStringsModule() {
|
||||
fun testMentionsProg8ContainerModules() {
|
||||
val orig = SourceCode.Text("\n")
|
||||
val (txt, _) = roundTrip(parseModule(orig))
|
||||
txt shouldContain Regex(";.*$INTERNED_STRINGS_MODULENAME")
|
||||
PROG8_CONTAINER_MODULES.forEach {
|
||||
txt shouldContain Regex(";.*$it")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -13,10 +13,11 @@ import io.kotest.matchers.types.shouldBeSameInstanceAs
|
||||
import prog8.ast.Module
|
||||
import prog8.ast.Program
|
||||
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.core.Position
|
||||
import prog8.code.source.SourceCode
|
||||
import prog8.code.INTERNED_STRINGS_MODULENAME
|
||||
import prog8.code.target.C64Target
|
||||
import prog8tests.helpers.DummyFunctions
|
||||
import prog8tests.helpers.DummyMemsizer
|
||||
@@ -30,7 +31,7 @@ class TestProgram: FunSpec({
|
||||
context("Constructor") {
|
||||
test("withNameBuiltinsAndMemsizer") {
|
||||
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].program shouldBeSameInstanceAs program
|
||||
program.modules[0].parent shouldBeSameInstanceAs program.namespace
|
||||
@@ -45,7 +46,7 @@ class TestProgram: FunSpec({
|
||||
val retVal = program.addModule(m1)
|
||||
|
||||
retVal shouldBeSameInstanceAs program
|
||||
program.modules.size shouldBe 2
|
||||
program.modules.size shouldBe PROG8_CONTAINER_MODULES.size + 1
|
||||
m1 shouldBeIn program.modules
|
||||
m1.program shouldBeSameInstanceAs program
|
||||
m1.parent shouldBeSameInstanceAs program.namespace
|
||||
@@ -163,7 +164,7 @@ datablock2 ${'$'}8000 {
|
||||
|
||||
val result = compileText(C64Target(), optimize=false, src, outputDir, writeAssembly=true)!!
|
||||
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]
|
||||
mainMod.name shouldStartWith "on_the_fly"
|
||||
result.compilerAst.modules[1].name shouldBe "prog8_interned_strings"
|
||||
@@ -183,7 +184,7 @@ datablock2 ${'$'}8000 {
|
||||
blocks[1].name shouldBe "p8_sys_startup"
|
||||
blocks[2].name shouldBe "p8b_otherblock1"
|
||||
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].library shouldBe true
|
||||
blocks[13].name shouldBe "p8b_datablock2"
|
||||
|
||||
@@ -6,6 +6,7 @@ import prog8.ast.statements.*
|
||||
import prog8.ast.walk.IAstVisitor
|
||||
import prog8.code.GENERATED_LABEL_PREFIX
|
||||
import prog8.code.INTERNED_STRINGS_MODULENAME
|
||||
import prog8.code.PROG8_CONTAINER_MODULES
|
||||
import prog8.code.core.*
|
||||
import prog8.code.source.SourceCode
|
||||
|
||||
@@ -22,17 +23,19 @@ class Program(val name: String,
|
||||
val namespace: GlobalNamespace = GlobalNamespace(_modules)
|
||||
|
||||
init {
|
||||
// insert a container module for all interned strings later
|
||||
val internedStringsModule = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated(INTERNED_STRINGS_MODULENAME))
|
||||
val block = Block(INTERNED_STRINGS_MODULENAME, null, mutableListOf(), true, 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)
|
||||
// insert container modules for all interned strings and struct instances
|
||||
PROG8_CONTAINER_MODULES.forEach { containername ->
|
||||
val module = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated(containername))
|
||||
val block = Block(containername, null, mutableListOf(), true, Position.DUMMY)
|
||||
val directive = Directive("%option", listOf(DirectiveArg("no_symbol_prefixing", null, Position.DUMMY)), Position.DUMMY)
|
||||
block.statements.add(directive)
|
||||
directive.linkParents(block)
|
||||
module.statements.add(block)
|
||||
|
||||
_modules.add(0, internedStringsModule)
|
||||
internedStringsModule.linkParents(namespace)
|
||||
internedStringsModule.program = this
|
||||
_modules.add(0, module)
|
||||
module.linkParents(namespace)
|
||||
module.program = this
|
||||
}
|
||||
}
|
||||
|
||||
fun addModule(module: Module): Program {
|
||||
@@ -67,7 +70,7 @@ class Program(val name: String,
|
||||
}
|
||||
|
||||
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>()
|
||||
|
||||
|
||||
@@ -52,10 +52,7 @@ needs_sphinx = '5.3'
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [ 'sphinxcontrib.jquery', 'sphinx_rtd_dark_mode']
|
||||
|
||||
# user starts in light mode
|
||||
default_dark_mode = False
|
||||
extensions = [ 'sphinxcontrib.jquery', 'sphinx_rtd_dark_mode', 'sphinx.ext.imgconverter']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@@ -177,6 +174,9 @@ texinfo_documents = [
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
|
||||
# user starts in light mode
|
||||
default_dark_mode = False
|
||||
|
||||
# -- Options for to do extension ----------------------------------------------
|
||||
|
||||
# todo_include_todos = True
|
||||
|
||||
@@ -58,7 +58,8 @@ and for example the below code omits line 5::
|
||||
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)
|
||||
- optimize deref in PointerAssignmentsGen: optimize 'forceTemporary' to only use a temporary when the offset is >0
|
||||
- update structpointers.rst docs with 6502 specific things?
|
||||
@@ -79,6 +80,7 @@ STRUCTS and TYPED POINTERS
|
||||
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
|
||||
- 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
|
||||
|
||||
@@ -282,9 +282,10 @@ For instance ``30_000.999_999`` is a valid floating point number 30000.999999.
|
||||
|
||||
Arrays
|
||||
^^^^^^
|
||||
Arrays can be created from a list of booleans, bytes, words, floats, or addresses of other variables
|
||||
(such as explicit address-of expressions, strings, or other array variables) - values in an array literal
|
||||
always have to be constants. A trailing comma is allowed, sometimes this is easier when copying values
|
||||
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), and struct initializers.
|
||||
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::
|
||||
|
||||
byte[10] array ; array of 10 bytes, initially set to 0
|
||||
|
||||
@@ -11,34 +11,32 @@ main{
|
||||
uword area ; 1000 km^2
|
||||
}
|
||||
|
||||
^^Country[100] countries ; won't be fully filled
|
||||
ubyte num_countries
|
||||
^^Country[] 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() {
|
||||
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")
|
||||
dump()
|
||||
|
||||
@@ -57,7 +55,7 @@ main{
|
||||
|
||||
sub sort_by_name() {
|
||||
; stupid slow bubble sort
|
||||
ubyte n = num_countries
|
||||
ubyte n = len(countries)
|
||||
do {
|
||||
ubyte newn=0
|
||||
ubyte i
|
||||
@@ -73,7 +71,7 @@ main{
|
||||
|
||||
sub sort_by_population() {
|
||||
; stupid slow bubble sort
|
||||
ubyte n = num_countries
|
||||
ubyte n = len(countries)
|
||||
do {
|
||||
ubyte newn=0
|
||||
ubyte i
|
||||
@@ -89,7 +87,7 @@ main{
|
||||
|
||||
sub sort_by_area() {
|
||||
; stupid slow bubble sort
|
||||
ubyte n = num_countries
|
||||
ubyte n = len(countries)
|
||||
do {
|
||||
ubyte newn=0
|
||||
ubyte i
|
||||
@@ -125,10 +123,5 @@ main{
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
||||
sub add(^^Country c) {
|
||||
countries[num_countries] = c
|
||||
num_countries++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,19 +8,20 @@ main {
|
||||
uword array
|
||||
}
|
||||
|
||||
^^Node @shared @zp node = 2000
|
||||
|
||||
sub start() {
|
||||
^^Node[] nodes = [
|
||||
^^Node:[1,"one", 1000 ],
|
||||
^^Node:[2,"two", 2000 ],
|
||||
^^Node:[3,"three", 3000]
|
||||
^^Node:[3,"three", 3000],
|
||||
^^Node:[],
|
||||
^^Node:[],
|
||||
^^Node:[],
|
||||
]
|
||||
txt.print_uw(nodes[0])
|
||||
txt.spc()
|
||||
txt.print_uw(nodes[1])
|
||||
txt.spc()
|
||||
txt.print_uw(nodes[2])
|
||||
|
||||
for cx16.r0 in nodes {
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.spc()
|
||||
}
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package prog8.intermediate
|
||||
|
||||
import prog8.code.INTERNED_STRINGS_MODULENAME
|
||||
import prog8.code.PROG8_CONTAINER_MODULES
|
||||
import prog8.code.core.BaseDataType
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.Encoding
|
||||
@@ -49,10 +49,9 @@ class IRSymbolTable {
|
||||
val prefix = "$label."
|
||||
val vars = table.filter { it.key.startsWith(prefix) }
|
||||
vars.forEach {
|
||||
// check if attempt is made to delete interned strings, if so, refuse that.
|
||||
if(!it.key.startsWith(INTERNED_STRINGS_MODULENAME)) {
|
||||
// check if attempt is made to delete fixed modules, if so, refuse that.
|
||||
if(!PROG8_CONTAINER_MODULES.any { containername -> it.key.startsWith(containername)})
|
||||
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 pos = "${call.position.line}_${call.position.startCol}"
|
||||
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 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 {
|
||||
if(number!=null) require(addressOfSymbol==null && boolean==null)
|
||||
if(addressOfSymbol!=null) require(number==null && boolean==null)
|
||||
if(boolean!=null) require(addressOfSymbol==null && number==null)
|
||||
if(number!=null) require(addressOfSymbol==null && boolean==null && structInstance==null && structInstanceUninitialized==null)
|
||||
if(addressOfSymbol!=null) require(number==null && boolean==null && structInstance==null && structInstanceUninitialized==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 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
|
||||
}
|
||||
is PtArray -> {
|
||||
initialArray = makeInitialArray(value)
|
||||
initialArray = makeInitialArray(value, scope)
|
||||
initialString = null
|
||||
initialNumeric = null
|
||||
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 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
|
||||
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") {
|
||||
val struct = node.type.subType!!
|
||||
if(struct is StStruct) {
|
||||
val label = SymbolTable.labelnameForStructInstance(node)
|
||||
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))
|
||||
val instance = handleStructAllocation(node)
|
||||
if(instance!=null) {
|
||||
scope.first().add(instance) // don't add struct instances in nested scope, just put them in the top level of the ST
|
||||
}
|
||||
}
|
||||
null
|
||||
@@ -153,20 +143,50 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
||||
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 {
|
||||
when(it) {
|
||||
is PtAddressOf -> {
|
||||
when {
|
||||
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 PtBool -> StArrayElement(null, null, it.value)
|
||||
is PtNumber -> StArrayElement(it.number, null, null,null,null)
|
||||
is PtBool -> StArrayElement(null, null, null,null,it.value)
|
||||
is PtBuiltinFunctionCall -> {
|
||||
val labelname = SymbolTable.labelnameForStructInstance(it)
|
||||
StArrayElement(null, labelname, null)
|
||||
if(it.name=="prog8_lib_structalloc") {
|
||||
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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user