mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
fixed datatype conversions
This commit is contained in:
parent
52e1661c8e
commit
6350bf8024
@ -27,15 +27,15 @@
|
|||||||
yy = flt((pixely-yoffset))/height/3.6+0.4
|
yy = flt((pixely-yoffset))/height/3.6+0.4
|
||||||
|
|
||||||
for pixelx in xoffset to xoffset+width-1 {
|
for pixelx in xoffset to xoffset+width-1 {
|
||||||
xx = flt((pixelx-xoffset))/width/3+0.2
|
xx = flt((pixelx-xoffset))/width/3.0+0.2
|
||||||
|
|
||||||
x = 0.0
|
x = 0.0
|
||||||
y = 0.0
|
y = 0.0
|
||||||
xsquared = 0
|
xsquared = 0
|
||||||
ysquared = 0
|
ysquared = 0
|
||||||
iter = 0
|
iter = 0
|
||||||
while (iter<32 and xsquared+ysquared<4) {
|
while (iter<32 and xsquared+ysquared<4.0) {
|
||||||
y = x*y*2 + yy
|
y = x*y*2.0 + yy
|
||||||
x = xsquared - ysquared + xx
|
x = xsquared - ysquared + xx
|
||||||
xsquared = x*x
|
xsquared = x*x
|
||||||
ysquared = y*y
|
ysquared = y*y
|
||||||
|
@ -25,9 +25,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub screenx(x: float) -> word {
|
sub screenx(x: float) -> word {
|
||||||
return floor(x * width/4.1) + width // 2
|
return floor(x * flt(width)/4.1) + width // 2 ; @todo const-fold x*y/z
|
||||||
}
|
}
|
||||||
sub screeny(y: float) -> word {
|
sub screeny(y: float) -> word {
|
||||||
return floor(y * height/4.1) + height // 2
|
return floor(y * flt(height)/4.1) + height // 2 ; @todo const-fold x*y/z
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,22 +4,18 @@
|
|||||||
|
|
||||||
~ main {
|
~ main {
|
||||||
|
|
||||||
X=0
|
|
||||||
|
|
||||||
word mainvar = 44*Y
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
A=99
|
const byte b1 = 20//7
|
||||||
|
const word w1 = 20//7
|
||||||
|
const float f1 = 20/7
|
||||||
|
|
||||||
byte bvar = 4*X
|
_vm_write_num(b1)
|
||||||
word wvar = 44*XY
|
_vm_write_char('\n')
|
||||||
float fvar = 128.34+XY
|
_vm_write_num(w1)
|
||||||
|
_vm_write_char('\n')
|
||||||
A=100
|
_vm_write_num(f1)
|
||||||
|
_vm_write_char('\n')
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -521,12 +521,43 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
stackvmProg.instr(Opcode.NOP)
|
stackvmProg.instr(Opcode.NOP)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkForFloatPrecisionProblem(left: IExpression, right: IExpression) {
|
private fun commonDatatype(leftDt: DataType, rightDt: DataType, leftpos: Position, rightpos: Position): DataType {
|
||||||
val leftDt = left.resultingDatatype(namespace, heap)
|
// byte + byte -> byte
|
||||||
val rightDt = right.resultingDatatype(namespace, heap)
|
// byte + word -> word
|
||||||
if (leftDt == DataType.BYTE || leftDt == DataType.WORD) {
|
// word + byte -> word
|
||||||
if(rightDt==DataType.FLOAT)
|
// word + word -> word
|
||||||
printWarning("byte or word value implicitly converted to float. Suggestion: use explicit flt() conversion or revert to byte/word arithmetic", left.position)
|
// a combination with a float will be float (but give a warning about this!)
|
||||||
|
|
||||||
|
val floatWarning = "byte or word value implicitly converted to float. Suggestion: use explicit flt() conversion, a float number, or revert to byte/word arithmetic"
|
||||||
|
|
||||||
|
return when(leftDt) {
|
||||||
|
DataType.BYTE -> {
|
||||||
|
when(rightDt) {
|
||||||
|
DataType.BYTE -> DataType.BYTE
|
||||||
|
DataType.WORD -> DataType.WORD
|
||||||
|
DataType.FLOAT -> {
|
||||||
|
printWarning(floatWarning, leftpos)
|
||||||
|
DataType.FLOAT
|
||||||
|
}
|
||||||
|
else -> throw CompilerException("non-numeric datatype $rightDt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataType.WORD -> {
|
||||||
|
when(rightDt) {
|
||||||
|
DataType.BYTE, DataType.WORD -> DataType.WORD
|
||||||
|
DataType.FLOAT -> {
|
||||||
|
printWarning(floatWarning, leftpos)
|
||||||
|
DataType.FLOAT
|
||||||
|
}
|
||||||
|
else -> throw CompilerException("non-numeric datatype $rightDt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataType.FLOAT -> {
|
||||||
|
if(rightDt!=DataType.FLOAT)
|
||||||
|
printWarning(floatWarning, rightpos)
|
||||||
|
DataType.FLOAT
|
||||||
|
}
|
||||||
|
else -> throw CompilerException("non-numeric datatype $leftDt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,10 +572,16 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
translatePrefixOperator(expr.operator, expr.expression.resultingDatatype(namespace, heap))
|
translatePrefixOperator(expr.operator, expr.expression.resultingDatatype(namespace, heap))
|
||||||
}
|
}
|
||||||
is BinaryExpression -> {
|
is BinaryExpression -> {
|
||||||
checkForFloatPrecisionProblem(expr.left, expr.right)
|
val leftDt = expr.left.resultingDatatype(namespace, heap)!!
|
||||||
|
val rightDt = expr.right.resultingDatatype(namespace, heap)!!
|
||||||
|
val commonDt = commonDatatype(leftDt, rightDt, expr.left.position, expr.right.position)
|
||||||
translate(expr.left)
|
translate(expr.left)
|
||||||
|
if(leftDt!=commonDt)
|
||||||
|
convertType(leftDt, commonDt)
|
||||||
translate(expr.right)
|
translate(expr.right)
|
||||||
translateBinaryOperator(expr.operator, expr.left.resultingDatatype(namespace, heap), expr.right.resultingDatatype(namespace, heap))
|
if(rightDt!=commonDt)
|
||||||
|
convertType(rightDt, commonDt)
|
||||||
|
translateBinaryOperator(expr.operator, commonDt)
|
||||||
}
|
}
|
||||||
is FunctionCall -> {
|
is FunctionCall -> {
|
||||||
val target = expr.target.targetStatement(namespace)
|
val target = expr.target.targetStatement(namespace)
|
||||||
@ -586,6 +623,33 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun convertType(givenDt: DataType, targetDt: DataType) {
|
||||||
|
// only WIDENS a type, never NARROWS
|
||||||
|
if(givenDt==targetDt)
|
||||||
|
return
|
||||||
|
if(givenDt!=DataType.BYTE && givenDt!=DataType.WORD && givenDt!=DataType.FLOAT)
|
||||||
|
throw CompilerException("converting a non-numeric $givenDt")
|
||||||
|
if(targetDt!=DataType.BYTE && targetDt!=DataType.WORD && targetDt!=DataType.FLOAT)
|
||||||
|
throw CompilerException("converting to non-numeric $targetDt")
|
||||||
|
when(givenDt) {
|
||||||
|
DataType.BYTE -> when(targetDt) {
|
||||||
|
DataType.WORD -> stackvmProg.instr(Opcode.B2WORD)
|
||||||
|
DataType.FLOAT -> stackvmProg.instr(Opcode.B2FLOAT)
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
DataType.WORD -> when(targetDt) {
|
||||||
|
DataType.BYTE -> throw CompilerException("narrowing type")
|
||||||
|
DataType.FLOAT -> stackvmProg.instr(Opcode.W2FLOAT)
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
DataType.FLOAT -> when(targetDt) {
|
||||||
|
DataType.BYTE, DataType.WORD -> throw CompilerException("narrowing type")
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun translate(identifierRef: IdentifierReference) {
|
private fun translate(identifierRef: IdentifierReference) {
|
||||||
val target = identifierRef.targetStatement(namespace)
|
val target = identifierRef.targetStatement(namespace)
|
||||||
when (target) {
|
when (target) {
|
||||||
@ -720,17 +784,13 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
stackvmProg.instr(Opcode.CALL, callLabel=subroutine.scopedname)
|
stackvmProg.instr(Opcode.CALL, callLabel=subroutine.scopedname)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateBinaryOperator(operator: String, leftDt: DataType?, rightDt: DataType?) {
|
private fun translateBinaryOperator(operator: String, dt: DataType) {
|
||||||
if(leftDt==null || rightDt==null)
|
|
||||||
throw CompilerException("left and/or right operand datatype not known")
|
|
||||||
val validDt = setOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
|
val validDt = setOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
|
||||||
if(leftDt !in validDt || rightDt !in validDt)
|
if(dt !in validDt)
|
||||||
throw CompilerException("invalid datatype(s) for operand(s)")
|
throw CompilerException("invalid datatype for operator: $dt")
|
||||||
if(leftDt!=rightDt)
|
|
||||||
throw CompilerException("operands have different datatypes")
|
|
||||||
val opcode = when(operator) {
|
val opcode = when(operator) {
|
||||||
"+" -> {
|
"+" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.ADD_B
|
DataType.BYTE -> Opcode.ADD_B
|
||||||
DataType.WORD -> Opcode.ADD_W
|
DataType.WORD -> Opcode.ADD_W
|
||||||
DataType.FLOAT -> Opcode.ADD_F
|
DataType.FLOAT -> Opcode.ADD_F
|
||||||
@ -738,7 +798,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"-" -> {
|
"-" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.SUB_B
|
DataType.BYTE -> Opcode.SUB_B
|
||||||
DataType.WORD -> Opcode.SUB_W
|
DataType.WORD -> Opcode.SUB_W
|
||||||
DataType.FLOAT -> Opcode.SUB_F
|
DataType.FLOAT -> Opcode.SUB_F
|
||||||
@ -746,7 +806,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"*" -> {
|
"*" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.MUL_B
|
DataType.BYTE -> Opcode.MUL_B
|
||||||
DataType.WORD -> Opcode.MUL_W
|
DataType.WORD -> Opcode.MUL_W
|
||||||
DataType.FLOAT -> Opcode.MUL_F
|
DataType.FLOAT -> Opcode.MUL_F
|
||||||
@ -754,7 +814,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"/" -> {
|
"/" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.DIV_B
|
DataType.BYTE -> Opcode.DIV_B
|
||||||
DataType.WORD -> Opcode.DIV_W
|
DataType.WORD -> Opcode.DIV_W
|
||||||
DataType.FLOAT -> Opcode.DIV_F
|
DataType.FLOAT -> Opcode.DIV_F
|
||||||
@ -762,7 +822,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"//" -> {
|
"//" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.FLOORDIV_B
|
DataType.BYTE -> Opcode.FLOORDIV_B
|
||||||
DataType.WORD -> Opcode.FLOORDIV_W
|
DataType.WORD -> Opcode.FLOORDIV_W
|
||||||
DataType.FLOAT -> Opcode.FLOORDIV_F
|
DataType.FLOAT -> Opcode.FLOORDIV_F
|
||||||
@ -770,7 +830,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"%" -> {
|
"%" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.REMAINDER_B
|
DataType.BYTE -> Opcode.REMAINDER_B
|
||||||
DataType.WORD -> Opcode.REMAINDER_W
|
DataType.WORD -> Opcode.REMAINDER_W
|
||||||
DataType.FLOAT -> Opcode.REMAINDER_F
|
DataType.FLOAT -> Opcode.REMAINDER_F
|
||||||
@ -778,7 +838,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"**" -> {
|
"**" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.POW_B
|
DataType.BYTE -> Opcode.POW_B
|
||||||
DataType.WORD -> Opcode.POW_W
|
DataType.WORD -> Opcode.POW_W
|
||||||
DataType.FLOAT -> Opcode.POW_F
|
DataType.FLOAT -> Opcode.POW_F
|
||||||
@ -786,49 +846,49 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"&" -> {
|
"&" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.BITAND
|
DataType.BYTE -> Opcode.BITAND
|
||||||
DataType.WORD -> Opcode.BITAND_W
|
DataType.WORD -> Opcode.BITAND_W
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"|" -> {
|
"|" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.BITOR
|
DataType.BYTE -> Opcode.BITOR
|
||||||
DataType.WORD -> Opcode.BITOR_W
|
DataType.WORD -> Opcode.BITOR_W
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"^" -> {
|
"^" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.BITXOR
|
DataType.BYTE -> Opcode.BITXOR
|
||||||
DataType.WORD -> Opcode.BITXOR_W
|
DataType.WORD -> Opcode.BITXOR_W
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"and" -> {
|
"and" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.AND
|
DataType.BYTE -> Opcode.AND
|
||||||
DataType.WORD -> Opcode.AND_W
|
DataType.WORD -> Opcode.AND_W
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"or" -> {
|
"or" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.OR
|
DataType.BYTE -> Opcode.OR
|
||||||
DataType.WORD -> Opcode.OR_W
|
DataType.WORD -> Opcode.OR_W
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"xor" -> {
|
"xor" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.XOR
|
DataType.BYTE -> Opcode.XOR
|
||||||
DataType.WORD -> Opcode.XOR_W
|
DataType.WORD -> Opcode.XOR_W
|
||||||
else -> throw CompilerException("only byte/word possible")
|
else -> throw CompilerException("only byte/word possible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"<" -> {
|
"<" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.LESS
|
DataType.BYTE -> Opcode.LESS
|
||||||
DataType.WORD -> Opcode.LESS_W
|
DataType.WORD -> Opcode.LESS_W
|
||||||
DataType.FLOAT -> Opcode.LESS_F
|
DataType.FLOAT -> Opcode.LESS_F
|
||||||
@ -836,7 +896,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
">" -> {
|
">" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.GREATER
|
DataType.BYTE -> Opcode.GREATER
|
||||||
DataType.WORD -> Opcode.GREATER_W
|
DataType.WORD -> Opcode.GREATER_W
|
||||||
DataType.FLOAT -> Opcode.GREATER_F
|
DataType.FLOAT -> Opcode.GREATER_F
|
||||||
@ -844,7 +904,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"<=" -> {
|
"<=" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.LESSEQ
|
DataType.BYTE -> Opcode.LESSEQ
|
||||||
DataType.WORD -> Opcode.LESSEQ_W
|
DataType.WORD -> Opcode.LESSEQ_W
|
||||||
DataType.FLOAT -> Opcode.LESSEQ_F
|
DataType.FLOAT -> Opcode.LESSEQ_F
|
||||||
@ -852,7 +912,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
">=" -> {
|
">=" -> {
|
||||||
when(leftDt) {
|
when(dt) {
|
||||||
DataType.BYTE -> Opcode.GREATEREQ
|
DataType.BYTE -> Opcode.GREATEREQ
|
||||||
DataType.WORD -> Opcode.GREATEREQ_W
|
DataType.WORD -> Opcode.GREATEREQ_W
|
||||||
DataType.FLOAT -> Opcode.GREATEREQ_F
|
DataType.FLOAT -> Opcode.GREATEREQ_F
|
||||||
@ -860,7 +920,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"==" -> {
|
"==" -> {
|
||||||
when (leftDt) {
|
when (dt) {
|
||||||
DataType.BYTE -> Opcode.EQUAL
|
DataType.BYTE -> Opcode.EQUAL
|
||||||
DataType.WORD -> Opcode.EQUAL_W
|
DataType.WORD -> Opcode.EQUAL_W
|
||||||
DataType.FLOAT -> Opcode.EQUAL_F
|
DataType.FLOAT -> Opcode.EQUAL_F
|
||||||
@ -868,7 +928,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"!=" -> {
|
"!=" -> {
|
||||||
when (leftDt) {
|
when (dt) {
|
||||||
DataType.BYTE -> Opcode.NOTEQUAL
|
DataType.BYTE -> Opcode.NOTEQUAL
|
||||||
DataType.WORD -> Opcode.NOTEQUAL_W
|
DataType.WORD -> Opcode.NOTEQUAL_W
|
||||||
DataType.FLOAT -> Opcode.NOTEQUAL_F
|
DataType.FLOAT -> Opcode.NOTEQUAL_F
|
||||||
|
@ -215,7 +215,8 @@ class ConstExprEvaluator {
|
|||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> {
|
right.asIntegerValue!=null -> {
|
||||||
if(right.asIntegerValue==0) divideByZeroError(right.position)
|
if(right.asIntegerValue==0) divideByZeroError(right.position)
|
||||||
LiteralValue.optimalNumeric(left.asIntegerValue / right.asIntegerValue, left.position)
|
val result = left.asIntegerValue.toDouble() / right.asIntegerValue.toDouble()
|
||||||
|
LiteralValue.optimalNumeric(result, left.position)
|
||||||
}
|
}
|
||||||
right.floatvalue!=null -> {
|
right.floatvalue!=null -> {
|
||||||
if(right.floatvalue==0.0) divideByZeroError(right.position)
|
if(right.floatvalue==0.0) divideByZeroError(right.position)
|
||||||
@ -273,7 +274,7 @@ class ConstExprEvaluator {
|
|||||||
left.asIntegerValue!=null -> when {
|
left.asIntegerValue!=null -> when {
|
||||||
right.asIntegerValue!=null -> {
|
right.asIntegerValue!=null -> {
|
||||||
if(right.asIntegerValue==0) divideByZeroError(right.position)
|
if(right.asIntegerValue==0) divideByZeroError(right.position)
|
||||||
LiteralValue.optimalNumeric(left.asIntegerValue % right.asIntegerValue, left.position)
|
LiteralValue.optimalNumeric(left.asIntegerValue.toDouble() % right.asIntegerValue.toDouble(), left.position)
|
||||||
}
|
}
|
||||||
right.floatvalue!=null -> {
|
right.floatvalue!=null -> {
|
||||||
if(right.floatvalue==0.0) divideByZeroError(right.position)
|
if(right.floatvalue==0.0) divideByZeroError(right.position)
|
||||||
|
@ -14,7 +14,6 @@ import kotlin.math.abs
|
|||||||
X % 1 -> constant 0 (if X is byte/word)
|
X % 1 -> constant 0 (if X is byte/word)
|
||||||
X % 2 -> X and 1 (if X is byte/word)
|
X % 2 -> X and 1 (if X is byte/word)
|
||||||
|
|
||||||
todo expression optimization: remove redundant builtin function calls
|
|
||||||
todo expression optimization: common (sub) expression elimination (turn common expressions into single subroutine call)
|
todo expression optimization: common (sub) expression elimination (turn common expressions into single subroutine call)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user