diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index 2de9819f8..73e9eeee8 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -359,14 +359,6 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: } } - override fun after(bfc: BuiltinFunctionCall, parent: Node): Iterable { - val constvalue = bfc.constValue(program) - return if(constvalue!=null) - listOf(IAstModification.ReplaceNode(bfc, constvalue, parent)) - else - noModifications - } - override fun after(forLoop: ForLoop, parent: Node): Iterable { fun adjustRangeDt(rangeFrom: NumericLiteral, targetDt: DataType, rangeTo: NumericLiteral, stepLiteral: NumericLiteral?, range: RangeExpression): RangeExpression? { val fromCast = rangeFrom.cast(targetDt, true) diff --git a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt index 92a758510..be2bdf7f5 100644 --- a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt @@ -70,7 +70,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr if (rightNum!=null && rightNum.type==DataType.UWORD) { if ((rightNum.number.toInt() and 0x00ff) == 0) { // if WORD & $xx00 -> if msb(WORD) & $xx - val msb = BuiltinFunctionCall(IdentifierReference(listOf("msb"), booleanCondition.left.position), mutableListOf(booleanCondition.left), booleanCondition.left.position) + val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), booleanCondition.left.position), mutableListOf(booleanCondition.left), booleanCondition.left.position) val bytevalue = NumericLiteral(DataType.UBYTE, (rightNum.number.toInt() shr 8).toDouble(), booleanCondition.right.position) return listOf( IAstModification.ReplaceNode(booleanCondition.left, msb, booleanCondition), @@ -78,7 +78,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr } else if ((rightNum.number.toInt() and 0xff00) == 0) { // if WORD & $00ff -> if lsb(WORD) & $ff - val lsb = BuiltinFunctionCall(IdentifierReference(listOf("lsb"), booleanCondition.left.position), mutableListOf(booleanCondition.left), booleanCondition.left.position) + val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), booleanCondition.left.position), mutableListOf(booleanCondition.left), booleanCondition.left.position) val bytevalue = NumericLiteral(DataType.UBYTE, rightNum.number, booleanCondition.right.position) return listOf( IAstModification.ReplaceNode(booleanCondition.left, lsb, booleanCondition), @@ -383,7 +383,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr if (andNum!=null) { if ((andNum and 0x00ff) == 0) { // (WORD & $xx00)==y -> (msb(WORD) & $xx)==y - val msb = BuiltinFunctionCall(IdentifierReference(listOf("msb"), bitwise.left.position), mutableListOf(bitwise.left), bitwise.left.position) + val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), bitwise.left.position), mutableListOf(bitwise.left), bitwise.left.position) val bytevalue = NumericLiteral(DataType.UBYTE, (andNum shr 8).toDouble(), bitwise.right.position) val rightvalByte = NumericLiteral(DataType.UBYTE, (rightVal.number.toInt() shr 8).toDouble(), rightVal.position) return listOf( @@ -394,7 +394,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr } else if((andNum and 0xff00) == 0) { // (WORD & $00xx)==y -> (lsb(WORD) & $xx)==y - val lsb = BuiltinFunctionCall(IdentifierReference(listOf("lsb"), bitwise.left.position), mutableListOf(bitwise.left), bitwise.left.position) + val lsb = FunctionCallExpression(IdentifierReference(listOf("lsb"), bitwise.left.position), mutableListOf(bitwise.left), bitwise.left.position) val bytevalue = NumericLiteral(DataType.UBYTE, andNum.toDouble(), bitwise.right.position) val rightvalByte = NumericLiteral(DataType.UBYTE, (rightVal.number.toInt() and 255).toDouble(), rightVal.position) return listOf( @@ -696,7 +696,7 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr DataType.BYTE -> return null // is either 0 or -1 we cannot tell here DataType.UWORD, DataType.WORD -> { // just use: msb(value) as type - val msb = BuiltinFunctionCall(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position) + val msb = FunctionCallExpression(IdentifierReference(listOf("msb"), expr.position), mutableListOf(expr.left), expr.position) return if(leftDt==DataType.WORD) TypecastExpression(msb, DataType.BYTE, true, expr.position) else diff --git a/codeOptimizers/src/prog8/optimizer/Inliner.kt b/codeOptimizers/src/prog8/optimizer/Inliner.kt index 5b8a74256..31027e7b6 100644 --- a/codeOptimizers/src/prog8/optimizer/Inliner.kt +++ b/codeOptimizers/src/prog8/optimizer/Inliner.kt @@ -48,11 +48,6 @@ class Inliner(private val program: Program, private val options: CompilationOpti true } else if (stmt.value!! is IFunctionCall && (stmt.value as IFunctionCall).args.size <= 1 && (stmt.value as IFunctionCall).args.all { it is NumericLiteral || it is IdentifierReference }) { when (stmt.value) { - is BuiltinFunctionCall -> { - makeFullyScoped(stmt.value as BuiltinFunctionCall) - true - } - is FunctionCallExpression -> { makeFullyScoped(stmt.value as FunctionCallExpression) true @@ -158,17 +153,6 @@ class Inliner(private val program: Program, private val options: CompilationOpti } } - private fun makeFullyScoped(call: BuiltinFunctionCall) { - call.target.targetSubroutine(program)?.let { sub -> - val scopedName = IdentifierReference(sub.scopedName, call.target.position) - val scopedArgs = makeScopedArgs(call.args) - if(scopedArgs.any()) { - val scopedCall = BuiltinFunctionCall(scopedName, scopedArgs.toMutableList(), call.position) - modifications += IAstModification.ReplaceNode(call, scopedCall, call.parent) - } - } - } - private fun makeFullyScoped(call: FunctionCallExpression) { makeFullyScoped(call.target) call.target.targetSubroutine(program)?.let { sub -> diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 17d22a149..80ee5b49c 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -1400,13 +1400,6 @@ internal class AstChecker(private val program: Program, super.visit(functionCallExpr) } - override fun visit(bfc: BuiltinFunctionCall) { - // most function calls, even to builtin functions, are still regular FunctionCall nodes here. - // they get converted to the more specialized node type in BeforeAsmTypecastCleaner - checkLongType(bfc) - super.visit(bfc) - } - override fun visit(functionCallStatement: FunctionCallStatement) { // most function calls, even to builtin functions, are still regular FunctionCall nodes here. // they get converted to the more specialized node type in BeforeAsmTypecastCleaner diff --git a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt index 5c9021cec..a1fd9dc5a 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt @@ -233,13 +233,6 @@ class AstPreprocessor(val program: Program, return noModifications } - override fun after(bfc: BuiltinFunctionCall, parent: Node): Iterable { - val stmtOfExpression = findParentNode(bfc) - ?: throw FatalAstException("cannot determine statement scope of function call expression at ${bfc.position}") - checkStringParam(bfc as IFunctionCall, stmtOfExpression) - return noModifications - } - override fun after(bfcs: BuiltinFunctionCallStatement, parent: Node): Iterable { checkStringParam(bfcs as IFunctionCall, bfcs) return noModifications diff --git a/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt b/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt index ce29456a7..dbd0899f1 100644 --- a/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt +++ b/compiler/src/prog8/compiler/astprocessing/BeforeAsmTypecastCleaner.kt @@ -84,18 +84,6 @@ internal class BeforeAsmTypecastCleaner(val program: Program, return noModifications } - override fun before(functionCallExpr: FunctionCallExpression, parent: Node): Iterable { - if(functionCallExpr.target.nameInSource.singleOrNull() 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 { if(bfcs.name=="cmp") { // if the datatype of the arguments of cmp() are different, cast the byte one to word. diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index 5dba8a8f3..395db57cb 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -48,7 +48,7 @@ internal class CodeDesugarer(val program: Program, private val errors: IErrorRep is ForLoop, is RepeatLoop, is UntilLoop, - is WhileLoop -> return jumpAfter(partof as Statement) + is WhileLoop -> return jumpAfter(partof) else -> partof = partof.parent } } @@ -238,7 +238,7 @@ _after: if(isStringComparison(leftDt, rightDt)) { // replace string comparison expressions with calls to string.compare() - val stringCompare = BuiltinFunctionCall( + val stringCompare = FunctionCallExpression( IdentifierReference(listOf("prog8_lib_stringcompare"), expr.position), mutableListOf(expr.left.copy(), expr.right.copy()), expr.position) val zero = NumericLiteral.optimalInteger(0, expr.position) @@ -250,7 +250,7 @@ _after: if(expr.operator=="*" && expr.inferType(program).isInteger && expr.left isSameAs expr.right) { // replace squaring with call to builtin function to do this in a more optimized way val function = if(expr.left.inferType(program).isBytes) "prog8_lib_square_byte" else "prog8_lib_square_word" - val squareCall = BuiltinFunctionCall( + val squareCall = FunctionCallExpression( IdentifierReference(listOf(function), expr.position), mutableListOf(expr.left.copy()), expr.position) return listOf(IAstModification.ReplaceNode(expr, squareCall, parent)) diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt index 8a4879af2..6cfec8365 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt @@ -76,7 +76,6 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr is ArrayIndexedExpression -> transform(expr) is ArrayLiteral -> transform(expr) is BinaryExpression -> transform(expr) - is BuiltinFunctionCall -> transform(expr) is CharLiteral -> throw FatalAstException("char literals should have been converted into bytes") is ContainmentCheck -> transform(expr) is DirectMemoryRead -> transform(expr) @@ -299,7 +298,21 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr return call } - private fun transform(srcCall: FunctionCallExpression): PtFunctionCall { + private fun transform(srcCall: FunctionCallExpression): PtExpression { + val singleName = srcCall.target.nameInSource.singleOrNull() + if(singleName!=null) { + val builtinFunc = BuiltinFunctions[singleName] + if (builtinFunc != null) { + // it's a builtin function. Create special node type for this. + val noSideFx = builtinFunc.pure + val type = srcCall.inferType(program).getOrElse { throw FatalAstException("unknown dt") } + val call = PtBuiltinFunctionCall(singleName, false, noSideFx, type, srcCall.position) + for (arg in srcCall.args) + call.add(transformExpression(arg)) + return call + } + } + val (target, _) = srcCall.target.targetNameAndType(program) val iType = srcCall.inferType(program) val call = PtFunctionCall(target, iType.isUnknown && srcCall.parent !is Assignment, iType.getOrElse { DataType.UNDEFINED }, srcCall.position) @@ -608,15 +621,6 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr return expr } - private fun transform(srcCall: BuiltinFunctionCall): PtBuiltinFunctionCall { - val type = srcCall.inferType(program).getOrElse { throw FatalAstException("unknown dt") } - val noSideFx = BuiltinFunctions.getValue(srcCall.name).pure - val call = PtBuiltinFunctionCall(srcCall.name, false, noSideFx, type, srcCall.position) - for (arg in srcCall.args) - call.add(transformExpression(arg)) - return call - } - private fun transform(srcCheck: ContainmentCheck): PtExpression { fun desugar(range: RangeExpression): PtExpression { @@ -684,7 +688,6 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr } } - private fun transform(memory: DirectMemoryWrite): PtMemoryByte { val mem = PtMemoryByte(memory.position) mem.add(transformExpression(memory.addressExpression)) diff --git a/compiler/test/vm/TestCompilerVirtual.kt b/compiler/test/vm/TestCompilerVirtual.kt index 7b4cf065d..e6bfe07a4 100644 --- a/compiler/test/vm/TestCompilerVirtual.kt +++ b/compiler/test/vm/TestCompilerVirtual.kt @@ -6,7 +6,7 @@ import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.string.shouldContain import io.kotest.matchers.string.shouldNotContain -import prog8.ast.expressions.BuiltinFunctionCall +import prog8.ast.expressions.FunctionCallExpression import prog8.ast.statements.Assignment import prog8.code.target.C64Target import prog8.code.target.Cx16Target @@ -175,7 +175,7 @@ main { val result = compileText(target, true, src, writeAssembly = true)!! val start = result.compilerAst.entrypoint start.statements.size shouldBe 9 - ((start.statements[1] as Assignment).value as BuiltinFunctionCall).name shouldBe "memory" + ((start.statements[1] as Assignment).value as FunctionCallExpression).target.nameInSource shouldBe listOf("memory") val virtfile = result.compilationOptions.outputDir.resolve(result.compilerAst.name + ".p8ir") VmRunner().runAndTestProgram(virtfile.readText()) { vm -> vm.memory.getUB(2) shouldBe 42u diff --git a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt index 873237e1f..2e50cac43 100644 --- a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt +++ b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt @@ -255,10 +255,6 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: printout(functionCallExpr as IFunctionCall) } - override fun visit(bfc: BuiltinFunctionCall) { - printout(bfc as IFunctionCall) - } - override fun visit(functionCallStatement: FunctionCallStatement) { printout(functionCallStatement as IFunctionCall) } diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 1e9d67927..c907cf75a 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -1214,8 +1214,10 @@ class FunctionCallExpression(override var target: IdentifierReference, } override fun copy() = FunctionCallExpression(target.copy(), args.map { it.copy() }.toMutableList(), position) - override val isSimple = false - + override val isSimple = when (target.nameInSource.singleOrNull()) { + in arrayOf("msb", "lsb", "mkword", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> this.args.all { it.isSimple } + else -> false + } override fun replaceChildNode(node: Node, replacement: Node) { if(node===target) target=replacement as IdentifierReference @@ -1343,50 +1345,6 @@ class ContainmentCheck(var element: Expression, } } -class BuiltinFunctionCall(override var target: IdentifierReference, - override val args: MutableList, - 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 = when (name) { - in arrayOf("msb", "lsb", "mkword", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> this.args.all { it.isSimple } - else -> false - } - - 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? { - val function = BuiltinFunctions.getValue(name) - if(function.pure) { - return program.builtinFunctions.constValue(name, args, position) - } - return 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): Boolean = target.referencesIdentifier(nameInSource) || args.any{it.referencesIdentifier(nameInSource)} - override fun inferType(program: Program) = program.builtinFunctions.returnType(name) -} - class IfExpression(var condition: Expression, var truevalue: Expression, var falsevalue: Expression, override val position: Position) : Expression() { override lateinit var parent: Node diff --git a/compilerAst/src/prog8/ast/walk/AstWalker.kt b/compilerAst/src/prog8/ast/walk/AstWalker.kt index da25ffc33..7c03a8e12 100644 --- a/compilerAst/src/prog8/ast/walk/AstWalker.kt +++ b/compilerAst/src/prog8/ast/walk/AstWalker.kt @@ -114,7 +114,6 @@ abstract class AstWalker { open fun before(repeatLoop: RepeatLoop, parent: Node): Iterable = noModifications open fun before(unrollLoop: UnrollLoop, parent: Node): Iterable = noModifications open fun before(functionCallExpr: FunctionCallExpression, parent: Node): Iterable = noModifications - open fun before(bfc: BuiltinFunctionCall, parent: Node): Iterable = noModifications open fun before(functionCallStatement: FunctionCallStatement, parent: Node): Iterable = noModifications open fun before(bfcs: BuiltinFunctionCallStatement, parent: Node): Iterable = noModifications open fun before(identifier: IdentifierReference, parent: Node): Iterable = noModifications @@ -161,7 +160,6 @@ abstract class AstWalker { open fun after(repeatLoop: RepeatLoop, parent: Node): Iterable = noModifications open fun after(unrollLoop: UnrollLoop, parent: Node): Iterable = noModifications open fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable = noModifications - open fun after(bfc: BuiltinFunctionCall, parent: Node): Iterable = noModifications open fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable = noModifications open fun after(bfcs: BuiltinFunctionCallStatement, parent: Node): Iterable = noModifications open fun after(identifier: IdentifierReference, parent: Node): Iterable = noModifications @@ -288,13 +286,6 @@ abstract class AstWalker { 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) { track(before(functionCallStatement, parent), functionCallStatement, parent) functionCallStatement.target.accept(this, functionCallStatement) diff --git a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt index 1c04ffc27..bdde208b4 100644 --- a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt +++ b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt @@ -54,11 +54,6 @@ interface IAstVisitor { functionCallExpr.args.forEach { it.accept(this) } } - fun visit(bfc: BuiltinFunctionCall) { - bfc.target.accept(this) - bfc.args.forEach { it.accept(this) } - } - fun visit(functionCallStatement: FunctionCallStatement) { functionCallStatement.target.accept(this) functionCallStatement.args.forEach { it.accept(this) }