mirror of
https://github.com/irmen/prog8.git
synced 2024-12-26 14:29:35 +00:00
simplified string handling a little in LiteralValue
This commit is contained in:
parent
2c69e10489
commit
31137743f0
@ -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!!
|
||||
|
@ -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 -> {
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user