diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index e3a7749e6..fa03fab27 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -47,6 +47,36 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val rightCv = expr.right.constValue(program) if(leftDt.isKnown && rightDt.isKnown) { + + if(expr.operator=="<<" && leftDt.isBytes) { + // uword ww = 1 << shift --> make the '1' a word constant + val leftConst = expr.left.constValue(program) + if(leftConst!=null) { + val leftConstAsWord = + if(leftDt.istype(DataType.UBYTE)) + NumericLiteral(DataType.UWORD, leftConst.number, leftConst.position) + else + NumericLiteral(DataType.WORD, leftConst.number, leftConst.position) + val modifications = mutableListOf() + if (parent is Assignment) { + if (parent.target.inferType(program).isWords) { + modifications += IAstModification.ReplaceNode(expr.left, leftConstAsWord, expr) + if(rightDt.isBytes) + modifications += IAstModification.ReplaceNode(expr.right, TypecastExpression(expr.right, leftConstAsWord.type, true, expr.right.position), expr) + } + } else if (parent is TypecastExpression && parent.type == DataType.UWORD && parent.parent is Assignment) { + val assign = parent.parent as Assignment + if (assign.target.inferType(program).isWords) { + modifications += IAstModification.ReplaceNode(expr.left, leftConstAsWord, expr) + if(rightDt.isBytes) + modifications += IAstModification.ReplaceNode(expr.right, TypecastExpression(expr.right, leftConstAsWord.type, true, expr.right.position), expr) + } + } + if(modifications.isNotEmpty()) + return modifications + } + } + if(expr.operator in LogicalOperators && leftDt.isInteger && rightDt.isInteger) { // see if any of the operands needs conversion to bool val modifications = mutableListOf() diff --git a/compiler/test/ast/TestVarious.kt b/compiler/test/ast/TestVarious.kt index 2fe8d7b60..4057e7e72 100644 --- a/compiler/test/ast/TestVarious.kt +++ b/compiler/test/ast/TestVarious.kt @@ -3,13 +3,19 @@ package prog8tests.ast import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe +import io.kotest.matchers.types.instanceOf import prog8.ast.IFunctionCall +import prog8.ast.expressions.BinaryExpression import prog8.ast.expressions.IdentifierReference +import prog8.ast.expressions.NumericLiteral import prog8.ast.expressions.StringLiteral +import prog8.ast.statements.Assignment import prog8.ast.statements.InlineAssembly import prog8.ast.statements.VarDecl +import prog8.code.core.DataType import prog8.code.core.Position import prog8.code.target.C64Target +import prog8.compiler.printProgram import prog8tests.helpers.compileText class TestVarious: FunSpec({ @@ -129,5 +135,31 @@ main { }""" compileText(C64Target(), optimize=false, src, writeAssembly=false) shouldNotBe null } + + test("bitshift left of const byte converted to word") { + val src=""" +main { + sub start() { + ubyte shift = 10 + uword value = 1< expr is treated as instead (or inverse order) - ir/vm: allow label in block scope - regression test the various projects - 6502 codegen: make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway) diff --git a/examples/test.p8 b/examples/test.p8 index b3989902e..ef433868f 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,6 +7,16 @@ alsostart: sub start() { internalstart: + ubyte fact = 10 + uword ww = 1<