diff --git a/codeAst/src/prog8/code/ast/AstStatements.kt b/codeAst/src/prog8/code/ast/AstStatements.kt index 20d6cc4b7..39257365a 100644 --- a/codeAst/src/prog8/code/ast/AstStatements.kt +++ b/codeAst/src/prog8/code/ast/AstStatements.kt @@ -86,13 +86,6 @@ class PtForLoop(position: Position) : PtNode(position) { } -class PtGosub(val identifier: PtIdentifier, position: Position) : PtNode(position) { - override fun printProperties() { - identifier.printProperties() - } -} - - class PtIfElse(position: Position) : PtNode(position) { val condition: PtExpression get() = children[0] as PtExpression diff --git a/codeGenExperimental/src/prog8/codegen/experimental/AstToXmlConverter.kt b/codeGenExperimental/src/prog8/codegen/experimental/AstToXmlConverter.kt index 12b751602..35a727443 100644 --- a/codeGenExperimental/src/prog8/codegen/experimental/AstToXmlConverter.kt +++ b/codeGenExperimental/src/prog8/codegen/experimental/AstToXmlConverter.kt @@ -164,7 +164,6 @@ class AstToXmlConverter(internal val program: PtProgram, is PtContainmentCheck -> write(it) is PtForLoop -> write(it) is PtFunctionCall -> write(it) - is PtGosub -> write(it) is PtIdentifier -> write(it) is PtIfElse -> write(it) is PtInlineAssembly -> write(it) @@ -554,12 +553,6 @@ class AstToXmlConverter(internal val program: PtProgram, xml.endElt() } - private fun write(gosub: PtGosub) { - xml.elt("gosub") - xml.attr("symbol", strTargetName(gosub.identifier)) - xml.endElt() - } - private fun write(sub: PtSub) { xml.elt("sub") xml.attr("name", sub.scopedName.joinToString(".")) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFunctionsGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFunctionsGen.kt deleted file mode 100644 index 199240187..000000000 --- a/codeGenVirtual/src/prog8/codegen/virtual/BuiltinFunctionsGen.kt +++ /dev/null @@ -1,43 +0,0 @@ -package prog8.codegen.virtual - -import prog8.code.ast.PtBuiltinFunctionCall -import prog8.code.ast.PtNumber -import prog8.vm.Instruction -import prog8.vm.Opcode - -internal class BuiltinFunctionsGen(val codegen: CodeGen) { - fun translate(call: PtBuiltinFunctionCall): VmCodeChunk { - val chunk = VmCodeChunk() - when(call.name) { - "syscall" -> { - val vExpr = call.args.single() as PtNumber - chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt())) - } - "syscall1" -> { - val vExpr = call.args[0] as PtNumber - val vExpr1 = call.args[1] as PtNumber - // TODO assign regs - chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt())) - } - "syscall2" -> { - val vExpr = call.args[0] as PtNumber - val vExpr1 = call.args[1] as PtNumber - val vExpr2 = call.args[2] as PtNumber - // TODO assign regs - chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt())) - } - "syscall3" -> { - val vExpr = call.args[0] as PtNumber - val vExpr1 = call.args[1] as PtNumber - val vExpr2 = call.args[2] as PtNumber - val vExpr3 = call.args[3] as PtNumber - // TODO assign regs - chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt())) - } - else -> { - TODO("builtinfunc ${call.name}") - } - } - return chunk - } -} diff --git a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt index a4f9692a6..902f38936 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/CodeGen.kt @@ -15,8 +15,7 @@ class CodeGen(internal val program: PtProgram, ): IAssemblyGenerator { internal val allocations = VariableAllocator(symbolTable, program, errors) - private val builtinFunctions = BuiltinFunctionsGen(this) - private val expressionEval = ExpressionGen(this, builtinFunctions) + private val expressionEval = ExpressionGen(this) private val instructions = mutableListOf() init { @@ -93,7 +92,7 @@ class CodeGen(internal val program: PtProgram, is PtArrayIndexer -> TODO() is PtArrayLiteral -> TODO() is PtBinaryExpression -> TODO() - is PtBuiltinFunctionCall -> builtinFunctions.translate(node) + is PtBuiltinFunctionCall -> expressionEval.translate(node) is PtContainmentCheck -> TODO() is PtFunctionCall -> translate(node) is PtIdentifier -> TODO() @@ -105,7 +104,6 @@ class CodeGen(internal val program: PtProgram, is PtString -> TODO() is PtTypeCast -> TODO() is PtForLoop -> TODO() - is PtGosub -> translate(node) is PtIfElse -> TODO() is PtJump -> TODO() is PtNodeGroup -> TODO() @@ -128,17 +126,17 @@ class CodeGen(internal val program: PtProgram, private fun translate(fcall: PtFunctionCall): VmCodeChunk { val chunk = VmCodeChunk() - // TODO evaluate function call arguments + for ((index, arg) in fcall.args.withIndex()) { + // TODO make sure the expressions code doesn't clobber the previous registers, and doesn't use the r0, r1, r2... which are needed to pass the args + val (expressionChunk, resultRegister) = expressionEval.translateExpression(arg) + chunk += expressionChunk + if(resultRegister!=index) + chunk += VmCodeInstruction(Instruction(Opcode.LOADR, vmType(arg.type), reg1=0, reg2=resultRegister)) + } chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(fcall.functionName)) return chunk } - private fun translate(gosub: PtGosub): VmCodeChunk { - val chunk = VmCodeChunk() - chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(gosub.identifier.targetName)) - return chunk - } - private fun translate(ret: PtReturn): VmCodeChunk { val chunk = VmCodeChunk() val value = ret.value diff --git a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt index 9d4dbaf41..e9e25fcd5 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/ExpressionGen.kt @@ -5,7 +5,7 @@ import prog8.code.core.AssemblyError import prog8.vm.Instruction import prog8.vm.Opcode -internal class ExpressionGen(val codeGen: CodeGen, val builtinFunctions: BuiltinFunctionsGen) { +internal class ExpressionGen(val codeGen: CodeGen) { fun translateExpression(expr: PtExpression): Pair { // TODO("Not yet implemented") val chunk = VmCodeChunk() @@ -80,4 +80,50 @@ internal class ExpressionGen(val codeGen: CodeGen, val builtinFunctions: Builtin return Pair(chunk, 0) // TODO function result always in r0? } + + + fun translate(call: PtBuiltinFunctionCall): VmCodeChunk { + val chunk = VmCodeChunk() + when(call.name) { + "syscall" -> { + val vExpr = call.args.single() as PtNumber + chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt())) + } + "syscall1" -> { + val vExpr = call.args[0] as PtNumber + // TODO make sure it evaluates into r0 + val (expressionChunk0, resultRegister0) = translateExpression(call.args[1]) + chunk += expressionChunk0 + chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt())) + } + "syscall2" -> { + val vExpr = call.args[0] as PtNumber + // TODO make sure it evaluates into r0 + val (expressionChunk0, resultRegister0) = translateExpression(call.args[1]) + chunk += expressionChunk0 + // TODO make sure it evaluates into r1 + val (expressionChunk1, resultRegister1) = translateExpression(call.args[2]) + chunk += expressionChunk1 + chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt())) + } + "syscall3" -> { + val vExpr = call.args[0] as PtNumber + // TODO make sure it evaluates into r0 + val (expressionChunk0, resultRegister0) = translateExpression(call.args[1]) + chunk += expressionChunk0 + // TODO make sure it evaluates into r1 + val (expressionChunk1, resultRegister1) = translateExpression(call.args[2]) + chunk += expressionChunk1 + // TODO make sure it evaluates into r2 + val (expressionChunk2, resultRegister2) = translateExpression(call.args[3]) + chunk += expressionChunk2 + chunk += VmCodeInstruction(Instruction(Opcode.SYSCALL, value=vExpr.number.toInt())) + } + else -> { + TODO("builtinfunc ${call.name}") + } + } + return chunk + } + } diff --git a/compiler/src/prog8/compiler/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/IntermediateAstMaker.kt index afe1a68d2..c0c50c846 100644 --- a/compiler/src/prog8/compiler/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/IntermediateAstMaker.kt @@ -4,6 +4,7 @@ import com.github.michaelbull.result.Ok import com.github.michaelbull.result.Result import com.github.michaelbull.result.getOrElse import com.github.michaelbull.result.mapError +import prog8.ast.IStatementContainer import prog8.ast.Program import prog8.ast.base.FatalAstException import prog8.ast.expressions.* @@ -87,7 +88,13 @@ class IntermediateAstMaker(val program: Program) { } } - private fun transform(srcAssign: Assignment): PtAssignment { + private fun transform(srcAssign: Assignment): PtNode { + if(srcAssign.origin==AssignmentOrigin.PARAMETERASSIGN) { + // assignments that are setting the parameters for a function call, + // will be gathered at the GoSub itself later. + return PtNop(srcAssign.position) + } + val assign = PtAssignment(srcAssign.isAugmentable, srcAssign.position) assign.add(transform(srcAssign.target)) assign.add(transformExpression(srcAssign.value)) @@ -222,7 +229,35 @@ class IntermediateAstMaker(val program: Program) { return call } - private fun transform(gosub: GoSub): PtGosub = PtGosub(transform(gosub.identifier), gosub.position) + private fun transform(gosub: GoSub): PtFunctionCall { + // Gather the Goto and any preceding parameter assignments back into a single Function call node. + // (the reason it was split up in the first place, is because the Compiler Ast optimizers + // can then work on any complex expressions that are used as arguments.) + val parent = gosub.parent as IStatementContainer + val gosubIdx = parent.statements.indexOf(gosub) + val previousNodes = parent.statements.subList(0, gosubIdx).reversed() + val paramAssigns = mutableListOf() + for (node in previousNodes) { + if(node !is Assignment || node.origin!=AssignmentOrigin.PARAMETERASSIGN) + break + paramAssigns += node + } + val parameters = gosub.identifier.targetSubroutine(program)!!.parameters + if(paramAssigns.size != parameters.size) + throw FatalAstException("mismatched number of parameter assignments for function call") + + val target = transform(gosub.identifier) + val call = PtFunctionCall(target.targetName, true, DataType.UNDEFINED, gosub.position) + + // put arguments in correct order for the parameters + val namedAssigns = paramAssigns.associate { it.target.identifier!!.targetVarDecl(program)!!.name to it.value } + parameters.forEach { + val argument = namedAssigns.getValue(it.name) + call.add(transformExpression(argument)) + } + + return call + } private fun transform(srcIf: IfElse): PtIfElse { val ifelse = PtIfElse(srcIf.position) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 155511126..cc46a9287 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- in new AST: combine param assignments + GoSub, back into PtFunctionCall node. PtGosub node should not exist. ...