simplified string handling a little in LiteralValue

This commit is contained in:
Irmen de Jong 2019-07-01 14:19:41 +02:00
parent 2c69e10489
commit 31137743f0
8 changed files with 39 additions and 53 deletions

View File

@ -1296,12 +1296,11 @@ open class LiteralValue(val type: DataType,
val bytevalue: Short? = null,
val wordvalue: Int? = null,
val floatvalue: Double? = null,
strvalue: String? = null,
val strvalue: String? = null,
val arrayvalue: Array<IExpression>? = null,
var heapId: Int? =null,
override val position: Position) : IExpression {
override lateinit var parent: Node
private val initialstrvalue = strvalue
override fun referencesIdentifier(name: String) = arrayvalue?.any { it.referencesIdentifier(name) } ?: false
@ -1356,12 +1355,12 @@ open class LiteralValue(val type: DataType,
in WordDatatypes -> if(wordvalue==null) throw FatalAstException("literal value missing wordvalue")
DataType.FLOAT -> if(floatvalue==null) throw FatalAstException("literal value missing floatvalue")
in StringDatatypes ->
if(initialstrvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")
if(strvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")
in ArrayDatatypes ->
if(arrayvalue==null && heapId==null) throw FatalAstException("literal value missing arrayvalue/heapId")
else -> throw FatalAstException("invalid type $type")
}
if(bytevalue==null && wordvalue==null && floatvalue==null && arrayvalue==null && initialstrvalue==null && heapId==null)
if(bytevalue==null && wordvalue==null && floatvalue==null && arrayvalue==null && strvalue==null && heapId==null)
throw FatalAstException("literal value without actual value")
}
@ -1383,7 +1382,7 @@ open class LiteralValue(val type: DataType,
(floatvalue!=null && floatvalue != 0.0) ||
(bytevalue!=null && bytevalue != 0.toShort()) ||
(wordvalue!=null && wordvalue != 0) ||
(initialstrvalue!=null && initialstrvalue.isNotEmpty()) ||
(strvalue!=null && strvalue.isNotEmpty()) ||
(arrayvalue != null && arrayvalue.isNotEmpty())
override fun linkParents(parent: Node) {
@ -1409,14 +1408,8 @@ open class LiteralValue(val type: DataType,
DataType.UWORD -> "uword:$wordvalue"
DataType.WORD -> "word:$wordvalue"
DataType.FLOAT -> "float:$floatvalue"
in StringDatatypes -> {
if(heapId!=null) "str:#$heapId"
else "str:$initialstrvalue"
}
in ArrayDatatypes -> {
if(heapId!=null) "array:#$heapId"
else "array:$arrayvalue"
}
in StringDatatypes -> "str:$strvalue"
in ArrayDatatypes -> "array:$arrayvalue"
else -> throw FatalAstException("weird datatype")
}
return "LiteralValue($vstr)"
@ -1428,7 +1421,7 @@ open class LiteralValue(val type: DataType,
val bh = bytevalue?.hashCode() ?: 0x10001234
val wh = wordvalue?.hashCode() ?: 0x01002345
val fh = floatvalue?.hashCode() ?: 0x00103456
val sh = initialstrvalue?.hashCode() ?: 0x00014567
val sh = strvalue?.hashCode() ?: 0x00014567
val ah = arrayvalue?.hashCode() ?: 0x11119876
var hash = bh * 31 xor wh
hash = hash*31 xor fh
@ -1446,7 +1439,7 @@ open class LiteralValue(val type: DataType,
if(isArray && other.isArray)
return arrayvalue!!.contentEquals(other.arrayvalue!!) && heapId==other.heapId
if(isString && other.isString)
return initialstrvalue==other.initialstrvalue && heapId==other.heapId
return strvalue==other.strvalue && heapId==other.heapId
if(type!=other.type)
return false
@ -1460,8 +1453,8 @@ open class LiteralValue(val type: DataType,
if(numLeft!=null && numRight!=null)
return numLeft.compareTo(numRight)
if(initialstrvalue!=null && other.initialstrvalue!=null)
return initialstrvalue.compareTo(other.initialstrvalue)
if(strvalue!=null && other.strvalue!=null)
return strvalue.compareTo(other.strvalue)
throw ExpressionError("cannot order compare type $type with ${other.type}", other.position)
}
@ -1529,12 +1522,6 @@ open class LiteralValue(val type: DataType,
}
return null // invalid type conversion from $this to $targettype
}
fun strvalue(heap: HeapValues): String {
if(initialstrvalue!=null)
return initialstrvalue
return heap.get(heapId!!).str!!
}
}
@ -1572,15 +1559,15 @@ class RangeExpr(var from: IExpression,
return "RangeExpr(from $from, to $to, step $step, pos=$position)"
}
fun size(heap: HeapValues): Int? {
fun size(): Int? {
val fromLv = (from as? LiteralValue)
val toLv = (to as? LiteralValue)
if(fromLv==null || toLv==null)
return null
return toConstantIntegerRange(heap)?.count()
return toConstantIntegerRange()?.count()
}
fun toConstantIntegerRange(heap: HeapValues): IntProgression? {
fun toConstantIntegerRange(): IntProgression? {
val fromLv = from as? LiteralValue
val toLv = to as? LiteralValue
if(fromLv==null || toLv==null)
@ -1589,8 +1576,8 @@ class RangeExpr(var from: IExpression,
val toVal: Int
if(fromLv.isString && toLv.isString) {
// string range -> int range over petscii values
fromVal = Petscii.encodePetscii(fromLv.strvalue(heap), true)[0].toInt()
toVal = Petscii.encodePetscii(toLv.strvalue(heap), true)[0].toInt()
fromVal = Petscii.encodePetscii(fromLv.strvalue!!, true)[0].toInt()
toVal = Petscii.encodePetscii(toLv.strvalue!!, true)[0].toInt()
} else {
// integer range
fromVal = (from as LiteralValue).asIntegerValue!!

View File

@ -788,8 +788,8 @@ private class AstChecker(private val program: Program,
err("descending range requires step < 0")
}
from.isString && to.isString -> {
val fromString = from.strvalue(program.heap)
val toString = to.strvalue(program.heap)
val fromString = from.strvalue!!
val toString = to.strvalue!!
if(fromString.length!=1 || toString.length!=1)
err("range from and to must be a single character")
if(fromString[0] == toString[0])
@ -977,7 +977,7 @@ private class AstChecker(private val program: Program,
checkResult.add(ExpressionError("range for string must have single characters from and to values", range.position))
return false
}
val rangeSize=range.size(program.heap)
val rangeSize=range.size()
if(rangeSize!=null && (rangeSize<0 || rangeSize>255)) {
checkResult.add(ExpressionError("size of range for string must be 0..255, instead of $rangeSize", range.position))
return false
@ -987,7 +987,7 @@ private class AstChecker(private val program: Program,
in ArrayDatatypes -> {
// range and length check bytes
val expectedSize = arrayspec.size()
val rangeSize=range.size(program.heap)
val rangeSize=range.size()
if(rangeSize!=null && rangeSize != expectedSize) {
checkResult.add(ExpressionError("range size doesn't match array size, expected $expectedSize found $rangeSize", range.position))
return false
@ -1049,8 +1049,7 @@ private class AstChecker(private val program: Program,
DataType.STR, DataType.STR_S -> {
if(!value.isString)
return err("string value expected")
val str = value.strvalue(heap)
if (str.length > 255)
if (value.strvalue!!.length > 255)
return err("string length must be 0-255")
}
DataType.ARRAY_UB, DataType.ARRAY_B -> {

View File

@ -127,7 +127,7 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
}
}
is RangeExpr -> {
val cRange = expr.toConstantIntegerRange(ctx.program.heap)
val cRange = expr.toConstantIntegerRange()
if(cRange!=null)
return RuntimeValueRange(expr.inferType(ctx.program)!!, cRange)
val fromVal = evaluate(expr.from, ctx).integerValue()

View File

@ -1563,7 +1563,7 @@ internal class Compiler(private val program: Program): IAstProcessor {
}
if(loop.iterable is RangeExpr) {
val range = (loop.iterable as RangeExpr).toConstantIntegerRange(program.heap)
val range = (loop.iterable as RangeExpr).toConstantIntegerRange()
if(range!=null) {
// loop over a range with constant start, last and step values
if (range.isEmpty())
@ -1630,7 +1630,7 @@ internal class Compiler(private val program: Program): IAstProcessor {
when(iterableValue.type) {
!in IterableDatatypes -> throw CompilerException("non-iterableValue type")
DataType.STR, DataType.STR_S -> {
numElements = iterableValue.strvalue(program.heap).length
numElements = iterableValue.strvalue!!.length
if(numElements>255) throw CompilerException("string length > 255")
}
DataType.ARRAY_UB, DataType.ARRAY_B,

View File

@ -314,7 +314,7 @@ private fun builtinStrlen(args: List<IExpression>, position: Position, program:
val argument = args[0].constValue(program) ?: throw NotConstArgumentException()
if(argument.type !in StringDatatypes)
throw SyntaxError("strlen must have string argument", position)
val string = argument.strvalue(program.heap)
val string = argument.strvalue!!
val zeroIdx = string.indexOf('\u0000')
return if(zeroIdx>=0)
LiteralValue.optimalInteger(zeroIdx, position=position)
@ -353,7 +353,7 @@ private fun builtinLen(args: List<IExpression>, position: Position, program: Pro
LiteralValue.optimalInteger(arraySize, args[0].position)
}
in StringDatatypes -> {
val str = argument.strvalue(program.heap)
val str = argument.strvalue!!
if(str.length>255)
throw CompilerException("string length exceeds byte limit ${argument.position}")
LiteralValue.optimalInteger(str.length, args[0].position)

View File

@ -10,11 +10,11 @@ val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "=
class ConstExprEvaluator {
fun evaluate(left: LiteralValue, operator: String, right: LiteralValue, heap: HeapValues): IExpression {
fun evaluate(left: LiteralValue, operator: String, right: LiteralValue): IExpression {
return when(operator) {
"+" -> plus(left, right, heap)
"+" -> plus(left, right)
"-" -> minus(left, right)
"*" -> multiply(left, right, heap)
"*" -> multiply(left, right)
"/" -> divide(left, right)
"%" -> remainder(left, right)
"**" -> power(left, right)
@ -161,7 +161,7 @@ class ConstExprEvaluator {
}
}
private fun plus(left: LiteralValue, right: LiteralValue, heap: HeapValues): LiteralValue {
private fun plus(left: LiteralValue, right: LiteralValue): LiteralValue {
val error = "cannot add $left and $right"
return when {
left.asIntegerValue!=null -> when {
@ -176,7 +176,7 @@ class ConstExprEvaluator {
}
left.isString -> when {
right.isString -> {
val newStr = left.strvalue(heap) + right.strvalue(heap)
val newStr = left.strvalue!! + right.strvalue!!
if(newStr.length > 255) throw ExpressionError("string too long", left.position)
LiteralValue(DataType.STR, strvalue = newStr, position = left.position)
}
@ -203,15 +203,15 @@ class ConstExprEvaluator {
}
}
private fun multiply(left: LiteralValue, right: LiteralValue, heap: HeapValues): LiteralValue {
private fun multiply(left: LiteralValue, right: LiteralValue): LiteralValue {
val error = "cannot multiply ${left.type} and ${right.type}"
return when {
left.asIntegerValue!=null -> when {
right.asIntegerValue!=null -> LiteralValue.optimalNumeric(left.asIntegerValue * right.asIntegerValue, left.position)
right.floatvalue!=null -> LiteralValue(DataType.FLOAT, floatvalue = left.asIntegerValue * right.floatvalue, position = left.position)
right.isString -> {
if(right.strvalue(heap).length * left.asIntegerValue > 255) throw ExpressionError("string too long", left.position)
LiteralValue(DataType.STR, strvalue = right.strvalue(heap).repeat(left.asIntegerValue), position = left.position)
if(right.strvalue!!.length * left.asIntegerValue > 255) throw ExpressionError("string too long", left.position)
LiteralValue(DataType.STR, strvalue = right.strvalue.repeat(left.asIntegerValue), position = left.position)
}
else -> throw ExpressionError(error, left.position)
}

View File

@ -68,9 +68,9 @@ class ConstantFolding(private val program: Program) : IAstProcessor {
if(rangeExpr!=null) {
// convert the initializer range expression to an actual array (will be put on heap later)
val declArraySize = decl.arraysize?.size()
if(declArraySize!=null && declArraySize!=rangeExpr.size(program.heap))
if(declArraySize!=null && declArraySize!=rangeExpr.size())
errors.add(ExpressionError("range expression size doesn't match declared array size", decl.value?.position!!))
val constRange = rangeExpr.toConstantIntegerRange(program.heap)
val constRange = rangeExpr.toConstantIntegerRange()
if(constRange!=null) {
val eltType = rangeExpr.inferType(program)!!
if(eltType in ByteDatatypes) {
@ -335,7 +335,7 @@ class ConstantFolding(private val program: Program) : IAstProcessor {
return when {
leftconst != null && rightconst != null -> {
optimizationsDone++
evaluator.evaluate(leftconst, expr.operator, rightconst, program.heap)
evaluator.evaluate(leftconst, expr.operator, rightconst)
}
else -> expr
}
@ -595,10 +595,10 @@ class ConstantFolding(private val program: Program) : IAstProcessor {
val litval = super.process(literalValue)
if(litval.isString) {
// intern the string; move it into the heap
if(litval.strvalue(program.heap).length !in 1..255)
if(litval.strvalue!!.length !in 1..255)
addError(ExpressionError("string literal length must be between 1 and 255", litval.position))
else {
litval.heapId = program.heap.addString(litval.type, litval.strvalue(program.heap)) // TODO: we don't know the actual string type yet, STR != STR_S etc...
litval.heapId = program.heap.addString(litval.type, litval.strvalue) // TODO: we don't know the actual string type yet, STR != STR_S etc...
}
} else if(litval.arrayvalue!=null) {
// first, adjust the array datatype

View File

@ -325,7 +325,7 @@ internal class StatementOptimizer(private val program: Program, private val opti
val range = forLoop.iterable as? RangeExpr
if(range!=null) {
if(range.size(program.heap)==1) {
if(range.size()==1) {
// for loop over a (constant) range of just a single value-- optimize the loop away
// loopvar/reg = range value , follow by block
val assignment = Assignment(listOf(AssignTarget(forLoop.loopRegister, forLoop.loopVar, null, null, forLoop.position)), null, range.from, forLoop.position)