fix split words arrays on m68k to be not split

This commit is contained in:
Irmen de Jong committed 2026-07-10 01:47:18 +02:00
1 parent c7a8e84fd0
commit 8a7922ffcc
45 files changed
+275 -234

No files matched your search

+22 -21
View File
@@ -20,7 +20,7 @@ enum class BaseDataType {
ARRAY_SPLITW, // pass by reference, split word layout, subtype is the element type (restricted to word types)
POINTER, // typed pointer, subtype is whatever type is pointed to
STRUCT_INSTANCE, // the actual instance of a struct (not directly supported in the language yet, but we need its type)
ARRAY_POINTER, // array of pointers (uwords), subtype is whatever type each element points to
ARRAY_POINTER, // array of pointers (uwords or longs), subtype is whatever type each element points to
UNDEFINED;
@@ -85,12 +85,6 @@ val BaseDataType.isIterable get() = this in setOf(BaseDataType.STR, BaseDataTyp
val BaseDataType.isPassByRef get() = this.isIterable && !this.isPointer
val BaseDataType.isPassByValue get() = !this.isIterable || this.isPointer
fun DataType.isSplitWordArrayOnTarget(target: ICompilationTarget): Boolean = when(base) {
BaseDataType.ARRAY_SPLITW -> true
BaseDataType.ARRAY_POINTER -> target.POINTER_MEM_SIZE <= 2u
else -> false
}
/**
* Interface for types that can be used as subtypes in DataType.
@@ -190,17 +184,19 @@ class DataType private constructor(
return simpletypes.getValue(dt)
}
fun arrayFor(elementDt: BaseDataType, splitwordarray: Boolean=true): DataType {
fun arrayFor(elementDt: BaseDataType): DataType {
// wether or not a word-array should be split-words, is determined later
require(!elementDt.isPointer) { "use other array constructor for arrays of pointers" }
val actualElementDt = if(elementDt==BaseDataType.STR) BaseDataType.UWORD else elementDt // array of strings is actually just an array of UWORD pointers
return if(splitwordarray && actualElementDt.isWord)
DataType(BaseDataType.ARRAY_SPLITW, actualElementDt, null)
else {
if(actualElementDt.isNumericOrBool)
DataType(BaseDataType.ARRAY, actualElementDt, null)
else
throw NoSuchElementException("invalid basic element dt $elementDt")
}
if(actualElementDt.isNumericOrBool)
return DataType(BaseDataType.ARRAY, actualElementDt, null)
else
throw NoSuchElementException("invalid basic element dt $elementDt")
}
fun splitWordArrayFor(elementDt: BaseDataType): DataType {
require(elementDt.isWord) { "split word array element type must be word" }
return DataType(BaseDataType.ARRAY_SPLITW, elementDt, null)
}
fun arrayOfPointersTo(sub: BaseDataType): DataType = DataType(BaseDataType.ARRAY_POINTER, sub, null)
@@ -225,8 +221,10 @@ class DataType private constructor(
// ============================================================================
fun elementToArray(splitwords: Boolean = true): DataType {
return if (base == BaseDataType.UWORD || base == BaseDataType.WORD || base == BaseDataType.STR) arrayFor(base, splitwords)
else arrayFor(base, false)
if (splitwords && (base == BaseDataType.UWORD || base == BaseDataType.WORD || base == BaseDataType.STR))
return splitWordArrayFor(base)
else
return arrayFor(base)
}
fun elementType(): DataType =
@@ -248,11 +246,14 @@ class DataType private constructor(
if (isPointer)
return untypedPointerType
if (isArray) {
if (msb || base == BaseDataType.ARRAY_SPLITW)
val isSplit = base == BaseDataType.ARRAY_SPLITW ||
(base == BaseDataType.ARRAY_POINTER && mem.memorySize(BaseDataType.POINTER) <= 2)
if (msb || isSplit)
return pointer(BaseDataType.UBYTE)
val elementDt = elementType()
require(elementDt.isBasic)
return pointer(elementDt)
if (elementDt.isBasic)
return pointer(elementDt)
return untypedPointerType
}
if (subType != null)
return pointer(this)
@@ -8,6 +8,7 @@ import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import prog8.code.core.*
/**
* Unit tests for DataType and BaseDataType classes in codeCore.
* Focus on type predicates, relationships, and key operations.
@@ -98,7 +99,7 @@ class TestDataType: FunSpec({
test("isSplitWordArray extension") {
BaseDataType.ARRAY_SPLITW.isSplitWordArray.shouldBeTrue()
BaseDataType.ARRAY_POINTER.isSplitWordArray.shouldBeFalse()
BaseDataType.ARRAY_POINTER.isSplitWordArray.shouldBeTrue()
BaseDataType.ARRAY.isSplitWordArray.shouldBeFalse()
}
@@ -124,9 +125,9 @@ class TestDataType: FunSpec({
ubyteArray.base shouldBe BaseDataType.ARRAY
ubyteArray.sub shouldBe BaseDataType.UBYTE
val wordArraySplit = DataType.arrayFor(BaseDataType.WORD)
wordArraySplit.base shouldBe BaseDataType.ARRAY_SPLITW
wordArraySplit.sub shouldBe BaseDataType.WORD
val wordArray = DataType.arrayFor(BaseDataType.WORD)
wordArray.base shouldBe BaseDataType.ARRAY
wordArray.sub shouldBe BaseDataType.WORD
}
test("DataType.pointer creates pointer types") {
@@ -306,6 +307,6 @@ class TestDataType: FunSpec({
test("DataType.toString for arrays") {
DataType.arrayFor(BaseDataType.UBYTE).toString() shouldBe "ubyte[]"
DataType.arrayFor(BaseDataType.WORD).toString() shouldBe "word[] (split)"
DataType.arrayFor(BaseDataType.WORD).toString() shouldBe "word[]"
}
})
@@ -1137,7 +1137,7 @@ import prog8.codegen.cpu6502.assignment.*
val msbAdd: Int
if(indexer.splitWords) {
val arrayVariable = indexer.variable ?: TODO("ptr indexing ${indexer.position}")
indexer.setChild(0, PtIdentifier(arrayVariable.name + (if(msb) "_msb" else "_lsb"), DataType.arrayFor(BaseDataType.UBYTE, false), arrayVariable.position))
indexer.setChild(0, PtIdentifier(arrayVariable.name + (if(msb) "_msb" else "_lsb"), DataType.arrayFor(BaseDataType.UBYTE), arrayVariable.position))
elementSize = 1
msbAdd = 0
} else {
+2 -3
View File
@@ -7,15 +7,14 @@ import prog8.code.SymbolTable
import prog8.code.ast.PtProgram
import prog8.code.core.DataType
import prog8.code.target.C64Target
import prog8.code.target.VMTarget
import prog8.codegen.cpu6502.*
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
class TestAsmOptimizer: FunSpec({
val machine = C64Target()
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val symbolTable = SymbolTable(program)
// Add test variables with known non-IO addresses so the optimizer can resolve them
+4 -4
View File
@@ -12,10 +12,9 @@ import prog8.code.ast.*
import prog8.code.core.*
import prog8.code.source.SourceCode
import prog8.code.target.C64Target
import prog8.code.target.VMTarget
import prog8.codegen.cpu6502.AsmGen6502
import prog8.codegen.cpu6502.VariableAllocator
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
import prog8tests.helpers.ErrorReporterForTests
import java.nio.file.Files
import kotlin.io.path.Path
@@ -46,8 +45,9 @@ class TestCodegen: FunSpec({
// xx += cx16.r0
// }
//}
val compTarget = C64Target()
val codegen = AsmGen6502(0)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main",false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
sub.add(PtVariable(
@@ -166,7 +166,7 @@ class TestCodegen: FunSpec({
}
test("memory mapped zp var is correctly considered to be zp var") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val st = SymbolTable(program)
st.add(StMemVar("zpmemvar", DataType.WORD, 0x20u, null, null))
st.add(StMemVar("normalmemvar", DataType.WORD, 0x9000u, null, null))
@@ -228,7 +228,7 @@ class IRCodeGen(
val shadowInit = IRVariableInitializer.Array(initBytes.map { IRStSymbolicReference.Numeric(it.toDouble()) })
val shadowVar = IRStStaticVariable(
shadowName,
DataType.arrayFor(BaseDataType.UBYTE, false),
DataType.arrayFor(BaseDataType.UBYTE),
shadowInit,
initBytes.size.toUInt(),
ZeropageWish.NOT_IN_ZEROPAGE,
+16 -16
View File
@@ -2,15 +2,15 @@ import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import prog8.code.*
import prog8.code.StNodeType
import prog8.code.SymbolTableMaker
import prog8.code.ast.*
import prog8.code.core.*
import prog8.code.source.SourceCode
import prog8.code.target.VMTarget
import prog8.codegen.intermediate.prefixScopedName
import prog8.codegen.intermediate.prefixSymbols
import prog8.codegen.intermediate.typePrefixChar
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
class TestSymbolPrefixer : FunSpec({
@@ -59,7 +59,7 @@ class TestSymbolPrefixer : FunSpec({
// --- full program prefixing tests ---
test("prefixSymbols prefixes a simple program") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
val varX = PtVariable("x", DataType.UBYTE, ZeropageWish.DONTCARE, 0u, false, null, null, Position.DUMMY)
@@ -84,7 +84,7 @@ class TestSymbolPrefixer : FunSpec({
}
test("prefixSymbols handles subroutine parameters") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
val param = PtSubroutineParameter("arg", DataType.UBYTE, null, Position.DUMMY)
@@ -100,7 +100,7 @@ class TestSymbolPrefixer : FunSpec({
}
test("prefixSymbols handles constants") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val constant = PtConstant("SIZE", DataType.UWORD, 100.0, null, Position.DUMMY)
block.add(constant)
@@ -114,7 +114,7 @@ class TestSymbolPrefixer : FunSpec({
}
test("prefixSymbols handles labels") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
val label = PtLabel("mylabel", Position.DUMMY)
@@ -130,7 +130,7 @@ class TestSymbolPrefixer : FunSpec({
}
test("prefixSymbols handles generated labels without prefixing them") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
val genLabel = PtLabel("p8_label_gen_42", Position.DUMMY)
@@ -146,7 +146,7 @@ class TestSymbolPrefixer : FunSpec({
}
test("prefixSymbols handles struct declarations") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val struct = PtStructDecl("Point", listOf(
PtStructField(DataType.UBYTE, "x", null),
@@ -163,7 +163,7 @@ class TestSymbolPrefixer : FunSpec({
}
test("prefixSymbols handles asmsub") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val asmsub = PtAsmSub("routine", PtAsmSub.Address(null, null, 0x5000u), setOf(CpuRegister.Y), emptyList(), emptyList(), false, Position.DUMMY)
block.add(asmsub)
@@ -177,7 +177,7 @@ class TestSymbolPrefixer : FunSpec({
}
test("prefixSymbols handles memmapped variables") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val memvar = PtMemMapped("reg", DataType.UBYTE, 0xd020u, null, Position.DUMMY)
block.add(memvar)
@@ -193,7 +193,7 @@ class TestSymbolPrefixer : FunSpec({
// --- noSymbolPrefixing tests ---
test("noSymbolPrefixing blocks keep their names intact") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val libOptions = PtBlock.Options(noSymbolPrefixing = true)
val libBlock = PtBlock("lib", false, SourceCode.Generated("test"), libOptions, Position.DUMMY)
val libSub = PtSub("func", emptyList(), emptyList(), Position.DUMMY)
@@ -209,7 +209,7 @@ class TestSymbolPrefixer : FunSpec({
}
test("references from user block to noSymbolPrefixing block are not prefixed") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
// Library block with no symbol prefixing
val libOptions = PtBlock.Options(noSymbolPrefixing = true)
@@ -240,7 +240,7 @@ class TestSymbolPrefixer : FunSpec({
}
test("references from noSymbolPrefixing block to regular block get prefixed") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
// Regular user block
val userBlock = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
@@ -267,7 +267,7 @@ class TestSymbolPrefixer : FunSpec({
}
test("identifier references are prefixed according to their target type") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
val varX = PtVariable("x", DataType.UBYTE, ZeropageWish.DONTCARE, 0u, false, null, null, Position.DUMMY)
@@ -290,7 +290,7 @@ class TestSymbolPrefixer : FunSpec({
}
test("prefixSymbols exception for unknown identifier") {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
val idRef = PtIdentifier("nonexistent", DataType.UBYTE, Position.DUMMY)
+13 -13
View File
@@ -12,8 +12,7 @@ import prog8.codegen.vm.VmCodeGen
import prog8.intermediate.IRSubroutine
import prog8.intermediate.Opcode
import prog8.intermediate.toAddress
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
import prog8tests.helpers.ErrorReporterForTests
class TestVmCodeGen: FunSpec({
@@ -41,8 +40,9 @@ class TestVmCodeGen: FunSpec({
// xx += cx16.r0
// }
//}
val compTarget = VMTarget()
val codegen = VmCodeGen(false)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
sub.add(PtVariable(
@@ -153,7 +153,7 @@ class TestVmCodeGen: FunSpec({
// Pattern: @(ptr+offset) = @(ptr+offset) + val i.e. ptr[offset] += val
// Non-zero offsets are used to avoid potential optimization of the address expression.
val codegen = VmCodeGen(false)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
sub.add(PtVariable("ptr", DataType.pointer(BaseDataType.UBYTE), ZeropageWish.DONTCARE, 0u, false, null, null, Position.DUMMY))
@@ -230,7 +230,7 @@ class TestVmCodeGen: FunSpec({
// }
//}
val codegen = VmCodeGen(false)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
sub.add(PtVariable(
@@ -302,7 +302,7 @@ class TestVmCodeGen: FunSpec({
// }
//}
val codegen = VmCodeGen(false)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
sub.add(PtVariable(
@@ -370,7 +370,7 @@ class TestVmCodeGen: FunSpec({
// }
//}
val codegen = VmCodeGen(false)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
sub.add(PtVariable(
@@ -426,7 +426,7 @@ class TestVmCodeGen: FunSpec({
// }
//}
val codegen = VmCodeGen(false)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
sub.add(PtVariable(
@@ -498,7 +498,7 @@ class TestVmCodeGen: FunSpec({
// }
//}
val codegen = VmCodeGen(false)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
sub.add(PtVariable(
@@ -566,7 +566,7 @@ class TestVmCodeGen: FunSpec({
// }
//}
val codegen = VmCodeGen(false)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
sub.add(PtVariable(
@@ -615,7 +615,7 @@ class TestVmCodeGen: FunSpec({
// }
//}
val codegen = VmCodeGen(false)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val extsub = PtAsmSub("routine", PtAsmSub.Address(null, null, 0x5000u), setOf(CpuRegister.Y), emptyList(), emptyList(), false, Position.DUMMY)
block.add(extsub)
@@ -640,7 +640,7 @@ class TestVmCodeGen: FunSpec({
test("ir codegen for target 'virtual' produces no prefixed names") {
val codegen = VmCodeGen(false)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
sub.add(PtVariable("x", DataType.UBYTE, ZeropageWish.DONTCARE, 0u, false, null, null, Position.DUMMY))
@@ -668,7 +668,7 @@ class TestVmCodeGen: FunSpec({
test("ir codegen for target 'cx16' via newcodegen produces prefixed names") {
val codegen = VmCodeGen(false)
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, SourceCode.Generated("test"), PtBlock.Options(), Position.DUMMY)
val sub = PtSub("start", emptyList(), emptyList(), Position.DUMMY)
sub.add(PtVariable("x", DataType.UBYTE, ZeropageWish.DONTCARE, 0u, false, null, null, Position.DUMMY))
@@ -110,7 +110,7 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
if (leftPtrConst != null && rightOffsetConst != null) {
val ptrDt = leftDt.getOrUndef()
val subDt = ptrDt.sub
val scale = if(subDt is BaseDataType) program.memsizer.memorySize(subDt) else ptrDt.size(program.memsizer)
val scale = if(subDt is BaseDataType) program.target.memorySize(subDt) else ptrDt.size(program.target)
val offset = rightOffsetConst.number.toInt() * scale
val result = if (expr.operator == "+") leftPtrConst.number + offset else leftPtrConst.number - offset
return listOf(AstReplaceNode(expr, NumericLiteral(BaseDataType.UWORD, result, expr.position), parent))
@@ -123,7 +123,7 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
if (rightPtrConst != null && leftOffsetConst != null) {
val ptrDt = rightDt.getOrUndef()
val subDt = ptrDt.sub
val scale = if(subDt is BaseDataType) program.memsizer.memorySize(subDt) else ptrDt.size(program.memsizer)
val scale = if(subDt is BaseDataType) program.target.memorySize(subDt) else ptrDt.size(program.target)
val offset = leftOffsetConst.number.toInt() * scale
val result = rightPtrConst.number + offset
return listOf(AstReplaceNode(expr, NumericLiteral(BaseDataType.UWORD, result, expr.position), parent))
@@ -142,8 +142,8 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
val concatenated = if(leftString.encoding==rightString.encoding) {
leftString.value + rightString.value
} else {
program.encoding.decodeString(
program.encoding.encodeString(leftString.value, leftString.encoding) + program.encoding.encodeString(rightString.value, rightString.encoding),
program.target.decodeString(
program.target.encodeString(leftString.value, leftString.encoding) + program.target.encodeString(rightString.value, rightString.encoding),
leftString.encoding)
}
val concatStr = StringLiteral.create(concatenated, leftString.encoding, expr.position)
@@ -535,7 +535,7 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
override fun after(decl: VarDecl, parent: Node): Iterable<AstModification> {
if (decl.type == VarDeclType.CONST && decl.datatype.isPointer) {
val sizer = program.memsizer
val sizer = program.target
if (decl.datatype.size(sizer) > 1) {
errors.err("due to internal compiler complexity, currently pointer variables with data type size > 1 cannot be const", decl.position)
}
@@ -149,7 +149,7 @@ class VarConstantValueTypeAdjuster(
private fun canBeMadeConst(decl: VarDecl, usages: List<Node>): Boolean {
if (decl.datatype.isPointer) {
if (decl.datatype.size(program.memsizer) > 1) return false
if (decl.datatype.size(program.target) > 1) return false
val derefCount = usages.count {
val p = it.parent
val gp = p.parent
@@ -599,7 +599,7 @@ internal class ConstantIdentifierReplacer(
if(declArraySize!=null && declArraySize!=rangeExpr.size())
errors.err("range expression size (${rangeExpr.size()}) doesn't match declared array size ($declArraySize)", decl.value?.position!!)
if(constRange!=null) {
return ArrayLiteral(InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.FLOAT, false)),
return ArrayLiteral(InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.FLOAT)),
constRange.map { NumericLiteral(BaseDataType.FLOAT, it.toDouble(), decl.value!!.position) }.toTypedArray(),
position = decl.value!!.position)
}
+4 -4
View File
@@ -123,7 +123,7 @@ sys {
; ------- memory routines --------
asmsub memcopy(^^ubyte source @D0, ^^ubyte tgt @D1, uword count @D2) {
asmsub memcopy(long source @D0, long tgt @D1, uword count @D2) {
; Copy bytes from source to target.
; Bulk of the work uses long-aligned longword copies;
; pre-alignment and remainder bytes use individual byte copies.
@@ -186,7 +186,7 @@ sys {
}}
}
asmsub memset(^^ubyte mem @D0, uword numbytes @D1, ubyte value @D2) {
asmsub memset(long mem @D0, uword numbytes @D1, ubyte value @D2) {
%asm {{
movea.l d0,a0
tst.w d1
@@ -237,7 +237,7 @@ sys {
}}
}
asmsub memclear(^^ubyte mem @D0, uword numbytes @D1) {
asmsub memclear(long mem @D0, uword numbytes @D1) {
; Clear memory (fill with zero). Uses movem.l d0-d7,-(a0)
; for the bulk clear (32 bytes per instruction, decrementing from
; the end address). Handles misaligned start and remaining bytes.
@@ -314,7 +314,7 @@ sys {
}}
}
asmsub memsetw(^^ubyte mem @D0, uword numwords @D1, uword value @D2) {
asmsub memsetw(long mem @D0, uword numwords @D1, uword value @D2) {
; Fill memory with the given 16-bit word value, for the given number of words.
; Word-aligned start: fast path with longword stores (2 words at a time).
; Odd start: first byte written individually to realign, then same fast path
+12 -12
View File
@@ -123,7 +123,7 @@ private fun builtinOffsetof(args: List<Expression>, position: Position, program:
val structname = identifier.dropLast(1)
val fieldname = identifier.last()
val struct = args[0].definingScope.lookup(structname) as? StructDecl ?: throw SyntaxError("cannot find struct '$structname'", args[0].position)
val offset = struct.offsetof(fieldname, program.memsizer) ?: throw SyntaxError("no such field '${identifier.joinToString(".")}'", args[0].position)
val offset = struct.offsetof(fieldname, program.target) ?: throw SyntaxError("no such field '${identifier.joinToString(".")}'", args[0].position)
return NumericLiteral.optimalInteger(offset.toInt(), position)
}
@@ -137,7 +137,7 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
val dt = args[0].inferType(program)
if(dt.isKnown) {
if(args[0] is NumericLiteral || args[0] is AddressOf || args[0] is MemorySlabRef)
return NumericLiteral.optimalInteger(program.memsizer.memorySize(dt.getOrUndef(), null), position)
return NumericLiteral.optimalInteger(program.target.memorySize(dt.getOrUndef(), null), position)
val target = (args[0] as? IdentifierReference)?.targetStatement()
?: throw SyntaxError("wrong argument type", position)
@@ -146,7 +146,7 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
dt.isArray -> {
val length = (target as VarDecl).arraysize?.constIndex() ?: throw CannotEvaluateException("sizeof", "unknown array size")
val elementDt = dt.getOrUndef().elementType()
NumericLiteral.optimalInteger(program.memsizer.memorySize(elementDt, length), position)
NumericLiteral.optimalInteger(program.target.memorySize(elementDt, length), position)
}
dt.isString -> {
if(target is VarDecl) {
@@ -156,26 +156,26 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
else
throw SyntaxError("sizeof(str) is undefined here. Perhaps use len, or strings.length?", position)
}
else -> NumericLiteral.optimalInteger( program.memsizer.memorySize(dt.getOrUndef(), null), position)
else -> NumericLiteral.optimalInteger( program.target.memorySize(dt.getOrUndef(), null), position)
}
} else {
val identifier = args[0] as? IdentifierReference
if(identifier?.nameInSource?.size==1) {
when(identifier.nameInSource[0]) {
"ubyte" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.UBYTE), position)
"byte" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.BYTE), position)
"uword" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.UWORD), position)
"word" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.WORD), position)
"long" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.LONG), position)
"float" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.FLOAT), position)
"bool" -> return NumericLiteral.optimalInteger(program.memsizer.memorySize(BaseDataType.BOOL), position)
"ubyte" -> return NumericLiteral.optimalInteger(program.target.memorySize(BaseDataType.UBYTE), position)
"byte" -> return NumericLiteral.optimalInteger(program.target.memorySize(BaseDataType.BYTE), position)
"uword" -> return NumericLiteral.optimalInteger(program.target.memorySize(BaseDataType.UWORD), position)
"word" -> return NumericLiteral.optimalInteger(program.target.memorySize(BaseDataType.WORD), position)
"long" -> return NumericLiteral.optimalInteger(program.target.memorySize(BaseDataType.LONG), position)
"float" -> return NumericLiteral.optimalInteger(program.target.memorySize(BaseDataType.FLOAT), position)
"bool" -> return NumericLiteral.optimalInteger(program.target.memorySize(BaseDataType.BOOL), position)
}
}
// the argument could refer to a struct declaration
val struct = (args[0] as? IdentifierReference)?.targetStructDecl()
if(struct!=null) {
val size = struct.memsize(program.memsizer)
val size = struct.memsize(program.target)
return NumericLiteral(BaseDataType.UBYTE, size.toDouble(), position)
}
+1 -1
View File
@@ -412,7 +412,7 @@ fun parseMainModule(filepath: Path,
quiet: Boolean,
traceImports: Boolean): Triple<Program, CompilationOptions, List<Path>> {
val bf = BuiltinFunctionsFacade(BuiltinFunctions)
val program = Program(filepath.nameWithoutExtension, bf, compTarget, compTarget)
val program = Program(filepath.nameWithoutExtension, bf, compTarget)
bf.program = program
val importer = ModuleImporter(program, compTarget.name, errors, sourceDirs, libraryDirs, cwd, quiet, traceImports)
@@ -1698,6 +1698,8 @@ internal class AstChecker(private val program: Program,
// exception allowed on 16 bits pointers: comparing uword (pointer) with string
} else if(compilerOptions.compTarget.POINTER_MEM_SIZE>2u && leftDt.isPointer && rightDt.isString) {
// exception allowed on 32 bits pointers: comparing pointer with string
} else if(compilerOptions.compTarget.POINTER_MEM_SIZE>2u && ((leftDt.isLong && rightDt.isPointer) || (leftDt.isPointer && rightDt.isLong))) {
// exception allowed on 32 bits pointers: comparing long (untyped pointer) with pointer
} else {
errors.err("left and right operands aren't the same type: $leftDt vs $rightDt", expr.position)
}
@@ -2310,7 +2312,7 @@ internal class AstChecker(private val program: Program,
val uniqueFields = struct.fields.mapTo(mutableSetOf()) { it.name }
if(uniqueFields.size!=struct.fields.size)
errors.err("duplicate field names in struct", struct.position)
val memsize = struct.memsize(program.memsizer)
val memsize = struct.memsize(program.target)
if(memsize>256)
errors.err("struct contains too many fields, max struct size is 256 bytes (actual: $memsize)", struct.position)
@@ -2642,7 +2644,7 @@ internal class AstChecker(private val program: Program,
targetDatatype.isUnsignedByte -> sourceDatatype.isUnsignedByte
targetDatatype.isSignedWord -> sourceDatatype.isSignedWord || sourceDatatype.isByte
targetDatatype.isUnsignedWord -> sourceDatatype.isUnsignedWord || sourceDatatype.isUnsignedByte
targetDatatype.isLong -> sourceDatatype.isLong || sourceDatatype.isWord || sourceDatatype.isByte
targetDatatype.isLong -> sourceDatatype.isLong || sourceDatatype.isPointer || sourceDatatype.isWord || sourceDatatype.isByte
targetDatatype.isFloat -> sourceDatatype.isNumeric
targetDatatype.isString -> sourceDatatype.isString
else -> false
@@ -2668,9 +2670,9 @@ internal class AstChecker(private val program: Program,
errors.err("cannot assign different pointer type, expected $targetDatatype or uword but got $sourceDatatype", position)
} else if(sourceDatatype.isString && targetDatatype.sub?.isByte==true) {
// assigning a string to a byte pointer is allowed.
} else if(!sourceDatatype.isUnsignedWord && !sourceDatatype.isStructInstance)
} else if(!sourceDatatype.isUnsignedWord && !sourceDatatype.isLong && !sourceDatatype.isStructInstance)
if(!(sourceDatatype isAssignableTo targetDatatype))
errors.err("incompatible value type, can only assign uword or correct pointer type", position)
errors.err("incompatible value type, can only assign uword, long, or correct pointer type", position)
}
else if(targetDatatype.isString && sourceDatatype.isUnsignedWord)
errors.err("can't assign uword to str. If the source is a string pointer and you actually want to overwrite the target string, use an explicit strings.copy(src,tgt) instead.", position)
@@ -161,7 +161,7 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co
if(options.compTarget.name != VMTarget.NAME && expr.left.inferType(program).isPointer) {
val cast = expr.right as? TypecastExpression
if(cast!=null && cast.type.isWord && cast.expression.inferType(program).isBytes) {
val structsize = expr.left.inferType(program).getOrUndef().size(program.memsizer)
val structsize = expr.left.inferType(program).getOrUndef().size(program.target)
// pointer + byte -> (pointer as uword) + (byte as uword * structsize) (yields better code on 6502 than the plain pointer arithmetic)
// but only if the struct/value size is >1
if(structsize>1) {
@@ -789,7 +789,7 @@ _after:
true // for calls (indirect JSR), split array is always the optimal choice
else
target.cpu==CpuType.CPU6502 // for goto (indirect JMP), split array is optimal for 6502, but NOT for the 65C02 (it has a different JMP addressing mode available)
val arrayDt = DataType.arrayFor(BaseDataType.UWORD, split)
val arrayDt = DataType.arrayFor(BaseDataType.UWORD)
val labelArray = ArrayLiteral(InferredTypes.knownFor(arrayDt), ongoto.labels.toTypedArray(), ongoto.position)
val jumplistArray = VarDecl.createAutoOptionalSplit(labelArray)
@@ -978,13 +978,13 @@ _after:
val ptrVar = deref.definingScope.lookup(ptrName) as? VarDecl
if(ptrVar!=null && (ptrVar.datatype.isPointer || ptrVar.datatype.isPointerArray)) {
val struct = ptrVar.datatype.subType!! as StructDecl
val offsetNumber = NumericLiteral.optimalInteger(struct.offsetof(field.first, program.memsizer)!!.toInt(), deref.position)
val offsetNumber = NumericLiteral.optimalInteger(struct.offsetof(field.first, program.target)!!.toInt(), deref.position)
val pointerIdentifier = IdentifierReference(ptrName, deref.position)
val addrType = if(target.POINTER_MEM_SIZE > 2u) DataType.LONG else DataType.UWORD
val address: Expression
if(ptrVar.datatype.isPointer) {
// pointer[idx].field = value --> pokeXXX(pointer as uword/long + idx*sizeof(Struct) + offsetof(Struct.field), value)
val structSize = ptrVar.datatype.dereference().size(program.memsizer)
val structSize = ptrVar.datatype.dereference().size(program.target)
val pointerAsAddr = TypecastExpression(pointerIdentifier, addrType, true, deref.position)
val idx = ptr.last().second!!.indexExpr
val scaledIndex = BinaryExpression(idx, "*", NumericLiteral(BaseDataType.UWORD, structSize.toDouble(), deref.position), deref.position)
@@ -1162,7 +1162,7 @@ _after:
if(targetDt.isStructInstance && sourceDt.isStructInstance) {
if(targetDt == sourceDt) {
// special case simple struct instance assignment via memory copy
val size = program.memsizer.memorySize(sourceDt.getOrUndef(), null)
val size = program.target.memorySize(sourceDt.getOrUndef(), null)
val structSizeNum = NumericLiteral.optimalInteger(size, assignment.position)
val deref = assignment.value as? PtrDereference
if(deref!=null) {
@@ -67,7 +67,7 @@ internal class LiteralsToAutoVarsAndRecombineIdentifiers(private val program: Pr
// turn the array literal it into an identifier reference
val litval2 = array.cast(targetDt.getOrUndef())
if (litval2 != null) {
val vardecl2 = VarDecl.createAuto(litval2)
val vardecl2 = VarDecl.createAuto(litval2, program.target)
val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position)
return listOf(
AstReplaceNode(array, identifier, parent),
@@ -85,7 +85,7 @@ internal class M68kAstChecker(private val errors: IErrorReporter) : IAstVisitor
if (decl.splitwordarray == SplitWish.NOSPLIT) {
errors.err("@nosplit is not available on the m68k target (there are no split word arrays)", decl.position)
}
if (decl.datatype.isSplitWordArray) {
if (decl.datatype.isSplitWordArray && decl.splitwordarray != SplitWish.DONTCARE) {
errors.err("split word arrays are not supported on the m68k target", decl.position)
}
decl.value?.accept(this)
@@ -42,8 +42,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
val ptProgram = PtProgram(
program.name,
program.memsizer,
program.encoding
program.target
)
// note: modules are not represented any longer in this Ast. All blocks have been moved into the top scope.
@@ -272,7 +271,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
// pointer arithmetic: add or subract the size of the struct times the argument
val leftDt = expr.left.inferType(program).getOrUndef()
require(leftDt.isPointer && !expr.right.inferType(program).isPointer)
val structSize = leftDt.size(program.memsizer)
val structSize = leftDt.size(program.target)
val constValue = augmentedValue.constValue(program)
if(constValue!=null) {
val total = constValue.number*structSize
@@ -991,7 +990,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
val offsType = addrType.base // use the target-appropriate offset type (UWORD on 6502, LONG on m68k)
if(leftDt.isPointer && !rightDt.isPointer) {
val structSize = leftDt.size(program.memsizer)
val structSize = leftDt.size(program.target)
val constValue = expr.right.constValue(program)
if(constValue!=null) {
// ptr + constvalue * structsize
@@ -1032,7 +1031,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
}
}
} else if(!leftDt.isPointer && rightDt.isPointer) {
val structSize = rightDt.size(program.memsizer)
val structSize = rightDt.size(program.target)
val constValue = expr.left.constValue(program)
if(constValue!=null) {
// ptr + constvalue * structsize
@@ -1176,8 +1175,8 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
if(type.isSplitWordArray) {
// ranges are never a split word array!
when(type.sub) {
BaseDataType.WORD -> type = DataType.arrayFor(BaseDataType.WORD, false)
BaseDataType.UWORD -> type = DataType.arrayFor(BaseDataType.UWORD, false)
BaseDataType.WORD -> type = DataType.arrayFor(BaseDataType.WORD)
BaseDataType.UWORD -> type = DataType.arrayFor(BaseDataType.UWORD)
else -> { }
}
}
@@ -318,7 +318,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val
paramsPossibleDatatypes = BuiltinFunctions.getValue(sub.name).parameters.map {
it.possibleDatatypes.map { dt ->
if(dt.isArray)
DataType.arrayFor(BaseDataType.BOOL, false) // the builtin function signature doesn't tell us the element type....
DataType.arrayFor(BaseDataType.BOOL) // the builtin function signature doesn't tell us the element type....
else if(dt.isPointer)
DataType.pointer(BaseDataType.UBYTE)
else
@@ -31,7 +31,9 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
VarDeclType.VAR -> {
if(decl.isArray) {
// using a array of words as initializer to a pointer array is fine
if (!valueDt.isSplitWordArray || !decl.datatype.isPointerArray)
val ok = valueDt.isSplitWordArray && decl.datatype.isPointerArray ||
valueDt.isWordArray && decl.datatype.isPointerArray && decl.splitwordarray == SplitWish.DONTCARE && options.compTarget.POINTER_MEM_SIZE == 2u
if (!ok)
errors.err("value has incompatible type ($valueType) for the variable (${decl.datatype})", decl.value!!.position)
} else if(!decl.datatype.isString) {
if (valueDt.largerSizeThan(decl.datatype)) {
@@ -87,17 +89,24 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
var changeDataType: DataType?
when(decl.splitwordarray) {
SplitWish.DONTCARE -> {
changeDataType = if(decl.datatype.isSplitWordArray) null else {
changeDataType = if(decl.datatype.isSplitWordArray) {
if(options.compTarget.POINTER_MEM_SIZE > 2u)
DataType.arrayFor(decl.datatype.elementType().base)
else
null
} else {
val eltDt = decl.datatype.elementType()
if(eltDt.isPointer)
TODO("convert array of pointers to split words array type ${decl.position}")
else if(options.compTarget.POINTER_MEM_SIZE == 2u)
DataType.splitWordArrayFor(eltDt.base)
else
DataType.arrayFor(eltDt.base)
null
}
}
SplitWish.NOSPLIT -> {
changeDataType = if(decl.datatype.isSplitWordArray && !decl.datatype.elementType().isPointer)
DataType.arrayFor(decl.datatype.elementType().base, false)
DataType.arrayFor(decl.datatype.elementType().base)
else null
}
}
@@ -116,7 +125,21 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
// handle @nosplit on pointer arrays: convert to regular non-split word array
if(decl.datatype.isPointerArray && decl.splitwordarray == SplitWish.NOSPLIT) {
val newDt = DataType.arrayFor(BaseDataType.UWORD, false) // false = not split (sequential)
val newDt = DataType.arrayFor(BaseDataType.UWORD) // non-split
var value = decl.value
if(value is ArrayLiteral && !(value.type istype newDt)) {
value = ArrayLiteral(InferredTypes.knownFor(newDt), value.value, value.position)
}
val newDecl = VarDecl.builder(newDt, decl.position)
.copyFrom(decl)
.value(value)
.build()
return listOf(AstReplaceNode(decl, newDecl, parent))
}
// handle DONTCARE pointer arrays on non-6502 targets: convert back to regular array with long elements
if(decl.datatype.isPointerArray && decl.splitwordarray == SplitWish.DONTCARE && options.compTarget.POINTER_MEM_SIZE > 2u) {
val newDt = DataType.arrayFor(BaseDataType.LONG)
var value = decl.value
if(value is ArrayLiteral && !(value.type istype newDt)) {
value = ArrayLiteral(InferredTypes.knownFor(newDt), value.value, value.position)
@@ -438,7 +461,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
if(stringVal.value.isEmpty())
return replaceWithFalse()
if(stringVal.value.length==1) {
val string = program.encoding.encodeString(stringVal.value, stringVal.encoding)
val string = program.target.encodeString(stringVal.value, stringVal.encoding)
return replaceWithEquals(NumericLiteral(BaseDataType.UBYTE, string[0].toDouble(), stringVal.position))
}
return noModifications
@@ -122,6 +122,14 @@ internal class VerifyFunctionArgTypes(val program: Program, val options: Compila
if(paramDt.isPointer && argDt.base==BaseDataType.LONG)
return true
// if expected is LONG and actual is an array, we allow it (address of array is a long on 32-bit targets)
if(paramDt.isLong && argDt.isArray)
return true
// if expected is LONG and actual is any pointer, we allow it (pointer is a long on m68k)
if(paramDt.isLong && argDt.isPointer)
return true
if(paramDt.isString && (argDt.isPointer && argDt.sub==BaseDataType.UBYTE))
return true
+6 -4
View File
@@ -19,7 +19,9 @@ import prog8.code.target.VMTarget
import prog8.compiler.CallGraph
import prog8.parser.Prog8Parser.parseModule
import prog8.vm.VmRunner
import prog8tests.helpers.*
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText
import kotlin.io.path.readText
class TestCallgraph: FunSpec({
@@ -166,7 +168,7 @@ class TestCallgraph: FunSpec({
}
}"""
val module = parseModule(SourceCode.Text(source))
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val program = Program("test", DummyFunctions, VMTarget())
program.addModule(module)
val callgraph = CallGraph(program)
val blockMain = program.allBlocks.single { it.name=="main" }
@@ -201,7 +203,7 @@ class TestCallgraph: FunSpec({
}
}"""
val module = parseModule(SourceCode.Text(source))
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val program = Program("test", DummyFunctions, VMTarget())
program.addModule(module)
val callgraph = CallGraph(program)
val errors = ErrorReporterForTests()
@@ -225,7 +227,7 @@ class TestCallgraph: FunSpec({
}
}"""
val module = parseModule(SourceCode.Text(source))
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val program = Program("test", DummyFunctions, VMTarget())
program.addModule(module)
val callgraph = CallGraph(program)
val errors = ErrorReporterForTests()
+15 -11
View File
@@ -14,10 +14,14 @@ import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteral
import prog8.ast.expressions.PrefixExpression
import prog8.ast.statements.*
import prog8.code.core.*
import prog8.code.core.BaseDataType
import prog8.code.core.DataType
import prog8.code.core.Position
import prog8.code.source.SourceCode
import prog8.code.target.*
import prog8tests.helpers.*
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText
class TestMemory: FunSpec({
@@ -26,7 +30,7 @@ class TestMemory: FunSpec({
val outputDir = tempdir().toPath()
fun wrapWithProgram(statements: List<Statement>): Program {
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val program = Program("test", DummyFunctions, c64target)
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, false, statements.toMutableList(), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
program.addModule(module)
@@ -271,7 +275,7 @@ class TestMemory: FunSpec({
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
Program("test", DummyFunctions, c64target)
.addModule(module)
target.isIOAddress(c64target) shouldBe false
}
@@ -294,7 +298,7 @@ class TestMemory: FunSpec({
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
Program("test", DummyFunctions, c64target)
.addModule(module)
target.isIOAddress(c64target) shouldBe false
}
@@ -317,7 +321,7 @@ class TestMemory: FunSpec({
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
Program("test", DummyFunctions, c64target)
.addModule(module)
target.isIOAddress(c64target) shouldBe true
}
@@ -331,7 +335,7 @@ class TestMemory: FunSpec({
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
Program("test", DummyFunctions, c64target)
.addModule(module)
target.isIOAddress(c64target) shouldBe false
}
@@ -348,7 +352,7 @@ class TestMemory: FunSpec({
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
Program("test", DummyFunctions, c64target)
.addModule(module)
target.isIOAddress(c64target) shouldBe false
}
@@ -365,7 +369,7 @@ class TestMemory: FunSpec({
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
Program("test", DummyFunctions, c64target)
.addModule(module)
target.isIOAddress(c64target) shouldBe true
}
@@ -421,8 +425,8 @@ class TestMemory: FunSpec({
target.memorySize(DataType.arrayFor(BaseDataType.UWORD), 10) shouldBe 20
target.memorySize(DataType.arrayFor(BaseDataType.LONG), 10) shouldBe 40
target.memorySize(DataType.arrayFor(BaseDataType.FLOAT), 10) shouldBe 10*target.FLOAT_MEM_SIZE.toInt()
target.memorySize(DataType.arrayFor(BaseDataType.WORD, true), 10) shouldBe 20
target.memorySize(DataType.arrayFor(BaseDataType.UWORD, true), 10) shouldBe 20
target.memorySize(DataType.splitWordArrayFor(BaseDataType.WORD), 10) shouldBe 20
target.memorySize(DataType.splitWordArrayFor(BaseDataType.UWORD), 10) shouldBe 20
target.memorySize(DataType.BOOL, 10) shouldBe 10
target.memorySize(DataType.UWORD, 10) shouldBe 20
+2 -1
View File
@@ -13,6 +13,7 @@ import prog8.code.INTERNED_STRINGS_MODULENAME
import prog8.code.PROG8_CONTAINER_MODULES
import prog8.code.core.IErrorReporter
import prog8.code.source.SourceCode
import prog8.code.target.VMTarget
import prog8.compiler.ModuleImporter
import prog8.parser.MultipleParseErrors
import prog8tests.helpers.*
@@ -25,7 +26,7 @@ class TestModuleImporter: FunSpec({
lateinit var program: Program
beforeTest {
program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
program = Program("foo", DummyFunctions, VMTarget())
}
fun makeImporter(errors: IErrorReporter? = null, searchIn: Iterable<String>) =
+7 -3
View File
@@ -23,7 +23,9 @@ import prog8.code.target.C64Target
import prog8.code.target.Cx16Target
import prog8.code.target.VMTarget
import prog8.vm.VmRunner
import prog8tests.helpers.*
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText
import kotlin.io.path.readText
@@ -141,9 +143,10 @@ other {
}
test("generated constvalue from typecast inherits proper parent linkage") {
val target = VMTarget()
val number = NumericLiteral(BaseDataType.UBYTE, 11.0, Position.DUMMY)
val tc = TypecastExpression(number, DataType.BYTE, false, Position.DUMMY)
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val program = Program("test", DummyFunctions, target)
tc.linkParents(ParentSentinel)
tc.parent shouldNotBe null
number.parent shouldNotBe null
@@ -156,9 +159,10 @@ other {
}
test("generated constvalue from prefixexpr inherits proper parent linkage") {
val target = VMTarget()
val number = NumericLiteral(BaseDataType.UBYTE, 11.0, Position.DUMMY)
val pfx = PrefixExpression("-", number, Position.DUMMY)
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val program = Program("test", DummyFunctions, target)
pfx.linkParents(ParentSentinel)
pfx.parent shouldNotBe null
number.parent shouldNotBe null
+7 -7
View File
@@ -662,7 +662,7 @@ main {
compileText(VMTarget(), false, src, outputDir, errors=errors)
val err = errors.errors
err.size shouldBe 1
err[0] shouldContain("15:16: incompatible value type, can only assign uword or correct pointer")
err[0] shouldContain("15:16: incompatible value type, can only assign uword")
}
test("pointer uword assignments with cast") {
@@ -757,12 +757,12 @@ main {
DataType.UNDEFINED.typeForUntypedAddressOf(false, memsizer) shouldBe DataType.UWORD
DataType.UNDEFINED.typeForUntypedAddressOf(true, memsizer) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.STR.typeForUntypedAddressOf(false, memsizer) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.arrayFor(BaseDataType.FLOAT, false).typeForUntypedAddressOf(false, memsizer) shouldBe DataType.pointer(BaseDataType.FLOAT)
DataType.arrayFor(BaseDataType.FLOAT, false).typeForUntypedAddressOf(true, memsizer) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.arrayFor(BaseDataType.UWORD, false).typeForUntypedAddressOf(false, memsizer) shouldBe DataType.pointer(BaseDataType.UWORD)
DataType.arrayFor(BaseDataType.UWORD, true).typeForUntypedAddressOf(false, memsizer) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.arrayFor(BaseDataType.UWORD, false).typeForUntypedAddressOf(true, memsizer) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.arrayFor(BaseDataType.UWORD, true).typeForUntypedAddressOf(true, memsizer) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.arrayFor(BaseDataType.FLOAT).typeForUntypedAddressOf(false, memsizer) shouldBe DataType.pointer(BaseDataType.FLOAT)
DataType.arrayFor(BaseDataType.FLOAT).typeForUntypedAddressOf(true, memsizer) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.arrayFor(BaseDataType.UWORD).typeForUntypedAddressOf(false, memsizer) shouldBe DataType.pointer(BaseDataType.UWORD)
DataType.splitWordArrayFor(BaseDataType.UWORD).typeForUntypedAddressOf(false, memsizer) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.arrayFor(BaseDataType.UWORD).typeForUntypedAddressOf(true, memsizer) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.splitWordArrayFor(BaseDataType.UWORD).typeForUntypedAddressOf(true, memsizer) shouldBe DataType.pointer(BaseDataType.UBYTE)
DataType.pointer(Struct("struct")).typeForUntypedAddressOf(false, memsizer) shouldBe DataType.UWORD
DataType.pointerFromAntlr(listOf("struct")).typeForUntypedAddressOf(false, memsizer) shouldBe DataType.UWORD
+3 -3
View File
@@ -7,18 +7,18 @@ import prog8.ast.Module
import prog8.ast.Program
import prog8.code.PROG8_CONTAINER_MODULES
import prog8.code.source.SourceCode
import prog8.code.target.VMTarget
import prog8.parser.ParseError
import prog8.parser.Prog8Parser.parseModule
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
class TestAstToSourceText: FunSpec({
// Helper function to generate Prog8 source from AST
fun generateP8(module: Module): String {
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("test", DummyFunctions, target)
.addModule(module)
var generatedText = ""
+3 -3
View File
@@ -14,10 +14,9 @@ import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl
import prog8.code.core.Position
import prog8.code.source.SourceCode
import prog8.code.target.VMTarget
import prog8.parser.Prog8Parser
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
class TestIdentifierRef: FunSpec({
@@ -55,7 +54,8 @@ class TestIdentifierRef: FunSpec({
}
} """)
val module = Prog8Parser.parseModule(src)
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("test", DummyFunctions, target)
program.addModule(module)
val mstmts = (module.statements.single() as Block).statements
val stmts = mstmts.filterIsInstance<Subroutine>().single().statements
+12 -7
View File
@@ -677,9 +677,10 @@ class TestProg8Parser: FunSpec( {
val char3 = CharLiteral.create('_', Encoding.ISO, Position.DUMMY)
val char4 = CharLiteral.create('_', Encoding.DEFAULT, Position.DUMMY)
val program = Program("test", DummyFunctions, DummyMemsizer, AsciiStringEncoder)
char1.constValue(program)?.number?.toInt() shouldBe 65
char2.constValue(program)?.number?.toInt() shouldBe 122
val target = VMTarget()
val program = Program("test", DummyFunctions, target)
char1.constValue(program)?.number?.toInt() shouldBe 193
char2.constValue(program)?.number?.toInt() shouldBe 26
char3.constValue(program)?.number?.toInt() shouldBe 95
char4.constValue(program) shouldBe null
}
@@ -810,7 +811,8 @@ class TestProg8Parser: FunSpec( {
}
""")
val module = parseModule(src)
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("test", DummyFunctions, target)
program.addModule(module)
val bb2 = (module.statements.single() as Block).statements[2] as VarDecl
val expr = bb2.value as BinaryExpression
@@ -833,7 +835,8 @@ class TestProg8Parser: FunSpec( {
}
""")
val module = parseModule(src)
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("test", DummyFunctions, target)
program.addModule(module)
val stmts = (module.statements.single() as Block).statements
stmts.size shouldBe 6
@@ -860,7 +863,8 @@ class TestProg8Parser: FunSpec( {
ubyte ub = (cos8(r)/2 + 100) as ubyte
}""")
val module = parseModule(src)
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("test", DummyFunctions, target)
program.addModule(module)
val stmts = (module.statements.single() as Block).statements
stmts.size shouldBe 2
@@ -891,7 +895,8 @@ class TestProg8Parser: FunSpec( {
}""")
val module = parseModule(src)
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("test", DummyFunctions, target)
program.addModule(module)
val stmts = program.entrypoint.statements
val expectedResults = listOf(
+15 -9
View File
@@ -19,9 +19,8 @@ import prog8.code.ast.PtBlock
import prog8.code.core.Position
import prog8.code.source.SourceCode
import prog8.code.target.C64Target
import prog8.code.target.VMTarget
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
import prog8tests.helpers.compileText
class TestProgram: FunSpec({
@@ -30,7 +29,8 @@ class TestProgram: FunSpec({
context("Constructor") {
test("withNameBuiltinsAndMemsizer") {
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("foo", DummyFunctions, target)
program.modules.size shouldBe PROG8_CONTAINER_MODULES.size
program.modules[0].name shouldBe INTERNED_STRINGS_MODULENAME
program.modules[0].program shouldBeSameInstanceAs program
@@ -40,7 +40,8 @@ class TestProgram: FunSpec({
context("AddModule") {
test("withEmptyModule") {
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("foo", DummyFunctions, target)
val m1 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar"))
val retVal = program.addModule(m1)
@@ -66,7 +67,8 @@ class TestProgram: FunSpec({
context("MoveModuleToFront") {
test("withInternedStringsModule") {
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("foo", DummyFunctions, target)
val m = program.modules[0]
m.name shouldBe INTERNED_STRINGS_MODULENAME
@@ -76,14 +78,16 @@ class TestProgram: FunSpec({
}
test("withForeignModule") {
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("foo", DummyFunctions, target)
val m = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar"))
shouldThrow<IllegalArgumentException> { program.moveModuleToFront(m) }
}
test("withFirstOfPreviouslyAddedModules") {
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("foo", DummyFunctions, target)
val m1 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar"))
val m2 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("qmbl"))
program.addModule(m1)
@@ -95,7 +99,8 @@ class TestProgram: FunSpec({
}
test("withSecondOfPreviouslyAddedModules") {
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("foo", DummyFunctions, target)
val m1 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar"))
val m2 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("qmbl"))
program.addModule(m1)
@@ -109,7 +114,8 @@ class TestProgram: FunSpec({
context("Properties") {
test("modules") {
val program = Program("foo", DummyFunctions, DummyMemsizer, DummyStringEncoder)
val target = VMTarget()
val program = Program("foo", DummyFunctions, target)
val ms1 = program.modules
val ms2 = program.modules
+4 -5
View File
@@ -1070,13 +1070,12 @@ main {
DataType.forDt(BaseDataType.STR).isString shouldBe true
DataType.forDt(BaseDataType.FLOAT).isFloat shouldBe true
DataType.arrayFor(BaseDataType.UBYTE, true).isUnsignedByteArray shouldBe true
DataType.arrayFor(BaseDataType.LONG).isLongArray shouldBe true
DataType.arrayFor(BaseDataType.FLOAT).isFloatArray shouldBe true
DataType.arrayFor(BaseDataType.UWORD).isUnsignedWordArray shouldBe true
DataType.arrayFor(BaseDataType.UWORD).isArray shouldBe true
DataType.arrayFor(BaseDataType.UWORD).isSplitWordArray shouldBe true
DataType.arrayFor(BaseDataType.UWORD, false).isSplitWordArray shouldBe false
DataType.splitWordArrayFor(BaseDataType.UWORD).isSplitWordArray shouldBe true
DataType.arrayFor(BaseDataType.UWORD).isSplitWordArray shouldBe false
shouldThrow<NoSuchElementException> {
DataType.forDt(BaseDataType.ARRAY)
@@ -1112,7 +1111,7 @@ main {
(st1[1] as VarDecl).name shouldBe "names"
val array1 = (st1[1] as VarDecl).value as ArrayLiteral
array1.type.isArray shouldBe true
array1.type.getOrUndef() shouldBe DataType.arrayFor(BaseDataType.UWORD, true)
array1.type.getOrUndef() shouldBe DataType.splitWordArrayFor(BaseDataType.UWORD)
val ast2 = result.codegenAst!!
val st2 = ast2.entrypoint()!!.children
@@ -1120,7 +1119,7 @@ main {
(st2[1] as PtVariable).name shouldBe "p8v_variable"
(st2[2] as PtVariable).name shouldBe "p8v_names"
val array2 = (st2[2] as PtVariable).value as PtArray
array2.type shouldBe DataType.arrayFor(BaseDataType.UWORD, true)
array2.type shouldBe DataType.splitWordArrayFor(BaseDataType.UWORD)
}
@@ -21,10 +21,13 @@ import prog8.code.target.VMTarget
import prog8.codegen.cpu6502.AsmGen6502Internal
import prog8.compiler.astprocessing.AstChecker
import prog8.compiler.astprocessing.SimplifiedAstMaker
import prog8tests.helpers.*
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText
class TestAsmGenSymbols: StringSpec({
val outputDir = tempdir().toPath()
val target = VMTarget()
fun createTestProgram(): Program {
/*
@@ -78,7 +81,7 @@ class TestAsmGenSymbols: StringSpec({
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder).addModule(module)
val program = Program("test", DummyFunctions, target).addModule(module)
return program
}
@@ -171,8 +174,8 @@ main {
asmgen.asmSymbolName(listOf("prog8_lib","P8ZP_SCRATCH_W2")) shouldBe "P8ZP_SCRATCH_W2"
val id1 = PtIdentifier("prog8_lib.P8ZP_SCRATCH_REG", DataType.UBYTE, Position.DUMMY)
val id2 = PtIdentifier("prog8_lib.P8ZP_SCRATCH_W2", DataType.UWORD, Position.DUMMY)
id1.parent = PtProgram("test", DummyMemsizer, DummyStringEncoder)
id2.parent = PtProgram("test", DummyMemsizer, DummyStringEncoder)
id1.parent = PtProgram("test", VMTarget())
id2.parent = PtProgram("test", VMTarget())
asmgen.asmSymbolName(id1) shouldBe "P8ZP_SCRATCH_REG"
asmgen.asmSymbolName(id2) shouldBe "P8ZP_SCRATCH_W2"
}
+3 -3
View File
@@ -61,7 +61,7 @@ library {
main.name shouldBe "p8b_main"
val jumptable = main.children[0] as PtVariable
jumptable.name shouldBe "p8v_jumptable"
jumptable.type shouldBe DataType.arrayFor(BaseDataType.UWORD, false)
jumptable.type shouldBe DataType.arrayFor(BaseDataType.UWORD)
jumptable.arraySize shouldBe 4u
val bin = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".bin").readBytes().map { it.toUByte() }
@@ -144,7 +144,7 @@ library {
main.name shouldBe "p8b_main"
val jumptable = main.children[0] as PtVariable
jumptable.name shouldBe "p8v_jumptable"
jumptable.type shouldBe DataType.arrayFor(BaseDataType.UWORD, false)
jumptable.type shouldBe DataType.arrayFor(BaseDataType.UWORD)
jumptable.arraySize shouldBe 4u
val asm = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".asm").readText()
println(asm)
@@ -187,4 +187,4 @@ library {
// check func2
bin[offset(func2Addr)] shouldBe 0xCeu // DEC abs
}
})
})
@@ -67,7 +67,7 @@ main {
val text="""
main {
sub start() {
uword[3] seed
uword[3] @nosplit seed
cx16.r0 = seed[0] + seed[1] + seed[2]
}
}"""
+2 -2
View File
@@ -434,9 +434,9 @@ open class Module(final override val statements: MutableList<Statement>,
val textEncoding: Encoding by lazy {
val encoding = statements.singleOrNull { it is Directive && it.directive == "%encoding" } as? Directive
if(encoding!=null)
Encoding.entries.firstOrNull { it.prefix==encoding.args[0].string } ?: program.encoding.defaultEncoding // invalid encoding will be noticed by ast checker error message
Encoding.entries.firstOrNull { it.prefix==encoding.args[0].string } ?: program.target.defaultEncoding // invalid encoding will be noticed by ast checker error message
else
program.encoding.defaultEncoding
program.target.defaultEncoding
}
val isLibrary get() = source.isFromLibrary
+1 -2
View File
@@ -14,8 +14,7 @@ import prog8.code.source.SourceCode
class Program(val name: String,
val builtinFunctions: IBuiltinFunctions,
val memsizer: IMemSizer,
val encoding: IStringEncoding
val target: ICompilationTarget
) {
private val _modules = mutableListOf<Module>()
@@ -12,6 +12,7 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.code.core.*
import prog8.code.source.SourceCode
import prog8.parser.Prog8ANTLRParser.*
import prog8.parser.Prog8ANTLRVisitor
import kotlin.io.path.Path
@@ -218,7 +219,7 @@ class Antlr2KotlinVisitor(val source: SourceCode): AbstractParseTreeVisitor<Node
else if(baseDt.isStructInstance)
throw SyntaxError("array of structures not allowed (use array of pointers)", ctx.toPosition())
else
DataType.arrayFor(baseDt.base, split!=SplitWish.NOSPLIT)
DataType.arrayFor(baseDt.base)
}
return VarDecl.builder(dt, ctx.toPosition())
@@ -669,7 +669,7 @@ data class AddressOf(var identifier: IdentifierReference?, var arrayIndex: Array
if (index != null) {
address += when {
target.datatype.isInteger -> index
target.datatype.isPointer || target.datatype.isArray -> index * targetVar.datatype.size(program.memsizer)
target.datatype.isPointer || target.datatype.isArray -> index * targetVar.datatype.size(program.target)
else -> throw FatalAstException("need array or ptr")
}
} else
@@ -691,16 +691,16 @@ data class AddressOf(var identifier: IdentifierReference?, var arrayIndex: Array
override fun referencesIdentifier(nameInSource: List<String>) = identifier?.nameInSource==nameInSource || arrayIndex?.referencesIdentifier(nameInSource)==true || dereference?.referencesIdentifier(nameInSource)==true
override fun inferType(program: Program): InferredTypes.InferredType {
if(!typed) {
val untypedPointerType = if(program.memsizer.memorySize(BaseDataType.POINTER)>2) BaseDataType.LONG else BaseDataType.UWORD
val untypedPointerType = if(program.target.memorySize(BaseDataType.POINTER)>2) BaseDataType.LONG else BaseDataType.UWORD
return InferredTypes.knownFor(untypedPointerType)
}
if(identifier!=null) {
val type = identifier!!.inferType(program).getOrUndef()
val addrofDt = type.typeForUntypedAddressOf(msb, program.memsizer)
val addrofDt = type.typeForUntypedAddressOf(msb, program.target)
return if(addrofDt.isUndefined) InferredTypes.unknown() else InferredTypes.knownFor(addrofDt)
} else if(dereference!=null) {
val type = dereference!!.inferType(program).getOrUndef()
val addrofDt = type.typeForUntypedAddressOf(msb, program.memsizer)
val addrofDt = type.typeForUntypedAddressOf(msb, program.target)
return if(addrofDt.isUndefined) InferredTypes.unknown() else InferredTypes.knownFor(addrofDt)
} else
throw FatalAstException("invalid addressof")
@@ -1149,7 +1149,7 @@ class CharLiteral private constructor(val value: Char,
override fun constValue(program: Program): NumericLiteral? {
if(encoding== Encoding.DEFAULT) // will be determined at a later stage, hopefully
return null
val bytevalue = program.encoding.encodeString(value.toString(), encoding).single()
val bytevalue = program.target.encodeString(value.toString(), encoding).single()
return NumericLiteral(BaseDataType.UBYTE, bytevalue.toDouble(), position)
}
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
@@ -1794,7 +1794,7 @@ class ContainmentCheck(var element: Expression,
val stringval = iterable as StringLiteral
if(stringval.encoding== Encoding.DEFAULT) // will be set at a later stage, hopefully
return null
val exists = program.encoding.encodeString(stringval.value, stringval.encoding).contains(elementConst.number.toInt().toUByte() )
val exists = program.target.encodeString(stringval.value, stringval.encoding).contains(elementConst.number.toInt().toUByte() )
return NumericLiteral.fromBoolean(exists, position)
}
}
@@ -107,21 +107,6 @@ object InferredTypes {
if(instance!=null)
return instance
else
return when {
type.isPointerArray -> InferredType.known(type)
type.isSplitWordArray -> {
when (type.sub) {
BaseDataType.UWORD -> InferredType.known(DataType.arrayFor(BaseDataType.UWORD))
BaseDataType.WORD -> InferredType.known(DataType.arrayFor(BaseDataType.WORD))
BaseDataType.STR -> InferredType.known(DataType.arrayFor(BaseDataType.STR))
else -> throw IllegalArgumentException("invalid sub type")
}
}
type.isArray -> InferredType.known(type)
type.isPointer -> InferredType.known(type)
type.isStructInstance -> InferredType.known(type)
else -> throw IllegalArgumentException("invalid type $type")
}
return InferredType.known(type)
}
}
@@ -389,14 +389,14 @@ class VarDecl(
.build()
}
fun createAuto(array: ArrayLiteral): VarDecl {
fun createAuto(array: ArrayLiteral, target: ICompilationTarget): VarDecl {
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
var arrayDt = array.type.getOrElse { throw FatalAstException("unknown dt") }
if(arrayDt.isSplitWordArray) {
// autovars for array literals are NEVER stored as a split word array!
when(arrayDt.sub) {
BaseDataType.WORD -> arrayDt = DataType.arrayFor(BaseDataType.WORD, false)
BaseDataType.UWORD -> arrayDt = DataType.arrayFor(BaseDataType.UWORD, false)
BaseDataType.WORD -> arrayDt = DataType.arrayFor(BaseDataType.WORD)
BaseDataType.UWORD -> arrayDt = DataType.arrayFor(BaseDataType.UWORD)
else -> { }
}
}
@@ -57,6 +57,8 @@ class IRFileReader {
}
}
}
private lateinit var options: CompilationOptions
private fun parseProgram(reader: XMLEventReader): IRProgram {
require(reader.nextEvent().isStartDocument)
@@ -64,7 +66,7 @@ class IRFileReader {
require(start.name.localPart=="PROGRAM") { "missing PROGRAM" }
val programName = start.attributes.asSequence().single { it.name.localPart == "NAME" }.value
val compilerVersion = start.attributes.asSequence().single { it.name.localPart == "COMPILERVERSION" }.value
val options = parseOptions(reader, compilerVersion)
options = parseOptions(reader, compilerVersion)
val asmsymbols = parseAsmSymbols(reader)
skipText(reader)
@@ -612,13 +614,13 @@ class IRFileReader {
}
}
return when(type) {
"bool" -> DataType.arrayFor(BaseDataType.BOOL, false)
"byte" -> DataType.arrayFor(BaseDataType.BYTE, false)
"ubyte", "str" -> DataType.arrayFor(BaseDataType.UBYTE, false)
"word" -> DataType.arrayFor(BaseDataType.WORD, false)
"uword" -> DataType.arrayFor(BaseDataType.UWORD, false)
"float" -> DataType.arrayFor(BaseDataType.FLOAT, false)
"long" -> DataType.arrayFor(BaseDataType.LONG, false)
"bool" -> DataType.arrayFor(BaseDataType.BOOL)
"byte" -> DataType.arrayFor(BaseDataType.BYTE)
"ubyte", "str" -> DataType.arrayFor(BaseDataType.UBYTE)
"word" -> DataType.arrayFor(BaseDataType.WORD)
"uword" -> DataType.arrayFor(BaseDataType.UWORD)
"float" -> DataType.arrayFor(BaseDataType.FLOAT)
"long" -> DataType.arrayFor(BaseDataType.LONG)
else -> {
throw IRParseException("invalid dt $type")
}
+4 -5
View File
@@ -132,15 +132,14 @@ sealed class PtNamedNode(initialName: String, position: Position): PtNode(positi
class PtProgram(
val name: String,
val memsizer: IMemSizer,
val encoding: IStringEncoding
val target: ICompilationTarget
) : PtNode(Position.DUMMY) {
val memsizer: IMemSizer get() = target
val encoding: IStringEncoding get() = target
// Root node is never transformed - return self
override fun copy(): PtNode = this
// fun allModuleDirectives(): Sequence<PtDirective> =
// children.asSequence().flatMap { it.children }.filterIsInstance<PtDirective>().distinct()
fun allBlocks(): Sequence<PtBlock> =
children.asSequence().filterIsInstance<PtBlock>()
@@ -8,8 +8,7 @@ import prog8.code.core.DataType
import prog8.code.core.Position
import prog8.code.optimize.ComparisonOptimizers
import prog8.code.target.VMTarget
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
/**
* Tests for ComparisonOptimizers, particularly the optimizeComparisonIdentities function.
@@ -21,7 +20,7 @@ class TestComparisonOptimizers: FunSpec({
// Helper to create a simple program with a binary expression in a sub
fun createProgramWithComparison(operator: String, leftType: DataType): PtProgram {
val program = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val program = PtProgram("test", VMTarget())
val block = PtBlock("main", false, prog8.code.source.SourceCode.Generated("main"), PtBlock.Options(), Position.DUMMY)
program.add(block)
@@ -12,8 +12,7 @@ import prog8.code.core.DataType
import prog8.code.core.Position
import prog8.code.core.ZeropageWish
import prog8.code.source.SourceCode
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder
import prog8.code.target.VMTarget
/**
* Tests for SymbolTable construction and structural integrity.
@@ -32,14 +31,14 @@ class TestSymbolTableConstruction: FunSpec({
// ============================================================================
fun makeSimpleSymbolTable(): SymbolTable {
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astProgram = PtProgram("test", VMTarget())
val astBlock = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY)
astProgram.add(astBlock)
return SymbolTable(astProgram)
}
fun makeSymbolTableWithDuplicates(): Pair<SymbolTable, StStaticVariable> {
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astProgram = PtProgram("test", VMTarget())
val astBlock = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY)
astProgram.add(astBlock)
val st = SymbolTable(astProgram)
@@ -59,7 +58,7 @@ class TestSymbolTableConstruction: FunSpec({
// ============================================================================
test("empty symboltable creation") {
val astNode = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astNode = PtProgram("test", VMTarget())
val st = SymbolTable(astNode)
st.name shouldBe "test"
st.type shouldBe StNodeType.GLOBAL
@@ -75,7 +74,7 @@ class TestSymbolTableConstruction: FunSpec({
}
test("symboltable with multiple modules") {
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astProgram = PtProgram("test", VMTarget())
val astBlock1 = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY)
val astBlock2 = PtBlock("block2", false, SourceCode.Generated("block2"), PtBlock.Options(), Position.DUMMY)
astProgram.add(astBlock1)
@@ -100,7 +99,7 @@ class TestSymbolTableConstruction: FunSpec({
}
test("duplicate struct instance insertion is handled") {
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astProgram = PtProgram("test", VMTarget())
val astBlock = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY)
astProgram.add(astBlock)
val st = SymbolTable(astProgram)
@@ -119,7 +118,7 @@ class TestSymbolTableConstruction: FunSpec({
}
test("duplicate memory slab insertion is handled") {
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astProgram = PtProgram("test", VMTarget())
val astBlock = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY)
astProgram.add(astBlock)
val st = SymbolTable(astProgram)
@@ -138,7 +137,7 @@ class TestSymbolTableConstruction: FunSpec({
}
test("duplicate label insertion is handled") {
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astProgram = PtProgram("test", VMTarget())
val astBlock = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY)
astProgram.add(astBlock)
val st = SymbolTable(astProgram)
@@ -218,7 +217,7 @@ class TestSymbolTableConstruction: FunSpec({
// ================================================================================
private fun makeStWithVariables(): SymbolTable {
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astProgram = PtProgram("test", VMTarget())
val astBlock = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY)
astProgram.add(astBlock)
val st = SymbolTable(astProgram)
@@ -235,7 +234,7 @@ private fun makeStWithVariables(): SymbolTable {
}
private fun makeStWithMemVars(): SymbolTable {
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astProgram = PtProgram("test", VMTarget())
val astBlock = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY)
astProgram.add(astBlock)
val st = SymbolTable(astProgram)
@@ -250,7 +249,7 @@ private fun makeStWithMemVars(): SymbolTable {
}
private fun makeStWithSlabs(): SymbolTable {
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astProgram = PtProgram("test", VMTarget())
val astBlock = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY)
astProgram.add(astBlock)
val st = SymbolTable(astProgram)
@@ -265,7 +264,7 @@ private fun makeStWithSlabs(): SymbolTable {
}
private fun makeStWithStructInstances(): SymbolTable {
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astProgram = PtProgram("test", VMTarget())
val astBlock = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY)
astProgram.add(astBlock)
val st = SymbolTable(astProgram)
@@ -280,7 +279,7 @@ private fun makeStWithStructInstances(): SymbolTable {
}
private fun makeStWithStructs(): SymbolTable {
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
val astProgram = PtProgram("test", VMTarget())
val astBlock = PtBlock("block1", false, SourceCode.Generated("block1"), PtBlock.Options(), Position.DUMMY)
astProgram.add(astBlock)
val st = SymbolTable(astProgram)