mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +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.UWORD -> Pair(DataType.UWORD, left)
|
||||||
DataType.WORD -> Pair(DataType.WORD, left)
|
DataType.WORD -> Pair(DataType.WORD, left)
|
||||||
DataType.FLOAT -> Pair(DataType.FLOAT, left)
|
DataType.FLOAT -> Pair(DataType.FLOAT, left)
|
||||||
else -> throw FatalAstException("non-numeric datatype $rightDt")
|
else -> Pair(leftDt, null) // non-numeric datatype
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.BYTE -> {
|
DataType.BYTE -> {
|
||||||
@ -179,7 +179,7 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
|
|||||||
DataType.UWORD -> Pair(DataType.WORD, left)
|
DataType.UWORD -> Pair(DataType.WORD, left)
|
||||||
DataType.WORD -> Pair(DataType.WORD, left)
|
DataType.WORD -> Pair(DataType.WORD, left)
|
||||||
DataType.FLOAT -> Pair(DataType.FLOAT, left)
|
DataType.FLOAT -> Pair(DataType.FLOAT, left)
|
||||||
else -> throw FatalAstException("non-numeric datatype $rightDt")
|
else -> Pair(leftDt, null) // non-numeric datatype
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.UWORD -> {
|
DataType.UWORD -> {
|
||||||
@ -189,7 +189,7 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
|
|||||||
DataType.UWORD -> Pair(DataType.UWORD, null)
|
DataType.UWORD -> Pair(DataType.UWORD, null)
|
||||||
DataType.WORD -> Pair(DataType.WORD, left)
|
DataType.WORD -> Pair(DataType.WORD, left)
|
||||||
DataType.FLOAT -> Pair(DataType.FLOAT, left)
|
DataType.FLOAT -> Pair(DataType.FLOAT, left)
|
||||||
else -> throw FatalAstException("non-numeric datatype $rightDt")
|
else -> Pair(leftDt, null) // non-numeric datatype
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.WORD -> {
|
DataType.WORD -> {
|
||||||
@ -199,13 +199,13 @@ class BinaryExpression(var left: IExpression, var operator: String, var right: I
|
|||||||
DataType.UWORD -> Pair(DataType.WORD, right)
|
DataType.UWORD -> Pair(DataType.WORD, right)
|
||||||
DataType.WORD -> Pair(DataType.WORD, null)
|
DataType.WORD -> Pair(DataType.WORD, null)
|
||||||
DataType.FLOAT -> Pair(DataType.FLOAT, left)
|
DataType.FLOAT -> Pair(DataType.FLOAT, left)
|
||||||
else -> throw FatalAstException("non-numeric datatype $rightDt")
|
else -> Pair(leftDt, null) // non-numeric datatype
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.FLOAT -> {
|
DataType.FLOAT -> {
|
||||||
Pair(DataType.FLOAT, right)
|
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 {
|
fun heapId(namespace: INameScope): Int {
|
||||||
val node = namespace.lookup(nameInSource, this) ?: throw UndefinedSymbolError(this)
|
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 {
|
override fun visit(refLiteral: ReferenceLiteralValue): IExpression {
|
||||||
if(refLiteral.parent !is VarDecl) {
|
if(refLiteral.parent !is VarDecl) {
|
||||||
// a referencetype literal value that's not declared as a variable
|
return makeIdentifierFromRefLv(refLiteral)
|
||||||
// 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 super.visit(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 {
|
override fun visit(addressOf: AddressOf): IExpression {
|
||||||
// register the scoped name of the referenced identifier
|
// register the scoped name of the referenced identifier
|
||||||
val variable= addressOf.identifier.targetVarDecl(program.namespace) ?: return addressOf
|
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)
|
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) {
|
private fun addVarDecl(scope: INameScope, variable: VarDecl) {
|
||||||
if(scope !in vardeclsToAdd)
|
if(scope !in vardeclsToAdd)
|
||||||
vardeclsToAdd[scope] = mutableListOf()
|
vardeclsToAdd[scope] = mutableListOf()
|
||||||
|
@ -172,15 +172,6 @@ class ConstExprEvaluator {
|
|||||||
right.type == DataType.FLOAT -> NumericLiteralValue(DataType.FLOAT, left.number.toDouble() + right.number.toDouble(), left.position)
|
right.type == DataType.FLOAT -> NumericLiteralValue(DataType.FLOAT, left.number.toDouble() + right.number.toDouble(), left.position)
|
||||||
else -> throw ExpressionError(error, 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)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,11 +199,6 @@ class ConstExprEvaluator {
|
|||||||
left.type in IntegerDatatypes -> when {
|
left.type in IntegerDatatypes -> when {
|
||||||
right.type in IntegerDatatypes -> NumericLiteralValue.optimalNumeric(left.number.toInt() * right.number.toInt(), left.position)
|
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)
|
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)
|
else -> throw ExpressionError(error, left.position)
|
||||||
}
|
}
|
||||||
left.type == DataType.FLOAT -> when {
|
left.type == DataType.FLOAT -> when {
|
||||||
|
@ -15,7 +15,6 @@ import kotlin.math.floor
|
|||||||
class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
||||||
var optimizationsDone: Int = 0
|
var optimizationsDone: Int = 0
|
||||||
var errors : MutableList<AstException> = mutableListOf()
|
var errors : MutableList<AstException> = mutableListOf()
|
||||||
|
|
||||||
private val reportedErrorMessages = mutableSetOf<String>()
|
private val reportedErrorMessages = mutableSetOf<String>()
|
||||||
|
|
||||||
fun addError(x: AstException) {
|
fun addError(x: AstException) {
|
||||||
@ -318,6 +317,10 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
|||||||
override fun visit(expr: BinaryExpression): IExpression {
|
override fun visit(expr: BinaryExpression): IExpression {
|
||||||
return try {
|
return try {
|
||||||
super.visit(expr)
|
super.visit(expr)
|
||||||
|
|
||||||
|
if(expr.left is ReferenceLiteralValue || expr.right is ReferenceLiteralValue)
|
||||||
|
TODO("binexpr with reference litval")
|
||||||
|
|
||||||
val leftconst = expr.left.constValue(program)
|
val leftconst = expr.left.constValue(program)
|
||||||
val rightconst = expr.right.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
|
// const fold when both operands are a const
|
||||||
val evaluator = ConstExprEvaluator()
|
|
||||||
return when {
|
return when {
|
||||||
leftconst != null && rightconst != null -> {
|
leftconst != null && rightconst != null -> {
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
|
val evaluator = ConstExprEvaluator()
|
||||||
evaluator.evaluate(leftconst, expr.operator, rightconst)
|
evaluator.evaluate(leftconst, expr.operator, rightconst)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> expr
|
else -> expr
|
||||||
}
|
}
|
||||||
} catch (ax: AstException) {
|
} 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,
|
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 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::
|
.. caution::
|
||||||
It's probably best that you don't change strings after they're created.
|
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),
|
This is because if your program exits and is restarted (without loading it again),
|
||||||
|
@ -5,22 +5,13 @@
|
|||||||
|
|
||||||
~ main {
|
~ main {
|
||||||
|
|
||||||
float[5] flarray
|
|
||||||
byte[5] barray
|
|
||||||
uword[5] uwarray
|
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
c64scr.print_uw(flarray)
|
str bla = "asfasd" + "zzz"
|
||||||
c64.CHROUT('=')
|
str bla2 = "sdfsdf" * 4
|
||||||
c64flt.print_f(flarray[0])
|
|
||||||
|
c64scr.print(bla)
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
c64scr.print_uw(barray)
|
c64scr.print(bla2)
|
||||||
c64.CHROUT('=')
|
|
||||||
c64scr.print_b(barray[0])
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
c64scr.print_uw(uwarray)
|
|
||||||
c64.CHROUT('=')
|
|
||||||
c64scr.print_uw(uwarray[0])
|
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user