mirror of
https://github.com/irmen/prog8.git
synced 2025-08-07 05:27:10 +00:00
introduced BuiltinFunctionCall (expression) node for codegen
This commit is contained in:
@@ -443,8 +443,8 @@ class AsmGen(internal val program: Program,
|
|||||||
internal fun translateExpression(expression: Expression) =
|
internal fun translateExpression(expression: Expression) =
|
||||||
expressionsAsmGen.translateExpression(expression)
|
expressionsAsmGen.translateExpression(expression)
|
||||||
|
|
||||||
internal fun translateBuiltinFunctionCallExpression(functionCallExpr: FunctionCallExpression, resultToStack: Boolean, resultRegister: RegisterOrPair?) =
|
internal fun translateBuiltinFunctionCallExpression(bfc: BuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) =
|
||||||
builtinFunctionsAsmGen.translateFunctioncallExpression(functionCallExpr, resultToStack, resultRegister)
|
builtinFunctionsAsmGen.translateFunctioncallExpression(bfc, resultToStack, resultRegister)
|
||||||
|
|
||||||
internal fun translateBuiltinFunctionCallExpression(name: String, args: List<AsmAssignSource>, scope: Subroutine): DataType =
|
internal fun translateBuiltinFunctionCallExpression(name: String, args: List<AsmAssignSource>, scope: Subroutine): DataType =
|
||||||
builtinFunctionsAsmGen.translateFunctioncall(name, args, false, scope)
|
builtinFunctionsAsmGen.translateFunctioncall(name, args, false, scope)
|
||||||
@@ -1200,7 +1200,7 @@ $repeatLabel lda $counterVar
|
|||||||
}
|
}
|
||||||
if(dt==DataType.UBYTE) {
|
if(dt==DataType.UBYTE) {
|
||||||
assignExpressionToRegister(left, RegisterOrPair.A, false)
|
assignExpressionToRegister(left, RegisterOrPair.A, false)
|
||||||
if (left is FunctionCallExpression && !left.isSimple)
|
if (left is IFunctionCall && !left.isSimple)
|
||||||
out(" cmp #0")
|
out(" cmp #0")
|
||||||
} else {
|
} else {
|
||||||
assignExpressionToRegister(left, RegisterOrPair.AY, false)
|
assignExpressionToRegister(left, RegisterOrPair.AY, false)
|
||||||
@@ -1216,7 +1216,7 @@ $repeatLabel lda $counterVar
|
|||||||
}
|
}
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> {
|
||||||
assignExpressionToRegister(left, RegisterOrPair.A, true)
|
assignExpressionToRegister(left, RegisterOrPair.A, true)
|
||||||
if (left is FunctionCallExpression && !left.isSimple)
|
if (left is IFunctionCall && !left.isSimple)
|
||||||
out(" cmp #0")
|
out(" cmp #0")
|
||||||
when (operator) {
|
when (operator) {
|
||||||
"==" -> out(" bne $jumpIfFalseLabel")
|
"==" -> out(" bne $jumpIfFalseLabel")
|
||||||
|
@@ -22,7 +22,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
|||||||
private val assignAsmGen: AssignmentAsmGen,
|
private val assignAsmGen: AssignmentAsmGen,
|
||||||
private val allocations: VariableAllocator) {
|
private val allocations: VariableAllocator) {
|
||||||
|
|
||||||
internal fun translateFunctioncallExpression(fcall: FunctionCallExpression, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
internal fun translateFunctioncallExpression(fcall: BuiltinFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
||||||
val func = BuiltinFunctions.getValue(fcall.target.nameInSource.single())
|
val func = BuiltinFunctions.getValue(fcall.target.nameInSource.single())
|
||||||
translateFunctioncall(fcall, func, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister)
|
translateFunctioncall(fcall, func, discardResult = false, resultToStack = resultToStack, resultRegister = resultRegister)
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.toMutableList()
|
}.toMutableList()
|
||||||
val fcall = FunctionCallExpression(IdentifierReference(listOf(name), Position.DUMMY), argExpressions, Position.DUMMY)
|
val fcall = BuiltinFunctionCall(IdentifierReference(listOf(name), Position.DUMMY), argExpressions, Position.DUMMY)
|
||||||
fcall.linkParents(scope)
|
fcall.linkParents(scope)
|
||||||
translateFunctioncall(fcall, func, discardResult = false, resultToStack = false, null)
|
translateFunctioncall(fcall, func, discardResult = false, resultToStack = false, null)
|
||||||
return if(isStatement) DataType.UNDEFINED else func.known_returntype!!
|
return if(isStatement) DataType.UNDEFINED else func.known_returntype!!
|
||||||
@@ -352,7 +352,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun funcMemory(fcall: IFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
private fun funcMemory(fcall: IFunctionCall, discardResult: Boolean, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
||||||
if(discardResult || fcall !is FunctionCallExpression)
|
if(discardResult || fcall !is BuiltinFunctionCall)
|
||||||
throw AssemblyError("should not discard result of memory allocation at $fcall")
|
throw AssemblyError("should not discard result of memory allocation at $fcall")
|
||||||
val name = (fcall.args[0] as StringLiteral).value
|
val name = (fcall.args[0] as StringLiteral).value
|
||||||
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
|
require(name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
|
||||||
|
@@ -3,8 +3,6 @@ package prog8.codegen.cpu6502
|
|||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
import prog8.ast.expressions.*
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.statements.BuiltinFunctionPlaceholder
|
|
||||||
import prog8.ast.statements.Subroutine
|
|
||||||
import prog8.ast.toHex
|
import prog8.ast.toHex
|
||||||
import prog8.compilerinterface.AssemblyError
|
import prog8.compilerinterface.AssemblyError
|
||||||
import prog8.compilerinterface.CpuType
|
import prog8.compilerinterface.CpuType
|
||||||
@@ -38,6 +36,7 @@ internal class ExpressionsAsmGen(private val program: Program,
|
|||||||
is NumericLiteral -> translateExpression(expression)
|
is NumericLiteral -> translateExpression(expression)
|
||||||
is IdentifierReference -> translateExpression(expression)
|
is IdentifierReference -> translateExpression(expression)
|
||||||
is FunctionCallExpression -> translateFunctionCallResultOntoStack(expression)
|
is FunctionCallExpression -> translateFunctionCallResultOntoStack(expression)
|
||||||
|
is BuiltinFunctionCall -> asmgen.translateBuiltinFunctionCallExpression(expression, true, null)
|
||||||
is PipeExpression -> asmgen.translatePipeExpression(expression.expressions, expression,false, true)
|
is PipeExpression -> asmgen.translatePipeExpression(expression.expressions, expression,false, true)
|
||||||
is ContainmentCheck -> throw AssemblyError("containment check as complex expression value is not supported")
|
is ContainmentCheck -> throw AssemblyError("containment check as complex expression value is not supported")
|
||||||
is ArrayLiteral, is StringLiteral -> throw AssemblyError("no asm gen for string/array literal value assignment - should have been replaced by a variable")
|
is ArrayLiteral, is StringLiteral -> throw AssemblyError("no asm gen for string/array literal value assignment - should have been replaced by a variable")
|
||||||
@@ -50,95 +49,90 @@ internal class ExpressionsAsmGen(private val program: Program,
|
|||||||
private fun translateFunctionCallResultOntoStack(call: FunctionCallExpression) {
|
private fun translateFunctionCallResultOntoStack(call: FunctionCallExpression) {
|
||||||
// only for use in nested expression evaluation
|
// only for use in nested expression evaluation
|
||||||
|
|
||||||
val sub = call.target.targetStatement(program)
|
val sub = call.target.targetSubroutine(program)!!
|
||||||
if(sub is BuiltinFunctionPlaceholder) {
|
asmgen.saveXbeforeCall(call)
|
||||||
asmgen.translateBuiltinFunctionCallExpression(call, true, null)
|
asmgen.translateFunctionCall(call, true)
|
||||||
} else {
|
if(sub.regXasResult()) {
|
||||||
sub as Subroutine
|
// store the return value in X somewhere that we can access again below
|
||||||
asmgen.saveXbeforeCall(call)
|
asmgen.out(" stx P8ZP_SCRATCH_REG")
|
||||||
asmgen.translateFunctionCall(call, true)
|
}
|
||||||
if(sub.regXasResult()) {
|
asmgen.restoreXafterCall(call)
|
||||||
// store the return value in X somewhere that we can acces again below
|
|
||||||
asmgen.out(" stx P8ZP_SCRATCH_REG")
|
|
||||||
}
|
|
||||||
asmgen.restoreXafterCall(call)
|
|
||||||
|
|
||||||
val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters)
|
val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters)
|
||||||
for ((_, reg) in returns) {
|
for ((_, reg) in returns) {
|
||||||
// result value is in cpu or status registers, put it on the stack instead (as we're evaluating an expression tree)
|
// result value is in cpu or status registers, put it on the stack instead (as we're evaluating an expression tree)
|
||||||
if (reg.registerOrPair != null) {
|
if (reg.registerOrPair != null) {
|
||||||
when (reg.registerOrPair!!) {
|
when (reg.registerOrPair!!) {
|
||||||
RegisterOrPair.A -> asmgen.out(" sta P8ESTACK_LO,x | dex")
|
RegisterOrPair.A -> asmgen.out(" sta P8ESTACK_LO,x | dex")
|
||||||
RegisterOrPair.Y -> asmgen.out(" tya | sta P8ESTACK_LO,x | dex")
|
RegisterOrPair.Y -> asmgen.out(" tya | sta P8ESTACK_LO,x | dex")
|
||||||
RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
|
RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | tya | sta P8ESTACK_HI,x | dex")
|
||||||
RegisterOrPair.X -> asmgen.out(" lda P8ZP_SCRATCH_REG | sta P8ESTACK_LO,x | dex")
|
RegisterOrPair.X -> asmgen.out(" lda P8ZP_SCRATCH_REG | sta P8ESTACK_LO,x | dex")
|
||||||
RegisterOrPair.AX -> asmgen.out(" sta P8ESTACK_LO,x | lda P8ZP_SCRATCH_REG | sta P8ESTACK_HI,x | dex")
|
RegisterOrPair.AX -> asmgen.out(" sta P8ESTACK_LO,x | lda P8ZP_SCRATCH_REG | sta P8ESTACK_HI,x | dex")
|
||||||
RegisterOrPair.XY -> asmgen.out(" tya | sta P8ESTACK_HI,x | lda P8ZP_SCRATCH_REG | sta P8ESTACK_LO,x | dex")
|
RegisterOrPair.XY -> asmgen.out(" tya | sta P8ESTACK_HI,x | lda P8ZP_SCRATCH_REG | sta P8ESTACK_LO,x | dex")
|
||||||
RegisterOrPair.FAC1 -> asmgen.out(" jsr floats.push_fac1")
|
RegisterOrPair.FAC1 -> asmgen.out(" jsr floats.push_fac1")
|
||||||
RegisterOrPair.FAC2 -> asmgen.out(" jsr floats.push_fac2")
|
RegisterOrPair.FAC2 -> asmgen.out(" jsr floats.push_fac2")
|
||||||
RegisterOrPair.R0,
|
RegisterOrPair.R0,
|
||||||
RegisterOrPair.R1,
|
RegisterOrPair.R1,
|
||||||
RegisterOrPair.R2,
|
RegisterOrPair.R2,
|
||||||
RegisterOrPair.R3,
|
RegisterOrPair.R3,
|
||||||
RegisterOrPair.R4,
|
RegisterOrPair.R4,
|
||||||
RegisterOrPair.R5,
|
RegisterOrPair.R5,
|
||||||
RegisterOrPair.R6,
|
RegisterOrPair.R6,
|
||||||
RegisterOrPair.R7,
|
RegisterOrPair.R7,
|
||||||
RegisterOrPair.R8,
|
RegisterOrPair.R8,
|
||||||
RegisterOrPair.R9,
|
RegisterOrPair.R9,
|
||||||
RegisterOrPair.R10,
|
RegisterOrPair.R10,
|
||||||
RegisterOrPair.R11,
|
RegisterOrPair.R11,
|
||||||
RegisterOrPair.R12,
|
RegisterOrPair.R12,
|
||||||
RegisterOrPair.R13,
|
RegisterOrPair.R13,
|
||||||
RegisterOrPair.R14,
|
RegisterOrPair.R14,
|
||||||
RegisterOrPair.R15 -> {
|
RegisterOrPair.R15 -> {
|
||||||
asmgen.out(
|
asmgen.out(
|
||||||
"""
|
"""
|
||||||
lda cx16.${reg.registerOrPair.toString().lowercase()}
|
lda cx16.${reg.registerOrPair.toString().lowercase()}
|
||||||
sta P8ESTACK_LO,x
|
|
||||||
lda cx16.${reg.registerOrPair.toString().lowercase()}+1
|
|
||||||
sta P8ESTACK_HI,x
|
|
||||||
dex
|
|
||||||
""")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else when(reg.statusflag) {
|
|
||||||
Statusflag.Pc -> {
|
|
||||||
asmgen.out("""
|
|
||||||
lda #0
|
|
||||||
rol a
|
|
||||||
sta P8ESTACK_LO,x
|
sta P8ESTACK_LO,x
|
||||||
dex""")
|
lda cx16.${reg.registerOrPair.toString().lowercase()}+1
|
||||||
|
sta P8ESTACK_HI,x
|
||||||
|
dex
|
||||||
|
""")
|
||||||
}
|
}
|
||||||
Statusflag.Pz -> {
|
|
||||||
asmgen.out("""
|
|
||||||
beq +
|
|
||||||
lda #0
|
|
||||||
beq ++
|
|
||||||
+ lda #1
|
|
||||||
+ sta P8ESTACK_LO,x
|
|
||||||
dex""")
|
|
||||||
}
|
|
||||||
Statusflag.Pv -> {
|
|
||||||
asmgen.out("""
|
|
||||||
bvs +
|
|
||||||
lda #0
|
|
||||||
beq ++
|
|
||||||
+ lda #1
|
|
||||||
+ sta P8ESTACK_LO,x
|
|
||||||
dex""")
|
|
||||||
}
|
|
||||||
Statusflag.Pn -> {
|
|
||||||
asmgen.out("""
|
|
||||||
bmi +
|
|
||||||
lda #0
|
|
||||||
beq ++
|
|
||||||
+ lda #1
|
|
||||||
+ sta P8ESTACK_LO,x
|
|
||||||
dex""")
|
|
||||||
}
|
|
||||||
null -> {}
|
|
||||||
}
|
}
|
||||||
|
} else when(reg.statusflag) {
|
||||||
|
Statusflag.Pc -> {
|
||||||
|
asmgen.out("""
|
||||||
|
lda #0
|
||||||
|
rol a
|
||||||
|
sta P8ESTACK_LO,x
|
||||||
|
dex""")
|
||||||
|
}
|
||||||
|
Statusflag.Pz -> {
|
||||||
|
asmgen.out("""
|
||||||
|
beq +
|
||||||
|
lda #0
|
||||||
|
beq ++
|
||||||
|
+ lda #1
|
||||||
|
+ sta P8ESTACK_LO,x
|
||||||
|
dex""")
|
||||||
|
}
|
||||||
|
Statusflag.Pv -> {
|
||||||
|
asmgen.out("""
|
||||||
|
bvs +
|
||||||
|
lda #0
|
||||||
|
beq ++
|
||||||
|
+ lda #1
|
||||||
|
+ sta P8ESTACK_LO,x
|
||||||
|
dex""")
|
||||||
|
}
|
||||||
|
Statusflag.Pn -> {
|
||||||
|
asmgen.out("""
|
||||||
|
bmi +
|
||||||
|
lda #0
|
||||||
|
beq ++
|
||||||
|
+ lda #1
|
||||||
|
+ sta P8ESTACK_LO,x
|
||||||
|
dex""")
|
||||||
|
}
|
||||||
|
null -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,7 @@ import prog8.compilerinterface.AssemblyError
|
|||||||
|
|
||||||
internal class FunctionCallAsmGen(private val program: Program, private val asmgen: AsmGen) {
|
internal class FunctionCallAsmGen(private val program: Program, private val asmgen: AsmGen) {
|
||||||
|
|
||||||
internal fun translateFunctionCallStatement(stmt: IFunctionCall) {
|
internal fun translateFunctionCallStatement(stmt: FunctionCallStatement) {
|
||||||
saveXbeforeCall(stmt)
|
saveXbeforeCall(stmt)
|
||||||
translateFunctionCall(stmt, false)
|
translateFunctionCall(stmt, false)
|
||||||
restoreXafterCall(stmt)
|
restoreXafterCall(stmt)
|
||||||
|
@@ -167,26 +167,20 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
|
|||||||
val dt = value.inferType(program).getOrElse { throw AssemblyError("unknown dt") }
|
val dt = value.inferType(program).getOrElse { throw AssemblyError("unknown dt") }
|
||||||
AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, dt, array = value)
|
AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, dt, array = value)
|
||||||
}
|
}
|
||||||
|
is BuiltinFunctionCall -> {
|
||||||
|
val returnType = value.inferType(program)
|
||||||
|
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType.getOrElse { throw AssemblyError("unknown dt") }, expression = value)
|
||||||
|
}
|
||||||
is FunctionCallExpression -> {
|
is FunctionCallExpression -> {
|
||||||
when (val sub = value.target.targetStatement(program)) {
|
val sub = value.target.targetSubroutine(program)!!
|
||||||
is Subroutine -> {
|
val returnType = sub.returntypes.zip(sub.asmReturnvaluesRegisters).firstOrNull { rr -> rr.second.registerOrPair != null || rr.second.statusflag!=null }?.first
|
||||||
val returnType = sub.returntypes.zip(sub.asmReturnvaluesRegisters).firstOrNull { rr -> rr.second.registerOrPair != null || rr.second.statusflag!=null }?.first
|
?: throw AssemblyError("can't translate zero return values in assignment")
|
||||||
?: throw AssemblyError("can't translate zero return values in assignment")
|
|
||||||
|
|
||||||
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType, expression = value)
|
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType, expression = value)
|
||||||
}
|
|
||||||
is BuiltinFunctionPlaceholder -> {
|
|
||||||
val returnType = value.inferType(program)
|
|
||||||
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType.getOrElse { throw AssemblyError("unknown dt") }, expression = value)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
throw AssemblyError("weird call")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val dt = value.inferType(program)
|
val returnType = value.inferType(program)
|
||||||
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, dt.getOrElse { throw AssemblyError("unknown dt") }, expression = value)
|
AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, returnType.getOrElse { throw AssemblyError("unknown dt") }, expression = value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -161,75 +161,74 @@ internal class AssignmentAsmGen(private val program: Program,
|
|||||||
is DirectMemoryRead -> throw AssemblyError("source kind should have been memory")
|
is DirectMemoryRead -> throw AssemblyError("source kind should have been memory")
|
||||||
is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, value)
|
is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, value)
|
||||||
is FunctionCallExpression -> {
|
is FunctionCallExpression -> {
|
||||||
when (val sub = value.target.targetStatement(program)) {
|
val sub = value.target.targetSubroutine(program)!!
|
||||||
is Subroutine -> {
|
asmgen.saveXbeforeCall(value)
|
||||||
asmgen.saveXbeforeCall(value)
|
asmgen.translateFunctionCall(value, true)
|
||||||
asmgen.translateFunctionCall(value, true)
|
val returnValue = sub.returntypes.zip(sub.asmReturnvaluesRegisters).singleOrNull { it.second.registerOrPair!=null } ?:
|
||||||
val returnValue = sub.returntypes.zip(sub.asmReturnvaluesRegisters).singleOrNull { it.second.registerOrPair!=null } ?:
|
sub.returntypes.zip(sub.asmReturnvaluesRegisters).single { it.second.statusflag!=null }
|
||||||
sub.returntypes.zip(sub.asmReturnvaluesRegisters).single { it.second.statusflag!=null }
|
when (returnValue.first) {
|
||||||
when (returnValue.first) {
|
DataType.STR -> {
|
||||||
DataType.STR -> {
|
asmgen.restoreXafterCall(value)
|
||||||
asmgen.restoreXafterCall(value)
|
when(assign.target.datatype) {
|
||||||
when(assign.target.datatype) {
|
DataType.UWORD -> {
|
||||||
DataType.UWORD -> {
|
// assign the address of the string result value
|
||||||
// assign the address of the string result value
|
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
||||||
assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
||||||
}
|
|
||||||
DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
|
||||||
// copy the actual string result into the target string variable
|
|
||||||
asmgen.out("""
|
|
||||||
pha
|
|
||||||
lda #<${assign.target.asmVarname}
|
|
||||||
sta P8ZP_SCRATCH_W1
|
|
||||||
lda #>${assign.target.asmVarname}
|
|
||||||
sta P8ZP_SCRATCH_W1+1
|
|
||||||
pla
|
|
||||||
jsr prog8_lib.strcpy""")
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("weird target dt")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
DataType.FLOAT -> {
|
DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||||
// float result from function sits in FAC1
|
// copy the actual string result into the target string variable
|
||||||
asmgen.restoreXafterCall(value)
|
asmgen.out("""
|
||||||
assignFAC1float(assign.target)
|
pha
|
||||||
}
|
lda #<${assign.target.asmVarname}
|
||||||
else -> {
|
sta P8ZP_SCRATCH_W1
|
||||||
// do NOT restore X register before assigning the result values first
|
lda #>${assign.target.asmVarname}
|
||||||
when (returnValue.second.registerOrPair) {
|
sta P8ZP_SCRATCH_W1+1
|
||||||
RegisterOrPair.A -> assignRegisterByte(assign.target, CpuRegister.A)
|
pla
|
||||||
RegisterOrPair.X -> assignRegisterByte(assign.target, CpuRegister.X)
|
jsr prog8_lib.strcpy""")
|
||||||
RegisterOrPair.Y -> assignRegisterByte(assign.target, CpuRegister.Y)
|
|
||||||
RegisterOrPair.AX -> assignRegisterpairWord(assign.target, RegisterOrPair.AX)
|
|
||||||
RegisterOrPair.AY -> assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
||||||
RegisterOrPair.XY -> assignRegisterpairWord(assign.target, RegisterOrPair.XY)
|
|
||||||
else -> {
|
|
||||||
val sflag = returnValue.second.statusflag
|
|
||||||
if(sflag!=null)
|
|
||||||
assignStatusFlagByte(assign.target, sflag)
|
|
||||||
else
|
|
||||||
throw AssemblyError("should be just one register byte result value")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// we've processed the result value in the X register by now, so it's now finally safe to restore it
|
|
||||||
asmgen.restoreXafterCall(value)
|
|
||||||
}
|
}
|
||||||
|
else -> throw AssemblyError("weird target dt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is BuiltinFunctionPlaceholder -> {
|
DataType.FLOAT -> {
|
||||||
asmgen.translateBuiltinFunctionCallExpression(value, false, assign.target.register)
|
// float result from function sits in FAC1
|
||||||
if(assign.target.register==null) {
|
asmgen.restoreXafterCall(value)
|
||||||
// still need to assign the result to the target variable/etc.
|
assignFAC1float(assign.target)
|
||||||
val returntype = builtinFunctionReturnType(sub.name, value.args, program)
|
}
|
||||||
if(!returntype.isKnown)
|
else -> {
|
||||||
throw AssemblyError("unknown dt")
|
// do NOT restore X register before assigning the result values first
|
||||||
when(returntype.getOr(DataType.UNDEFINED)) {
|
when (returnValue.second.registerOrPair) {
|
||||||
in ByteDatatypes -> assignRegisterByte(assign.target, CpuRegister.A) // function's byte result is in A
|
RegisterOrPair.A -> assignRegisterByte(assign.target, CpuRegister.A)
|
||||||
in WordDatatypes -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) // function's word result is in AY
|
RegisterOrPair.X -> assignRegisterByte(assign.target, CpuRegister.X)
|
||||||
|
RegisterOrPair.Y -> assignRegisterByte(assign.target, CpuRegister.Y)
|
||||||
|
RegisterOrPair.AX -> assignRegisterpairWord(assign.target, RegisterOrPair.AX)
|
||||||
|
RegisterOrPair.AY -> assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
||||||
|
RegisterOrPair.XY -> assignRegisterpairWord(assign.target, RegisterOrPair.XY)
|
||||||
|
else -> {
|
||||||
|
val sflag = returnValue.second.statusflag
|
||||||
|
if(sflag!=null)
|
||||||
|
assignStatusFlagByte(assign.target, sflag)
|
||||||
|
else
|
||||||
|
throw AssemblyError("should be just one register byte result value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we've processed the result value in the X register by now, so it's now finally safe to restore it
|
||||||
|
asmgen.restoreXafterCall(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is BuiltinFunctionCall -> {
|
||||||
|
asmgen.translateBuiltinFunctionCallExpression(value, false, assign.target.register)
|
||||||
|
if(assign.target.register==null) {
|
||||||
|
// still need to assign the result to the target variable/etc.
|
||||||
|
val returntype = builtinFunctionReturnType(value.name, value.args, program)
|
||||||
|
if(!returntype.isKnown)
|
||||||
|
throw AssemblyError("unknown dt")
|
||||||
|
when(returntype.getOr(DataType.UNDEFINED)) {
|
||||||
|
in ByteDatatypes -> assignRegisterByte(assign.target, CpuRegister.A) // function's byte result is in A
|
||||||
|
in WordDatatypes -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) // function's word result is in AY
|
||||||
|
DataType.STR -> {
|
||||||
|
when (assign.target.datatype) {
|
||||||
DataType.STR -> {
|
DataType.STR -> {
|
||||||
when (assign.target.datatype) {
|
asmgen.out("""
|
||||||
DataType.STR -> {
|
|
||||||
asmgen.out("""
|
|
||||||
pha
|
pha
|
||||||
lda #<${assign.target.asmVarname}
|
lda #<${assign.target.asmVarname}
|
||||||
sta P8ZP_SCRATCH_W1
|
sta P8ZP_SCRATCH_W1
|
||||||
@@ -237,21 +236,16 @@ internal class AssignmentAsmGen(private val program: Program,
|
|||||||
sta P8ZP_SCRATCH_W1+1
|
sta P8ZP_SCRATCH_W1+1
|
||||||
pla
|
pla
|
||||||
jsr prog8_lib.strcpy""")
|
jsr prog8_lib.strcpy""")
|
||||||
}
|
|
||||||
DataType.UWORD -> assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
|
||||||
else -> throw AssemblyError("str return value type mismatch with target")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
DataType.FLOAT -> {
|
DataType.UWORD -> assignRegisterpairWord(assign.target, RegisterOrPair.AY)
|
||||||
// float result from function sits in FAC1
|
else -> throw AssemblyError("str return value type mismatch with target")
|
||||||
assignFAC1float(assign.target)
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("weird result type")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
DataType.FLOAT -> {
|
||||||
else -> {
|
// float result from function sits in FAC1
|
||||||
throw AssemblyError("weird func call")
|
assignFAC1float(assign.target)
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("weird result type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -682,7 +676,7 @@ $containsLabel lda #1
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun assignCastViaLsbFunc(value: Expression, target: AsmAssignTarget) {
|
private fun assignCastViaLsbFunc(value: Expression, target: AsmAssignTarget) {
|
||||||
val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), value.position), mutableListOf(value), value.position)
|
val lsb = BuiltinFunctionCall(IdentifierReference(listOf("lsb"), value.position), mutableListOf(value), value.position)
|
||||||
lsb.linkParents(value.parent)
|
lsb.linkParents(value.parent)
|
||||||
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UBYTE, expression = lsb)
|
val src = AsmAssignSource(SourceStorageKind.EXPRESSION, program, asmgen, DataType.UBYTE, expression = lsb)
|
||||||
val assign = AsmAssignment(src, target, false, program.memsizer, value.position)
|
val assign = AsmAssignment(src, target, false, program.memsizer, value.position)
|
||||||
|
@@ -3,8 +3,8 @@ package prog8.codegen.target.cbm
|
|||||||
import prog8.ast.base.Cx16VirtualRegisters
|
import prog8.ast.base.Cx16VirtualRegisters
|
||||||
import prog8.ast.base.RegisterOrPair
|
import prog8.ast.base.RegisterOrPair
|
||||||
import prog8.ast.expressions.ArrayIndexedExpression
|
import prog8.ast.expressions.ArrayIndexedExpression
|
||||||
|
import prog8.ast.expressions.BuiltinFunctionCall
|
||||||
import prog8.ast.expressions.Expression
|
import prog8.ast.expressions.Expression
|
||||||
import prog8.ast.expressions.FunctionCallExpression
|
|
||||||
import prog8.ast.statements.RegisterOrStatusflag
|
import prog8.ast.statements.RegisterOrStatusflag
|
||||||
import prog8.ast.statements.Subroutine
|
import prog8.ast.statements.Subroutine
|
||||||
|
|
||||||
@@ -46,10 +46,10 @@ internal fun asmsub6502ArgsHaveRegisterClobberRisk(args: List<Expression>,
|
|||||||
it.registerOrPair in listOf(RegisterOrPair.Y, RegisterOrPair.AY, RegisterOrPair.XY)
|
it.registerOrPair in listOf(RegisterOrPair.Y, RegisterOrPair.AY, RegisterOrPair.XY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is FunctionCallExpression -> {
|
is BuiltinFunctionCall -> {
|
||||||
if (expr.target.nameInSource == listOf("lsb") || expr.target.nameInSource == listOf("msb"))
|
if (expr.name == "lsb" || expr.name == "msb")
|
||||||
return isClobberRisk(expr.args[0])
|
return isClobberRisk(expr.args[0])
|
||||||
if (expr.target.nameInSource == listOf("mkword"))
|
if (expr.name == "mkword")
|
||||||
return isClobberRisk(expr.args[0]) && isClobberRisk(expr.args[1])
|
return isClobberRisk(expr.args[0]) && isClobberRisk(expr.args[1])
|
||||||
return !expr.isSimple
|
return !expr.isSimple
|
||||||
}
|
}
|
||||||
|
@@ -267,43 +267,6 @@ internal class BeforeAsmAstChanger(val program: Program,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
|
||||||
if(functionCallStatement.target.nameInSource.size==1
|
|
||||||
&& functionCallStatement.target.nameInSource[0] in program.builtinFunctions.names) {
|
|
||||||
return listOf(IAstModification.ReplaceNode(
|
|
||||||
functionCallStatement,
|
|
||||||
BuiltinFunctionCallStatement(functionCallStatement.target, functionCallStatement.args, functionCallStatement.position),
|
|
||||||
parent
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun after(bfcs: BuiltinFunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
|
||||||
if(bfcs.name=="cmp") {
|
|
||||||
// if the datatype of the arguments of cmp() are different, cast the byte one to word.
|
|
||||||
val arg1 = bfcs.args[0]
|
|
||||||
val arg2 = bfcs.args[1]
|
|
||||||
val dt1 = arg1.inferType(program).getOr(DataType.UNDEFINED)
|
|
||||||
val dt2 = arg2.inferType(program).getOr(DataType.UNDEFINED)
|
|
||||||
if(dt1 in ByteDatatypes) {
|
|
||||||
if(dt2 in ByteDatatypes)
|
|
||||||
return noModifications
|
|
||||||
val (replaced, cast) = arg1.typecastTo(if(dt1== DataType.UBYTE) DataType.UWORD else DataType.WORD, dt1, true)
|
|
||||||
if(replaced)
|
|
||||||
return listOf(IAstModification.ReplaceNode(arg1, cast, bfcs))
|
|
||||||
} else {
|
|
||||||
if(dt2 in WordDatatypes)
|
|
||||||
return noModifications
|
|
||||||
val (replaced, cast) = arg2.typecastTo(if(dt2== DataType.UBYTE) DataType.UWORD else DataType.WORD, dt2, true)
|
|
||||||
if(replaced)
|
|
||||||
return listOf(IAstModification.ReplaceNode(arg2, cast, bfcs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
|
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
|
||||||
|
|
||||||
val containingStatement = getContainingStatement(arrayIndexedExpression)
|
val containingStatement = getContainingStatement(arrayIndexedExpression)
|
||||||
|
@@ -7,10 +7,9 @@ import prog8.ast.base.ByteDatatypes
|
|||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.PassByReferenceDatatypes
|
import prog8.ast.base.PassByReferenceDatatypes
|
||||||
import prog8.ast.base.WordDatatypes
|
import prog8.ast.base.WordDatatypes
|
||||||
import prog8.ast.expressions.AddressOf
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.expressions.Expression
|
import prog8.ast.statements.BuiltinFunctionCallStatement
|
||||||
import prog8.ast.expressions.IdentifierReference
|
import prog8.ast.statements.FunctionCallStatement
|
||||||
import prog8.ast.expressions.TypecastExpression
|
|
||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
import prog8.compilerinterface.IErrorReporter
|
import prog8.compilerinterface.IErrorReporter
|
||||||
@@ -73,4 +72,59 @@ internal class BeforeAsmTypecastCleaner(val program: Program,
|
|||||||
|
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// also convert calls to builtin functions to BuiltinFunctionCall nodes to make things easier for codegen
|
||||||
|
|
||||||
|
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||||
|
if(functionCallStatement.target.nameInSource.size==1
|
||||||
|
&& functionCallStatement.target.nameInSource[0] in program.builtinFunctions.names) {
|
||||||
|
return listOf(IAstModification.ReplaceNode(
|
||||||
|
functionCallStatement,
|
||||||
|
BuiltinFunctionCallStatement(functionCallStatement.target, functionCallStatement.args, functionCallStatement.position),
|
||||||
|
parent
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return noModifications
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun before(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
|
||||||
|
if(functionCallExpr.target.nameInSource.size==1
|
||||||
|
&& functionCallExpr.target.nameInSource[0] in program.builtinFunctions.names) {
|
||||||
|
return listOf(IAstModification.ReplaceNode(
|
||||||
|
functionCallExpr,
|
||||||
|
BuiltinFunctionCall(functionCallExpr.target, functionCallExpr.args, functionCallExpr.position),
|
||||||
|
parent
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return noModifications
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun after(bfcs: BuiltinFunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||||
|
if(bfcs.name=="cmp") {
|
||||||
|
// if the datatype of the arguments of cmp() are different, cast the byte one to word.
|
||||||
|
val arg1 = bfcs.args[0]
|
||||||
|
val arg2 = bfcs.args[1]
|
||||||
|
val dt1 = arg1.inferType(program).getOr(DataType.UNDEFINED)
|
||||||
|
val dt2 = arg2.inferType(program).getOr(DataType.UNDEFINED)
|
||||||
|
if(dt1 in ByteDatatypes) {
|
||||||
|
if(dt2 in ByteDatatypes)
|
||||||
|
return noModifications
|
||||||
|
val (replaced, cast) = arg1.typecastTo(if(dt1== DataType.UBYTE) DataType.UWORD else DataType.WORD, dt1, true)
|
||||||
|
if(replaced)
|
||||||
|
return listOf(IAstModification.ReplaceNode(arg1, cast, bfcs))
|
||||||
|
} else {
|
||||||
|
if(dt2 in WordDatatypes)
|
||||||
|
return noModifications
|
||||||
|
val (replaced, cast) = arg2.typecastTo(if(dt2== DataType.UBYTE) DataType.UWORD else DataType.WORD, dt2, true)
|
||||||
|
if(replaced)
|
||||||
|
return listOf(IAstModification.ReplaceNode(arg2, cast, bfcs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return noModifications
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -206,6 +206,10 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
|||||||
printout(functionCallExpr as IFunctionCall)
|
printout(functionCallExpr as IFunctionCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visit(bfc: BuiltinFunctionCall) {
|
||||||
|
printout(bfc as IFunctionCall)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visit(functionCallStatement: FunctionCallStatement) {
|
override fun visit(functionCallStatement: FunctionCallStatement) {
|
||||||
printout(functionCallStatement as IFunctionCall)
|
printout(functionCallStatement as IFunctionCall)
|
||||||
}
|
}
|
||||||
|
@@ -965,10 +965,6 @@ class FunctionCallExpression(override var target: IdentifierReference,
|
|||||||
val stmt = target.targetStatement(program) ?: return InferredTypes.unknown()
|
val stmt = target.targetStatement(program) ?: return InferredTypes.unknown()
|
||||||
when (stmt) {
|
when (stmt) {
|
||||||
is BuiltinFunctionPlaceholder -> {
|
is BuiltinFunctionPlaceholder -> {
|
||||||
if(target.nameInSource[0] == "set_carry" || target.nameInSource[0]=="set_irqd" ||
|
|
||||||
target.nameInSource[0] == "clear_carry" || target.nameInSource[0]=="clear_irqd") {
|
|
||||||
return InferredTypes.void() // these have no return value
|
|
||||||
}
|
|
||||||
return program.builtinFunctions.returnType(target.nameInSource[0], this.args)
|
return program.builtinFunctions.returnType(target.nameInSource[0], this.args)
|
||||||
}
|
}
|
||||||
is Subroutine -> {
|
is Subroutine -> {
|
||||||
@@ -1132,3 +1128,39 @@ fun invertCondition(cond: Expression): BinaryExpression? {
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class BuiltinFunctionCall(override var target: IdentifierReference,
|
||||||
|
override var args: MutableList<Expression>,
|
||||||
|
override val position: Position) : Expression(), IFunctionCall {
|
||||||
|
|
||||||
|
val name = target.nameInSource.single()
|
||||||
|
|
||||||
|
override lateinit var parent: Node
|
||||||
|
|
||||||
|
override fun linkParents(parent: Node) {
|
||||||
|
this.parent = parent
|
||||||
|
target.linkParents(this)
|
||||||
|
args.forEach { it.linkParents(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun copy() = BuiltinFunctionCall(target.copy(), args.map { it.copy() }.toMutableList(), position)
|
||||||
|
override val isSimple = name in arrayOf("msb", "lsb", "peek", "peekw", "set_carry", "set_irqd", "clear_carry", "clear_irqd")
|
||||||
|
|
||||||
|
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||||
|
if(node===target)
|
||||||
|
target=replacement as IdentifierReference
|
||||||
|
else {
|
||||||
|
val idx = args.indexOfFirst { it===node }
|
||||||
|
args[idx] = replacement as Expression
|
||||||
|
}
|
||||||
|
replacement.parent = this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun constValue(program: Program): NumericLiteral? = null
|
||||||
|
override fun toString() = "BuiltinFunctionCall(name=$name, pos=$position)"
|
||||||
|
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
|
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||||
|
override fun referencesIdentifier(nameInSource: List<String>): Boolean = target.referencesIdentifier(nameInSource) || args.any{it.referencesIdentifier(nameInSource)}
|
||||||
|
override fun inferType(program: Program) = program.builtinFunctions.returnType(name, this.args)
|
||||||
|
}
|
||||||
|
@@ -95,6 +95,7 @@ abstract class AstWalker {
|
|||||||
open fun before(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun before(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun before(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
|
open fun before(bfc: BuiltinFunctionCall, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun before(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun before(bfcs: BuiltinFunctionCallStatement, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(bfcs: BuiltinFunctionCallStatement, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun before(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = noModifications
|
open fun before(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
@@ -139,6 +140,7 @@ abstract class AstWalker {
|
|||||||
open fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
|
open fun after(bfc: BuiltinFunctionCall, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun after(bfcs: BuiltinFunctionCallStatement, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(bfcs: BuiltinFunctionCallStatement, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
open fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = noModifications
|
open fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = noModifications
|
||||||
@@ -266,6 +268,13 @@ abstract class AstWalker {
|
|||||||
track(after(functionCallExpr, parent), functionCallExpr, parent)
|
track(after(functionCallExpr, parent), functionCallExpr, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun visit(bfc: BuiltinFunctionCall, parent: Node) {
|
||||||
|
track(before(bfc, parent), bfc, parent)
|
||||||
|
bfc.target.accept(this, bfc)
|
||||||
|
bfc.args.forEach { it.accept(this, bfc) }
|
||||||
|
track(after(bfc, parent), bfc, parent)
|
||||||
|
}
|
||||||
|
|
||||||
fun visit(functionCallStatement: FunctionCallStatement, parent: Node) {
|
fun visit(functionCallStatement: FunctionCallStatement, parent: Node) {
|
||||||
track(before(functionCallStatement, parent), functionCallStatement, parent)
|
track(before(functionCallStatement, parent), functionCallStatement, parent)
|
||||||
functionCallStatement.target.accept(this, functionCallStatement)
|
functionCallStatement.target.accept(this, functionCallStatement)
|
||||||
|
@@ -49,6 +49,11 @@ interface IAstVisitor {
|
|||||||
functionCallExpr.args.forEach { it.accept(this) }
|
functionCallExpr.args.forEach { it.accept(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun visit(bfc: BuiltinFunctionCall) {
|
||||||
|
bfc.target.accept(this)
|
||||||
|
bfc.args.forEach { it.accept(this) }
|
||||||
|
}
|
||||||
|
|
||||||
fun visit(functionCallStatement: FunctionCallStatement) {
|
fun visit(functionCallStatement: FunctionCallStatement) {
|
||||||
functionCallStatement.target.accept(this)
|
functionCallStatement.target.accept(this)
|
||||||
functionCallStatement.args.forEach { it.accept(this) }
|
functionCallStatement.args.forEach { it.accept(this) }
|
||||||
|
@@ -176,6 +176,9 @@ private fun builtinAll(array: List<Double>): Double = if(array.all { it!=0.0 })
|
|||||||
|
|
||||||
fun builtinFunctionReturnType(function: String, args: List<Expression>, program: Program): InferredTypes.InferredType {
|
fun builtinFunctionReturnType(function: String, args: List<Expression>, program: Program): InferredTypes.InferredType {
|
||||||
|
|
||||||
|
if(function in arrayOf("set_carry", "set_irqd", "clear_carry", "clear_irqd"))
|
||||||
|
return InferredTypes.InferredType.void()
|
||||||
|
|
||||||
fun datatypeFromIterableArg(arglist: Expression): DataType {
|
fun datatypeFromIterableArg(arglist: Expression): DataType {
|
||||||
if(arglist is ArrayLiteral) {
|
if(arglist is ArrayLiteral) {
|
||||||
val dt = arglist.value.map {it.inferType(program).getOr(DataType.UNDEFINED)}.toSet()
|
val dt = arglist.value.map {it.inferType(program).getOr(DataType.UNDEFINED)}.toSet()
|
||||||
|
@@ -3,7 +3,6 @@ TODO
|
|||||||
|
|
||||||
For next release
|
For next release
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
- introduce BuiltinFunctionCallExpression as well?
|
|
||||||
- see if we can get rid of storing the origAstTarget in AsmAssignTarget
|
- see if we can get rid of storing the origAstTarget in AsmAssignTarget
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user