Compare commits

..

16 Commits

Author SHA1 Message Date
Irmen de Jong
357be82446 first setup of LSP languageserver 2025-08-01 23:39:10 +02:00
Irmen de Jong
7ea80babfc todo 2025-08-01 23:38:49 +02:00
Irmen de Jong
67fb45a55b don't produce invalid boolean initalization error. Fixes #173 2025-07-26 12:35:23 +02:00
Irmen de Jong
11186f1dbe make sure that the virtual target -emu (vm) only runs the actual .p8ir file (fixes #172)
added emudbg.console_nl()
2025-07-26 11:19:01 +02:00
Irmen de Jong
0116fac201 release 11.4.1 2025-07-24 23:00:10 +02:00
Irmen de Jong
866313209b fixed zp vars 0 initialization 2025-07-24 00:17:31 +02:00
Irmen de Jong
e2901cca1b fix virtual diskio save_raw() 2025-07-21 22:10:50 +02:00
Irmen de Jong
dd7adde387 fix virtual diskio.f_write 2025-07-21 20:52:11 +02:00
Irmen de Jong
2f90c53ad0 started changing libs to typed pointers 2025-07-20 23:59:59 +02:00
Irmen de Jong
720988ae72 proper warnings for using pure builtin functions as a statement (discarding the result)
swallow a defer warning for a very common use case
2025-07-18 22:37:07 +02:00
Irmen de Jong
ea5deeefbd new links to Codebase64 website 2025-07-17 23:06:39 +02:00
Irmen de Jong
054c98da7c add link to extra prog8 compilation targets 2025-07-15 00:17:04 +02:00
Irmen de Jong
a4a1b563aa sdks 2025-07-14 21:54:56 +02:00
Irmen de Jong
7dd64b4f13 fix 'cpa' instruction generated in certain boolean assignment, must be 'cmp' 2025-07-06 22:43:19 +02:00
Irmen de Jong
edc353cc24 more kotlin 2.2 settings 2025-07-06 00:37:15 +02:00
Irmen de Jong
0a16dcafc0 update kotlin and gradle wrapper 2025-07-06 00:01:24 +02:00
47 changed files with 624 additions and 102 deletions

8
.idea/kotlinc.xml generated
View File

@@ -7,13 +7,13 @@
<option name="jvmTarget" value="11" />
</component>
<component name="KotlinCommonCompilerArguments">
<option name="apiVersion" value="2.1" />
<option name="languageVersion" value="2.1" />
<option name="apiVersion" value="2.2" />
<option name="languageVersion" value="2.2" />
</component>
<component name="KotlinCompilerSettings">
<option name="additionalArguments" value="-Xwhen-guards" />
<option name="additionalArguments" value="-Xwhen-guards -jvm-default=no-compatibility" />
</component>
<component name="KotlinJpsPluginSettings">
<option name="version" value="2.1.10" />
<option name="version" value="2.2.0" />
</component>
</project>

View File

@@ -1,23 +1,23 @@
<component name="libraryTable">
<library name="KotlinJavaRuntime" type="repository">
<properties maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.20" />
<properties maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.1.20/kotlin-stdlib-jdk8-2.1.20.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.20/kotlin-stdlib-2.1.20.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.2.0/kotlin-stdlib-jdk8-2.2.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.2.0/kotlin-stdlib-2.2.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.1.20/kotlin-stdlib-jdk7-2.1.20.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.2.0/kotlin-stdlib-jdk7-2.2.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.1.20/kotlin-stdlib-jdk8-2.1.20-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.20/kotlin-stdlib-2.1.20-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.2.0/kotlin-stdlib-jdk8-2.2.0-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.2.0/kotlin-stdlib-2.2.0-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.1.20/kotlin-stdlib-jdk7-2.1.20-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.2.0/kotlin-stdlib-jdk7-2.2.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.1.20/kotlin-stdlib-jdk8-2.1.20-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.20/kotlin-stdlib-2.1.20-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.2.0/kotlin-stdlib-jdk8-2.2.0-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.2.0/kotlin-stdlib-2.2.0-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.1.20/kotlin-stdlib-jdk7-2.1.20-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.2.0/kotlin-stdlib-jdk7-2.2.0-sources.jar!/" />
</SOURCES>
</library>
</component>

1
.idea/modules.xml generated
View File

@@ -15,6 +15,7 @@
<module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
<module fileurl="file://$PROJECT_DIR$/intermediate/intermediate.iml" filepath="$PROJECT_DIR$/intermediate/intermediate.iml" />
<module fileurl="file://$PROJECT_DIR$/languageServer/languageServer.iml" filepath="$PROJECT_DIR$/languageServer/languageServer.iml" />
<module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/prog8.iml" filepath="$PROJECT_DIR$/.idea/modules/prog8.iml" />
<module fileurl="file://$PROJECT_DIR$/simpleAst/simpleAst.iml" filepath="$PROJECT_DIR$/simpleAst/simpleAst.iml" />

View File

@@ -1,9 +1,10 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode
import org.jetbrains.kotlin.gradle.internal.config.LanguageFeature
plugins {
kotlin("jvm") version "2.1.20"
kotlin("jvm") version "2.2.0"
}
allprojects {
@@ -18,6 +19,7 @@ allprojects {
compilerOptions {
freeCompilerArgs = listOf("-Xwhen-guards")
jvmTarget = JvmTarget.JVM_11
jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
}
sourceSets.all {
languageSettings {

View File

@@ -3,6 +3,7 @@ package prog8.code.target
import prog8.code.core.*
import prog8.code.target.encodings.Encoder
import java.nio.file.Path
import kotlin.io.path.extension
import kotlin.io.path.isReadable
import kotlin.io.path.name
import kotlin.io.path.readText
@@ -73,16 +74,11 @@ class VMTarget: ICompilationTarget,
// to not have external module dependencies in our own module, we launch the virtual machine via reflection
val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner
val filename = programNameWithPath.name
if(programNameWithPath.isReadable()) {
vm.runProgram(programNameWithPath.readText(), quiet)
} else {
val withExt = programNameWithPath.resolveSibling("$filename.p8ir")
if(withExt.isReadable())
vm.runProgram(withExt.readText(), quiet)
else
throw java.nio.file.NoSuchFileException(withExt.name, null, "not a .p8ir file")
}
val withExt = if(programNameWithPath.extension=="p8ir") programNameWithPath else programNameWithPath.resolveSibling("${programNameWithPath.name}.p8ir")
if(withExt.isReadable())
vm.runProgram(withExt.readText(), quiet)
else
throw java.nio.file.NoSuchFileException(withExt.name, null, "not a .p8ir file")
}
override fun isIOAddress(address: UInt): Boolean = false

View File

@@ -328,10 +328,9 @@ internal class ProgramAndVarsGen(
if (initializers.isNotEmpty()) {
asmgen.out("prog8_init_vars\t.block")
initializers.forEach { assign ->
if((assign.value as? PtNumber)?.number != 0.0 || allocator.isZpVar(assign.target.identifier!!.name))
val constvalue = assign.value as? PtNumber
if(constvalue==null || constvalue.number!=0.0 || allocator.isZpVar(assign.target.identifier!!.name))
asmgen.translate(assign)
else
throw AssemblyError("non-zp variable should not be initialized to zero; it will be zeroed as part of BSS clear")
// the other variables that should be set to zero are done so as part of the BSS section clear.
}
asmgen.out(" rts\n .bend")

View File

@@ -2491,8 +2491,9 @@ $endLabel""")
BaseDataType.UBYTE -> {
when(targetDt) {
BaseDataType.BOOL -> {
val compare = if(regs==RegisterOrPair.A) "cmp" else "cp${regs.toString().lowercase()}"
asmgen.out("""
cp${regs.toString().lowercase()} #0
$compare #0
beq +
ld${regs.toString().lowercase()} #1
+ st${regs.toString().lowercase()} $targetAsmVarName""")

View File

@@ -70,12 +70,12 @@ class IRCodeGen(
val initValue = initialization?.value
when(initValue){
is PtBool -> {
require(initValue.asInt()!=0) { "boolean var should not be initialized with false, it wil be set to false as part of BSS clear, initializer=$initialization" }
require(initValue.asInt()!=0 || variable.zpwish!=ZeropageWish.NOT_IN_ZEROPAGE) { "non-zp variable should not be initialized with 0, it will already be zeroed as part of BSS clear, initializer=$initialization" }
variable.setOnetimeInitNumeric(initValue.asInt().toDouble())
initsToRemove += block to initialization
}
is PtNumber -> {
require(initValue.number!=0.0) { "variable should not be initialized with 0, it will already be zeroed as part of BSS clear, initializer=$initialization" }
require(initValue.number!=0.0 || variable.zpwish!=ZeropageWish.NOT_IN_ZEROPAGE) { "non-zp variable should not be initialized with 0, it will already be zeroed as part of BSS clear, initializer=$initialization" }
variable.setOnetimeInitNumeric(initValue.number)
initsToRemove += block to initialization
}

View File

@@ -19,7 +19,7 @@ class StatementOptimizer(private val program: Program,
val functionName = functionCallStatement.target.nameInSource[0]
if (functionName in functions.purefunctionNames) {
if("ignore_unused" !in parent.definingBlock.options())
errors.info("statement has no effect (function return value is discarded)", functionCallStatement.position)
errors.warn("statement has no effect (function return value is discarded)", functionCallStatement.position)
return listOf(IAstModification.Remove(functionCallStatement, parent as IStatementContainer))
}
}

View File

@@ -376,7 +376,7 @@ hline_filled_right .byte 0, %10000000, %11000000, %11100000, %11110000, %1111
_ormask .byte 128, 64, 32, 16, 8, 4, 2, 1
; note: this can be even faster if we also have a 320 word x-lookup table, but hey, that's a lot of memory.
; see http://codebase64.org/doku.php?id=base:various_techniques_to_calculate_adresses_fast_common_screen_formats_for_pixel_graphics
; see https://codebase64.net/doku.php?id=base:various_techniques_to_calculate_adresses_fast_common_screen_formats_for_pixel_graphics
; the y lookup tables encodes this formula: BITMAP_ADDRESS + 320*(py>>3) + (py & 7) (y from 0..199)
; We use the 64tass syntax for range expressions to calculate this table on assembly time.

View File

@@ -47,6 +47,12 @@ emudbg {
}
}
sub console_nl() {
; write a newline to the debug output console.
; because '\n' gets encoded in the x16 value for it (13) which is different than what the shell expects (10).
console_chrout(10)
}
sub console_chrout(ubyte char) {
; note: make sure the character is in Iso encoding.
if is_emulator()

View File

@@ -3,7 +3,7 @@
;
; some more interesting routines can be found here:
; http://6502org.wikidot.com/software-math
; http://codebase64.org/doku.php?id=base:6502_6510_maths
; https://codebase64.net/doku.php?id=base:6502_6510_maths
; https://github.com/TobyLobster/multiply_test
; https://github.com/TobyLobster/sqrt_test
@@ -353,7 +353,7 @@ _divisor .word ?
randword .proc
; -- 16 bit pseudo random number generator into AY
; default seed = $00c2 $1137. NOTE: uses self-modifying code so won't work in ROM (use randword_rom instead)
; routine from https://codebase64.org/doku.php?id=base:x_abc_random_number_generator_8_16_bit
; routine from https://codebase64.net/doku.php?id=6502_6510_maths:x_abc_random_number_generator_8_16_bit
inc x1
clc
x1=*+1
@@ -377,7 +377,7 @@ b1=*+1
randword_rom .proc
; -- 16 bit pseudo random number generator into AY. Can run from ROM.
; NOTE: you have to set the initial seed using randseed_rom! (a good default seed = $00c2 $1137)
; routine from https://codebase64.org/doku.php?id=base:x_abc_random_number_generator_8_16_bit
; routine from https://codebase64.net/doku.php?id=6502_6510_maths:x_abc_random_number_generator_8_16_bit
inc _x1
clc
lda _x1

View File

@@ -380,7 +380,7 @@ _quadrant_region_to_direction:
asmsub atan2(ubyte x1 @R0, ubyte y1 @R1, ubyte x2 @R2, ubyte y2 @R3) -> ubyte @A {
;; Calculate the angle, in a 256-degree circle, between two points into A.
;; The points (x1, y1) and (x2, y2) have to use *unsigned coordinates only* from the positive quadrant in the carthesian plane!
;; https://www.codebase64.org/doku.php?id=base:8bit_atan2_8-bit_angle
;; http://codebase64.net/doku.php?id=base:8bit_atan2_8-bit_angle
;; This uses 2 large lookup tables so uses a lot of memory but is super fast.
%asm {{

View File

@@ -138,8 +138,8 @@ diskio {
; you can call this multiple times to append more data
repeat num_bytes {
%ir {{
loadm.w r0,diskio.f_write.bufferpointer
loadi.b r99100,r0
loadm.w r99000,diskio.f_write.bufferpointer
loadi.b r99100,r99000
syscall 55 (r99100.b): r99100.b
storem.b r99100,$ff02
}}
@@ -216,12 +216,12 @@ diskio {
}
; like save() but omits the 2 byte prg header.
sub save_raw(uword filenameptr, uword startaddress, uword savesize) -> bool {
sub save_raw(uword filenameptr, uword start_address, uword savesize) -> bool {
%ir {{
load.b r99100,1
loadm.w r99000,diskio.save.filenameptr
loadm.w r99001,diskio.save.start_address
loadm.w r99002,diskio.save.savesize
loadm.w r99000,diskio.save_raw.filenameptr
loadm.w r99001,diskio.save_raw.start_address
loadm.w r99002,diskio.save_raw.savesize
syscall 42 (r99100.b, r99000.w, r99001.w, r99002.w): r99100.b
returnr.b r99100
}}

View File

@@ -468,7 +468,7 @@ private fun processAst(program: Program, errors: IErrorReporter, compilerOptions
errors.report()
program.constantFold(errors, compilerOptions)
errors.report()
program.reorderStatements(errors)
program.reorderStatements(compilerOptions, errors)
errors.report()
program.desugaring(errors, compilerOptions)
errors.report()

View File

@@ -1470,6 +1470,17 @@ internal class AstChecker(private val program: Program,
}
override fun visit(functionCallStatement: FunctionCallStatement) {
if(functionCallStatement.target.nameInSource.size==1) {
val functionName = functionCallStatement.target.nameInSource[0]
if (functionName in program.builtinFunctions.purefunctionNames) {
if("ignore_unused" !in functionCallStatement.parent.definingBlock.options()) {
errors.warn("statement has no effect (function return value is discarded)", functionCallStatement.position)
return
}
}
}
// most function calls, even to builtin functions, are still regular FunctionCall nodes here.
// they get converted to the more specialized node type in BeforeAsmTypecastCleaner
val targetStatement = functionCallStatement.target.checkFunctionOrLabelExists(program, functionCallStatement, errors)

View File

@@ -20,8 +20,8 @@ internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: Compila
checker.visit(this)
}
internal fun Program.reorderStatements(errors: IErrorReporter) {
val reorder = StatementReorderer(this, errors)
internal fun Program.reorderStatements(options: CompilationOptions, errors: IErrorReporter) {
val reorder = StatementReorderer(this, options, errors)
reorder.visit(this)
if(errors.noErrors()) {
reorder.applyModifications()

View File

@@ -165,8 +165,11 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro
}
}
if(srcAssign.origin == AssignmentOrigin.VARINIT && srcAssign.parent is Block && srcAssign.value.constValue(program)?.number==0.0)
throw FatalAstException("should not have a redundant block-level variable=0 assignment; it will be zeroed as part of BSS clear")
if(srcAssign.origin == AssignmentOrigin.VARINIT && srcAssign.parent is Block && srcAssign.value.constValue(program)?.number==0.0) {
val zeropages = srcAssign.target.targetIdentifiers().mapNotNull { it.targetVarDecl()?.zeropage }
if(zeropages.any {it==ZeropageWish.NOT_IN_ZEROPAGE})
throw FatalAstException("should not have a redundant block-level variable=0 assignment for a non-ZP variable; it will be zeroed as part of BSS clear")
}
val assign = PtAssignment(srcAssign.position, srcAssign.origin==AssignmentOrigin.VARINIT)
val multi = srcAssign.target.multi

View File

@@ -133,7 +133,7 @@ private fun integrateDefers(subdefers: Map<PtSub, List<PtDefer>>, program: PtPro
is PtNumber,
is PtRange,
is PtString -> true
// note that unlike most other times, PtIdentifier IS "complex" this time (it's a variable that might change)
is PtIdentifier -> true // actually PtIdentifier IS "complex" this time (it's a variable that might change) but it's kinda annoying to give a warning message for this very common case
else -> false
}

View File

@@ -5,13 +5,11 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.code.core.AssociativeOperators
import prog8.code.core.BaseDataType
import prog8.code.core.DataType
import prog8.code.core.IErrorReporter
import prog8.code.core.*
internal class StatementReorderer(
val program: Program,
val options: CompilationOptions,
val errors: IErrorReporter
) : AstWalker() {
// Reorders the statements in a way the compiler needs.
@@ -114,10 +112,17 @@ internal class StatementReorderer(
}
private fun canSkipInitializationWith0(decl: VarDecl): Boolean {
// if the variable is declared in a block, we can omit the init with 0 because
// the variable will be initialized to zero when the BSS section is cleared as a whole.
if(decl.parent is Block)
return true
if(decl.parent is Block) {
// if the variable is declared in a block and is NOT in ZEROPAGE, we can omit the init with 0 because
// the variable will be initialized to zero when the BSS section is cleared as a whole.
if (decl.zeropage == ZeropageWish.NOT_IN_ZEROPAGE)
return true
// block level zp var that is not in zeropage, doesn't have to be cleared (will be done as part of bss clear at startup)
// note: subroutine level var HAS to be cleared because it needs to be zero at every subroutine call!
if (decl.zeropage == ZeropageWish.DONTCARE && options.zeropage == ZeropageType.DONTUSE)
return true
}
// if there is an assignment to the variable below it (regular assign, or For loop),
// and there is nothing important in between, we can skip the initialization.

View File

@@ -5,6 +5,7 @@ import io.kotest.engine.spec.tempdir
import io.kotest.inspectors.shouldForAll
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
import prog8.ast.expressions.NumericLiteral
import prog8.ast.statements.Assignment
import prog8.ast.statements.FunctionCallStatement
@@ -13,6 +14,7 @@ import prog8.code.core.BuiltinFunctions
import prog8.code.core.RegisterOrPair
import prog8.code.core.isNumeric
import prog8.code.target.Cx16Target
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText
class TestBuiltinFunctions: FunSpec({
@@ -103,5 +105,31 @@ main {
compileText(Cx16Target(), true, src, outputDir, writeAssembly = true) shouldNotBe null
}
test("warning for return value discarding of pure functions") {
val src="""
main {
sub start() {
word @shared ww = 2222
abs(ww)
sgn(ww)
sqrt(ww)
min(ww, 0)
max(ww, 0)
clamp(ww, 0, 319)
}
}"""
val errors = ErrorReporterForTests(keepMessagesAfterReporting = true)
compileText(Cx16Target(), true, src, outputDir, errors=errors, writeAssembly = false) shouldNotBe null
errors.warnings.size shouldBe 6
errors.warnings[0] shouldContain "statement has no effect"
errors.warnings[1] shouldContain "statement has no effect"
errors.warnings[2] shouldContain "statement has no effect"
errors.warnings[3] shouldContain "statement has no effect"
errors.warnings[4] shouldContain "statement has no effect"
errors.warnings[5] shouldContain "statement has no effect"
}
})

View File

@@ -10,7 +10,12 @@ import prog8.ast.statements.Assignment
import prog8.ast.statements.AssignmentOrigin
import prog8.ast.statements.ForLoop
import prog8.ast.statements.VarDecl
import prog8.code.ast.PtAssignment
import prog8.code.ast.PtBool
import prog8.code.ast.PtNumber
import prog8.code.target.C64Target
import prog8.code.target.Cx16Target
import prog8.code.target.VMTarget
import prog8tests.helpers.ErrorReporterForTests
import prog8tests.helpers.compileText
@@ -106,6 +111,7 @@ class TestVariables: FunSpec({
test("global var init with array lookup should sometimes be const") {
val src="""
%zeropage dontuse
main {
bool[] barray = [true, false, true, false]
@@ -220,4 +226,98 @@ main {
(st[5] as Assignment).target.identifier?.nameInSource shouldBe listOf("v1")
(st[6] as Assignment).target.identifier?.nameInSource shouldBe listOf("v0")
}
test("nondirty zp variables should be explicitly initialized to 0") {
val src="""
main {
ubyte @shared @requirezp zpvar
bool @shared @requirezp zpbool
ubyte @shared @requirezp @dirty dirtyzpvar
bool @shared @requirezp @dirty dirtyzpbool
sub start() {
ubyte @shared @requirezp zpvar2
bool @shared @requirezp zpbool2
ubyte @shared @requirezp @dirty dirtyzpvar2
bool @shared @requirezp @dirty dirtyzpbool2
}
}"""
val result = compileText(Cx16Target(), false, src, outputDir, writeAssembly = true)!!.codegenAst
val main = result!!.allBlocks().first { it.name=="p8b_main" }
main.children.size shouldBe 7
val zeroassignsglobal = main.children.filterIsInstance<PtAssignment>()
zeroassignsglobal.size shouldBe 2
(zeroassignsglobal[0].value as PtNumber).number shouldBe 0.0
zeroassignsglobal[0].target.identifier!!.name shouldBe "p8b_main.p8v_zpvar"
(zeroassignsglobal[1].value as PtBool).value shouldBe false
zeroassignsglobal[1].target.identifier!!.name shouldBe "p8b_main.p8v_zpbool"
val st = result.entrypoint()!!.children
st.size shouldBe 7
val zeroassigns = st.filterIsInstance<PtAssignment>()
zeroassigns.size shouldBe 2
(zeroassigns[0].value as PtNumber).number shouldBe 0.0
zeroassigns[0].target.identifier!!.name shouldBe "p8b_main.p8s_start.p8v_zpvar2"
(zeroassigns[1].value as PtBool).value shouldBe false
zeroassigns[1].target.identifier!!.name shouldBe "p8b_main.p8s_start.p8v_zpbool2"
compileText(VMTarget(), false, src, outputDir, writeAssembly = true) shouldNotBe null
}
test("nondirty non zp variables in block scope should not be explicitly initialized to 0 (bss clear takes care of it)") {
val src="""
%zeropage dontuse
main {
ubyte @shared v1
ubyte @shared @dirty dv1
sub start() {
ubyte @shared v2
ubyte @shared @dirty dv2
}
}"""
val result = compileText(Cx16Target(), false, src, outputDir, writeAssembly = true)!!.codegenAst
// block level should not be intialized to 0 (will be done by BSS clear)
val main = result!!.allBlocks().first { it.name=="p8b_main" }
main.children.size shouldBe 3
main.children.any { it is PtAssignment } shouldBe false
// subroutine should be initialized to 0 because that needs to be done on every call to the subroutine
val st = result.entrypoint()!!.children
st.size shouldBe 4
val zeroassign = st.single { it is PtAssignment } as PtAssignment
(zeroassign.value as PtNumber).number shouldBe 0.0
zeroassign.target.identifier!!.name shouldBe "p8b_main.p8s_start.p8v_v2"
}
test("nondirty explicit non zp variables in block scope should not be explicitly initialized to 0 (bss clear takes care of it)") {
val src="""
main {
ubyte @shared @nozp v1
ubyte @shared @dirty @nozp dv1
sub start() {
ubyte @shared @nozp v2
ubyte @shared @dirty @nozp dv2
}
}"""
val result = compileText(Cx16Target(), false, src, outputDir, writeAssembly = true)!!.codegenAst
// block level should not be intialized to 0 (will be done by BSS clear)
val main = result!!.allBlocks().first { it.name=="p8b_main" }
main.children.size shouldBe 3
main.children.any { it is PtAssignment } shouldBe false
// subroutine should be initialized to 0 because that needs to be done on every call to the subroutine
val st = result.entrypoint()!!.children
st.size shouldBe 4
val zeroassign = st.single { it is PtAssignment } as PtAssignment
(zeroassign.value as PtNumber).number shouldBe 0.0
zeroassign.target.identifier!!.name shouldBe "p8b_main.p8s_start.p8v_v2"
}
})

View File

@@ -5,7 +5,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="jdk" jdkName="Python 3.12" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -1,5 +1,6 @@
Prog8 compiler v11.4 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v11.5-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 0116fac2 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c128.p8

View File

@@ -1,5 +1,6 @@
Prog8 compiler v11.4 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v11.5-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 0116fac2 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-c64.p8

View File

@@ -1,5 +1,6 @@
Prog8 compiler v11.4 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v11.5-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 0116fac2 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-cx16.p8
@@ -262,6 +263,7 @@ emudbg {
&ubyte EMU_RECORD_WAV
&ubyte EMU_SAVE_ON_EXIT
console_chrout (ubyte char)
console_nl ()
console_value1 (ubyte value)
console_value2 (ubyte value)
console_write (str isoString)

View File

@@ -1,5 +1,6 @@
Prog8 compiler v11.4 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v11.5-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 0116fac2 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-pet32.p8

View File

@@ -1,5 +1,6 @@
Prog8 compiler v11.4 by Irmen de Jong (irmen@razorvine.net)
Prog8 compiler v11.5-SNAPSHOT by Irmen de Jong (irmen@razorvine.net)
Prerelease version from git commit 0116fac2 in branch master
This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html
Compiling program import-all-virtual.p8
@@ -129,7 +130,7 @@ diskio {
rename (uword oldfileptr, uword newfileptr)
rmdir (str name)
save (uword filenameptr, uword start_address, uword savesize) -> bool
save_raw (uword filenameptr, uword startaddress, uword savesize) -> bool
save_raw (uword filenameptr, uword start_address, uword savesize) -> bool
status () -> str
status_code () -> ubyte
}

View File

@@ -27,7 +27,7 @@ of these library modules automatically as required.
.. note::
Several algorithms and math routines in Prog8's assembly library files are adapted from
code publicly available on https://www.codebase64.org/
code publicly available on https://www.codebase64.net/
.. _builtinfunctions:
@@ -488,7 +488,17 @@ emudbg (cx16 only)
X16Emu Emulator debug routines, for Cx16 only.
Allows you to interface with the emulator's debug routines/registers.
There's stuff like ``is_emulator`` to detect if running in the emulator,
and ``console_write`` to write a (iso) string to the emulator's console (stdout) etc.
and ``console_write`` to write a (iso) string to the emulator's console (stdout), etc.
*EOL (end of line) character handling:*
Writing ``iso:'\n'`` to the console doesn't produce a proper new line there, because prog8 encodes
the newline to character 13 on the X16 (this is what the X16 uses to print a newline on the screen).
You have to explicitly output a character 10 on the console to see a newline there. You can do that in several ways::
emudbg.console_nl()
emudbg.console_chrout(10)
emudbg.console_write(iso:"hello\x0a")
Read the `emudbg source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/cx16/emudbg.p8>`_
to see what's in there.

View File

@@ -65,6 +65,11 @@ Various things:
and it does it at run time. In this demo a jump table is not only created in the library,
but also in the main program and copied into the library for its use.
`Additional custom compilation targets (such as VIC-20) <https://github.com/gillham/prog8targets>`_
Various custom targets for Prog8 that are not (yet?) part of the Prog8 examples themselves.
These additional compilation targets may be in varying state of completeness.
Perhaps most recognisable at the time of adding this link, are the various VIC-20 targets.
.. image:: _static/curious.png
:align: center

View File

@@ -1,6 +1,9 @@
TODO
====
Port benchmarks from https://thred.github.io/c-bench-64/ to prog8 and see how it stacks up.
STRUCTS: are being developed in their own separate branch for now, called "structs".
Idea is to make it feature complete in the IR/Virtual target, then merge it to master?, and then start building the 6502 code generation for it.
@@ -68,6 +71,7 @@ Libraries
Optimizations
-------------
- Since fixing the missing zp-var initialization, programs grew in size again because STZ's reappered. Can we add more intelligent (and correct!) optimizations to remove those STZs that might be redundant again?
- in Identifier: use typedarray of strings instead of listOf? Other places?
- Compilation speed: try to join multiple modifications in 1 result in the AST processors instead of returning it straight away every time
- Compare output of some Oscar64 samples to what prog8 does for the equivalent code (see https://github.com/drmortalwombat/OscarTutorials/tree/main and https://github.com/drmortalwombat/oscar64/tree/main/samples)

View File

@@ -1,27 +1,13 @@
main {
ubyte @shared @requirezp zpvar
bool @shared @requirezp zpbool
ubyte @shared @requirezp @dirty dirtyzpvar
bool @shared @requirezp @dirty dirtyzpbool
sub start() {
uword uw = 9999
word sw = -2222
ubyte ub = 42
byte sb = -99
bool bb = true
cx16.r0 = uw
cx16.r0s = sw
cx16.r0L = ub
cx16.r0H = ub
cx16.r0sL = sb
cx16.r0sH = sb
cx16.r0bL = bb
cx16.r0bH = bb
uw = cx16.r0
sw = cx16.r0s
ub = cx16.r0L
ub = cx16.r0H
sb = cx16.r0sL
sb = cx16.r0sH
bb = cx16.r0bL
bb = cx16.r0bH
ubyte @shared @requirezp zpvar2
bool @shared @requirezp zpbool2
ubyte @shared @requirezp @dirty dirtyzpvar2
bool @shared @requirezp @dirty dirtyzpbool2
}
}

View File

@@ -3,4 +3,4 @@ org.gradle.console=rich
org.gradle.parallel=true
org.gradle.daemon=true
kotlin.code.style=official
version=11.4
version=11.5-SNAPSHOT

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

9
gradlew vendored
View File

@@ -86,8 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -115,7 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -206,7 +205,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
@@ -214,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.

4
gradlew.bat vendored
View File

@@ -70,11 +70,11 @@ goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell

View File

@@ -11,8 +11,10 @@ Intermediate Representation instructions for the IR Virtual machine.
Specs of the virtual machine this will run on:
Program to execute is not stored in the system memory, it's just a separate list of instructions.
65536 virtual registers, 16 bits wide, can also be used as 8 bits. r0-r65535
65536 virtual floating point registers (64 bits double precision) fr0-fr65535
100K virtual registers, 16 bits wide, can also be used as 8 bits. r0-r99999
reserved 99000 - 99099 : WORD registers for syscall arguments and response value(s)
reserved 99100 - 99199 : BYTE registers for syscall arguments and response value(s)
100K virtual floating point registers (64 bits double precision) fr0-fr99999
65536 bytes of memory. Thus memory pointers (addresses) are limited to 16 bits.
Value stack, max 128 entries of 1 byte each.
Status flags: Carry, Zero, Negative. NOTE: status flags are only affected by the CMP instruction or explicit CLC/SEC,

View File

@@ -0,0 +1,103 @@
plugins {
kotlin("jvm")
id("application")
}
val debugPort = 8000
val debugArgs = "-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n,quiet=y"
val serverMainClassName = "prog8lsp.MainKt"
val applicationName = "prog8-language-server"
application {
mainClass.set(serverMainClassName)
description = "Code completions, diagnostics and more for Prog8"
// applicationDefaultJvmArgs = listOf("-DkotlinLanguageServer.version=$version")
applicationDistribution.into("bin") {
filePermissions {
user {
read=true
execute=true
write=true
}
other.execute = true
group.execute = true
}
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.eclipse.lsp4j:org.eclipse.lsp4j:0.24.0")
implementation("org.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc:0.24.0")
}
configurations.forEach { config ->
config.resolutionStrategy {
preferProjectModules()
}
}
sourceSets.main {
java.srcDir("src")
resources.srcDir("resources")
}
sourceSets.test {
java.srcDir("src")
resources.srcDir("resources")
}
tasks.startScripts {
applicationName = "prog8-language-server"
}
tasks.register<Exec>("fixFilePermissions") {
// When running on macOS or Linux the start script
// needs executable permissions to run.
onlyIf { !System.getProperty("os.name").lowercase().contains("windows") }
commandLine("chmod", "+x", "${tasks.installDist.get().destinationDir}/bin/prog8-language-server")
}
tasks.register<JavaExec>("debugRun") {
mainClass.set(serverMainClassName)
classpath(sourceSets.main.get().runtimeClasspath)
standardInput = System.`in`
jvmArgs(debugArgs)
doLast {
println("Using debug port $debugPort")
}
}
tasks.register<CreateStartScripts>("debugStartScripts") {
applicationName = "prog8-language-server"
mainClass.set(serverMainClassName)
outputDir = tasks.installDist.get().destinationDir.toPath().resolve("bin").toFile()
classpath = tasks.startScripts.get().classpath
defaultJvmOpts = listOf(debugArgs)
}
tasks.register<Sync>("installDebugDist") {
dependsOn("installDist")
finalizedBy("debugStartScripts")
}
tasks.withType<Test>() {
testLogging {
events("failed")
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
}
tasks.installDist {
finalizedBy("fixFilePermissions")
}
tasks.build {
finalizedBy("installDist")
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="eclipse.lsp4j" level="project" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
</component>
</module>

View File

@@ -0,0 +1,34 @@
package prog8lsp
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.function.Supplier
private var threadCount = 0
class AsyncExecutor {
private val workerThread = Executors.newSingleThreadExecutor { Thread(it, "async${threadCount++}") }
fun execute(task: () -> Unit) =
CompletableFuture.runAsync(Runnable(task), workerThread)
fun <R> compute(task: () -> R) =
CompletableFuture.supplyAsync(Supplier(task), workerThread)
fun <R> computeOr(defaultValue: R, task: () -> R?) =
CompletableFuture.supplyAsync(Supplier {
try {
task() ?: defaultValue
} catch (e: Exception) {
defaultValue
}
}, workerThread)
fun shutdown(awaitTermination: Boolean) {
workerThread.shutdown()
if (awaitTermination) {
workerThread.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS)
}
}
}

View File

@@ -0,0 +1,19 @@
package prog8lsp
import org.eclipse.lsp4j.launch.LSPLauncher
import java.util.concurrent.Executors
import java.util.logging.Level
import java.util.logging.Logger
fun main(args: Array<String>) {
Logger.getLogger("").level = Level.INFO
val inStream = System.`in`
val outStream = System.out
val server = Prog8LanguageServer()
val threads = Executors.newSingleThreadExecutor { Thread(it, "client") }
val launcher = LSPLauncher.createServerLauncher(server, inStream, outStream, threads) { it }
server.connect(launcher.remoteProxy)
launcher.startListening()
}

View File

@@ -0,0 +1,46 @@
package prog8lsp
import org.eclipse.lsp4j.InitializeParams
import org.eclipse.lsp4j.InitializeResult
import org.eclipse.lsp4j.services.*
import java.io.Closeable
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletableFuture.completedFuture
import java.util.logging.Logger
class Prog8LanguageServer: LanguageServer, LanguageClientAware, Closeable {
private lateinit var client: LanguageClient
private val textDocuments = Prog8TextDocumentService()
private val workspaces = Prog8WorkspaceService()
private val async = AsyncExecutor()
private val logger = Logger.getLogger(Prog8LanguageServer::class.simpleName)
override fun initialize(params: InitializeParams): CompletableFuture<InitializeResult> = async.compute {
logger.info("Initializing LanguageServer")
InitializeResult()
}
override fun shutdown(): CompletableFuture<Any> {
close()
return completedFuture(null)
}
override fun exit() { }
override fun getTextDocumentService(): TextDocumentService = textDocuments
override fun getWorkspaceService(): WorkspaceService = workspaces
override fun connect(client: LanguageClient) {
logger.info("connecting to language client")
this.client = client
workspaces.connect(client)
textDocuments.connect(client)
}
override fun close() {
logger.info("closing down")
async.shutdown(awaitTermination = true)
}
}

View File

@@ -0,0 +1,62 @@
package prog8lsp
import org.eclipse.lsp4j.*
import org.eclipse.lsp4j.jsonrpc.messages.Either
import org.eclipse.lsp4j.services.LanguageClient
import org.eclipse.lsp4j.services.TextDocumentService
import java.util.concurrent.CompletableFuture
import java.util.logging.Logger
import kotlin.system.measureTimeMillis
class Prog8TextDocumentService: TextDocumentService {
private var client: LanguageClient? = null
private val async = AsyncExecutor()
private val logger = Logger.getLogger(Prog8TextDocumentService::class.simpleName)
fun connect(client: LanguageClient) {
this.client = client
}
override fun didOpen(params: DidOpenTextDocumentParams) {
logger.info("didOpen: $params")
}
override fun didChange(params: DidChangeTextDocumentParams) {
logger.info("didChange: $params")
}
override fun didClose(params: DidCloseTextDocumentParams) {
logger.info("didClose: $params")
}
override fun didSave(params: DidSaveTextDocumentParams) {
logger.info("didSave: $params")
}
override fun documentSymbol(params: DocumentSymbolParams): CompletableFuture<MutableList<Either<SymbolInformation, DocumentSymbol>>> = async.compute {
logger.info("Find symbols in ${params.textDocument.uri}")
val result: MutableList<Either<SymbolInformation, DocumentSymbol>>
val time = measureTimeMillis {
result = mutableListOf()
val range = Range(Position(1,1), Position(1,5))
val selectionRange = Range(Position(1,2), Position(1,10))
val symbol = DocumentSymbol("test-symbolName", SymbolKind.Constant, range, selectionRange)
result.add(Either.forRight(symbol))
}
logger.info("Finished in $time ms")
result
}
override fun completion(position: CompletionParams): CompletableFuture<Either<MutableList<CompletionItem>, CompletionList>> = async.compute{
logger.info("Completion for ${position}")
val result: Either<MutableList<CompletionItem>, CompletionList>
val time = measureTimeMillis {
val list = CompletionList(false, listOf(CompletionItem("test-completionItem")))
result = Either.forRight(list)
}
logger.info("Finished in $time ms")
result
}
// TODO add all other methods that get called.... :P
}

View File

@@ -0,0 +1,80 @@
package prog8lsp
import org.eclipse.lsp4j.*
import org.eclipse.lsp4j.jsonrpc.messages.Either
import org.eclipse.lsp4j.services.LanguageClient
import org.eclipse.lsp4j.services.WorkspaceService
import java.util.concurrent.CompletableFuture
import java.util.logging.Logger
class Prog8WorkspaceService: WorkspaceService {
private var client: LanguageClient? = null
private val logger = Logger.getLogger(Prog8WorkspaceService::class.simpleName)
fun connect(client: LanguageClient) {
this.client = client
}
override fun executeCommand(params: ExecuteCommandParams): CompletableFuture<Any> {
logger.info("executeCommand $params")
return super.executeCommand(params)
}
override fun symbol(params: WorkspaceSymbolParams): CompletableFuture<Either<MutableList<out SymbolInformation>, MutableList<out WorkspaceSymbol>>> {
logger.info("symbol $params")
return super.symbol(params)
}
override fun resolveWorkspaceSymbol(workspaceSymbol: WorkspaceSymbol): CompletableFuture<WorkspaceSymbol> {
logger.info("resolveWorkspaceSymbol $workspaceSymbol")
return super.resolveWorkspaceSymbol(workspaceSymbol)
}
override fun didChangeConfiguration(params: DidChangeConfigurationParams) {
logger.info("didChangeConfiguration: $params")
}
override fun didChangeWatchedFiles(params: DidChangeWatchedFilesParams) {
logger.info("didChangeWatchedFiles: $params")
}
override fun didChangeWorkspaceFolders(params: DidChangeWorkspaceFoldersParams) {
logger.info("didChangeWorkspaceFolders $params")
super.didChangeWorkspaceFolders(params)
}
override fun willCreateFiles(params: CreateFilesParams): CompletableFuture<WorkspaceEdit> {
logger.info("willCreateFiles $params")
return super.willCreateFiles(params)
}
override fun didCreateFiles(params: CreateFilesParams) {
logger.info("didCreateFiles $params")
super.didCreateFiles(params)
}
override fun willRenameFiles(params: RenameFilesParams): CompletableFuture<WorkspaceEdit> {
logger.info("willRenameFiles $params")
return super.willRenameFiles(params)
}
override fun didRenameFiles(params: RenameFilesParams) {
logger.info("didRenameFiles $params")
super.didRenameFiles(params)
}
override fun willDeleteFiles(params: DeleteFilesParams): CompletableFuture<WorkspaceEdit> {
logger.info("willDeleteFiles $params")
return super.willDeleteFiles(params)
}
override fun didDeleteFiles(params: DeleteFilesParams) {
logger.info("didDeleteFiles $params")
super.didDeleteFiles(params)
}
override fun diagnostic(params: WorkspaceDiagnosticParams): CompletableFuture<WorkspaceDiagnosticReport> {
logger.info("diagnostic $params")
return super.diagnostic(params)
}
}

View File

@@ -10,5 +10,6 @@ include(
':codeGenCpu6502',
':codeGenExperimental',
':compiler',
':beanshell'
':beanshell',
':languageServer'
)

View File

@@ -200,7 +200,7 @@ class StStaticVariable(name: String,
// Certain codegens might want to put them back into the variable directly.
// For strings and arrays this doesn't occur - these are always already specced at creation time.
require(number!=0.0) { "variable should not be initialized with 0, it will already be zeroed as part of BSS clear" }
require(number!=0.0 || zpwish!=ZeropageWish.NOT_IN_ZEROPAGE) { "non-zp variable should not be initialized with 0, it will already be zeroed as part of BSS clear" }
initializationNumericValue = number
}