mirror of
https://github.com/irmen/prog8.git
synced 2025-04-07 16:41:46 +00:00
New [x]*42 syntax to create array literals with repeated values (like "abc"*10 already exists for strings)
Should be used in place of array initializer expressions that contain only a single numeric value to initialize the whole array with. That isn't supported anymore.
This commit is contained in:
parent
7a0eaf3148
commit
66829203d8
@ -2,6 +2,7 @@ package prog8.optimizer
|
||||
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.maySwapOperandOrder
|
||||
import prog8.ast.statements.*
|
||||
@ -112,6 +113,28 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors:
|
||||
}
|
||||
}
|
||||
|
||||
if(expr.left.inferType(program).isArray) {
|
||||
if (expr.operator=="*" && rightconst!=null) {
|
||||
if (expr.left is ArrayLiteral) {
|
||||
// concatenate array literal.
|
||||
val part = expr.left as ArrayLiteral
|
||||
if(part.value.isEmpty())
|
||||
errors.warn("resulting array has length zero", part.position)
|
||||
val tmp = mutableListOf<Expression>()
|
||||
repeat(rightconst.number.toInt()) {
|
||||
tmp += part.value
|
||||
}
|
||||
val newArray = ArrayLiteral(part.type, tmp.toTypedArray(), part.position)
|
||||
return listOf(IAstModification.ReplaceNode(expr, newArray, parent))
|
||||
}
|
||||
else {
|
||||
val leftTarget = (expr.left as? IdentifierReference)?.targetVarDecl(program)
|
||||
if(leftTarget!=null && leftTarget.origin==VarDeclOrigin.ARRAYLITERAL)
|
||||
throw FatalAstException("shouldn't see an array literal converted to an autovar here")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(expr.operator=="==" && rightconst!=null) {
|
||||
val leftExpr = expr.left as? BinaryExpression
|
||||
// only do this shuffling when the LHS is not a constant itself (otherwise problematic nested replacements)
|
||||
|
@ -60,17 +60,19 @@ internal class LiteralsToAutoVars(private val program: Program, private val erro
|
||||
return noModifications
|
||||
}
|
||||
if(arrayDt.isKnown) {
|
||||
val parentAssign = parent as? Assignment
|
||||
val targetDt = parentAssign?.target?.inferType(program) ?: arrayDt
|
||||
// turn the array literal it into an identifier reference
|
||||
val litval2 = array.cast(targetDt.getOr(DataType.UNDEFINED))
|
||||
if(litval2!=null) {
|
||||
val vardecl2 = VarDecl.createAuto(litval2, targetDt.getOr(DataType.UNDEFINED) in SplitWordArrayTypes)
|
||||
val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position)
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(array, identifier, parent),
|
||||
IAstModification.InsertFirst(vardecl2, array.definingScope)
|
||||
)
|
||||
if((array.parent as? BinaryExpression)?.operator!="*") {
|
||||
val parentAssign = parent as? Assignment
|
||||
val targetDt = parentAssign?.target?.inferType(program) ?: arrayDt
|
||||
// turn the array literal it into an identifier reference
|
||||
val litval2 = array.cast(targetDt.getOr(DataType.UNDEFINED))
|
||||
if (litval2 != null) {
|
||||
val vardecl2 = VarDecl.createAuto(litval2, targetDt.getOr(DataType.UNDEFINED) in SplitWordArrayTypes)
|
||||
val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position)
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(array, identifier, parent),
|
||||
IAstModification.InsertFirst(vardecl2, array.definingScope)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,10 @@ import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import prog8.code.ast.PtBuiltinFunctionCall
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.SymbolTableMaker
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.VMTarget
|
||||
import prog8tests.helpers.ErrorReporterForTests
|
||||
@ -403,5 +406,139 @@ main {
|
||||
(x.children[18] as PtBuiltinFunctionCall).name shouldBe "prog8_lib_arraycopy"
|
||||
(x.children[19] as PtBuiltinFunctionCall).name shouldBe "prog8_lib_arraycopy"
|
||||
}
|
||||
|
||||
test("array and string initializer with multiplication") {
|
||||
val src="""
|
||||
%option enable_floats
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
str name = "xyz" * 3
|
||||
bool[3] boolarray = [true] * 3
|
||||
ubyte[3] bytearray = [42] * 3
|
||||
uword[3] wordarray = [5555] * 3
|
||||
float[3] floatarray = [123.45] * 3
|
||||
}
|
||||
}"""
|
||||
val result = compileText(C64Target(), false, src, writeAssembly = true)!!
|
||||
val x = result.codegenAst!!.entrypoint()!!
|
||||
x.children.size shouldBe 6
|
||||
((x.children[0] as PtVariable).value as PtString).value shouldBe "xyzxyzxyz"
|
||||
val array1 = (x.children[1] as PtVariable).value as PtArray
|
||||
val array2 = (x.children[2] as PtVariable).value as PtArray
|
||||
val array3 = (x.children[3] as PtVariable).value as PtArray
|
||||
val array4 = (x.children[4] as PtVariable).value as PtArray
|
||||
array1.children.map { (it as PtBool).value } shouldBe listOf(true, true, true)
|
||||
array2.children.map { (it as PtNumber).number } shouldBe listOf(42, 42, 42)
|
||||
array3.children.map { (it as PtNumber).number } shouldBe listOf(5555, 5555, 5555)
|
||||
array4.children.map { (it as PtNumber).number } shouldBe listOf(123.45, 123.45, 123.45)
|
||||
}
|
||||
|
||||
test("array initializer with range") {
|
||||
val src="""
|
||||
%option enable_floats
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
ubyte[3] bytearray2 = 10 to 12
|
||||
uword[3] wordarray2 = 5000 to 5002
|
||||
float[3] floatarray2 = 100 to 102
|
||||
}
|
||||
}"""
|
||||
val result = compileText(C64Target(), false, src, writeAssembly = true)!!
|
||||
val x = result.codegenAst!!.entrypoint()!!
|
||||
x.children.size shouldBe 4
|
||||
val array1 = (x.children[0] as PtVariable).value as PtArray
|
||||
val array2 = (x.children[1] as PtVariable).value as PtArray
|
||||
val array3 = (x.children[2] as PtVariable).value as PtArray
|
||||
array1.children.map { (it as PtNumber).number } shouldBe listOf(10, 11, 12)
|
||||
array2.children.map { (it as PtNumber).number } shouldBe listOf(5000, 5001, 5002)
|
||||
array3.children.map { (it as PtNumber).number } shouldBe listOf(100, 101, 102)
|
||||
}
|
||||
|
||||
|
||||
fun getTestOptions(): CompilationOptions {
|
||||
val target = VMTarget()
|
||||
return CompilationOptions(
|
||||
OutputType.RAW,
|
||||
CbmPrgLauncherType.NONE,
|
||||
ZeropageType.DONTUSE,
|
||||
zpReserved = emptyList(),
|
||||
zpAllowed = CompilationOptions.AllZeropageAllowed,
|
||||
floats = true,
|
||||
noSysInit = false,
|
||||
compTarget = target,
|
||||
loadAddress = target.machine.PROGRAM_LOAD_ADDRESS
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
test("array assignments with ranges and multiplications") {
|
||||
val src="""
|
||||
%option enable_floats
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
bool[4] boolarray3
|
||||
ubyte[4] bytearray3
|
||||
uword[4] wordarray3
|
||||
float[4] floatarray3
|
||||
|
||||
boolarray3 = [true] *4
|
||||
bytearray3 = [42]*4
|
||||
wordarray3 = [999]*4
|
||||
wordarray3 = [&bytearray3]*4
|
||||
wordarray3 = [bytearray3]*4
|
||||
floatarray3 = [99.77]*4
|
||||
|
||||
bytearray3 = 10 to 13
|
||||
wordarray3 = 5000 to 5003
|
||||
floatarray3 = 100 to 103
|
||||
}
|
||||
}"""
|
||||
val ast = compileText(C64Target(), false, src, writeAssembly = true)!!.codegenAst!!
|
||||
val x = ast.entrypoint()!!
|
||||
x.children.size shouldBe 23
|
||||
val assign1value = (x.children[13] as PtBuiltinFunctionCall).args[1]
|
||||
val assign2value = (x.children[14] as PtBuiltinFunctionCall).args[1]
|
||||
val assign3value = (x.children[15] as PtBuiltinFunctionCall).args[1]
|
||||
val assign4value = (x.children[16] as PtBuiltinFunctionCall).args[1]
|
||||
val assign5value = (x.children[17] as PtBuiltinFunctionCall).args[1]
|
||||
val assign6value = (x.children[18] as PtBuiltinFunctionCall).args[1]
|
||||
val assign7value = (x.children[19] as PtBuiltinFunctionCall).args[1]
|
||||
val assign8value = (x.children[20] as PtBuiltinFunctionCall).args[1]
|
||||
val assign9value = (x.children[21] as PtBuiltinFunctionCall).args[1]
|
||||
val options = getTestOptions()
|
||||
val st = SymbolTableMaker(ast, options).make()
|
||||
|
||||
val heapvar1 = st.lookup((assign1value as PtIdentifier).name) as StStaticVariable
|
||||
val heapvar2 = st.lookup((assign2value as PtIdentifier).name) as StStaticVariable
|
||||
val heapvar3 = st.lookup((assign3value as PtIdentifier).name) as StStaticVariable
|
||||
val heapvar4 = st.lookup((assign4value as PtIdentifier).name) as StStaticVariable
|
||||
val heapvar5 = st.lookup((assign5value as PtIdentifier).name) as StStaticVariable
|
||||
val heapvar6 = st.lookup((assign6value as PtIdentifier).name) as StStaticVariable
|
||||
val heapvar7 = st.lookup((assign7value as PtIdentifier).name) as StStaticVariable
|
||||
val heapvar8 = st.lookup((assign8value as PtIdentifier).name) as StStaticVariable
|
||||
val heapvar9 = st.lookup((assign9value as PtIdentifier).name) as StStaticVariable
|
||||
heapvar1.length shouldBe 4
|
||||
heapvar2.length shouldBe 4
|
||||
heapvar3.length shouldBe 4
|
||||
heapvar4.length shouldBe 4
|
||||
heapvar5.length shouldBe 4
|
||||
heapvar6.length shouldBe 4
|
||||
heapvar7.length shouldBe 4
|
||||
heapvar8.length shouldBe 4
|
||||
heapvar9.length shouldBe 4
|
||||
heapvar1.dt shouldBe DataType.ARRAY_BOOL
|
||||
heapvar2.dt shouldBe DataType.ARRAY_UB
|
||||
heapvar3.dt shouldBe DataType.ARRAY_UW
|
||||
heapvar4.dt shouldBe DataType.ARRAY_UW
|
||||
heapvar5.dt shouldBe DataType.ARRAY_UW
|
||||
heapvar6.dt shouldBe DataType.ARRAY_F
|
||||
heapvar7.dt shouldBe DataType.ARRAY_UB
|
||||
heapvar8.dt shouldBe DataType.ARRAY_UW
|
||||
heapvar9.dt shouldBe DataType.ARRAY_F
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
@ -1,12 +1,11 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- remove support for array variable initialization with a single value, just require explicitly creating the value array [42] * 10 (which is what the compiler now does for you implicitly)
|
||||
- word arrays (after ast processing) should no longer contain identifiers, these should have been replaced by &identifier.
|
||||
- should the array-to-array assignment support be removed and instead require an explicit copy function call? What prog8_lib_arraycopy() now does. Or just use memcopy.
|
||||
- should we add a cleararray builtin function that can efficiently set every element in the array to the given value
|
||||
|
||||
|
||||
|
||||
Improve register load order in subroutine call args assignments:
|
||||
in certain situations, the "wrong" order of evaluation of function call arguments is done which results
|
||||
in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!)
|
||||
|
@ -6,22 +6,13 @@
|
||||
|
||||
main {
|
||||
|
||||
str name = "xyz" * 3
|
||||
bool[3] boolarray = true
|
||||
ubyte[3] bytearray = 52
|
||||
uword[3] wordarray = 5544
|
||||
float[3] floatarray = 123.45
|
||||
sub arrayinit_with_multiplier() {
|
||||
str name = "xyz" * 3
|
||||
bool[3] boolarray = [true] * 3
|
||||
ubyte[3] bytearray = [42] * 3
|
||||
uword[3] wordarray = [5555] * 3
|
||||
float[3] floatarray = [123.45] * 3
|
||||
|
||||
ubyte[3] bytearray2 = 10 to 12
|
||||
uword[3] wordarray2 = 5540 to 5542
|
||||
float[3] floatarray2 = 123 to 125
|
||||
|
||||
bool[3] boolarray3
|
||||
ubyte[3] bytearray3
|
||||
uword[3] wordarray3
|
||||
float[3] floatarray3
|
||||
|
||||
sub start() {
|
||||
txt.print(name)
|
||||
txt.nl()
|
||||
for cx16.r1L in 0 to 2 {
|
||||
@ -36,6 +27,12 @@ main {
|
||||
}
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub arrayinit_with_range() {
|
||||
ubyte[3] bytearray2 = 10 to 12
|
||||
uword[3] wordarray2 = 5000 to 5002
|
||||
float[3] floatarray2 = 100 to 102
|
||||
|
||||
for cx16.r1L in 0 to 2 {
|
||||
txt.print_ub(bytearray2[cx16.r1L])
|
||||
@ -47,6 +44,20 @@ main {
|
||||
}
|
||||
txt.nl()
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub arrayassign() {
|
||||
bool[4] boolarray3
|
||||
ubyte[4] bytearray3
|
||||
uword[4] wordarray3
|
||||
float[4] floatarray3
|
||||
|
||||
boolarray3 = [true] *4
|
||||
bytearray3 = [42]*4
|
||||
wordarray3 = [999]*4
|
||||
wordarray3 = [&bytearray3]*4
|
||||
wordarray3 = [bytearray3]*4
|
||||
floatarray3 = [99.77]*4
|
||||
|
||||
for cx16.r1L in 0 to 2 {
|
||||
txt.print_bool(boolarray3[cx16.r1L])
|
||||
@ -60,4 +71,10 @@ main {
|
||||
}
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub start() {
|
||||
arrayinit_with_multiplier()
|
||||
arrayinit_with_range()
|
||||
arrayassign()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user