string literal concatenation and repeating added again

This commit is contained in:
Irmen de Jong 2019-07-16 23:34:43 +02:00
parent c0e83ef8df
commit 07d8caf884
6 changed files with 75 additions and 46 deletions

View File

@ -169,7 +169,7 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
DataType.UWORD -> Pair(DataType.UWORD, left)
DataType.WORD -> Pair(DataType.WORD, left)
DataType.FLOAT -> Pair(DataType.FLOAT, left)
else -> throw FatalAstException("non-numeric datatype $rightDt")
else -> Pair(leftDt, null) // non-numeric datatype
}
}
DataType.BYTE -> {
@ -179,7 +179,7 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
DataType.UWORD -> Pair(DataType.WORD, left)
DataType.WORD -> Pair(DataType.WORD, left)
DataType.FLOAT -> Pair(DataType.FLOAT, left)
else -> throw FatalAstException("non-numeric datatype $rightDt")
else -> Pair(leftDt, null) // non-numeric datatype
}
}
DataType.UWORD -> {
@ -189,7 +189,7 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
DataType.UWORD -> Pair(DataType.UWORD, null)
DataType.WORD -> Pair(DataType.WORD, left)
DataType.FLOAT -> Pair(DataType.FLOAT, left)
else -> throw FatalAstException("non-numeric datatype $rightDt")
else -> Pair(leftDt, null) // non-numeric datatype
}
}
DataType.WORD -> {
@ -199,13 +199,13 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
DataType.UWORD -> Pair(DataType.WORD, right)
DataType.WORD -> Pair(DataType.WORD, null)
DataType.FLOAT -> Pair(DataType.FLOAT, left)
else -> throw FatalAstException("non-numeric datatype $rightDt")
else -> Pair(leftDt, null) // non-numeric datatype
}
}
DataType.FLOAT -> {
Pair(DataType.FLOAT, right)
}
else -> throw FatalAstException("non-numeric datatype $leftDt")
else -> Pair(leftDt, null) // non-numeric datatype
}
}
}
@ -700,7 +700,12 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
fun heapId(namespace: INameScope): Int {
val node = namespace.lookup(nameInSource, this) ?: throw UndefinedSymbolError(this)
return ((node as? VarDecl)?.value as? ReferenceLiteralValue)?.heapId ?: throw FatalAstException("identifier is not on the heap: $this")
val value = (node as? VarDecl)?.value ?: throw FatalAstException("requires a reference value")
return when (value) {
is IdentifierReference -> value.heapId(namespace)
is ReferenceLiteralValue -> value.heapId ?: throw FatalAstException("refLv is not on the heap: $value")
else -> throw FatalAstException("requires a reference value")
}
}
}

View File

@ -222,19 +222,23 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
override fun visit(refLiteral: ReferenceLiteralValue): IExpression {
if(refLiteral.parent !is VarDecl) {
return makeIdentifierFromRefLv(refLiteral)
}
return super.visit(refLiteral)
}
private fun makeIdentifierFromRefLv(refLiteral: ReferenceLiteralValue): IdentifierReference {
// a referencetype literal value that's not declared as a variable
// we need to introduce an auto-generated variable for this to be able to refer to the value
refLiteral.addToHeap(program.heap)
val variable = VarDecl.createAuto(refLiteral, program.heap)
addVarDecl(refLiteral.definingScope(), variable)
// replace the reference literal by a identfier reference
// replace the reference literal by a identifier reference
val identifier = IdentifierReference(listOf(variable.name), variable.position)
identifier.parent = refLiteral.parent
// TODO anonymousVariablesFromHeap[variable.name] = Pair(refLiteral, variable)
return identifier
}
return super.visit(refLiteral)
}
override fun visit(addressOf: AddressOf): IExpression {
// register the scoped name of the referenced identifier
@ -253,6 +257,38 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
return super.visit(structDecl)
}
override fun visit(expr: BinaryExpression): IExpression {
return when {
expr.left is ReferenceLiteralValue ->
processBinaryExprWithReferenceVal(expr.left as ReferenceLiteralValue, expr.right, expr)
expr.right is ReferenceLiteralValue ->
processBinaryExprWithReferenceVal(expr.right as ReferenceLiteralValue, expr.left, expr)
else -> super.visit(expr)
}
}
private fun processBinaryExprWithReferenceVal(refLv: ReferenceLiteralValue, operand: IExpression, expr: BinaryExpression): IExpression {
// expressions on strings or arrays
if(refLv.isString) {
val constvalue = operand.constValue(program)
if(constvalue!=null) {
if (expr.operator == "*") {
// repeat a string a number of times
return ReferenceLiteralValue(refLv.inferType(program),
refLv.str!!.repeat(constvalue.number.toInt()), null, null, expr.position)
}
}
if(expr.operator == "+" && operand is ReferenceLiteralValue) {
if (operand.isString) {
// concatenate two strings
return ReferenceLiteralValue(refLv.inferType(program),
"${refLv.str}${operand.str}", null, null, expr.position)
}
}
}
return expr
}
private fun addVarDecl(scope: INameScope, variable: VarDecl) {
if(scope !in vardeclsToAdd)
vardeclsToAdd[scope] = mutableListOf()

View File

@ -172,15 +172,6 @@ class ConstExprEvaluator {
right.type == DataType.FLOAT -> NumericLiteralValue(DataType.FLOAT, left.number.toDouble() + right.number.toDouble(), left.position)
else -> throw ExpressionError(error, left.position)
}
// TODO: string concatenation
// left.isString -> when {
// right.isString -> {
// val newStr = left.strvalue!! + right.strvalue!!
// if(newStr.length > 255) throw ExpressionError("string too long", left.position)
// NumericLiteralValue(DataType.STR, strvalue = newStr, left.position)
// }
// else -> throw ExpressionError(error, left.position)
// }
else -> throw ExpressionError(error, left.position)
}
}
@ -208,11 +199,6 @@ class ConstExprEvaluator {
left.type in IntegerDatatypes -> when {
right.type in IntegerDatatypes -> NumericLiteralValue.optimalNumeric(left.number.toInt() * right.number.toInt(), left.position)
right.type == DataType.FLOAT -> NumericLiteralValue(DataType.FLOAT, left.number.toInt() * right.number.toDouble(), left.position)
// TODO: string multiplication
// right.isString -> {
// if(right.strvalue!!.length * left.number.toInt() > 255) throw ExpressionError("string too long", left.position)
// NumericLiteralValue(DataType.STR, strvalue = right.strvalue.repeat(left.number.toInt()), left.position)
// }
else -> throw ExpressionError(error, left.position)
}
left.type == DataType.FLOAT -> when {

View File

@ -15,7 +15,6 @@ import kotlin.math.floor
class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
var optimizationsDone: Int = 0
var errors : MutableList<AstException> = mutableListOf()
private val reportedErrorMessages = mutableSetOf<String>()
fun addError(x: AstException) {
@ -318,6 +317,10 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
override fun visit(expr: BinaryExpression): IExpression {
return try {
super.visit(expr)
if(expr.left is ReferenceLiteralValue || expr.right is ReferenceLiteralValue)
TODO("binexpr with reference litval")
val leftconst = expr.left.constValue(program)
val rightconst = expr.right.constValue(program)
@ -338,12 +341,13 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
}
// const fold when both operands are a const
val evaluator = ConstExprEvaluator()
return when {
leftconst != null && rightconst != null -> {
optimizationsDone++
val evaluator = ConstExprEvaluator()
evaluator.evaluate(leftconst, expr.operator, rightconst)
}
else -> expr
}
} catch (ax: AstException) {

View File

@ -267,6 +267,13 @@ Strings in your source code files will be encoded (translated from ASCII/UTF-8)
PETSCII is the default choice. If you need screencodes (also called 'poke' codes) instead,
you have to use the ``str_s`` variants of the string type identifier.
You can concatenate two string literals using '+' (not very useful though) or repeat
a string literal a given number of times using '*'::
str string1 = "first part" + "second part"
str string2 = "hello!" * 10
.. caution::
It's probably best that you don't change strings after they're created.
This is because if your program exits and is restarted (without loading it again),

View File

@ -5,22 +5,13 @@
~ main {
float[5] flarray
byte[5] barray
uword[5] uwarray
sub start() {
c64scr.print_uw(flarray)
c64.CHROUT('=')
c64flt.print_f(flarray[0])
str bla = "asfasd" + "zzz"
str bla2 = "sdfsdf" * 4
c64scr.print(bla)
c64.CHROUT('\n')
c64scr.print_uw(barray)
c64.CHROUT('=')
c64scr.print_b(barray[0])
c64.CHROUT('\n')
c64scr.print_uw(uwarray)
c64.CHROUT('=')
c64scr.print_uw(uwarray[0])
c64scr.print(bla2)
c64.CHROUT('\n')
}