mirror of
https://github.com/irmen/prog8.git
synced 2024-09-09 02:54:28 +00:00
uword == str is now possible (sugar for string.compare)
This commit is contained in:
parent
a587482edf
commit
04e4e71f2e
@ -473,7 +473,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null)
|
addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null)
|
||||||
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
|
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
|
||||||
} else {
|
} else {
|
||||||
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) {
|
||||||
throw AssemblyError("str compares should have been replaced with builtin function call to do the compare")
|
throw AssemblyError("str compares should have been replaced with builtin function call to do the compare")
|
||||||
} else {
|
} else {
|
||||||
val leftTr = translateExpression(binExpr.left)
|
val leftTr = translateExpression(binExpr.left)
|
||||||
@ -515,7 +515,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null)
|
addInstr(result, IRInstruction(ins, IRDataType.BYTE, reg1 = resultRegister, reg2 = zeroRegister), null)
|
||||||
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
|
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
|
||||||
} else {
|
} else {
|
||||||
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) {
|
||||||
throw AssemblyError("str compares should have been replaced with builtin function call to do the compare")
|
throw AssemblyError("str compares should have been replaced with builtin function call to do the compare")
|
||||||
} else {
|
} else {
|
||||||
val leftTr = translateExpression(binExpr.left)
|
val leftTr = translateExpression(binExpr.left)
|
||||||
@ -554,7 +554,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
|
|||||||
result += IRCodeChunk(label, null)
|
result += IRCodeChunk(label, null)
|
||||||
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
|
return ExpressionCodeResult(result, IRDataType.BYTE, resultRegister, -1)
|
||||||
} else {
|
} else {
|
||||||
if(binExpr.left.type==DataType.STR && binExpr.right.type==DataType.STR) {
|
if(binExpr.left.type==DataType.STR || binExpr.right.type==DataType.STR) {
|
||||||
throw AssemblyError("str compares should have been replaced with builtin function call to do the compare")
|
throw AssemblyError("str compares should have been replaced with builtin function call to do the compare")
|
||||||
} else {
|
} else {
|
||||||
return if(constValue(binExpr.right)==0.0) {
|
return if(constValue(binExpr.right)==0.0) {
|
||||||
|
@ -966,6 +966,8 @@ internal class AstChecker(private val program: Program,
|
|||||||
// expression with one side BOOL other side (U)BYTE is allowed; bool==byte
|
// expression with one side BOOL other side (U)BYTE is allowed; bool==byte
|
||||||
} else if((expr.operator == "<<" || expr.operator == ">>") && (leftDt in WordDatatypes && rightDt in ByteDatatypes)) {
|
} else if((expr.operator == "<<" || expr.operator == ">>") && (leftDt in WordDatatypes && rightDt in ByteDatatypes)) {
|
||||||
// exception allowed: shifting a word by a byte
|
// exception allowed: shifting a word by a byte
|
||||||
|
} else if((leftDt==DataType.UWORD && rightDt==DataType.STR) || (leftDt==DataType.STR && rightDt==DataType.UWORD)) {
|
||||||
|
// exception allowed: comparing uword (pointer) with string
|
||||||
} 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)
|
||||||
}
|
}
|
||||||
|
@ -36,19 +36,6 @@ internal class BeforeAsmAstChanger(val program: Program,
|
|||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
|
||||||
if(expr.operator in ComparisonOperators && expr.left.inferType(program) istype DataType.STR && expr.right.inferType(program) istype DataType.STR) {
|
|
||||||
// replace string comparison expressions with calls to string.compare()
|
|
||||||
val stringCompare = BuiltinFunctionCall(
|
|
||||||
IdentifierReference(listOf("prog8_lib_stringcompare"), expr.position),
|
|
||||||
mutableListOf(expr.left.copy(), expr.right.copy()), expr.position)
|
|
||||||
val zero = NumericLiteral.optimalInteger(0, expr.position)
|
|
||||||
val comparison = BinaryExpression(stringCompare, expr.operator, zero, expr.position)
|
|
||||||
return listOf(IAstModification.ReplaceNode(expr, comparison, parent))
|
|
||||||
}
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||||
if (decl.type == VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes)
|
if (decl.type == VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes)
|
||||||
throw InternalCompilerException("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl")
|
throw InternalCompilerException("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl")
|
||||||
|
@ -5,6 +5,7 @@ import prog8.ast.expressions.*
|
|||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.ast.walk.AstWalker
|
import prog8.ast.walk.AstWalker
|
||||||
import prog8.ast.walk.IAstModification
|
import prog8.ast.walk.IAstModification
|
||||||
|
import prog8.code.core.ComparisonOperators
|
||||||
import prog8.code.core.DataType
|
import prog8.code.core.DataType
|
||||||
import prog8.code.core.IErrorReporter
|
import prog8.code.core.IErrorReporter
|
||||||
import prog8.code.core.Position
|
import prog8.code.core.Position
|
||||||
@ -173,10 +174,32 @@ _after:
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
|
||||||
|
fun isStringComparison(leftDt: InferredTypes.InferredType, rightDt: InferredTypes.InferredType): Boolean =
|
||||||
|
if(leftDt istype DataType.STR && rightDt istype DataType.STR)
|
||||||
|
true
|
||||||
|
else
|
||||||
|
leftDt istype DataType.UWORD && rightDt istype DataType.STR || leftDt istype DataType.STR && rightDt istype DataType.UWORD
|
||||||
|
|
||||||
if(expr.operator=="in") {
|
if(expr.operator=="in") {
|
||||||
val containment = ContainmentCheck(expr.left, expr.right, expr.position)
|
val containment = ContainmentCheck(expr.left, expr.right, expr.position)
|
||||||
return listOf(IAstModification.ReplaceNode(expr, containment, parent))
|
return listOf(IAstModification.ReplaceNode(expr, containment, parent))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(expr.operator in ComparisonOperators) {
|
||||||
|
val leftDt = expr.left.inferType(program)
|
||||||
|
val rightDt = expr.right.inferType(program)
|
||||||
|
|
||||||
|
if(isStringComparison(leftDt, rightDt)) {
|
||||||
|
// replace string comparison expressions with calls to string.compare()
|
||||||
|
val stringCompare = BuiltinFunctionCall(
|
||||||
|
IdentifierReference(listOf("prog8_lib_stringcompare"), expr.position),
|
||||||
|
mutableListOf(expr.left.copy(), expr.right.copy()), expr.position)
|
||||||
|
val zero = NumericLiteral.optimalInteger(0, expr.position)
|
||||||
|
val comparison = BinaryExpression(stringCompare, expr.operator, zero, expr.position)
|
||||||
|
return listOf(IAstModification.ReplaceNode(expr, comparison, parent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import prog8.ast.statements.VarDecl
|
|||||||
import prog8.code.core.DataType
|
import prog8.code.core.DataType
|
||||||
import prog8.code.core.Position
|
import prog8.code.core.Position
|
||||||
import prog8.code.target.C64Target
|
import prog8.code.target.C64Target
|
||||||
|
import prog8.code.target.VMTarget
|
||||||
import prog8tests.helpers.ErrorReporterForTests
|
import prog8tests.helpers.ErrorReporterForTests
|
||||||
import prog8tests.helpers.compileText
|
import prog8tests.helpers.compileText
|
||||||
|
|
||||||
@ -70,25 +71,42 @@ main {
|
|||||||
compileText(C64Target(), false, text, writeAssembly = false) shouldBe null
|
compileText(C64Target(), false, text, writeAssembly = false) shouldBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
test("simple string comparison still works") {
|
test("string comparisons") {
|
||||||
val src="""
|
val src="""
|
||||||
main {
|
main {
|
||||||
sub start() {
|
|
||||||
ubyte @shared value
|
sub start() {
|
||||||
str thing = "????"
|
str name = "name"
|
||||||
|
uword nameptr = &name
|
||||||
if thing=="name" {
|
|
||||||
value++
|
cx16.r0L= name=="foo"
|
||||||
}
|
cx16.r1L= name!="foo"
|
||||||
|
cx16.r2L= name<"foo"
|
||||||
if thing!="name" {
|
cx16.r3L= name>"foo"
|
||||||
value++
|
|
||||||
}
|
cx16.r0L= nameptr=="foo"
|
||||||
}
|
cx16.r1L= nameptr!="foo"
|
||||||
}"""
|
cx16.r2L= nameptr<"foo"
|
||||||
|
cx16.r3L= nameptr>"foo"
|
||||||
|
|
||||||
|
void compare(name, "foo")
|
||||||
|
void compare(name, "name")
|
||||||
|
void compare(nameptr, "foo")
|
||||||
|
void compare(nameptr, "name")
|
||||||
|
}
|
||||||
|
|
||||||
|
sub compare(str s1, str s2) -> ubyte {
|
||||||
|
if s1==s2
|
||||||
|
return 42
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}"""
|
||||||
val result = compileText(C64Target(), optimize=false, src, writeAssembly=true)!!
|
val result = compileText(C64Target(), optimize=false, src, writeAssembly=true)!!
|
||||||
val stmts = result.compilerAst.entrypoint.statements
|
val stmts = result.compilerAst.entrypoint.statements
|
||||||
stmts.size shouldBe 6
|
stmts.size shouldBe 16
|
||||||
|
val result2 = compileText(VMTarget(), optimize=false, src, writeAssembly=true)!!
|
||||||
|
val stmts2 = result2.compilerAst.entrypoint.statements
|
||||||
|
stmts2.size shouldBe 16
|
||||||
}
|
}
|
||||||
|
|
||||||
test("string concatenation and repeats") {
|
test("string concatenation and repeats") {
|
||||||
|
@ -218,6 +218,7 @@ Provides string manipulation routines.
|
|||||||
Returns -1, 0 or 1 depending on whether string1 sorts before, equal or after string2.
|
Returns -1, 0 or 1 depending on whether string1 sorts before, equal or after string2.
|
||||||
Note that you can also directly compare strings and string values with each other
|
Note that you can also directly compare strings and string values with each other
|
||||||
using ``==``, ``<`` etcetera (it will use string.compare for you under water automatically).
|
using ``==``, ``<`` etcetera (it will use string.compare for you under water automatically).
|
||||||
|
This even works when dealing with uword (pointer) variables when comparing them to a string type.
|
||||||
|
|
||||||
``copy (from, to) -> ubyte length``
|
``copy (from, to) -> ubyte length``
|
||||||
Copy a string to another, overwriting that one. Returns the length of the string that was copied.
|
Copy a string to another, overwriting that one. Returns the length of the string that was copied.
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
|
- replace all the string.compare calls in rockrunner with equalites
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,38 +4,29 @@
|
|||||||
main {
|
main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
txt.print_ub(danglingelse(32))
|
str name = "name"
|
||||||
txt.spc()
|
uword nameptr = &name
|
||||||
txt.print_ub(danglingelse(99))
|
|
||||||
txt.spc()
|
cx16.r0L= name=="foo"
|
||||||
txt.print_ub(danglingelse(1))
|
cx16.r1L= name!="foo"
|
||||||
txt.spc()
|
cx16.r2L= name<"foo"
|
||||||
txt.print_ub(danglingelse(100))
|
cx16.r3L= name>"foo"
|
||||||
txt.nl()
|
|
||||||
txt.print_ub(danglingelse2(32))
|
cx16.r0L= nameptr=="foo"
|
||||||
txt.spc()
|
cx16.r1L= nameptr!="foo"
|
||||||
txt.print_ub(danglingelse2(99))
|
cx16.r2L= nameptr<"foo"
|
||||||
txt.spc()
|
cx16.r3L= nameptr>"foo"
|
||||||
txt.print_ub(danglingelse2(1))
|
|
||||||
txt.spc()
|
void compare(name, "foo")
|
||||||
txt.print_ub(danglingelse2(100))
|
void compare(name, "name")
|
||||||
txt.nl()
|
void compare(nameptr, "foo")
|
||||||
|
void compare(nameptr, "name")
|
||||||
}
|
}
|
||||||
|
|
||||||
sub danglingelse(ubyte bb) -> ubyte {
|
sub compare(str s1, str s2) -> ubyte {
|
||||||
if bb==32
|
if s1==s2
|
||||||
return 32
|
return 42
|
||||||
else if bb==99
|
|
||||||
return 99
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
sub danglingelse2(ubyte bb) -> ubyte {
|
|
||||||
if bb==32
|
|
||||||
return 32
|
|
||||||
if bb==99
|
|
||||||
return 99
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user