mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 03:54:27 +00:00
first steps to add support for str parameter type
This commit is contained in:
parent
17175df835
commit
69a8813a3d
@ -74,6 +74,27 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
|
|||||||
override fun before(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
|
override fun before(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
|
||||||
subroutineVariables.clear()
|
subroutineVariables.clear()
|
||||||
addedIfConditionVars.clear()
|
addedIfConditionVars.clear()
|
||||||
|
|
||||||
|
if(!subroutine.isAsmSubroutine) {
|
||||||
|
// change 'str' parameters into 'uword' (just treat it as an address)
|
||||||
|
// TODO fix [TypecastsAdder] to treat str param vars as uword instead of adding casts/addressof (which is wrong for str *parameters*)
|
||||||
|
val stringParams = subroutine.parameters.filter { it.type==DataType.STR }
|
||||||
|
val parameterChanges = stringParams.map {
|
||||||
|
val uwordParam = SubroutineParameter(it.name, DataType.UWORD, it.position)
|
||||||
|
IAstModification.ReplaceNode(it, uwordParam, subroutine)
|
||||||
|
}
|
||||||
|
|
||||||
|
val stringParamNames = stringParams.map { it.name }.toSet()
|
||||||
|
val varsChanges = subroutine.statements
|
||||||
|
.filterIsInstance<VarDecl>()
|
||||||
|
.filter { it.autogeneratedDontRemove && it.name in stringParamNames }
|
||||||
|
.map {
|
||||||
|
val newvar = VarDecl(it.type, DataType.UWORD, it.zeropage, null, it.name, null, false, true, it.sharedWithAsm, it.position)
|
||||||
|
IAstModification.ReplaceNode(it, newvar, subroutine)
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameterChanges + varsChanges
|
||||||
|
}
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +346,7 @@ private fun writeAssembly(programAst: Program,
|
|||||||
programAst.processAstBeforeAsmGeneration(errors, compilerOptions.compTarget)
|
programAst.processAstBeforeAsmGeneration(errors, compilerOptions.compTarget)
|
||||||
errors.report()
|
errors.report()
|
||||||
|
|
||||||
// printAst(programAst)
|
printAst(programAst) // TODO
|
||||||
|
|
||||||
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
|
compilerOptions.compTarget.machine.initializeZeropage(compilerOptions)
|
||||||
val assembly = asmGeneratorFor(compilerOptions.compTarget,
|
val assembly = asmGeneratorFor(compilerOptions.compTarget,
|
||||||
|
@ -382,10 +382,12 @@ internal class AstChecker(private val program: Program,
|
|||||||
err("can only use Carry as status flag parameter")
|
err("can only use Carry as status flag parameter")
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Pass-by-reference datatypes can not occur as parameters to a subroutine directly
|
// Non-string Pass-by-reference datatypes can not occur as parameters to a subroutine directly
|
||||||
// Instead, their reference (address) should be passed (as an UWORD).
|
// Instead, their reference (address) should be passed (as an UWORD).
|
||||||
if(subroutine.parameters.any{it.type in PassByReferenceDatatypes }) {
|
for(p in subroutine.parameters) {
|
||||||
err("Pass-by-reference types (str, array) cannot occur as a parameter type directly. Instead, use an uword to receive their address, or access the variable from the outer scope directly.")
|
if(p.type in PassByReferenceDatatypes && p.type != DataType.STR) {
|
||||||
|
err("Non-string pass-by-reference types cannot occur as a parameter type directly. Instead, use an uword to receive their address, or access the variable from the outer scope directly.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ locallabel:
|
|||||||
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
val assign8 = Assignment(tgt, AddressOf(IdentifierReference(listOf("main","label_outside"), Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||||
|
|
||||||
val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8)
|
val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8)
|
||||||
val subroutine = Subroutine("start", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, statements, Position.DUMMY)
|
val subroutine = Subroutine("start", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, statements, Position.DUMMY)
|
||||||
val labelInBlock = Label("label_outside", Position.DUMMY)
|
val labelInBlock = Label("label_outside", Position.DUMMY)
|
||||||
val varInBlock = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, false, Position.DUMMY)
|
val varInBlock = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, false, Position.DUMMY)
|
||||||
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
|
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
|
||||||
|
@ -89,7 +89,7 @@ class TestMemory {
|
|||||||
val memexpr = IdentifierReference(listOf("address"), Position.DUMMY)
|
val memexpr = IdentifierReference(listOf("address"), Position.DUMMY)
|
||||||
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
||||||
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
module.linkIntoProgram(program)
|
module.linkIntoProgram(program)
|
||||||
return target
|
return target
|
||||||
@ -107,7 +107,7 @@ class TestMemory {
|
|||||||
val decl = VarDecl(VarDeclType.VAR, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", null, false, false, false, Position.DUMMY)
|
val decl = VarDecl(VarDeclType.VAR, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", null, false, false, false, Position.DUMMY)
|
||||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
||||||
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
@ -121,7 +121,7 @@ class TestMemory {
|
|||||||
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY)
|
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY)
|
||||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
||||||
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
@ -135,7 +135,7 @@ class TestMemory {
|
|||||||
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY)
|
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY)
|
||||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
||||||
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
@ -149,7 +149,7 @@ class TestMemory {
|
|||||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||||
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
||||||
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
@ -164,7 +164,7 @@ class TestMemory {
|
|||||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||||
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
||||||
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
@ -179,7 +179,7 @@ class TestMemory {
|
|||||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||||
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
|
||||||
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
val program = Program("test", DummyFunctions, DummyMemsizer)
|
val program = Program("test", DummyFunctions, DummyMemsizer)
|
||||||
.addModule(module)
|
.addModule(module)
|
||||||
|
@ -4,8 +4,8 @@ import org.junit.jupiter.api.Disabled
|
|||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.statements.Block
|
import prog8.ast.expressions.IdentifierReference
|
||||||
import prog8.ast.statements.Subroutine
|
import prog8.ast.statements.*
|
||||||
import prog8.compiler.target.C64Target
|
import prog8.compiler.target.C64Target
|
||||||
import prog8tests.helpers.ErrorReporterForTests
|
import prog8tests.helpers.ErrorReporterForTests
|
||||||
import prog8tests.helpers.assertFailure
|
import prog8tests.helpers.assertFailure
|
||||||
@ -17,31 +17,6 @@ import kotlin.test.*
|
|||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
class TestSubroutines {
|
class TestSubroutines {
|
||||||
|
|
||||||
@Test
|
|
||||||
fun stringParameterNotYetAllowed_ButShouldPerhapsBe() {
|
|
||||||
// note: the *parser* accepts this as it is valid *syntax*,
|
|
||||||
// however, it's not (yet) valid for the compiler
|
|
||||||
val text = """
|
|
||||||
main {
|
|
||||||
sub start() {
|
|
||||||
str zzz ; should give uninitialized error
|
|
||||||
}
|
|
||||||
|
|
||||||
asmsub asmfunc(str thing @AY) {
|
|
||||||
}
|
|
||||||
|
|
||||||
sub func(str thing) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
val errors = ErrorReporterForTests()
|
|
||||||
compileText(C64Target, false, text, errors, false).assertFailure("currently str type in signature is invalid") // TODO should not be invalid
|
|
||||||
assertEquals(0, errors.warnings.size)
|
|
||||||
assertEquals(2, errors.errors.size)
|
|
||||||
assertContains(errors.errors[0], ".p8:4:20: string var must be initialized with a string literal")
|
|
||||||
assertContains(errors.errors[1], ".p8:10:16: Pass-by-reference types (str, array) cannot occur as a parameter type directly")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun arrayParameterNotYetAllowed_ButShouldPerhapsBe() {
|
fun arrayParameterNotYetAllowed_ButShouldPerhapsBe() {
|
||||||
// note: the *parser* accepts this as it is valid *syntax*,
|
// note: the *parser* accepts this as it is valid *syntax*,
|
||||||
@ -62,11 +37,10 @@ class TestSubroutines {
|
|||||||
val errors = ErrorReporterForTests()
|
val errors = ErrorReporterForTests()
|
||||||
compileText(C64Target, false, text, errors, false).assertFailure("currently array dt in signature is invalid") // TODO should not be invalid?
|
compileText(C64Target, false, text, errors, false).assertFailure("currently array dt in signature is invalid") // TODO should not be invalid?
|
||||||
assertEquals(0, errors.warnings.size)
|
assertEquals(0, errors.warnings.size)
|
||||||
assertContains(errors.errors.single(), ".p8:9:16: Pass-by-reference types (str, array) cannot occur as a parameter type directly")
|
assertContains(errors.errors.single(), ".p8:9:16: Non-string pass-by-reference types cannot occur as a parameter type directly")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled("TODO: allow string parameter in signature") // TODO allow this
|
|
||||||
fun stringParameter() {
|
fun stringParameter() {
|
||||||
val text = """
|
val text = """
|
||||||
main {
|
main {
|
||||||
@ -76,17 +50,17 @@ class TestSubroutines {
|
|||||||
asmfunc("text")
|
asmfunc("text")
|
||||||
asmfunc(text)
|
asmfunc(text)
|
||||||
asmfunc($2000)
|
asmfunc($2000)
|
||||||
asmfunc(12.345)
|
|
||||||
func("text")
|
func("text")
|
||||||
func(text)
|
func(text)
|
||||||
func($2000)
|
func($2000)
|
||||||
func(12.345)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub asmfunc(str thing @AY) {
|
asmsub asmfunc(str thing @AY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub func(str thing) {
|
sub func(str thing) {
|
||||||
|
uword t2 = thing as uword
|
||||||
|
asmfunc(thing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@ -100,7 +74,69 @@ class TestSubroutines {
|
|||||||
assertTrue(asmfunc.statements.isEmpty())
|
assertTrue(asmfunc.statements.isEmpty())
|
||||||
assertFalse(func.isAsmSubroutine)
|
assertFalse(func.isAsmSubroutine)
|
||||||
assertEquals(DataType.STR, func.parameters.single().type)
|
assertEquals(DataType.STR, func.parameters.single().type)
|
||||||
assertTrue(func.statements.isEmpty())
|
assertEquals(3, func.statements.size)
|
||||||
|
val paramvar = func.statements[0] as VarDecl
|
||||||
|
assertEquals("thing", paramvar.name)
|
||||||
|
assertEquals(DataType.STR, paramvar.datatype)
|
||||||
|
val t2var = func.statements[1] as VarDecl
|
||||||
|
assertEquals("t2", t2var.name)
|
||||||
|
assertTrue(t2var.value is IdentifierReference, "str param in function body should be treated as plain uword")
|
||||||
|
assertEquals("thing", (t2var.value as IdentifierReference).nameInSource.single())
|
||||||
|
val call = func.statements[2] as FunctionCallStatement
|
||||||
|
assertEquals("asmfunc", call.target.nameInSource.single())
|
||||||
|
assertTrue(call.args.single() is IdentifierReference, "str param in function body should be treated as plain uword")
|
||||||
|
assertEquals("thing", (call.args.single() as IdentifierReference).nameInSource.single())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun stringParameterAsmGen() {
|
||||||
|
val text = """
|
||||||
|
main {
|
||||||
|
sub start() {
|
||||||
|
str text = "test"
|
||||||
|
|
||||||
|
asmfunc("text")
|
||||||
|
asmfunc(text)
|
||||||
|
asmfunc($2000)
|
||||||
|
func("text")
|
||||||
|
func(text)
|
||||||
|
func($2000)
|
||||||
|
}
|
||||||
|
|
||||||
|
asmsub asmfunc(str thing @AY) {
|
||||||
|
}
|
||||||
|
|
||||||
|
sub func(str thing) {
|
||||||
|
uword t2 = thing as uword
|
||||||
|
asmfunc(thing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
val result = compileText(C64Target, false, text, writeAssembly = true).assertSuccess()
|
||||||
|
val module = result.programAst.toplevelModule
|
||||||
|
val mainBlock = module.statements.single() as Block
|
||||||
|
val asmfunc = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="asmfunc"}
|
||||||
|
val func = mainBlock.statements.filterIsInstance<Subroutine>().single { it.name=="func"}
|
||||||
|
assertTrue(asmfunc.isAsmSubroutine)
|
||||||
|
assertEquals(DataType.STR, asmfunc.parameters.single().type)
|
||||||
|
assertTrue(asmfunc.statements.single() is Return)
|
||||||
|
assertFalse(func.isAsmSubroutine)
|
||||||
|
assertEquals(DataType.UWORD, func.parameters.single().type, "asmgen should have changed str to uword type")
|
||||||
|
assertTrue(asmfunc.statements.last() is Return)
|
||||||
|
|
||||||
|
assertEquals(4, func.statements.size)
|
||||||
|
assertTrue(func.statements[3] is Return)
|
||||||
|
val paramvar = func.statements[0] as VarDecl
|
||||||
|
assertEquals("thing", paramvar.name)
|
||||||
|
assertEquals(DataType.UWORD, paramvar.datatype, "pre-asmgen should have changed str to uword type")
|
||||||
|
val t2var = func.statements[1] as VarDecl
|
||||||
|
assertEquals("t2", t2var.name)
|
||||||
|
assertTrue(t2var.value is IdentifierReference, "str param in function body should be treated as plain uword")
|
||||||
|
assertEquals("thing", (t2var.value as IdentifierReference).nameInSource.single())
|
||||||
|
val call = func.statements[2] as FunctionCallStatement
|
||||||
|
assertEquals("asmfunc", call.target.nameInSource.single())
|
||||||
|
assertTrue(call.args.single() is IdentifierReference, "str param in function body should be treated as plain uword")
|
||||||
|
assertEquals("thing", (call.args.single() as IdentifierReference).nameInSource.single())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -186,7 +186,7 @@ private fun Prog8ANTLRParser.AsmsubroutineContext.toAst(): Subroutine {
|
|||||||
val inline = this.inline()!=null
|
val inline = this.inline()!=null
|
||||||
val subdecl = asmsub_decl().toAst()
|
val subdecl = asmsub_decl().toAst()
|
||||||
val statements = statement_block()?.toAst() ?: mutableListOf()
|
val statements = statement_block()?.toAst() ?: mutableListOf()
|
||||||
return Subroutine(subdecl.name, subdecl.parameters, subdecl.returntypes,
|
return Subroutine(subdecl.name, subdecl.parameters.toMutableList(), subdecl.returntypes,
|
||||||
subdecl.asmParameterRegisters, subdecl.asmReturnvaluesRegisters,
|
subdecl.asmParameterRegisters, subdecl.asmReturnvaluesRegisters,
|
||||||
subdecl.asmClobbers, null, true, inline, statements, toPosition())
|
subdecl.asmClobbers, null, true, inline, statements, toPosition())
|
||||||
}
|
}
|
||||||
@ -194,7 +194,7 @@ private fun Prog8ANTLRParser.AsmsubroutineContext.toAst(): Subroutine {
|
|||||||
private fun Prog8ANTLRParser.RomsubroutineContext.toAst(): Subroutine {
|
private fun Prog8ANTLRParser.RomsubroutineContext.toAst(): Subroutine {
|
||||||
val subdecl = asmsub_decl().toAst()
|
val subdecl = asmsub_decl().toAst()
|
||||||
val address = integerliteral().toAst().number.toInt()
|
val address = integerliteral().toAst().number.toInt()
|
||||||
return Subroutine(subdecl.name, subdecl.parameters, subdecl.returntypes,
|
return Subroutine(subdecl.name, subdecl.parameters.toMutableList(), subdecl.returntypes,
|
||||||
subdecl.asmParameterRegisters, subdecl.asmReturnvaluesRegisters,
|
subdecl.asmParameterRegisters, subdecl.asmReturnvaluesRegisters,
|
||||||
subdecl.asmClobbers, address, true, inline = false, statements = mutableListOf(), position = toPosition()
|
subdecl.asmClobbers, address, true, inline = false, statements = mutableListOf(), position = toPosition()
|
||||||
)
|
)
|
||||||
@ -306,7 +306,7 @@ private fun Prog8ANTLRParser.SubroutineContext.toAst() : Subroutine {
|
|||||||
val inline = inline()!=null
|
val inline = inline()!=null
|
||||||
val returntypes = sub_return_part()?.toAst() ?: emptyList()
|
val returntypes = sub_return_part()?.toAst() ?: emptyList()
|
||||||
return Subroutine(identifier().text,
|
return Subroutine(identifier().text,
|
||||||
sub_params()?.toAst() ?: emptyList(),
|
sub_params()?.toAst()?.toMutableList() ?: mutableListOf(),
|
||||||
returntypes,
|
returntypes,
|
||||||
statement_block()?.toAst() ?: mutableListOf(),
|
statement_block()?.toAst() ?: mutableListOf(),
|
||||||
inline,
|
inline,
|
||||||
|
@ -597,7 +597,7 @@ class AsmGenInfo {
|
|||||||
// and also the predefined/ROM/register-based subroutines.
|
// and also the predefined/ROM/register-based subroutines.
|
||||||
// (multiple return types can only occur for the latter type)
|
// (multiple return types can only occur for the latter type)
|
||||||
class Subroutine(override val name: String,
|
class Subroutine(override val name: String,
|
||||||
val parameters: List<SubroutineParameter>,
|
val parameters: MutableList<SubroutineParameter>,
|
||||||
val returntypes: List<DataType>,
|
val returntypes: List<DataType>,
|
||||||
val asmParameterRegisters: List<RegisterOrStatusflag>,
|
val asmParameterRegisters: List<RegisterOrStatusflag>,
|
||||||
val asmReturnvaluesRegisters: List<RegisterOrStatusflag>,
|
val asmReturnvaluesRegisters: List<RegisterOrStatusflag>,
|
||||||
@ -608,7 +608,7 @@ class Subroutine(override val name: String,
|
|||||||
override var statements: MutableList<Statement>,
|
override var statements: MutableList<Statement>,
|
||||||
override val position: Position) : Statement(), INameScope, ISymbolStatement {
|
override val position: Position) : Statement(), INameScope, ISymbolStatement {
|
||||||
|
|
||||||
constructor(name: String, parameters: List<SubroutineParameter>, returntypes: List<DataType>, statements: MutableList<Statement>, inline: Boolean, position: Position)
|
constructor(name: String, parameters: MutableList<SubroutineParameter>, returntypes: List<DataType>, statements: MutableList<Statement>, inline: Boolean, position: Position)
|
||||||
: this(name, parameters, returntypes, emptyList(), determineReturnRegisters(returntypes), emptySet(), null, false, inline, statements, position)
|
: this(name, parameters, returntypes, emptyList(), determineReturnRegisters(returntypes), emptySet(), null, false, inline, statements, position)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -635,10 +635,19 @@ class Subroutine(override val name: String,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||||
require(replacement is Statement)
|
when(replacement) {
|
||||||
val idx = statements.indexOfFirst { it===node }
|
is SubroutineParameter -> {
|
||||||
statements[idx] = replacement
|
val idx = parameters.indexOf(node)
|
||||||
replacement.parent = this
|
parameters[idx] = replacement
|
||||||
|
replacement.parent = this
|
||||||
|
}
|
||||||
|
is Statement -> {
|
||||||
|
val idx = statements.indexOfFirst { it===node }
|
||||||
|
statements[idx] = replacement
|
||||||
|
replacement.parent = this
|
||||||
|
}
|
||||||
|
else -> throw FatalAstException("can't replace")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
|
@ -1,17 +1,39 @@
|
|||||||
|
%import string
|
||||||
|
%import textio
|
||||||
|
%zeropage basicsafe
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
str zzz
|
str text = "variable"
|
||||||
|
|
||||||
|
@($2000) = 'a'
|
||||||
|
@($2001) = 'b'
|
||||||
|
@($2002) = 'c'
|
||||||
|
@($2003) = 0
|
||||||
|
|
||||||
asmfunc("text")
|
asmfunc("text")
|
||||||
|
asmfunc(text)
|
||||||
|
asmfunc($2000)
|
||||||
func("text")
|
func("text")
|
||||||
|
func(text)
|
||||||
|
func($2000)
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub asmfunc(str thing @AY) {
|
asmsub asmfunc(str thing @AY) {
|
||||||
%asm {{
|
%asm {{
|
||||||
rts
|
sta func.thing
|
||||||
|
sty func.thing+1
|
||||||
|
jmp func
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; TODO fix asmgen when using 'str' type
|
||||||
sub func(str thing) {
|
sub func(uword thing) {
|
||||||
|
uword t2 = thing as uword
|
||||||
|
ubyte length = string.length(thing)
|
||||||
|
txt.print_ub(length)
|
||||||
|
txt.nl()
|
||||||
|
txt.print(thing)
|
||||||
|
txt.nl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user