mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
string literal concatenation and repeating added again
This commit is contained in:
parent
c0e83ef8df
commit
07d8caf884
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,20 +222,24 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
||||
|
||||
override fun visit(refLiteral: ReferenceLiteralValue): IExpression {
|
||||
if(refLiteral.parent !is VarDecl) {
|
||||
// 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
|
||||
val identifier = IdentifierReference(listOf(variable.name), variable.position)
|
||||
identifier.parent = refLiteral.parent
|
||||
// TODO anonymousVariablesFromHeap[variable.name] = Pair(refLiteral, variable)
|
||||
return identifier
|
||||
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 identifier reference
|
||||
val identifier = IdentifierReference(listOf(variable.name), variable.position)
|
||||
identifier.parent = refLiteral.parent
|
||||
// TODO anonymousVariablesFromHeap[variable.name] = Pair(refLiteral, variable)
|
||||
return identifier
|
||||
}
|
||||
|
||||
override fun visit(addressOf: AddressOf): IExpression {
|
||||
// register the scoped name of the referenced identifier
|
||||
val variable= addressOf.identifier.targetVarDecl(program.namespace) ?: return addressOf
|
||||
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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),
|
||||
|
@ -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')
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user