Compare commits

..
11 Commits
13 changed files with 119 additions and 82 deletions

No files matched your search

+12 -8
View File
@@ -35,13 +35,17 @@ jobs:
name: prog8-compiler-jar-zipped
path: compiler/build/libs/*-all.jar
- uses: MCJack123/ghaction-generate-release-hashes@v4
if: "github.event_name == 'release'"
- name: Calculate hash
uses: MCJack123/ghaction-generate-release-hashes@v4
if: github.event_name == 'release'
with:
hash-type: sha256
file-name: hashes.txt
- uses: actions/upload-artifact@v4
if: "github.event_name == 'release'"
get-assets: true
hash-type: sha256
file-name: hashes.txt
- name: Upload hashes
uses: actions/upload-artifact@v4
if: github.event_name == 'release'
with:
name: Artifact Hashes
path: hashes.txt
name: Artifact Hashes
path: hashes.txt
+1 -1
View File
@@ -1,6 +1,6 @@
package prog8.code.core
val AssociativeOperators = setOf("+", "*", "&", "|", "^", "==", "!=", "and", "or", "xor")
val AssociativeOperators = setOf("+", "*", "&", "|", "^", "==", "!=", "xor") // note: and,or are no longer associative because of Shortcircuit/McCarthy evaluation
val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
val LogicalOperators = setOf("and", "or", "xor", "not", "in")
val BitwiseOperators = setOf("&", "|", "^", "~")
@@ -4,7 +4,6 @@ import prog8.ast.*
import prog8.ast.base.FatalAstException
import prog8.ast.expressions.*
import prog8.ast.statements.AnonymousScope
import prog8.ast.statements.Assignment
import prog8.ast.statements.IfElse
import prog8.ast.statements.Jump
import prog8.ast.walk.AstWalker
@@ -109,12 +108,6 @@ class ExpressionSimplifier(private val program: Program, private val options: Co
if (!leftIDt.isKnown || !rightIDt.isKnown)
throw FatalAstException("can't determine datatype of both expression operands $expr")
// NonBinaryExpression <associativeoperator> BinaryExpression --> BinaryExpression <associativeoperator> NonBinaryExpression
if (expr.operator in AssociativeOperators && expr.left !is BinaryExpression && expr.right is BinaryExpression) {
if(parent !is Assignment || !(expr.left isSameAs parent.target) && maySwapOperandOrder(expr))
return listOf(IAstModification.SwapOperands(expr))
}
// X + (-A) --> X - A
if (expr.operator == "+" && (expr.right as? PrefixExpression)?.operator == "-") {
return listOf(IAstModification.ReplaceNode(
+5 -3
View File
@@ -55,9 +55,11 @@ gfx2 {
}
else -> {
; back to default text mode
cx16.r15L = cx16.VERA_DC_VIDEO & %00000111 ; retain chroma + output mode
cbm.CINT()
cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11111000) | cx16.r15L
if active_mode!=0 {
cx16.r15L = cx16.VERA_DC_VIDEO & %00000111 ; retain chroma + output mode
cbm.CINT()
cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11111000) | cx16.r15L
}
}
}
@@ -76,4 +76,44 @@ string {
return s+cx16.r0L
}
sub startswith(str st, str prefix) -> bool {
ubyte prefix_len = string.length(prefix)
ubyte str_len = string.length(st)
if prefix_len > str_len
return false
cx16.r9L = st[prefix_len]
st[prefix_len] = 0
cx16.r9H = string.compare(st, prefix) as ubyte
st[prefix_len] = cx16.r9L
return cx16.r9H==0
}
sub endswith(str st, str suffix) -> bool {
ubyte suffix_len = string.length(suffix)
ubyte str_len = string.length(st)
if suffix_len > str_len
return false
return string.compare(st + str_len - suffix_len, suffix) == 0
}
sub findstr(str haystack, str needle) -> ubyte {
; searches for needle in haystack.
; returns index in haystack where it first occurs, and Carry set,
; or if needle doesn't occur in haystack it returns Carry clear and 255 (an invalid index.)
cx16.r2L = string.length(haystack)
cx16.r3L = string.length(needle)
if cx16.r3L <= cx16.r2L {
cx16.r2L = cx16.r2L-cx16.r3L+1
cx16.r3 = haystack
repeat cx16.r2L {
if string.startswith(cx16.r3, needle) {
sys.set_carry()
return cx16.r3-haystack as ubyte
}
cx16.r3++
}
}
sys.clear_carry()
return 255
}
}
+2 -23
View File
@@ -129,7 +129,7 @@ _startloop dey
asmsub find(uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc {
; Locates the first position of the given character in the string,
; returns Carry set if found + index in A, or A=0 + Carry clear if not found.
; returns Carry set if found + index in A, or Carry clear if not found (and A will be 255, an invalid index).
%asm {{
; need to copy the the cx16 virtual registers to zeropage to make this run on C64...
sta P8ZP_SCRATCH_W1
@@ -142,7 +142,7 @@ _startloop dey
beq _found
iny
bne -
_notfound lda #0
_notfound lda #255
clc
rts
_found tya
@@ -277,26 +277,6 @@ _done rts
}}
}
sub startswith(str st, str prefix) -> bool {
ubyte prefix_len = length(prefix)
ubyte str_len = length(st)
if prefix_len > str_len
return false
cx16.r9L = st[prefix_len]
st[prefix_len] = 0
cx16.r9H = compare(st, prefix) as ubyte
st[prefix_len] = cx16.r9L
return cx16.r9H==0
}
sub endswith(str st, str suffix) -> bool {
ubyte suffix_len = length(suffix)
ubyte str_len = length(st)
if suffix_len > str_len
return false
return compare(st + str_len - suffix_len, suffix) == 0
}
asmsub pattern_match(str string @AY, str pattern @R0) clobbers(Y) -> bool @A {
%asm {{
; pattern matching of a string.
@@ -366,7 +346,6 @@ fail clc ; yes, no match found, return with c=0
}}
}
asmsub hash(str string @R0) -> ubyte @A {
; experimental 8 bit hashing function.
; hash(-1)=179; clear carry; hash(i) = ROL hash(i-1) XOR string[i]
+2 -22
View File
@@ -55,7 +55,7 @@ string {
sub find(str st, ubyte character) -> ubyte {
; Locates the first position of the given character in the string,
; returns Carry set if found + index in A, or Carry clear if not found.
; returns Carry set if found + index in A, or Carry clear if not found (and A will be 255, an invalid index).
ubyte ix
for ix in 0 to length(st)-1 {
if st[ix]==character {
@@ -64,7 +64,7 @@ string {
}
}
sys.clear_carry()
return 0
return 255
}
sub contains(str st, ubyte character) -> bool {
@@ -147,26 +147,6 @@ string {
return char
}
sub startswith(str st, str prefix) -> bool {
ubyte prefix_len = length(prefix)
ubyte str_len = length(st)
if prefix_len > str_len
return false
cx16.r9L = st[prefix_len]
st[prefix_len] = 0
cx16.r9H = compare(st, prefix) as ubyte
st[prefix_len] = cx16.r9L
return cx16.r9H==0
}
sub endswith(str st, str suffix) -> bool {
ubyte suffix_len = length(suffix)
ubyte str_len = length(st)
if suffix_len > str_len
return false
return compare(st + str_len - suffix_len, suffix) == 0
}
sub hash(str st) -> ubyte {
; experimental 8 bit hashing function.
; hash(-1)=179; hash(i) = ROL hash(i-1) XOR string[i]
@@ -825,7 +825,7 @@ internal class AstChecker(private val program: Program,
err("invalid import directive, cannot import itself")
}
"%breakpoint" -> {
if(directive.parent !is INameScope || directive.parent is Module)
if(directive.parent !is INameScope && directive.parent !is AnonymousScope || directive.parent is Module)
err("this directive can't be used here")
if(directive.args.isNotEmpty())
err("invalid breakpoint directive, expected no arguments")
@@ -214,8 +214,12 @@ internal class StatementReorderer(
}
}
if(valueType.isString && (targetType istype DataType.STR || targetType istype DataType.ARRAY_B || targetType istype DataType.ARRAY_UB))
return copyStringValue(assignment)
if(!assignment.isAugmentable) {
if (valueType.isString && (targetType istype DataType.STR || targetType istype DataType.ARRAY_B || targetType istype DataType.ARRAY_UB)) {
// replace string assignment by a call to stringcopy
return copyStringValue(assignment)
}
}
return noModifications
}
+37
View File
@@ -935,4 +935,41 @@ main {
funcarg3.target.nameInSource shouldBe listOf("msb")
funcarg3.args.single() shouldBe instanceOf<BinaryExpression>()
}
test("no operand swap on logical expressions with shortcircuit evaluation") {
val src="""
%import diskio
%zeropage basicsafe
%option no_sysinit
main {
str scanline_buf = "?"* 20
sub start() {
if diskio.f_open("test.prg") and diskio.f_read(scanline_buf, 2)==2
cx16.r0++
if diskio.f_open("test.prg") or diskio.f_read(scanline_buf, 2)==2
cx16.r0++
if diskio.f_open("test.prg") xor diskio.f_read(scanline_buf, 2)==2
cx16.r0++
}
}"""
val result = compileText(Cx16Target(), true, src, writeAssembly = false)!!
val st = result.compilerAst.entrypoint.statements
st.size shouldBe 3
val ifCond1 = (st[0] as IfElse).condition as BinaryExpression
val ifCond2 = (st[1] as IfElse).condition as BinaryExpression
val ifCond3 = (st[2] as IfElse).condition as BinaryExpression
(ifCond1.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_open")
(ifCond2.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_open")
(ifCond3.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_open")
val right1 = ifCond1.right as BinaryExpression
val right2 = ifCond2.right as BinaryExpression
val right3 = ifCond3.right as BinaryExpression
(right1.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_read")
(right2.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_read")
(right3.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_read")
}
})
+3 -1
View File
@@ -238,7 +238,6 @@ Directives
Level: not at module scope.
Declares that a piece of *assembly code* is inside the curly braces.
This code will be copied as-is into the generated output assembly source file.
The assembler syntax used should be for the 3rd party cross assembler tool that Prog8 uses (64tass).
Note that the start and end markers are both *double curly braces* to minimize the chance
that the assembly code itself contains either of those. If it does contain a ``}}``,
it will confuse the parser.
@@ -247,6 +246,9 @@ Directives
the assembly code. Sometimes you'll have to declare a variable in prog8 with `@shared` if it
is only used in such assembly code.
.. note::
64tass syntax is required for the assembly code. As such, mnemonics need to be written in lowercase.
.. caution::
Avoid using single-letter symbols in included assembly code, as they could be confused with CPU registers.
Also, note that all prog8 symbols are prefixed in assembly code, see :ref:`symbol-prefixing`.
+9 -13
View File
@@ -1,22 +1,18 @@
%import textio
%import diskio
%zeropage basicsafe
%option no_sysinit
main {
str scanline_buf = "?"* 20
sub start() {
ubyte[] ubarray = [11,22,33]
uword[] uwarray = [1111,2222,3333]
uword[] @split suwarray = [1111,2222,3333]
if diskio.f_open("test.prg") and diskio.f_read(scanline_buf, 2)==2
cx16.r0++
ubarray[1] *= 10
uwarray[1] *= 10
suwarray[1] *= 10
if diskio.f_open("test.prg") or diskio.f_read(scanline_buf, 2)==2
cx16.r0++
txt.print_ub(ubarray[1])
txt.nl()
txt.print_uw(uwarray[1])
txt.nl()
txt.print_uw(suwarray[1])
txt.nl()
if diskio.f_open("test.prg") xor diskio.f_read(scanline_buf, 2)==2
cx16.r0++
}
}
+1 -1
View File
@@ -5,4 +5,4 @@ org.gradle.daemon=true
kotlin.code.style=official
javaVersion=11
kotlinVersion=1.9.22
version=10.2
version=10.2.1