mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
error reporting improved
This commit is contained in:
parent
50bbbc67e2
commit
b6ea33efa3
@ -64,7 +64,7 @@ statement :
|
||||
| inlineasm
|
||||
| labeldef
|
||||
| returnstmt
|
||||
// @todo forloop, whileloop, repeatloop, ifelse
|
||||
// @todo forloop, whileloop, repeatloop
|
||||
;
|
||||
|
||||
labeldef : identifier ':' ;
|
||||
|
@ -8,13 +8,16 @@
|
||||
memory byte derp = max($ffdd)
|
||||
memory byte derpA = abs(-2.5-0.5)
|
||||
memory byte derpB = max(1, 2.2, 4.4, 100)
|
||||
memory byte cderp = min($ffdd)
|
||||
memory byte cderp = min($ffdd)+ (1/1)
|
||||
memory byte cderp1 = foobar
|
||||
memory byte cderp2 = boo.bar.booz
|
||||
memory byte cderp3 = main.doesnt_exist
|
||||
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))
|
||||
memory byte derp3 = round(100*sin(3))
|
||||
memory byte derp3 = round2(100*sin(3))
|
||||
const byte hopla=55-33
|
||||
const byte hopla2=100+(-main.hopla)
|
||||
const byte hopla2=100+(-main.hopla2)
|
||||
const byte hopla3=100+(-hopla)
|
||||
const byte hopla4 = 100-hopla
|
||||
const byte hopla1=main.hopla
|
||||
|
@ -137,8 +137,10 @@ fun main(args: Array<String>) {
|
||||
moduleAst.statements.forEach {
|
||||
println(it)
|
||||
}
|
||||
} catch(sx: SyntaxError) {
|
||||
sx.printError()
|
||||
// } catch(sx: SyntaxError) {
|
||||
// System.err.println(sx)
|
||||
// } catch(ex: ExpressionException) {
|
||||
// System.err.println(ex)
|
||||
} catch (px: ParsingFailedError) {
|
||||
System.err.println(px.message)
|
||||
}
|
||||
|
@ -34,13 +34,21 @@ enum class Register {
|
||||
}
|
||||
|
||||
|
||||
open class AstException(override var message: String) : Exception(message)
|
||||
class ExpressionException(override var message: String) : AstException(message)
|
||||
class FatalAstException (override var message: String) : Exception(message)
|
||||
|
||||
class SyntaxError(override var message: String, val position: Position?) : AstException(message) {
|
||||
fun printError() {
|
||||
open class AstException (override var message: String) : Exception(message)
|
||||
|
||||
open class SyntaxError(override var message: String, val position: Position?) : AstException(message) {
|
||||
override fun toString(): String {
|
||||
val location = position?.toString() ?: ""
|
||||
System.err.println("$location $message")
|
||||
return "$location Syntax error: $message"
|
||||
}
|
||||
}
|
||||
|
||||
class ExpressionException(message: String, val position: Position?) : AstException(message) {
|
||||
override fun toString(): String {
|
||||
val location = position?.toString() ?: ""
|
||||
return "$location Error: $message"
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,7 +105,7 @@ interface IAstProcessor {
|
||||
fun process(ifStatement: IfStatement): IStatement {
|
||||
ifStatement.condition = ifStatement.condition.process(this)
|
||||
ifStatement.statements = ifStatement.statements.map { it.process(this) }
|
||||
ifStatement.elsepart = ifStatement.elsepart?.map { it.process(this) }
|
||||
ifStatement.elsepart = ifStatement.elsepart.map { it.process(this) }
|
||||
return ifStatement
|
||||
}
|
||||
|
||||
@ -134,13 +142,7 @@ interface INameScope {
|
||||
fun subScopes() = statements.filter { it is INameScope } .map { it as INameScope }.associate { it.name to it }
|
||||
|
||||
fun definedNames() = statements.filter { it is Label || it is VarDecl }
|
||||
.associate {
|
||||
when(it) {
|
||||
is Label -> it.name to it
|
||||
is VarDecl -> it.name to it
|
||||
else -> throw AstException("expected label or vardecl")
|
||||
}
|
||||
}
|
||||
.associate {((it as? Label)?.name ?: (it as? VarDecl)?.name) to it }
|
||||
|
||||
fun lookup(scopedName: List<String>, statement: Node) : IStatement? {
|
||||
if(scopedName.size>1) {
|
||||
@ -391,6 +393,7 @@ data class AssignTarget(val register: Register?, val identifier: Identifier?) :
|
||||
interface IExpression: Node {
|
||||
fun constValue(namespace: INameScope): LiteralValue?
|
||||
fun process(processor: IAstProcessor): IExpression
|
||||
fun referencesIdentifier(name: String): Boolean
|
||||
}
|
||||
|
||||
|
||||
@ -407,6 +410,7 @@ data class PrefixExpression(val operator: String, var expression: IExpression) :
|
||||
|
||||
override fun constValue(namespace: INameScope): LiteralValue? = null
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
override fun referencesIdentifier(name: String) = expression.referencesIdentifier(name)
|
||||
}
|
||||
|
||||
|
||||
@ -421,10 +425,11 @@ data class BinaryExpression(var left: IExpression, val operator: String, var rig
|
||||
}
|
||||
|
||||
override fun constValue(namespace: INameScope): LiteralValue? {
|
||||
throw ExpressionException("should have been optimized away before const value was asked")
|
||||
throw ExpressionException("expression should have been optimized away into a single value, before const value was requested (this error is often caused by another)", position)
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
override fun referencesIdentifier(name: String) = left.referencesIdentifier(name) || right.referencesIdentifier(name)
|
||||
}
|
||||
|
||||
data class LiteralValue(val intvalue: Int? = null,
|
||||
@ -433,6 +438,7 @@ data class LiteralValue(val intvalue: Int? = null,
|
||||
val arrayvalue: List<IExpression>? = null) : IExpression {
|
||||
override var position: Position? = null
|
||||
override var parent: Node? = null
|
||||
override fun referencesIdentifier(name: String) = arrayvalue?.any { it.referencesIdentifier(name) } ?: false
|
||||
|
||||
fun asInt(errorIfNotNumeric: Boolean=true): Int? {
|
||||
return when {
|
||||
@ -486,6 +492,7 @@ data class RangeExpr(var from: IExpression, var to: IExpression) : IExpression {
|
||||
|
||||
override fun constValue(namespace: INameScope): LiteralValue? = null
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
override fun referencesIdentifier(name: String): Boolean = from.referencesIdentifier(name) || to.referencesIdentifier(name)
|
||||
}
|
||||
|
||||
|
||||
@ -499,6 +506,7 @@ data 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
|
||||
}
|
||||
|
||||
|
||||
@ -513,11 +521,10 @@ data class Identifier(val scopedName: List<String>) : IExpression {
|
||||
override fun constValue(namespace: INameScope): LiteralValue? {
|
||||
val node = namespace.lookup(scopedName, this)
|
||||
?:
|
||||
throw SyntaxError("undefined symbol: ${scopedName.joinToString(".")}", position) // todo add to a list of errors instead
|
||||
throw ExpressionException("undefined symbol: ${scopedName.joinToString(".")}", position)
|
||||
val vardecl = node as? VarDecl
|
||||
if(vardecl==null) {
|
||||
// todo add to a list of errors instead
|
||||
throw SyntaxError("name should be a constant, instead of: ${node::class.simpleName}", position)
|
||||
throw ExpressionException("name should be a constant, instead of: ${node::class.simpleName}", position)
|
||||
} else if(vardecl.type!=VarDeclType.CONST) {
|
||||
return null
|
||||
}
|
||||
@ -525,6 +532,7 @@ data class Identifier(val scopedName: List<String>) : IExpression {
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
override fun referencesIdentifier(name: String): Boolean = scopedName.last() == name // @todo is this correct all the time?
|
||||
}
|
||||
|
||||
|
||||
@ -571,26 +579,27 @@ data class FunctionCall(override var location: Identifier, override var arglist:
|
||||
// if the function is a built-in function and the args are consts, should evaluate!
|
||||
if(location.scopedName.size>1) return null
|
||||
return when(location.scopedName[0]){
|
||||
"sin" -> builtin_sin(arglist, namespace)
|
||||
"cos" -> builtin_cos(arglist, namespace)
|
||||
"abs" -> builtin_abs(arglist, namespace)
|
||||
"acos" -> builtin_acos(arglist, namespace)
|
||||
"asin" -> builtin_asin(arglist, namespace)
|
||||
"tan" -> builtin_tan(arglist, namespace)
|
||||
"atan" -> builtin_atan(arglist, namespace)
|
||||
"log" -> builtin_log(arglist, namespace)
|
||||
"log10" -> builtin_log10(arglist, namespace)
|
||||
"sqrt" -> builtin_sqrt(arglist, namespace)
|
||||
"max" -> builtin_max(arglist, namespace)
|
||||
"min" -> builtin_min(arglist, namespace)
|
||||
"round" -> builtin_round(arglist, namespace)
|
||||
"rad" -> builtin_rad(arglist, namespace)
|
||||
"deg" -> builtin_deg(arglist, namespace)
|
||||
"sin" -> builtin_sin(arglist, position, namespace)
|
||||
"cos" -> builtin_cos(arglist, position, namespace)
|
||||
"abs" -> builtin_abs(arglist, position, namespace)
|
||||
"acos" -> builtin_acos(arglist, position, namespace)
|
||||
"asin" -> builtin_asin(arglist, position, namespace)
|
||||
"tan" -> builtin_tan(arglist, position, namespace)
|
||||
"atan" -> builtin_atan(arglist, position, namespace)
|
||||
"log" -> builtin_log(arglist, position, namespace)
|
||||
"log10" -> builtin_log10(arglist, position, namespace)
|
||||
"sqrt" -> builtin_sqrt(arglist, position, namespace)
|
||||
"max" -> builtin_max(arglist, position, namespace)
|
||||
"min" -> builtin_min(arglist, position, namespace)
|
||||
"round" -> builtin_round(arglist, position, namespace)
|
||||
"rad" -> builtin_rad(arglist, position, namespace)
|
||||
"deg" -> builtin_deg(arglist, position, namespace)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
override fun referencesIdentifier(name: String): Boolean = location.referencesIdentifier(name) || arglist.any{it.referencesIdentifier(name)}
|
||||
}
|
||||
|
||||
|
||||
@ -708,7 +717,7 @@ private fun il65Parser.ModulestatementContext.toAst(withPosition: Boolean) : ISt
|
||||
val block = block()?.toAst(withPosition)
|
||||
if(block!=null) return block
|
||||
|
||||
throw UnsupportedOperationException(text)
|
||||
throw FatalAstException(text)
|
||||
}
|
||||
|
||||
|
||||
@ -820,7 +829,7 @@ private fun il65Parser.StatementContext.toAst(withPosition: Boolean) : IStatemen
|
||||
val asm = inlineasm()?.toAst(withPosition)
|
||||
if(asm!=null) return asm
|
||||
|
||||
throw UnsupportedOperationException(text)
|
||||
throw FatalAstException(text)
|
||||
}
|
||||
|
||||
private fun il65Parser.Functioncall_stmtContext.toAst(withPosition: Boolean): IStatement {
|
||||
@ -952,7 +961,7 @@ private fun il65Parser.IntegerliteralContext.toAst(): Int {
|
||||
il65Parser.DEC_INTEGER -> text.toInt()
|
||||
il65Parser.HEX_INTEGER -> text.substring(1).toInt(16)
|
||||
il65Parser.BIN_INTEGER -> text.substring(1).toInt(2)
|
||||
else -> throw UnsupportedOperationException(text)
|
||||
else -> throw FatalAstException(terminal.text)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1013,7 +1022,7 @@ private fun il65Parser.ExpressionContext.toAst(withPosition: Boolean) : IExpress
|
||||
if(childCount==3 && children[0].text=="(" && children[2].text==")")
|
||||
return expression(0).toAst(withPosition) // expression within ( )
|
||||
|
||||
throw UnsupportedOperationException(text)
|
||||
throw FatalAstException(text)
|
||||
}
|
||||
|
||||
|
||||
@ -1040,7 +1049,7 @@ private fun il65Parser.FloatliteralContext.toAst() = text.toDouble()
|
||||
private fun il65Parser.BooleanliteralContext.toAst() = when(text) {
|
||||
"true" -> true
|
||||
"false" -> false
|
||||
else -> throw UnsupportedOperationException(text)
|
||||
else -> throw FatalAstException(text)
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@ fun Module.checkValid(globalNamespace: INameScope) {
|
||||
this.process(checker)
|
||||
val checkResult = checker.result()
|
||||
checkResult.forEach {
|
||||
it.printError()
|
||||
System.err.println(it)
|
||||
}
|
||||
if(checkResult.isNotEmpty())
|
||||
throw ParsingFailedError("There are ${checkResult.size} errors in module '$name'.")
|
||||
@ -157,6 +157,14 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor {
|
||||
fun err(msg: String) {
|
||||
checkResult.add(SyntaxError(msg, decl.position))
|
||||
}
|
||||
|
||||
// the initializer value can't refer to the variable itself (recursive definition)
|
||||
if(decl.value?.referencesIdentifier(decl.name) == true||
|
||||
decl.arrayspec?.x?.referencesIdentifier(decl.name) == true ||
|
||||
decl.arrayspec?.y?.referencesIdentifier(decl.name) == true) {
|
||||
err("recursive var declaration")
|
||||
}
|
||||
|
||||
when(decl.type) {
|
||||
VarDeclType.VAR, VarDeclType.CONST -> {
|
||||
when {
|
||||
@ -176,7 +184,7 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor {
|
||||
VarDeclType.MEMORY -> {
|
||||
if(decl.value !is LiteralValue)
|
||||
// @todo normal error reporting
|
||||
throw AstException("${decl.value?.position} value of memory var decl is not a literal (it is a ${decl.value!!::class.simpleName}).")
|
||||
throw SyntaxError("value of memory var decl is not a literal (it is a ${decl.value!!::class.simpleName}).", decl.value?.position)
|
||||
|
||||
val value = decl.value as LiteralValue
|
||||
if(value.intvalue==null || value.intvalue<0 || value.intvalue>65535) {
|
||||
@ -263,7 +271,7 @@ class AstChecker(private val globalNamespace: INameScope) : IAstProcessor {
|
||||
if(directive.args.size!=1 || directive.args[0].name != "enable_floats")
|
||||
err("invalid option directive argument, expected enable_floats")
|
||||
}
|
||||
else -> throw AstException("invalid directive ${directive.directive}")
|
||||
else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position)
|
||||
}
|
||||
return super.process(directive)
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ fun Module.checkImportedValid() {
|
||||
this.process(checker)
|
||||
val result = checker.result()
|
||||
result.forEach {
|
||||
it.printError()
|
||||
System.err.println(it)
|
||||
}
|
||||
if(result.isNotEmpty())
|
||||
throw ParsingFailedError("There are ${result.size} errors in imported module '$name'.")
|
||||
|
@ -1,13 +1,10 @@
|
||||
package il65.functions
|
||||
|
||||
import il65.ast.IExpression
|
||||
import il65.ast.INameScope
|
||||
import il65.ast.LiteralValue
|
||||
import il65.ast.Position
|
||||
import il65.ast.*
|
||||
|
||||
private fun oneDoubleArg(args: List<IExpression>, namespace: INameScope, function: (arg: Double)->Double): LiteralValue {
|
||||
private fun oneDoubleArg(args: List<IExpression>, position: Position?, namespace:INameScope, function: (arg: Double)->Double): LiteralValue {
|
||||
if(args.size!=1)
|
||||
throw UnsupportedOperationException("built-in function requires one floating point argument")
|
||||
throw SyntaxError("built-in function requires one floating point argument", position)
|
||||
|
||||
val float = args[0].constValue(namespace)?.asFloat()
|
||||
if(float!=null) {
|
||||
@ -16,12 +13,12 @@ private fun oneDoubleArg(args: List<IExpression>, namespace: INameScope, functio
|
||||
return result
|
||||
}
|
||||
else
|
||||
throw UnsupportedOperationException("built-in function requires floating point value as argument")
|
||||
throw SyntaxError("built-in function requires floating point value as argument", position)
|
||||
}
|
||||
|
||||
private fun oneDoubleArgOutputInt(args: List<IExpression>, namespace: INameScope, function: (arg: Double)->Int): LiteralValue {
|
||||
private fun oneDoubleArgOutputInt(args: List<IExpression>, position: Position?, namespace:INameScope, function: (arg: Double)->Int): LiteralValue {
|
||||
if(args.size!=1)
|
||||
throw UnsupportedOperationException("built-in function requires one floating point argument")
|
||||
throw SyntaxError("built-in function requires one floating point argument", position)
|
||||
|
||||
val float = args[0].constValue(namespace)?.asFloat()
|
||||
if(float!=null) {
|
||||
@ -30,86 +27,72 @@ private fun oneDoubleArgOutputInt(args: List<IExpression>, namespace: INameScope
|
||||
return result
|
||||
}
|
||||
else
|
||||
throw UnsupportedOperationException("built-in function requires floating point value as argument")
|
||||
throw SyntaxError("built-in function requires floating point value as argument", position)
|
||||
}
|
||||
|
||||
private fun twoDoubleArg(args: List<IExpression>, namespace: INameScope, function: (arg1: Double, arg2: Double)->Double): LiteralValue {
|
||||
if(args.size!=2)
|
||||
throw UnsupportedOperationException("built-in function requires two floating point arguments")
|
||||
|
||||
val float1 = args[0].constValue(namespace)?.asFloat()
|
||||
val float2 = args[1].constValue(namespace)?.asFloat()
|
||||
if(float1!=null && float2!=null) {
|
||||
val result = LiteralValue(floatvalue = function(float1, float2))
|
||||
result.position = args[0].position
|
||||
return result
|
||||
}
|
||||
else
|
||||
throw UnsupportedOperationException("built-in function requires two floating point values as argument")
|
||||
}
|
||||
fun builtin_round(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArgOutputInt(args, position, namespace) { it -> Math.round(it).toInt() }
|
||||
|
||||
fun builtin_round(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArgOutputInt(args, namespace) { it -> Math.round(it).toInt() }
|
||||
fun builtin_sin(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::sin)
|
||||
|
||||
fun builtin_sin(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArg(args, namespace, Math::sin)
|
||||
fun builtin_cos(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::cos)
|
||||
|
||||
fun builtin_cos(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArg(args, namespace, Math::cos)
|
||||
fun builtin_acos(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::acos)
|
||||
|
||||
fun builtin_acos(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArg(args, namespace, Math::acos)
|
||||
fun builtin_asin(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::asin)
|
||||
|
||||
fun builtin_asin(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArg(args, namespace, Math::asin)
|
||||
fun builtin_tan(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::tan)
|
||||
|
||||
fun builtin_tan(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArg(args, namespace, Math::tan)
|
||||
fun builtin_atan(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::atan)
|
||||
|
||||
fun builtin_atan(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArg(args, namespace, Math::atan)
|
||||
fun builtin_log(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::log)
|
||||
|
||||
fun builtin_log(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArg(args, namespace, Math::log)
|
||||
fun builtin_log10(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::log10)
|
||||
|
||||
fun builtin_log10(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArg(args, namespace, Math::log10)
|
||||
fun builtin_sqrt(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::sqrt)
|
||||
|
||||
fun builtin_sqrt(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArg(args, namespace, Math::sqrt)
|
||||
fun builtin_rad(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::toRadians)
|
||||
|
||||
fun builtin_rad(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArg(args, namespace, Math::toRadians)
|
||||
fun builtin_deg(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue
|
||||
= oneDoubleArg(args, position, namespace, Math::toDegrees)
|
||||
|
||||
fun builtin_deg(args: List<IExpression>, namespace: INameScope): LiteralValue
|
||||
= oneDoubleArg(args, namespace, Math::toDegrees)
|
||||
|
||||
fun builtin_abs(args: List<IExpression>, namespace: INameScope): LiteralValue {
|
||||
fun builtin_abs(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue {
|
||||
if(args.size!=1)
|
||||
throw UnsupportedOperationException("built-in function abs requires one numeric argument")
|
||||
throw SyntaxError("built-in function abs requires one numeric argument", position)
|
||||
val float = args[0].constValue(namespace)?.asFloat()
|
||||
if(float!=null)
|
||||
return IntOrFloatLiteral(Math.abs(float), args[0].position)
|
||||
else
|
||||
throw UnsupportedOperationException("built-in function abs requires floating point value as argument")
|
||||
throw SyntaxError("built-in function abs requires floating point value as argument", position)
|
||||
}
|
||||
|
||||
fun builtin_max(args: List<IExpression>, namespace: INameScope): LiteralValue {
|
||||
fun builtin_max(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue {
|
||||
if(args.isEmpty())
|
||||
throw UnsupportedOperationException("max requires at least one argument")
|
||||
throw SyntaxError("max requires at least one argument", position)
|
||||
val constants = args.map { it.constValue(namespace) }
|
||||
if(constants.contains(null))
|
||||
throw UnsupportedOperationException("not all arguments to max are a constant value")
|
||||
throw SyntaxError("not all arguments to max are a constant value", position)
|
||||
val result = constants.map { it?.asFloat()!! }.max()
|
||||
return IntOrFloatLiteral(result!!, args[0].position)
|
||||
}
|
||||
|
||||
fun builtin_min(args: List<IExpression>, namespace: INameScope): LiteralValue {
|
||||
fun builtin_min(args: List<IExpression>, position: Position?, namespace:INameScope): LiteralValue {
|
||||
if(args.isEmpty())
|
||||
throw UnsupportedOperationException("min requires at least one argument")
|
||||
throw SyntaxError("min requires at least one argument", position)
|
||||
val constants = args.map { it.constValue(namespace) }
|
||||
if(constants.contains(null))
|
||||
throw UnsupportedOperationException("not all arguments to min are a constant value")
|
||||
throw SyntaxError("not all arguments to min are a constant value", position)
|
||||
val result = constants.map { it?.asFloat()!! }.min()
|
||||
return IntOrFloatLiteral(result!!, args[0].position)
|
||||
}
|
||||
|
@ -1,42 +1,72 @@
|
||||
package il65.optimizing
|
||||
|
||||
import il65.ParsingFailedError
|
||||
import il65.ast.*
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
fun Module.optimizeExpressions(globalNamespace: INameScope) {
|
||||
val optimizer = ExpressionOptimizer(globalNamespace)
|
||||
this.process(optimizer)
|
||||
try {
|
||||
this.process(optimizer)
|
||||
} catch (ax: AstException) {
|
||||
optimizer.errors.add(ax)
|
||||
}
|
||||
|
||||
if(optimizer.optimizationsDone==0)
|
||||
println("[${this.name}] 0 optimizations performed")
|
||||
|
||||
while(optimizer.optimizationsDone>0) {
|
||||
while(optimizer.errors.isEmpty() && optimizer.optimizationsDone>0) {
|
||||
println("[${this.name}] ${optimizer.optimizationsDone} optimizations performed")
|
||||
optimizer.reset()
|
||||
optimizer.optimizationsDone = 0
|
||||
this.process(optimizer)
|
||||
}
|
||||
this.linkParents() // re-link in final configuration
|
||||
|
||||
if(optimizer.errors.isNotEmpty()) {
|
||||
optimizer.errors.forEach { System.err.println(it) }
|
||||
throw ParsingFailedError("There are ${optimizer.errors.size} errors.")
|
||||
} else {
|
||||
this.linkParents() // re-link in final configuration
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcessor {
|
||||
var optimizationsDone: Int = 0
|
||||
private set
|
||||
var errors : MutableList<AstException> = mutableListOf()
|
||||
|
||||
fun reset() {
|
||||
optimizationsDone = 0
|
||||
|
||||
override fun process(decl: VarDecl): IStatement {
|
||||
// the initializer value can't refer to the variable itself (recursive definition)
|
||||
if(decl.value?.referencesIdentifier(decl.name) == true||
|
||||
decl.arrayspec?.x?.referencesIdentifier(decl.name) == true ||
|
||||
decl.arrayspec?.y?.referencesIdentifier(decl.name) == true) {
|
||||
errors.add(ExpressionException("recursive var declaration", decl.position))
|
||||
return decl
|
||||
}
|
||||
return super.process(decl)
|
||||
}
|
||||
|
||||
/**
|
||||
* replace identifiers that refer to const value, with the value itself
|
||||
*/
|
||||
override fun process(identifier: Identifier): IExpression {
|
||||
return identifier.constValue(globalNamespace) ?: identifier
|
||||
return try {
|
||||
identifier.constValue(globalNamespace) ?: identifier
|
||||
} catch (ax: AstException) {
|
||||
errors.add(ax)
|
||||
identifier
|
||||
}
|
||||
}
|
||||
|
||||
override fun process(functionCall: FunctionCall): IExpression {
|
||||
super.process(functionCall)
|
||||
return functionCall.constValue(globalNamespace) ?: functionCall
|
||||
return try {
|
||||
super.process(functionCall)
|
||||
functionCall.constValue(globalNamespace) ?: functionCall
|
||||
} catch (ax: AstException) {
|
||||
errors.add(ax)
|
||||
functionCall
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,48 +75,53 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
|
||||
* For instance, the expression for "- 4.5" will be optimized into the float literal -4.5
|
||||
*/
|
||||
override fun process(expr: PrefixExpression): IExpression {
|
||||
super.process(expr)
|
||||
return try {
|
||||
super.process(expr)
|
||||
|
||||
val subexpr = expr.expression
|
||||
if (subexpr is LiteralValue) {
|
||||
// process prefixed literal values (such as -3, not true)
|
||||
val result = when {
|
||||
expr.operator == "+" -> subexpr
|
||||
expr.operator == "-" -> when {
|
||||
subexpr.intvalue != null -> {
|
||||
optimizationsDone++
|
||||
LiteralValue(intvalue = -subexpr.intvalue)
|
||||
val subexpr = expr.expression
|
||||
if (subexpr is LiteralValue) {
|
||||
// process prefixed literal values (such as -3, not true)
|
||||
val result = when {
|
||||
expr.operator == "+" -> subexpr
|
||||
expr.operator == "-" -> when {
|
||||
subexpr.intvalue != null -> {
|
||||
optimizationsDone++
|
||||
LiteralValue(intvalue = -subexpr.intvalue)
|
||||
}
|
||||
subexpr.floatvalue != null -> {
|
||||
optimizationsDone++
|
||||
LiteralValue(floatvalue = -subexpr.floatvalue)
|
||||
}
|
||||
else -> throw ExpressionException("can only take negative of int or float", subexpr.position)
|
||||
}
|
||||
subexpr.floatvalue != null -> {
|
||||
optimizationsDone++
|
||||
LiteralValue(floatvalue = -subexpr.floatvalue)
|
||||
expr.operator == "~" -> when {
|
||||
subexpr.intvalue != null -> {
|
||||
optimizationsDone++
|
||||
LiteralValue(intvalue = subexpr.intvalue.inv())
|
||||
}
|
||||
else -> throw ExpressionException("can only take bitwise inversion of int", subexpr.position)
|
||||
}
|
||||
else -> throw UnsupportedOperationException("can only take negative of int or float")
|
||||
expr.operator == "not" -> when {
|
||||
subexpr.intvalue != null -> {
|
||||
optimizationsDone++
|
||||
LiteralValue(intvalue = if (subexpr.intvalue == 0) 1 else 0)
|
||||
}
|
||||
subexpr.floatvalue != null -> {
|
||||
optimizationsDone++
|
||||
LiteralValue(intvalue = if (subexpr.floatvalue == 0.0) 1 else 0)
|
||||
}
|
||||
else -> throw ExpressionException("can not take logical not of $subexpr", subexpr.position)
|
||||
}
|
||||
else -> throw ExpressionException(expr.operator, subexpr.position)
|
||||
}
|
||||
expr.operator == "~" -> when {
|
||||
subexpr.intvalue != null -> {
|
||||
optimizationsDone++
|
||||
LiteralValue(intvalue = subexpr.intvalue.inv())
|
||||
}
|
||||
else -> throw UnsupportedOperationException("can only take bitwise inversion of int")
|
||||
}
|
||||
expr.operator == "not" -> when {
|
||||
subexpr.intvalue != null -> {
|
||||
optimizationsDone++
|
||||
LiteralValue(intvalue = if (subexpr.intvalue == 0) 1 else 0)
|
||||
}
|
||||
subexpr.floatvalue != null -> {
|
||||
optimizationsDone++
|
||||
LiteralValue(intvalue = if (subexpr.floatvalue == 0.0) 1 else 0)
|
||||
}
|
||||
else -> throw UnsupportedOperationException("can not take logical not of $subexpr")
|
||||
}
|
||||
else -> throw UnsupportedOperationException(expr.operator)
|
||||
result.position = subexpr.position
|
||||
return result
|
||||
}
|
||||
result.position = subexpr.position
|
||||
return result
|
||||
return expr
|
||||
} catch (ax: AstException) {
|
||||
errors.add(ax)
|
||||
expr
|
||||
}
|
||||
return expr
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,53 +130,63 @@ class ExpressionOptimizer(private val globalNamespace: INameScope) : IAstProcess
|
||||
* For instance, "9 * (4 + 2)" will be optimized into the integer literal 54.
|
||||
*/
|
||||
override fun process(expr: BinaryExpression): IExpression {
|
||||
super.process(expr)
|
||||
return try {
|
||||
super.process(expr)
|
||||
|
||||
val evaluator = ConstExprEvaluator()
|
||||
val leftconst = expr.left.constValue(globalNamespace)
|
||||
val rightconst = expr.right.constValue(globalNamespace)
|
||||
return when {
|
||||
leftconst != null && rightconst != null -> {
|
||||
optimizationsDone++
|
||||
evaluator.evaluate(leftconst, expr.operator, rightconst)
|
||||
val evaluator = ConstExprEvaluator()
|
||||
val leftconst = expr.left.constValue(globalNamespace)
|
||||
val rightconst = expr.right.constValue(globalNamespace)
|
||||
return when {
|
||||
leftconst != null && rightconst != null -> {
|
||||
optimizationsDone++
|
||||
evaluator.evaluate(leftconst, expr.operator, rightconst)
|
||||
}
|
||||
else -> expr
|
||||
}
|
||||
else -> expr
|
||||
} catch (ax: AstException) {
|
||||
errors.add(ax)
|
||||
expr
|
||||
}
|
||||
}
|
||||
|
||||
override fun process(range: RangeExpr): IExpression {
|
||||
super.process(range)
|
||||
val from = range.from.constValue(globalNamespace)
|
||||
val to = range.to.constValue(globalNamespace)
|
||||
if(from!=null && to != null) {
|
||||
when {
|
||||
from.intvalue!=null && to.intvalue!=null -> {
|
||||
// int range
|
||||
val rangevalue = from.intvalue.rangeTo(to.intvalue)
|
||||
if(rangevalue.last-rangevalue.first > 65535) {
|
||||
throw AstException("amount of values in range exceeds 65535, at ${range.position}")
|
||||
return try {
|
||||
super.process(range)
|
||||
val from = range.from.constValue(globalNamespace)
|
||||
val to = range.to.constValue(globalNamespace)
|
||||
if (from != null && to != null) {
|
||||
when {
|
||||
from.intvalue != null && to.intvalue != null -> {
|
||||
// int range
|
||||
val rangevalue = from.intvalue.rangeTo(to.intvalue)
|
||||
if (rangevalue.last - rangevalue.first > 65535) {
|
||||
throw ExpressionException("amount of values in range exceeds 65535", range.position)
|
||||
}
|
||||
return LiteralValue(arrayvalue = rangevalue.map {
|
||||
val v = LiteralValue(intvalue = it)
|
||||
v.position = range.position
|
||||
v.parent = range.parent
|
||||
v
|
||||
})
|
||||
}
|
||||
return LiteralValue(arrayvalue = rangevalue.map {
|
||||
val v = LiteralValue(intvalue=it)
|
||||
v.position=range.position
|
||||
v.parent=range.parent
|
||||
v
|
||||
})
|
||||
}
|
||||
from.strvalue!=null && to.strvalue!=null -> {
|
||||
// char range
|
||||
val rangevalue = from.strvalue[0].rangeTo(to.strvalue[0])
|
||||
if(rangevalue.last-rangevalue.first > 65535) {
|
||||
throw AstException("amount of characters in range exceeds 65535, at ${range.position}")
|
||||
from.strvalue != null && to.strvalue != null -> {
|
||||
// char range
|
||||
val rangevalue = from.strvalue[0].rangeTo(to.strvalue[0])
|
||||
if (rangevalue.last - rangevalue.first > 65535) {
|
||||
throw ExpressionException("amount of characters in range exceeds 65535", range.position)
|
||||
}
|
||||
val newval = LiteralValue(strvalue = rangevalue.toList().joinToString(""))
|
||||
newval.position = range.position
|
||||
newval.parent = range.parent
|
||||
return newval
|
||||
}
|
||||
val newval = LiteralValue(strvalue = rangevalue.toList().joinToString(""))
|
||||
newval.position = range.position
|
||||
newval.parent = range.parent
|
||||
return newval
|
||||
}
|
||||
}
|
||||
return range
|
||||
} catch (ax: AstException) {
|
||||
errors.add(ax)
|
||||
range
|
||||
}
|
||||
return range
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,7 +216,7 @@ class ConstExprEvaluator {
|
||||
">=" -> comparegreaterequal(left, right)
|
||||
"==" -> compareequal(left, right)
|
||||
"!=" -> comparenotequal(left, right)
|
||||
else -> throw AstException("const evaluation for invalid operator $operator")
|
||||
else -> throw FatalAstException("const evaluation for invalid operator $operator")
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,14 +233,14 @@ class ConstExprEvaluator {
|
||||
left.floatvalue!=null -> left.floatvalue
|
||||
left.strvalue!=null -> left.strvalue
|
||||
left.arrayvalue!=null -> left.arrayvalue
|
||||
else -> throw AstException("missing literal value")
|
||||
else -> throw FatalAstException("missing literal value")
|
||||
}
|
||||
val rightvalue: Any = when {
|
||||
right.intvalue!=null -> right.intvalue
|
||||
right.floatvalue!=null -> right.floatvalue
|
||||
right.strvalue!=null -> right.strvalue
|
||||
right.arrayvalue!=null -> right.arrayvalue
|
||||
else -> throw AstException("missing literal value")
|
||||
else -> throw FatalAstException("missing literal value")
|
||||
}
|
||||
val litval = LiteralValue(intvalue = if (leftvalue == rightvalue) 1 else 0)
|
||||
litval.position = left.position
|
||||
@ -210,16 +255,16 @@ class ConstExprEvaluator {
|
||||
intvalue = if (left.intvalue >= right.intvalue) 1 else 0)
|
||||
right.floatvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.intvalue >= right.floatvalue) 1 else 0)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
left.floatvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.floatvalue >= right.intvalue) 1 else 0)
|
||||
right.floatvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.floatvalue >= right.floatvalue) 1 else 0)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
litval.position = left.position
|
||||
return litval
|
||||
@ -233,16 +278,16 @@ class ConstExprEvaluator {
|
||||
intvalue = if (left.intvalue <= right.intvalue) 1 else 0)
|
||||
right.floatvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.intvalue <= right.floatvalue) 1 else 0)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
left.floatvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.floatvalue <= right.intvalue) 1 else 0)
|
||||
right.floatvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.floatvalue <= right.floatvalue) 1 else 0)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
litval.position = left.position
|
||||
return litval
|
||||
@ -270,16 +315,16 @@ class ConstExprEvaluator {
|
||||
intvalue = if ((left.intvalue != 0).xor(right.intvalue != 0)) 1 else 0)
|
||||
right.floatvalue!=null -> LiteralValue(
|
||||
intvalue = if ((left.intvalue != 0).xor(right.floatvalue != 0.0)) 1 else 0)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
left.floatvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(
|
||||
intvalue = if ((left.floatvalue != 0.0).xor(right.intvalue != 0)) 1 else 0)
|
||||
right.floatvalue!=null -> LiteralValue(
|
||||
intvalue = if ((left.floatvalue != 0.0).xor(right.floatvalue != 0.0)) 1 else 0)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
litval.position = left.position
|
||||
return litval
|
||||
@ -293,16 +338,16 @@ class ConstExprEvaluator {
|
||||
intvalue = if (left.intvalue != 0 || right.intvalue != 0) 1 else 0)
|
||||
right.floatvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.intvalue != 0 || right.floatvalue != 0.0) 1 else 0)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
left.floatvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.floatvalue != 0.0 || right.intvalue != 0) 1 else 0)
|
||||
right.floatvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.floatvalue != 0.0 || right.floatvalue != 0.0) 1 else 0)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
litval.position = left.position
|
||||
return litval
|
||||
@ -316,16 +361,16 @@ class ConstExprEvaluator {
|
||||
intvalue = if (left.intvalue != 0 && right.intvalue != 0) 1 else 0)
|
||||
right.floatvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.intvalue != 0 && right.floatvalue != 0.0) 1 else 0)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
left.floatvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.floatvalue != 0.0 && right.intvalue != 0) 1 else 0)
|
||||
right.floatvalue!=null -> LiteralValue(
|
||||
intvalue = if (left.floatvalue != 0.0 && right.floatvalue != 0.0) 1 else 0)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
litval.position = left.position
|
||||
return litval
|
||||
@ -337,7 +382,7 @@ class ConstExprEvaluator {
|
||||
litval.position = left.position
|
||||
return litval
|
||||
}
|
||||
throw ExpressionException("cannot calculate $left ^ $right")
|
||||
throw ExpressionException("cannot calculate $left ^ $right", left.position)
|
||||
}
|
||||
|
||||
private fun bitwiseor(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||
@ -346,7 +391,7 @@ class ConstExprEvaluator {
|
||||
litval.position = left.position
|
||||
return litval
|
||||
}
|
||||
throw ExpressionException("cannot calculate $left | $right")
|
||||
throw ExpressionException("cannot calculate $left | $right", left.position)
|
||||
}
|
||||
|
||||
private fun bitwiseand(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||
@ -355,15 +400,15 @@ class ConstExprEvaluator {
|
||||
litval.position = left.position
|
||||
return litval
|
||||
}
|
||||
throw ExpressionException("cannot calculate $left & $right")
|
||||
throw ExpressionException("cannot calculate $left & $right", left.position)
|
||||
}
|
||||
|
||||
private fun rotateright(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||
throw ExpressionException("ror not possible on literal values")
|
||||
throw ExpressionException("ror not possible on literal values", left.position)
|
||||
}
|
||||
|
||||
private fun rotateleft(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||
throw ExpressionException("rol not possible on literal values")
|
||||
throw ExpressionException("rol not possible on literal values", left.position)
|
||||
}
|
||||
|
||||
private fun shiftright(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||
@ -372,7 +417,7 @@ class ConstExprEvaluator {
|
||||
litval.position = left.position
|
||||
return litval
|
||||
}
|
||||
throw ExpressionException("cannot calculate $left >> $right")
|
||||
throw ExpressionException("cannot calculate $left >> $right", left.position)
|
||||
}
|
||||
|
||||
private fun shiftleft(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||
@ -381,7 +426,7 @@ class ConstExprEvaluator {
|
||||
litval.position = left.position
|
||||
return litval
|
||||
}
|
||||
throw ExpressionException("cannot calculate $left << $right")
|
||||
throw ExpressionException("cannot calculate $left << $right", left.position)
|
||||
}
|
||||
|
||||
private fun power(left: LiteralValue, right: LiteralValue): LiteralValue {
|
||||
@ -390,14 +435,14 @@ class ConstExprEvaluator {
|
||||
left.intvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(intvalue = left.intvalue.toDouble().pow(right.intvalue).toInt())
|
||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue.toDouble().pow(right.floatvalue))
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
left.floatvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue.pow(right.intvalue))
|
||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue.pow(right.floatvalue))
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
litval.position = left.position
|
||||
return litval
|
||||
@ -409,14 +454,14 @@ class ConstExprEvaluator {
|
||||
left.intvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(intvalue = left.intvalue + right.intvalue)
|
||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue + right.floatvalue)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
left.floatvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue + right.intvalue)
|
||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue + right.floatvalue)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
litval.position = left.position
|
||||
return litval
|
||||
@ -428,14 +473,14 @@ class ConstExprEvaluator {
|
||||
left.intvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(intvalue = left.intvalue - right.intvalue)
|
||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue - right.floatvalue)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
left.floatvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue - right.intvalue)
|
||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue - right.floatvalue)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
litval.position = left.position
|
||||
return litval
|
||||
@ -448,24 +493,24 @@ class ConstExprEvaluator {
|
||||
right.intvalue!=null -> LiteralValue(intvalue = left.intvalue * right.intvalue)
|
||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.intvalue * right.floatvalue)
|
||||
right.strvalue!=null -> {
|
||||
if(right.strvalue.length * left.intvalue > 65535) throw ExpressionException("string too large")
|
||||
if(right.strvalue.length * left.intvalue > 65535) throw ExpressionException("string too large", left.position)
|
||||
LiteralValue(strvalue = right.strvalue.repeat(left.intvalue))
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
left.floatvalue!=null -> when {
|
||||
right.intvalue!=null -> LiteralValue(floatvalue = left.floatvalue * right.intvalue)
|
||||
right.floatvalue!=null -> LiteralValue(floatvalue = left.floatvalue * right.floatvalue)
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
left.strvalue!=null -> when {
|
||||
right.intvalue!=null -> {
|
||||
if(left.strvalue.length * right.intvalue > 65535) throw ExpressionException("string too large")
|
||||
if(left.strvalue.length * right.intvalue > 65535) throw ExpressionException("string too large", left.position)
|
||||
LiteralValue(strvalue = left.strvalue.repeat(right.intvalue))
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
litval.position = left.position
|
||||
return litval
|
||||
@ -476,27 +521,27 @@ class ConstExprEvaluator {
|
||||
val litval = when {
|
||||
left.intvalue!=null -> when {
|
||||
right.intvalue!=null -> {
|
||||
if(right.intvalue==0) throw ExpressionException("attempt to divide by zero")
|
||||
if(right.intvalue==0) throw ExpressionException("attempt to divide by zero", left.position)
|
||||
LiteralValue(intvalue = left.intvalue / right.intvalue)
|
||||
}
|
||||
right.floatvalue!=null -> {
|
||||
if(right.floatvalue==0.0) throw ExpressionException("attempt to divide by zero")
|
||||
if(right.floatvalue==0.0) throw ExpressionException("attempt to divide by zero", left.position)
|
||||
LiteralValue(floatvalue = left.intvalue / right.floatvalue)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
left.floatvalue!=null -> when {
|
||||
right.intvalue!=null -> {
|
||||
if(right.intvalue==0) throw ExpressionException("attempt to divide by zero")
|
||||
if(right.intvalue==0) throw ExpressionException("attempt to divide by zero", left.position)
|
||||
LiteralValue(floatvalue = left.floatvalue / right.intvalue)
|
||||
}
|
||||
right.floatvalue!=null -> {
|
||||
if(right.floatvalue==0.0) throw ExpressionException("attempt to divide by zero")
|
||||
if(right.floatvalue==0.0) throw ExpressionException("attempt to divide by zero", left.position)
|
||||
LiteralValue(floatvalue = left.floatvalue / right.floatvalue)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
else -> throw ExpressionException(error)
|
||||
else -> throw ExpressionException(error, left.position)
|
||||
}
|
||||
litval.position = left.position
|
||||
return litval
|
||||
|
@ -1,7 +1,6 @@
|
||||
package il65.optimizing
|
||||
|
||||
import il65.ast.*
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
fun Module.optimizeStatements(globalNamespace: INameScope) {
|
||||
@ -31,7 +30,6 @@ class StatementOptimizer(private val globalNamespace: INameScope) : IAstProcesso
|
||||
super.process(ifStatement)
|
||||
val constvalue = ifStatement.condition.constValue(globalNamespace)
|
||||
if(constvalue!=null) {
|
||||
val statements: List<IStatement>
|
||||
return if(constvalue.asBoolean()) {
|
||||
// always true -> keep only if-part
|
||||
println("${ifStatement.position} Warning: condition is always true")
|
||||
|
Loading…
Reference in New Issue
Block a user