From 3228fa4c76740d9c6bc03bcc5e005830a3348721 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 14 Sep 2018 01:24:12 +0200 Subject: [PATCH] stuff --- il65/examples/test.ill | 4 -- il65/examples/todos.ill | 29 ++++++++++++ il65/src/il65/ast/AST.kt | 7 ++- il65/src/il65/ast/AstChecker.kt | 47 ++++++++++++++++++- il65/src/il65/functions/BuiltinFunctions.kt | 2 + .../il65/optimizing/StatementsOptimizer.kt | 17 +++++++ 6 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 il65/examples/todos.ill diff --git a/il65/examples/test.ill b/il65/examples/test.ill index 567060a86..bf995b682 100644 --- a/il65/examples/test.ill +++ b/il65/examples/test.ill @@ -103,14 +103,10 @@ const byte equalQQ2 = (4+hopla)>0 equalQQ++ - cos(2) ; @todo warning statement has no effect (returnvalue of builtin function not used) (remove statement) - cos(A) ; @todo warning statement has no effect (returnvalue of builtin function not used) (remove statement) AX++ A=X + round(sin(Y)) equalQQ= X equalQQ= len([X, Y, AX]) - len([X, Y, AX]) ; @todo warning statement has no effect (returnvalue of builtin function not used) (remove statement) - sin(1) ; @todo warning statement has no effect (returnvalue of builtin function not used) (remove statement) P_carry(1) P_irqd(0) diff --git a/il65/examples/todos.ill b/il65/examples/todos.ill new file mode 100644 index 000000000..f5315d1c7 --- /dev/null +++ b/il65/examples/todos.ill @@ -0,0 +1,29 @@ +%output prg +%launcher basic + +~ main { +; memory byte derp = max([$ffdd]) ; @todo implement memory vars in stackvm +; memory byte derpA = abs(-20000) +; memory byte derpB = max([1, 2.2, 4.4, 100]) +; memory byte cderp = min([$ffdd])+ (1/1) +; memory byte cderpA = min([$ffdd, 10, 20, 30]) +; memory byte cderpB = min([1, 2.2, 4.4, 100]) +; memory byte derp2 = 2+$ffdd+round(10*sin(3.1)) + +sub start() -> () { + P_irqd(1) ; is okay. (has side-effects, is not a pure function) + + word dinges = 0 + word blerp1 =999 + word blerp3 = 1 + byte blerp2 =99 + dinges=blerp1 + blerp3 = blerp2 + A=blerp2 + A=X + XY=X + XY=AX + + return + } +} diff --git a/il65/src/il65/ast/AST.kt b/il65/src/il65/ast/AST.kt index d508d7ae9..a347620f5 100644 --- a/il65/src/il65/ast/AST.kt +++ b/il65/src/il65/ast/AST.kt @@ -117,7 +117,7 @@ interface IAstProcessor { } fun process(subroutine: Subroutine): IStatement { - subroutine.statements = subroutine.statements.asSequence().map { it.process(this) }.toMutableList() + subroutine.statements = subroutine.statements.map { it.process(this) }.toMutableList() return subroutine } @@ -630,6 +630,7 @@ interface IExpression: Node { fun constValue(namespace: INameScope): LiteralValue? fun process(processor: IAstProcessor): IExpression fun referencesIdentifier(name: String): Boolean + // TODO fun resultingDatatype(): DataType } @@ -771,6 +772,10 @@ class RegisterExpr(val register: Register) : IExpression { override fun constValue(namespace: INameScope): LiteralValue? = null override fun process(processor: IAstProcessor) = this override fun referencesIdentifier(name: String): Boolean = false + + override fun toString(): String { + return "RegisterExpr(register=$register, pos=$position)" + } } diff --git a/il65/src/il65/ast/AstChecker.kt b/il65/src/il65/ast/AstChecker.kt index ca3e0b9a7..2ad45e3f9 100644 --- a/il65/src/il65/ast/AstChecker.kt +++ b/il65/src/il65/ast/AstChecker.kt @@ -160,13 +160,35 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions: } } - if(assignment.value is LiteralValue) { - val targetDatatype = assignment.target.determineDatatype(namespace, assignment) + val targetDatatype = assignment.target.determineDatatype(namespace, assignment) + val constVal = assignment.value.constValue(namespace) + if(constVal!=null) { checkValueTypeAndRange(targetDatatype, null, assignment.value as LiteralValue, assignment.position) + } else { + val sourceDatatype: DataType = when(assignment.value) { + is RegisterExpr -> { + when((assignment.value as RegisterExpr).register) { + Register.A, Register.X, Register.Y -> DataType.BYTE + Register.AX, Register.AY, Register.XY -> DataType.WORD + } + } + is IdentifierReference -> { + val targetStmt = (assignment.value as IdentifierReference).targetStatement(namespace) + if(targetStmt is VarDecl) { + targetStmt.datatype + } else { + throw FatalAstException("cannot get datatype from assignment value ${assignment.value}, pos=${assignment.position}") + } + } + else -> TODO("check assignment compatibility for value ${assignment.value}, pos=${assignment.position}") + } + checkAssignmentCompatible(targetDatatype, sourceDatatype, assignment.position) } + return super.process(assignment) } + /** * Check the variable declarations (values within range etc) */ @@ -499,4 +521,25 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions: } return true } + + private fun checkAssignmentCompatible(targetDatatype: DataType, sourceDatatype: DataType, position: Position?) : Boolean { + val result = when(targetDatatype) { + DataType.BYTE -> sourceDatatype==DataType.BYTE + DataType.WORD -> sourceDatatype==DataType.BYTE || sourceDatatype==DataType.WORD + DataType.FLOAT -> sourceDatatype==DataType.BYTE || sourceDatatype==DataType.WORD || sourceDatatype==DataType.FLOAT + DataType.STR -> sourceDatatype==DataType.STR + DataType.STR_P -> sourceDatatype==DataType.STR_P + DataType.STR_S -> sourceDatatype==DataType.STR_S + DataType.STR_PS -> sourceDatatype==DataType.STR_PS + DataType.ARRAY -> sourceDatatype==DataType.ARRAY + DataType.ARRAY_W -> sourceDatatype==DataType.ARRAY_W + DataType.MATRIX -> sourceDatatype==DataType.MATRIX + } + + if(result) + return true + + checkResult.add(ExpressionError("cannot assign ${sourceDatatype.toString().toLowerCase()} to ${targetDatatype.toString().toLowerCase()}", position)) + return false + } } diff --git a/il65/src/il65/functions/BuiltinFunctions.kt b/il65/src/il65/functions/BuiltinFunctions.kt index f75962a71..f40883f83 100644 --- a/il65/src/il65/functions/BuiltinFunctions.kt +++ b/il65/src/il65/functions/BuiltinFunctions.kt @@ -11,6 +11,8 @@ val BuiltinFunctionNames = setOf( "log", "log10", "sqrt", "rad", "deg", "round", "floor", "ceil", "max", "min", "avg", "sum", "len", "any", "all", "lsb", "msb") +val BuiltinFunctionsWithoutSideEffects = BuiltinFunctionNames - setOf("P_carry", "P_irqd") + class NotConstArgumentException: AstException("not a const argument to a built-in function") diff --git a/il65/src/il65/optimizing/StatementsOptimizer.kt b/il65/src/il65/optimizing/StatementsOptimizer.kt index 40cd24076..9d59f9f49 100644 --- a/il65/src/il65/optimizing/StatementsOptimizer.kt +++ b/il65/src/il65/optimizing/StatementsOptimizer.kt @@ -1,6 +1,8 @@ package il65.optimizing import il65.ast.* +import il65.functions.BuiltinFunctionNames +import il65.functions.BuiltinFunctionsWithoutSideEffects fun Module.optimizeStatements(globalNamespace: INameScope, allScopedSymbolDefinitions: MutableMap) { @@ -33,6 +35,8 @@ class StatementOptimizer(private val globalNamespace: INameScope) : IAstProcesso var optimizationsDone: Int = 0 private set + private var statementsToRemove = mutableListOf() + fun reset() { optimizationsDone = 0 } @@ -48,6 +52,15 @@ class StatementOptimizer(private val globalNamespace: INameScope) : IAstProcesso val target = globalNamespace.lookup(functionCall.target.nameInSource, functionCall) if(target!=null) used(target) + + if(functionCall.target.nameInSource.size==1 && BuiltinFunctionNames.contains(functionCall.target.nameInSource[0])) { + val functionName = functionCall.target.nameInSource[0] + if (BuiltinFunctionsWithoutSideEffects.contains(functionName)) { + println("${functionCall.position} Warning: statement has no effect (function return value is discarded)") + statementsToRemove.add(functionCall) + } + } + return super.process(functionCall) } @@ -99,5 +112,9 @@ class StatementOptimizer(private val globalNamespace: INameScope) : IAstProcesso optimizationsDone++ } } + + for(stmt in statementsToRemove) { + stmt.definingScope().removeStatement(stmt) + } } } \ No newline at end of file