now correctly accepts "xxx" * constexpr (where constexpr is not just a single const number)

This commit is contained in:
Irmen de Jong 2022-05-05 22:30:52 +02:00
parent 09d3451d9d
commit 348b3036ff
6 changed files with 47 additions and 64 deletions

View File

@ -108,9 +108,32 @@ class ConstantFoldingOptimizer(private val program: Program) : AstWalker() {
* (X + c1) - c2 -> X + (c1-c2) * (X + c1) - c2 -> X + (c1-c2)
*/ */
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> { override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
val modifications = mutableListOf<IAstModification>()
val leftconst = expr.left.constValue(program) val leftconst = expr.left.constValue(program)
val rightconst = expr.right.constValue(program) val rightconst = expr.right.constValue(program)
val modifications = mutableListOf<IAstModification>()
if(expr.left.inferType(program) istype DataType.STR) {
if(expr.operator=="+" && expr.left is StringLiteral && expr.right is StringLiteral) {
// concatenate two strings.
val leftString = expr.left as StringLiteral
val rightString = expr.right as StringLiteral
val concatenated = if(leftString.encoding==rightString.encoding) {
leftString.value + rightString.value
} else {
program.encoding.decodeString(
program.encoding.encodeString(leftString.value, leftString.encoding) + program.encoding.encodeString(rightString.value, rightString.encoding),
leftString.encoding)
}
val concatStr = StringLiteral(concatenated, leftString.encoding, expr.position)
return listOf(IAstModification.ReplaceNode(expr, concatStr, parent))
}
else if(expr.operator=="*" && rightconst!=null && expr.left is StringLiteral) {
// mutiply a string.
val part = expr.left as StringLiteral
val newStr = StringLiteral(part.value.repeat(rightconst.number.toInt()), part.encoding, expr.position)
return listOf(IAstModification.ReplaceNode(expr, newStr, parent))
}
}
if(expr.operator=="==" && rightconst!=null) { if(expr.operator=="==" && rightconst!=null) {
val leftExpr = expr.left as? BinaryExpression val leftExpr = expr.left as? BinaryExpression

View File

@ -649,6 +649,9 @@ internal class AstChecker(private val program: Program,
if(parameter==null) if(parameter==null)
err("string var must be initialized with a string literal") err("string var must be initialized with a string literal")
} }
if(decl.value !is StringLiteral)
err("string var must be initialized with a string literal")
} }
if(compilerOptions.zeropage==ZeropageType.DONTUSE && decl.zeropage == ZeropageWish.REQUIRE_ZEROPAGE) if(compilerOptions.zeropage==ZeropageType.DONTUSE && decl.zeropage == ZeropageWish.REQUIRE_ZEROPAGE)
@ -886,7 +889,7 @@ internal class AstChecker(private val program: Program,
if(leftDt!=rightDt) { if(leftDt!=rightDt) {
if(leftDt==DataType.STR && rightDt in IntegerDatatypes) { if(leftDt==DataType.STR && rightDt in IntegerDatatypes) {
// only exception allowed: str * constvalue // only exception allowed: str * constvalue
if(expr.right.constValue(program)!=null) if(expr.right.constValue(program)==null)
errors.err("can only use string repeat with a constant number value", expr.left.position) errors.err("can only use string repeat with a constant number value", expr.left.position)
} else { } else {
errors.err("left and right operands aren't the same type", expr.left.position) errors.err("left and right operands aren't the same type", expr.left.position)

View File

@ -5,7 +5,6 @@ import prog8.ast.Program
import prog8.ast.expressions.ArrayIndexedExpression import prog8.ast.expressions.ArrayIndexedExpression
import prog8.ast.expressions.BinaryExpression import prog8.ast.expressions.BinaryExpression
import prog8.ast.expressions.DirectMemoryRead import prog8.ast.expressions.DirectMemoryRead
import prog8.ast.expressions.StringLiteral
import prog8.ast.statements.AssignTarget import prog8.ast.statements.AssignTarget
import prog8.ast.statements.DirectMemoryWrite import prog8.ast.statements.DirectMemoryWrite
import prog8.ast.statements.Subroutine import prog8.ast.statements.Subroutine
@ -39,65 +38,9 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker()
return noModifications return noModifications
} }
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
val leftStr = expr.left as? StringLiteral
val rightStr = expr.right as? StringLiteral
if(expr.operator == "+") {
val concatenatedString = concatString(expr)
if(concatenatedString!=null)
return listOf(IAstModification.ReplaceNode(expr, concatenatedString, parent))
}
else if(expr.operator == "*") {
if (leftStr!=null) {
val amount = expr.right.constValue(program)
if(amount!=null) {
val string = leftStr.value.repeat(amount.number.toInt())
val strval = StringLiteral(string, leftStr.encoding, expr.position)
return listOf(IAstModification.ReplaceNode(expr, strval, parent))
}
}
else if (rightStr!=null) {
val amount = expr.right.constValue(program)
if(amount!=null) {
val string = rightStr.value.repeat(amount.number.toInt())
val strval = StringLiteral(string, rightStr.encoding, expr.position)
return listOf(IAstModification.ReplaceNode(expr, strval, parent))
}
}
}
return noModifications
}
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> { override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
return replacePointerVarIndexWithMemreadOrMemwrite(program, arrayIndexedExpression, parent) return replacePointerVarIndexWithMemreadOrMemwrite(program, arrayIndexedExpression, parent)
} }
private fun concatString(expr: BinaryExpression): StringLiteral? {
val rightStrval = expr.right as? StringLiteral
val leftStrval = expr.left as? StringLiteral
return when {
expr.operator!="+" -> null
expr.left is BinaryExpression && rightStrval!=null -> {
val subStrVal = concatString(expr.left as BinaryExpression)
if(subStrVal==null)
null
else
StringLiteral("${subStrVal.value}${rightStrval.value}", subStrVal.encoding, rightStrval.position)
}
expr.right is BinaryExpression && leftStrval!=null -> {
val subStrVal = concatString(expr.right as BinaryExpression)
if(subStrVal==null)
null
else
StringLiteral("${leftStrval.value}${subStrVal.value}", subStrVal.encoding, leftStrval.position)
}
leftStrval!=null && rightStrval!=null -> {
StringLiteral("${leftStrval.value}${rightStrval.value}", leftStrval.encoding, leftStrval.position)
}
else -> null
}
}
} }

View File

@ -4,6 +4,7 @@ import prog8.ast.IFunctionCall
import prog8.ast.Node import prog8.ast.Node
import prog8.ast.Program import prog8.ast.Program
import prog8.ast.expressions.ArrayLiteral import prog8.ast.expressions.ArrayLiteral
import prog8.ast.expressions.BinaryExpression
import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.StringLiteral import prog8.ast.expressions.StringLiteral
import prog8.ast.statements.VarDecl import prog8.ast.statements.VarDecl
@ -26,7 +27,7 @@ internal class LiteralsToAutoVars(private val program: Program,
errors.err("compilation target doesn't support this text encoding", string.position) errors.err("compilation target doesn't support this text encoding", string.position)
return noModifications return noModifications
} }
if(string.parent !is VarDecl && string.parent !is WhenChoice) { if(string.parent !is VarDecl && string.parent !is WhenChoice && string.parent !is BinaryExpression) {
// replace the literal string by an identifier reference to the interned string // replace the literal string by an identifier reference to the interned string
val parentFunc = (string.parent as? IFunctionCall)?.target val parentFunc = (string.parent as? IFunctionCall)?.target
if(parentFunc!=null) { if(parentFunc!=null) {

View File

@ -4,7 +4,6 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls. - pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls.
- allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type
- make it possible to inline non-asmsub routines that just contain a single statement (return, functioncall, assignment) - make it possible to inline non-asmsub routines that just contain a single statement (return, functioncall, assignment)
but this requires all identifiers in the inlined expression to be changed to fully scoped names. but this requires all identifiers in the inlined expression to be changed to fully scoped names.
If we can do that why not perhaps also able to inline multi-line subroutines? Why would it be limited to just 1 line? Maybe to protect against code size bloat. If we can do that why not perhaps also able to inline multi-line subroutines? Why would it be limited to just 1 line? Maybe to protect against code size bloat.

View File

@ -7,9 +7,23 @@
main { main {
sub start() { sub start() {
ubyte xx=10 const ubyte times=3
xx = xx>9 ; expected output: aaabbb aaa bbb
txt.print_ub(xx) txt.print("aaa"+"bbb"+"ccc")
txt.nl()
; txt.print("aaa")
; txt.nl()
; txt.print("bbb")
; txt.nl()
; expected output: xxx xxxxxx xxxxxxxxx xxx
; txt.print("xxx"*(times-2))
; txt.nl()
; txt.print("xxx"*(times-1))
; txt.nl()
txt.print("xxx"*times)
txt.nl()
; txt.print("xxx")
; txt.nl()
sys.exit(42) sys.exit(42)
; floats.print_f(-42.42) ; floats.print_f(-42.42)
; float f1 = 1.2345 ; float f1 = 1.2345