fixed string + string/ string * number

This commit is contained in:
Irmen de Jong 2020-10-11 02:22:09 +02:00
parent 01ac5f29db
commit 9e54e11113
6 changed files with 112 additions and 81 deletions

View File

@ -57,6 +57,9 @@ internal fun Program.checkIdentifiers(errors: ErrorReporter) {
val transforms = AstVariousTransforms(this) val transforms = AstVariousTransforms(this)
transforms.visit(this) transforms.visit(this)
transforms.applyModifications() transforms.applyModifications()
val lit2decl = LiteralsToAutoVars(this)
lit2decl.visit(this)
lit2decl.applyModifications()
} }
if (modules.map { it.name }.toSet().size != modules.size) { if (modules.map { it.name }.toSet().size != modules.size) {

View File

@ -832,10 +832,10 @@ internal class AstChecker(private val program: Program,
} }
} }
if(leftDt !in NumericDatatypes) if(leftDt !in NumericDatatypes && leftDt != DataType.STR)
errors.err("left operand is not numeric", expr.left.position) errors.err("left operand is not numeric or str", expr.left.position)
if(rightDt!in NumericDatatypes) if(rightDt!in NumericDatatypes && rightDt != DataType.STR)
errors.err("right operand is not numeric", expr.right.position) errors.err("right operand is not numeric or str", expr.right.position)
if(leftDt!=rightDt) if(leftDt!=rightDt)
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

@ -47,78 +47,59 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker()
return noModifications return noModifications
} }
override fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> { override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
when { val leftStr = expr.left as? StringLiteralValue
expr.left is StringLiteralValue -> val rightStr = expr.right as? StringLiteralValue
return listOf(IAstModification.ReplaceNode( if(expr.operator == "+") {
expr, val concatenatedString = concatString(expr)
processBinaryExprWithString(expr.left as StringLiteralValue, expr.right, expr), if(concatenatedString!=null)
parent return listOf(IAstModification.ReplaceNode(expr, concatenatedString, parent))
))
expr.right is StringLiteralValue ->
return listOf(IAstModification.ReplaceNode(
expr,
processBinaryExprWithString(expr.right as StringLiteralValue, expr.left, expr),
parent
))
} }
else if(expr.operator == "*") {
return noModifications if (leftStr!=null) {
} val amount = expr.right.constValue(program)
if(amount!=null) {
override fun after(string: StringLiteralValue, parent: Node): Iterable<IAstModification> { val string = leftStr.value.repeat(amount.number.toInt())
if(string.parent !is VarDecl) { val strval = StringLiteralValue(string, leftStr.altEncoding, expr.position)
// replace the literal string by a identifier reference to a new local vardecl return listOf(IAstModification.ReplaceNode(expr, strval, parent))
val vardecl = VarDecl.createAuto(string) }
val identifier = IdentifierReference(listOf(vardecl.name), vardecl.position)
return listOf(
IAstModification.ReplaceNode(string, identifier, parent),
IAstModification.InsertFirst(vardecl, string.definingScope() as Node)
)
}
return noModifications
}
override fun after(array: ArrayLiteralValue, parent: Node): Iterable<IAstModification> {
val vardecl = array.parent as? VarDecl
if(vardecl!=null) {
// adjust the datatype of the array (to an educated guess)
val arrayDt = array.type
if(!arrayDt.istype(vardecl.datatype)) {
val cast = array.cast(vardecl.datatype)
if (cast != null && cast !== array)
return listOf(IAstModification.ReplaceNode(vardecl.value!!, cast, vardecl))
} }
} else { else if (rightStr!=null) {
val arrayDt = array.guessDatatype(program) val amount = expr.right.constValue(program)
if(arrayDt.isKnown) { if(amount!=null) {
// this array literal is part of an expression, turn it into an identifier reference val string = rightStr.value.repeat(amount.number.toInt())
val litval2 = array.cast(arrayDt.typeOrElse(DataType.STRUCT)) val strval = StringLiteralValue(string, rightStr.altEncoding, expr.position)
if(litval2!=null) { return listOf(IAstModification.ReplaceNode(expr, strval, parent))
val vardecl2 = VarDecl.createAuto(litval2)
val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position)
return listOf(
IAstModification.ReplaceNode(array, identifier, parent),
IAstModification.InsertFirst(vardecl2, array.definingScope() as Node)
)
} }
} }
} }
return noModifications return noModifications
} }
private fun processBinaryExprWithString(string: StringLiteralValue, operand: Expression, expr: BinaryExpression): Expression { private fun concatString(expr: BinaryExpression): StringLiteralValue? {
val constvalue = operand.constValue(program) val rightStrval = expr.right as? StringLiteralValue
if(constvalue!=null) { val leftStrval = expr.left as? StringLiteralValue
if (expr.operator == "*") { return when {
// repeat a string a number of times expr.operator!="+" -> null
return StringLiteralValue(string.value.repeat(constvalue.number.toInt()), string.altEncoding, expr.position) expr.left is BinaryExpression && rightStrval!=null -> {
val subStrVal = concatString(expr.left as BinaryExpression)
if(subStrVal==null)
null
else
StringLiteralValue("${subStrVal.value}${rightStrval.value}", subStrVal.altEncoding, rightStrval.position)
} }
expr.right is BinaryExpression && leftStrval!=null -> {
val subStrVal = concatString(expr.right as BinaryExpression)
if(subStrVal==null)
null
else
StringLiteralValue("${leftStrval.value}${subStrVal.value}", subStrVal.altEncoding, leftStrval.position)
}
leftStrval!=null && rightStrval!=null -> {
StringLiteralValue("${leftStrval.value}${rightStrval.value}", leftStrval.altEncoding, leftStrval.position)
}
else -> null
} }
if(expr.operator == "+" && operand is StringLiteralValue) {
// concatenate two strings
return StringLiteralValue("${string.value}${operand.value}", string.altEncoding, expr.position)
}
return expr
} }
} }

View File

@ -0,0 +1,53 @@
package prog8.ast.processing
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
internal class LiteralsToAutoVars(private val program: Program) : AstWalker() {
private val noModifications = emptyList<IAstModification>()
override fun after(string: StringLiteralValue, parent: Node): Iterable<IAstModification> {
if(string.parent !is VarDecl) {
// replace the literal string by a identifier reference to a new local vardecl
val vardecl = VarDecl.createAuto(string)
val identifier = IdentifierReference(listOf(vardecl.name), vardecl.position)
return listOf(
IAstModification.ReplaceNode(string, identifier, parent),
IAstModification.InsertFirst(vardecl, string.definingScope() as Node)
)
}
return noModifications
}
override fun after(array: ArrayLiteralValue, parent: Node): Iterable<IAstModification> {
val vardecl = array.parent as? VarDecl
if(vardecl!=null) {
// adjust the datatype of the array (to an educated guess)
val arrayDt = array.type
if(!arrayDt.istype(vardecl.datatype)) {
val cast = array.cast(vardecl.datatype)
if (cast != null && cast !== array)
return listOf(IAstModification.ReplaceNode(vardecl.value!!, cast, vardecl))
}
} else {
val arrayDt = array.guessDatatype(program)
if(arrayDt.isKnown) {
// this array literal is part of an expression, turn it into an identifier reference
val litval2 = array.cast(arrayDt.typeOrElse(DataType.STRUCT))
if(litval2!=null) {
val vardecl2 = VarDecl.createAuto(litval2)
val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position)
return listOf(
IAstModification.ReplaceNode(array, identifier, parent),
IAstModification.InsertFirst(vardecl2, array.definingScope() as Node)
)
}
}
}
return noModifications
}
}

View File

@ -7,11 +7,10 @@ main {
sub start() { sub start() {
; TODO fix multi- string concatenation: txt.print("\nCommands are:\n"+
; txt.print("\nCommands are:\n"+ "buy jump inf cash\n" +
; "buy jump inf cash\n" + "sell teleport market hold\n" +
; "sell teleport market hold\n" + "fuel galhyp local quit\n")
; "fuel galhyp local quit\n")
; str name = "irmen de jong" ; str name = "irmen de jong"
; uword strptr = &name ; uword strptr = &name
@ -28,14 +27,6 @@ main {
; txt.print_ub(strlen(strptr)) ; txt.print_ub(strlen(strptr))
; txt.chrout('\n') ; txt.chrout('\n')
ubyte q
for q in 0 to 255 {
txt.print_ub(q)
txt.chrout(' ')
txt.print_uw(q*5) ; TODO fix
txt.chrout('\n')
}
} }

View File

@ -31,7 +31,10 @@ main {
if num_chars { if num_chars {
when input[0] { when input[0] {
'?' -> { '?' -> {
txt.print("\nCommands are:\nbuy jump info cash\nsell teleport market hold\nfuel galhyp local quit\n") txt.print("\nCommands are:\n"+
"buy jump info cash\n"+
"sell teleport market hold\n"+
"fuel galhyp local quit\n")
} }
'q' -> break 'q' -> break
'b' -> trader.do_buy() 'b' -> trader.do_buy()