mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 04:30:03 +00:00
fixed string + string/ string * number
This commit is contained in:
parent
01ac5f29db
commit
9e54e11113
@ -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) {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
53
compiler/src/prog8/ast/processing/LiteralsToAutoVars.kt
Normal file
53
compiler/src/prog8/ast/processing/LiteralsToAutoVars.kt
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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')
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user