split out the code generator into own project submodule

This commit is contained in:
Irmen de Jong 2021-10-29 05:00:30 +02:00
parent 82da8f4946
commit 0b5ddcdc9b
61 changed files with 322 additions and 186 deletions

1
.idea/modules.xml generated
View File

@ -2,6 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/codeGeneration/codeGeneration.iml" filepath="$PROJECT_DIR$/codeGeneration/codeGeneration.iml" />
<module fileurl="file://$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" filepath="$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" />
<module fileurl="file://$PROJECT_DIR$/compiler/compiler.iml" filepath="$PROJECT_DIR$/compiler/compiler.iml" />
<module fileurl="file://$PROJECT_DIR$/compilerAst/compilerAst.iml" filepath="$PROJECT_DIR$/compilerAst/compilerAst.iml" />

View File

@ -0,0 +1,73 @@
plugins {
id 'java'
id 'application'
id "org.jetbrains.kotlin.jvm"
}
targetCompatibility = 11
sourceCompatibility = 11
repositories {
mavenLocal()
mavenCentral()
maven { url "https://kotlin.bintray.com/kotlinx" }
}
dependencies {
implementation project(':compilerInterfaces')
implementation project(':compilerAst')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
// implementation "org.jetbrains.kotlin:kotlin-reflect"
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.12"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit5"
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.2'
testImplementation 'org.hamcrest:hamcrest:2.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2'
}
compileKotlin {
kotlinOptions {
jvmTarget = "11"
// verbose = true
// freeCompilerArgs += "-XXLanguage:+NewInference"
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = "11"
}
}
sourceSets {
main {
java {
srcDirs = ["${project.projectDir}/src"]
}
resources {
srcDirs = ["${project.projectDir}/res"]
}
}
test {
java {
srcDirs = ["${project.projectDir}/test"]
}
}
}
test {
// Enable JUnit 5 (Gradle 4.6+).
useJUnitPlatform()
// Always run tests, even when nothing changed.
dependsOn 'cleanTest'
// Show test results.
testLogging {
events "skipped", "failed"
}
}

View File

@ -0,0 +1,18 @@
<?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" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
</content>
<orderEntry type="jdk" jdkName="openjdk-11" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
<orderEntry type="module" module-name="compilerInterfaces" />
<orderEntry type="module" module-name="compilerAst" />
<orderEntry type="library" scope="TEST" name="hamcrest" level="project" />
<orderEntry type="library" name="junit.jupiter" level="project" />
</component>
</module>

View File

@ -0,0 +1,3 @@
package prog8.compiler.target
class AssemblyError(msg: String) : RuntimeException(msg)

View File

@ -10,7 +10,7 @@ import prog8.compiler.target.cbm.Petscii
import prog8.compilerinterface.*
internal object C64Target: ICompilationTarget {
object C64Target: ICompilationTarget {
override val name = "c64"
override val machine = C64MachineDefinition
override fun encodeString(str: String, altEncoding: Boolean): List<Short> {

View File

@ -10,7 +10,7 @@ import prog8.compiler.target.cx16.CX16MachineDefinition
import prog8.compilerinterface.*
internal object Cx16Target: ICompilationTarget {
object Cx16Target: ICompilationTarget {
override val name = "cx16"
override val machine = CX16MachineDefinition
override fun encodeString(str: String, altEncoding: Boolean): List<Short> {

View File

@ -1,6 +1,5 @@
package prog8.compiler.target.c64
import prog8.compiler.*
import prog8.compiler.target.cbm.viceMonListPostfix
import prog8.compilerinterface.*
import java.io.IOException
@ -8,7 +7,7 @@ import java.nio.file.Path
import kotlin.math.absoluteValue
import kotlin.math.pow
internal object C64MachineDefinition: IMachineDefinition {
object C64MachineDefinition: IMachineDefinition {
override val cpu = CpuType.CPU6502
@ -75,7 +74,7 @@ internal object C64MachineDefinition: IMachineDefinition {
"sta", "stx", "sty", "tas", "tax", "tay", "tsx", "txa", "txs", "tya", "xaa")
internal class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
override val SCRATCH_B1 = 0x02 // temp storage for a single byte
override val SCRATCH_REG = 0x03 // temp storage for a register, must be B1+1
@ -144,7 +143,7 @@ internal object C64MachineDefinition: IMachineDefinition {
}
}
internal data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, val b4: Short):
data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, val b4: Short):
IMachineFloat {
companion object {

View File

@ -1,10 +1,17 @@
package prog8.compiler.target.cbm
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
import com.github.michaelbull.result.mapError
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.IAssemblyProgram
import prog8.compilerinterface.OutputType
import prog8.compilerinterface.generatedLabelPrefix
import prog8.parser.SourceCode
import java.io.File
import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.isRegularFile
internal const val viceMonListPostfix = "vice-mon-list"
@ -76,3 +83,18 @@ class AssemblyProgram(
viceMonListFile.toFile().appendText(breakpoints.joinToString("\n") + "\n")
}
}
internal fun loadAsmIncludeFile(filename: String, source: SourceCode): Result<String, NoSuchFileException> {
return if (filename.startsWith(SourceCode.libraryFilePrefix)) {
return com.github.michaelbull.result.runCatching {
SourceCode.Resource("/prog8lib/${filename.substring(SourceCode.libraryFilePrefix.length)}").readText()
}.mapError { NoSuchFileException(File(filename)) }
} else {
val sib = Path(source.origin).resolveSibling(filename)
if (sib.isRegularFile())
Ok(SourceCode.File(sib).readText())
else
Ok(SourceCode.File(Path(filename)).readText())
}
}

View File

@ -1098,7 +1098,7 @@ object Petscii {
fun decodePetscii(petscii: Iterable<Short>, lowercase: Boolean = false): String {
return petscii.map {
val code = it.toInt()
if(code<0 || code>=decodingPetsciiLowercase.size)
if(code<0 || code>= decodingPetsciiLowercase.size)
throw CharConversionException("petscii $code out of range 0..${decodingPetsciiLowercase.size-1}")
if(lowercase) decodingPetsciiLowercase[code] else decodingPetsciiUppercase[code]
}.joinToString("")
@ -1137,7 +1137,7 @@ object Petscii {
fun decodeScreencode(screencode: Iterable<Short>, lowercase: Boolean = false): String {
return screencode.map {
val code = it.toInt()
if(code<0 || code>=decodingScreencodeLowercase.size)
if(code<0 || code>= decodingScreencodeLowercase.size)
throw CharConversionException("screencode $code out of range 0..${decodingScreencodeLowercase.size-1}")
if (lowercase) decodingScreencodeLowercase[code] else decodingScreencodeUppercase[code]
}.joinToString("")

View File

@ -7,14 +7,12 @@ import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.compiler.*
import prog8.compiler.functions.BuiltinFunctions
import prog8.compiler.functions.FSignature
import prog8.compiler.target.*
import prog8.compiler.target.cbm.AssemblyProgram
import prog8.compiler.target.cbm.loadAsmIncludeFile
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignment
import prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen
import prog8.compilerinterface.*
import prog8.optimizer.CallGraph
import prog8.parser.SourceCode
import java.nio.file.Path
import java.time.LocalDate
@ -24,7 +22,7 @@ import kotlin.io.path.Path
import kotlin.math.absoluteValue
internal class AsmGen(private val program: Program,
class AsmGen(private val program: Program,
val errors: IErrorReporter,
val zeropage: Zeropage,
val options: CompilationOptions,
@ -275,7 +273,7 @@ internal class AsmGen(private val program: Program,
&& variable.datatype != DataType.FLOAT
&& options.zeropage != ZeropageType.DONTUSE) {
try {
val errors = ErrorReporter()
val errors = ErrorReporter() // TODO why not just use this.errors? then we can clean up the visibility of ErrorReporter class again too
val address = zeropage.allocate(fullName, variable.datatype, null, errors)
errors.report()
out("${variable.name} = $address\t; auto zp ${variable.datatype}")
@ -500,7 +498,7 @@ internal class AsmGen(private val program: Program,
return newName
}
internal fun asmSymbolName(identifier: IdentifierReference): String {
fun asmSymbolName(identifier: IdentifierReference): String {
if(identifier.nameInSource.size==2 && identifier.nameInSource[0]=="prog8_slabs")
return identifier.nameInSource.joinToString(".")
@ -531,7 +529,7 @@ internal class AsmGen(private val program: Program,
}
}
internal fun asmVariableName(identifier: IdentifierReference) =
fun asmVariableName(identifier: IdentifierReference) =
fixNameSymbols(identifier.nameInSource.joinToString("."))
private fun getScopedSymbolNameForTarget(actualName: String, target: Statement): MutableList<String> {
@ -546,16 +544,16 @@ internal class AsmGen(private val program: Program,
return scopedName
}
internal fun asmSymbolName(regs: RegisterOrPair): String =
fun asmSymbolName(regs: RegisterOrPair): String =
if (regs in Cx16VirtualRegisters)
"cx16." + regs.toString().lowercase()
else
throw AssemblyError("no symbol name for register $regs")
internal fun asmSymbolName(name: String) = fixNameSymbols(name)
internal fun asmVariableName(name: String) = fixNameSymbols(name)
internal fun asmSymbolName(name: Iterable<String>) = fixNameSymbols(name.joinToString("."))
internal fun asmVariableName(name: Iterable<String>) = fixNameSymbols(name.joinToString("."))
fun asmSymbolName(name: String) = fixNameSymbols(name)
fun asmVariableName(name: String) = fixNameSymbols(name)
fun asmSymbolName(name: Iterable<String>) = fixNameSymbols(name.joinToString("."))
fun asmVariableName(name: Iterable<String>) = fixNameSymbols(name.joinToString("."))
internal fun loadByteFromPointerIntoA(pointervar: IdentifierReference): String {

View File

@ -10,11 +10,11 @@ import prog8.ast.statements.DirectMemoryWrite
import prog8.ast.statements.FunctionCallStatement
import prog8.ast.statements.Subroutine
import prog8.ast.toHex
import prog8.compiler.AssemblyError
import prog8.compilerinterface.CpuType
import prog8.compiler.functions.FSignature
import prog8.compiler.target.AssemblyError
import prog8.compiler.target.Cx16Target
import prog8.compiler.target.cpu6502.codegen.assignment.*
import prog8.compilerinterface.FSignature
import prog8.compilerinterface.subroutineFloatEvalResultVar2
internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen, private val assignAsmGen: AssignmentAsmGen) {
@ -1532,7 +1532,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
AsmAssignSource.fromAstSource(value, program, asmgen)
}
}
val tgt = AsmAssignTarget.fromRegisters(conv.reg, null, program, asmgen)
val tgt = AsmAssignTarget.fromRegisters(conv.reg!!, null, program, asmgen)
val assign = AsmAssignment(src, tgt, false, program.memsizer, value.position)
asmgen.translateNormalAssignment(assign)
}

View File

@ -7,9 +7,9 @@ import prog8.ast.statements.ArrayIndex
import prog8.ast.statements.BuiltinFunctionStatementPlaceholder
import prog8.ast.statements.Subroutine
import prog8.ast.toHex
import prog8.compiler.AssemblyError
import prog8.compilerinterface.CpuType
import prog8.compiler.functions.BuiltinFunctions
import prog8.compiler.target.AssemblyError
import prog8.compilerinterface.BuiltinFunctions
import prog8.compilerinterface.subroutineFloatEvalResultVar1
import kotlin.math.absoluteValue

View File

@ -8,7 +8,7 @@ import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.RangeExpr
import prog8.ast.statements.ForLoop
import prog8.ast.toHex
import prog8.compiler.AssemblyError
import prog8.compiler.target.AssemblyError
import prog8.compilerinterface.toConstantIntegerRange
import kotlin.math.absoluteValue

View File

@ -9,7 +9,7 @@ import prog8.ast.statements.InlineAssembly
import prog8.ast.statements.RegisterOrStatusflag
import prog8.ast.statements.Subroutine
import prog8.ast.statements.SubroutineParameter
import prog8.compiler.AssemblyError
import prog8.compiler.target.AssemblyError
import prog8.compilerinterface.CpuType
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignSource
import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignTarget

View File

@ -6,7 +6,7 @@ import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.PostIncrDecr
import prog8.ast.toHex
import prog8.compiler.AssemblyError
import prog8.compiler.target.AssemblyError
internal class PostIncrDecrAsmGen(private val program: Program, private val asmgen: AsmGen) {

View File

@ -4,8 +4,8 @@ import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.compiler.AssemblyError
import prog8.compiler.IMemSizer
import prog8.compiler.target.AssemblyError
import prog8.compiler.target.cpu6502.codegen.AsmGen
@ -61,9 +61,9 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
throw AssemblyError("unknown dt")
val dt = idt.getOr(DataType.UNDEFINED)
when {
identifier != null -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, assign.definingSubroutine, variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this)
arrayindexed != null -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, dt, assign.definingSubroutine, array = arrayindexed, origAstTarget = this)
memoryAddress != null -> AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, dt, assign.definingSubroutine, memory = memoryAddress, origAstTarget = this)
identifier != null -> AsmAssignTarget(prog8.compiler.target.cpu6502.codegen.assignment.TargetStorageKind.VARIABLE, program, asmgen, dt, assign.definingSubroutine, variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this)
arrayindexed != null -> AsmAssignTarget(prog8.compiler.target.cpu6502.codegen.assignment.TargetStorageKind.ARRAY, program, asmgen, dt, assign.definingSubroutine, array = arrayindexed, origAstTarget = this)
memoryAddress != null -> AsmAssignTarget(prog8.compiler.target.cpu6502.codegen.assignment.TargetStorageKind.MEMORY, program, asmgen, dt, assign.definingSubroutine, memory = memoryAddress, origAstTarget = this)
else -> throw AssemblyError("weird target")
}
}

View File

@ -5,12 +5,12 @@ import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.toHex
import prog8.compiler.AssemblyError
import prog8.compiler.target.AssemblyError
import prog8.compilerinterface.CpuType
import prog8.compiler.functions.BuiltinFunctions
import prog8.compiler.functions.builtinFunctionReturnType
import prog8.compiler.target.cpu6502.codegen.AsmGen
import prog8.compiler.target.cpu6502.codegen.ExpressionsAsmGen
import prog8.compilerinterface.BuiltinFunctions
import prog8.compilerinterface.builtinFunctionReturnType
internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen,
@ -21,7 +21,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
fun translate(assignment: Assignment) {
val target = AsmAssignTarget.fromAstAssignment(assignment, program, asmgen)
val source = AsmAssignSource.fromAstSource(assignment.value, program, asmgen).adjustSignedUnsigned(target)
val source = AsmAssignSource.Companion.fromAstSource(assignment.value, program, asmgen).adjustSignedUnsigned(target)
val assign = AsmAssignment(source, target, assignment.isAugmentable, program.memsizer, assignment.position)
target.origAssign = assign
@ -1363,7 +1363,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
// these will be correctly typecasted from a byte to a word value
if(target.register !in Cx16VirtualRegisters &&
target.register!=RegisterOrPair.AX && target.register!=RegisterOrPair.AY && target.register!=RegisterOrPair.XY) {
if(target.kind==TargetStorageKind.VARIABLE) {
if(target.kind== TargetStorageKind.VARIABLE) {
val parts = target.asmVarname.split('.')
if (parts.size != 2 || parts[0] != "cx16")
require(target.datatype in ByteDatatypes)
@ -2158,14 +2158,14 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
}
internal fun assignExpressionToRegister(expr: Expression, register: RegisterOrPair) {
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
val src = AsmAssignSource.Companion.fromAstSource(expr, program, asmgen)
val tgt = AsmAssignTarget.fromRegisters(register, null, program, asmgen)
val assign = AsmAssignment(src, tgt, false, program.memsizer, expr.position)
translateNormalAssignment(assign)
}
internal fun assignExpressionToVariable(expr: Expression, asmVarName: String, dt: DataType, scope: Subroutine?) {
val src = AsmAssignSource.fromAstSource(expr, program, asmgen)
val src = AsmAssignSource.Companion.fromAstSource(expr, program, asmgen)
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, scope, variableAsmName = asmVarName)
val assign = AsmAssignment(src, tgt, false, program.memsizer, expr.position)
translateNormalAssignment(assign)

View File

@ -5,7 +5,7 @@ import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.Subroutine
import prog8.ast.toHex
import prog8.compiler.AssemblyError
import prog8.compiler.target.AssemblyError
import prog8.compilerinterface.CpuType
import prog8.compiler.target.cpu6502.codegen.AsmGen
import prog8.compiler.target.cpu6502.codegen.ExpressionsAsmGen
@ -246,19 +246,37 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
indexVar!=null -> {
when (target.datatype) {
in ByteDatatypes -> {
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.A, null, program, asmgen)
val tgt =
prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignTarget.fromRegisters(
RegisterOrPair.A,
null,
program,
asmgen
)
val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position)
assignmentAsmGen.translateNormalAssignment(assign)
assignmentAsmGen.assignRegisterByte(target, CpuRegister.A)
}
in WordDatatypes -> {
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.AY, null, program, asmgen)
val tgt =
prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignTarget.fromRegisters(
RegisterOrPair.AY,
null,
program,
asmgen
)
val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position)
assignmentAsmGen.translateNormalAssignment(assign)
assignmentAsmGen.assignRegisterpairWord(target, RegisterOrPair.AY)
}
DataType.FLOAT -> {
val tgt = AsmAssignTarget.fromRegisters(RegisterOrPair.FAC1, null, program, asmgen)
val tgt =
prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignTarget.fromRegisters(
RegisterOrPair.FAC1,
null,
program,
asmgen
)
val assign = AsmAssignment(target.origAssign.source, tgt, false, program.memsizer, value.position)
assignmentAsmGen.translateNormalAssignment(assign)
assignmentAsmGen.assignFAC1float(target)

View File

@ -8,7 +8,7 @@ import java.io.IOException
import java.nio.file.Path
internal object CX16MachineDefinition: IMachineDefinition {
object CX16MachineDefinition: IMachineDefinition {
override val cpu = CpuType.CPU65c02
@ -88,7 +88,7 @@ internal object CX16MachineDefinition: IMachineDefinition {
"rmb", "smb", "stp", "wai")
internal class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
override val SCRATCH_B1 = 0x7a // temp storage for a single byte
override val SCRATCH_REG = 0x7b // temp storage for a register, must be B1+1

View File

@ -0,0 +1,21 @@
package prog8tests
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlin.test.fail
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestCodeGeneration {
@Test
@Disabled("for future implementation")
fun dummy() {
fail("dummy")
}
}

View File

@ -9,6 +9,7 @@ import prog8.ast.expressions.TypecastExpression
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compilerinterface.CallGraph
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
import prog8.compilerinterface.isInRegularRAMof

View File

@ -21,6 +21,7 @@ dependencies {
implementation project(':compilerInterfaces')
implementation project(':codeOptimizers')
implementation project(':compilerAst')
implementation project(':codeGeneration')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
// implementation "org.jetbrains.kotlin:kotlin-reflect"
implementation 'org.jetbrains.kotlinx:kotlinx-cli:0.3.3'

View File

@ -24,5 +24,6 @@
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
<orderEntry type="module" module-name="codeOptimizers" />
<orderEntry type="module" module-name="compilerInterfaces" />
<orderEntry type="module" module-name="codeGeneration" />
</component>
</module>

View File

@ -1,3 +0,0 @@
package prog8.compiler
internal class AssemblyError(msg: String) : RuntimeException(msg)

View File

@ -10,7 +10,6 @@ import prog8.ast.expressions.Expression
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.Directive
import prog8.compiler.astprocessing.*
import prog8.compiler.functions.*
import prog8.compiler.target.C64Target
import prog8.compiler.target.Cx16Target
import prog8.compiler.target.cpu6502.codegen.AsmGen
@ -18,12 +17,8 @@ import prog8.compilerinterface.*
import prog8.optimizer.*
import prog8.parser.ParseError
import prog8.parser.ParsingFailedError
import prog8.parser.SourceCode
import prog8.parser.SourceCode.Companion.libraryFilePrefix
import java.io.File
import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.isRegularFile
import kotlin.io.path.nameWithoutExtension
import kotlin.system.measureTimeMillis
@ -351,20 +346,6 @@ fun printAst(programAst: Program) {
println()
}
internal fun loadAsmIncludeFile(filename: String, source: SourceCode): Result<String, NoSuchFileException> {
return if (filename.startsWith(libraryFilePrefix)) {
return runCatching {
SourceCode.Resource("/prog8lib/${filename.substring(libraryFilePrefix.length)}").readText()
}.mapError { NoSuchFileException(File(filename)) }
} else {
val sib = Path(source.origin).resolveSibling(filename)
if (sib.isRegularFile())
Ok(SourceCode.File(sib).readText())
else
Ok(SourceCode.File(Path(filename)).readText())
}
}
internal fun asmGeneratorFor(
compTarget: ICompilationTarget,
program: Program,

View File

@ -1,48 +0,0 @@
package prog8.compiler
import prog8.ast.base.Position
import prog8.compilerinterface.IErrorReporter
internal class ErrorReporter: IErrorReporter {
private enum class MessageSeverity {
WARNING,
ERROR
}
private class CompilerMessage(val severity: MessageSeverity, val message: String, val position: Position)
private val messages = mutableListOf<CompilerMessage>()
private val alreadyReportedMessages = mutableSetOf<String>()
override fun err(msg: String, position: Position) {
messages.add(CompilerMessage(MessageSeverity.ERROR, msg, position))
}
override fun warn(msg: String, position: Position) {
messages.add(CompilerMessage(MessageSeverity.WARNING, msg, position))
}
override fun report() {
var numErrors = 0
var numWarnings = 0
messages.forEach {
when(it.severity) {
MessageSeverity.ERROR -> System.err.print("\u001b[91m") // bright red
MessageSeverity.WARNING -> System.err.print("\u001b[93m") // bright yellow
}
val msg = "${it.position.toClickableStr()} ${it.severity} ${it.message}".trim()
if(msg !in alreadyReportedMessages) {
System.err.println(msg)
alreadyReportedMessages.add(msg)
when(it.severity) {
MessageSeverity.WARNING -> numWarnings++
MessageSeverity.ERROR -> numErrors++
}
}
System.err.print("\u001b[0m") // reset color
}
messages.clear()
finalizeNumErrors(numErrors, numWarnings)
}
override fun noErrors() = messages.none { it.severity==MessageSeverity.ERROR }
}

View File

@ -8,12 +8,7 @@ import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
import prog8.compilerinterface.ZeropageType
import prog8.compiler.functions.BuiltinFunctions
import prog8.compiler.functions.builtinFunctionReturnType
import prog8.compilerinterface.*
import java.io.CharConversionException
import java.io.File
import java.util.*

View File

@ -4,9 +4,9 @@ import prog8.ast.base.Position
import prog8.ast.expressions.StringLiteralValue
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.compilerinterface.BuiltinFunctions
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
import prog8.compiler.functions.BuiltinFunctions
internal class AstIdentifiersChecker(private val errors: IErrorReporter, private val compTarget: ICompilationTarget) : IAstVisitor {
private var blocks = mutableMapOf<String, Block>()

View File

@ -10,8 +10,8 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compilerinterface.BuiltinFunctions
import prog8.compilerinterface.IErrorReporter
import prog8.compiler.functions.BuiltinFunctions
internal class StatementReorderer(val program: Program, val errors: IErrorReporter) : AstWalker() {

View File

@ -8,8 +8,8 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compilerinterface.BuiltinFunctions
import prog8.compilerinterface.IErrorReporter
import prog8.compiler.functions.BuiltinFunctions
class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalker() {

View File

@ -8,8 +8,8 @@ import prog8.ast.expressions.FunctionCall
import prog8.ast.expressions.TypecastExpression
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.compilerinterface.BuiltinFunctions
import prog8.compilerinterface.CompilerException
import prog8.compiler.functions.BuiltinFunctions
class VerifyFunctionArgTypes(val program: Program) : IAstVisitor {

View File

@ -14,19 +14,17 @@ import prog8.ast.expressions.AddressOf
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.*
import prog8.compiler.*
import prog8.compiler.target.C64Target
import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.cpu6502.codegen.AsmGen
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.LauncherType
import prog8.compilerinterface.OutputType
import prog8.compilerinterface.ZeropageType
import prog8.compilerinterface.*
import prog8.parser.SourceCode
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.ast.helpers.DummyFunctions
import prog8tests.ast.helpers.DummyMemsizer
import java.nio.file.Path
// TODO move to codegen project, readjust symbol protection levels
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestAsmGen6502 {

View File

@ -13,6 +13,7 @@ import prog8.compilerinterface.IErrorReporter
import prog8.compiler.ModuleImporter
import prog8.parser.ParseError
import prog8.parser.SourceCode
import prog8tests.ast.helpers.*
import prog8tests.helpers.*
import kotlin.io.path.*
import kotlin.test.assertContains

View File

@ -5,7 +5,7 @@ import org.junit.jupiter.api.TestInstance
import prog8.ast.statements.Block
import prog8.ast.statements.Subroutine
import prog8.compiler.target.C64Target
import prog8.optimizer.CallGraph
import prog8.compilerinterface.CallGraph
import prog8tests.helpers.assertSuccess
import prog8tests.helpers.compileText
import kotlin.test.assertEquals

View File

@ -8,6 +8,10 @@ import prog8.compilerinterface.ICompilationTarget
import prog8.compiler.compileProgram
import prog8.compiler.target.C64Target
import prog8.compiler.target.Cx16Target
import prog8tests.ast.helpers.assumeDirectory
import prog8tests.ast.helpers.mapCombinations
import prog8tests.ast.helpers.outputDir
import prog8tests.ast.helpers.workingDir
import prog8tests.helpers.*
import kotlin.io.path.absolute
import kotlin.io.path.exists

View File

@ -8,6 +8,7 @@ import prog8.ast.expressions.StringLiteralValue
import prog8.ast.statements.FunctionCallStatement
import prog8.ast.statements.Label
import prog8.compiler.target.Cx16Target
import prog8tests.ast.helpers.*
import prog8tests.helpers.*
import kotlin.io.path.name
import kotlin.test.assertEquals

View File

@ -13,6 +13,7 @@ import prog8.compilerinterface.size
import prog8.compiler.target.C64Target
import prog8.compiler.target.Cx16Target
import prog8.compilerinterface.toConstantIntegerRange
import prog8tests.ast.helpers.mapCombinations
import prog8tests.helpers.*
import kotlin.test.assertContains
import kotlin.test.assertEquals

View File

@ -6,6 +6,10 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import prog8.compiler.compileProgram
import prog8.compiler.target.Cx16Target
import prog8tests.ast.helpers.assumeReadableFile
import prog8tests.ast.helpers.fixturesDir
import prog8tests.ast.helpers.outputDir
import prog8tests.ast.helpers.workingDir
import prog8tests.helpers.*
import java.nio.file.Path
import kotlin.io.path.absolute

View File

@ -3,14 +3,14 @@ package prog8tests
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import prog8.ast.internedStringsModuleName
import prog8.compiler.ErrorReporter
import prog8.compilerinterface.ZeropageType
import prog8.compiler.determineCompilationOptions
import prog8.compiler.parseImports
import prog8.compiler.target.C64Target
import prog8.compilerinterface.ErrorReporter
import prog8tests.ast.helpers.outputDir
import prog8tests.helpers.assertSuccess
import prog8tests.helpers.compileText
import prog8tests.helpers.outputDir
import kotlin.test.assertEquals
import kotlin.test.assertTrue

View File

@ -15,8 +15,8 @@ import prog8.ast.statements.*
import prog8.compilerinterface.isInRegularRAMof
import prog8.compiler.target.C64Target
import prog8.parser.SourceCode
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.ast.helpers.DummyFunctions
import prog8tests.ast.helpers.DummyMemsizer
import kotlin.test.assertFalse
import kotlin.test.assertTrue

View File

@ -3,7 +3,6 @@ package prog8tests
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import prog8.ast.base.DataType
import prog8.compiler.*
import prog8.compiler.target.C64Target
import prog8.compiler.target.Cx16Target
import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage

View File

@ -1,8 +1,11 @@
package prog8tests.helpers
import prog8.compiler.*
import prog8.compilerinterface.ErrorReporter
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
import prog8tests.ast.helpers.assumeReadableFile
import prog8tests.ast.helpers.outputDir
import java.nio.file.Path
import kotlin.io.path.name
import kotlin.test.assertFalse
@ -28,7 +31,7 @@ internal fun compileFile(
optimize: Boolean,
fileDir: Path,
fileName: String,
outputDir: Path = prog8tests.helpers.outputDir,
outputDir: Path = prog8tests.ast.helpers.outputDir,
errors: IErrorReporter? = null,
writeAssembly: Boolean = true
) : CompilationResult {

View File

@ -1,4 +1,4 @@
package prog8tests
package prog8tests.ast
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
@ -9,8 +9,8 @@ import prog8.ast.internedStringsModuleName
import prog8.parser.ParseError
import prog8.parser.Prog8Parser.parseModule
import prog8.parser.SourceCode
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.ast.helpers.DummyFunctions
import prog8tests.ast.helpers.DummyMemsizer
import kotlin.test.assertContains

View File

@ -1,4 +1,4 @@
package prog8tests
package prog8tests.ast
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
@ -16,9 +16,9 @@ import prog8.ast.statements.*
import prog8.parser.ParseError
import prog8.parser.Prog8Parser.parseModule
import prog8.parser.SourceCode
import prog8tests.helpers.assumeNotExists
import prog8tests.helpers.assumeReadableFile
import prog8tests.helpers.fixturesDir
import prog8tests.ast.helpers.assumeNotExists
import prog8tests.ast.helpers.assumeReadableFile
import prog8tests.ast.helpers.fixturesDir
import kotlin.io.path.Path
import kotlin.io.path.isRegularFile
import kotlin.io.path.name

View File

@ -1,4 +1,4 @@
package prog8tests
package prog8tests.ast
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.StringStartsWith
@ -6,10 +6,10 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import prog8.parser.SourceCode
import prog8.parser.SourceCode.Companion.libraryFilePrefix
import prog8tests.helpers.assumeNotExists
import prog8tests.helpers.assumeReadableFile
import prog8tests.helpers.fixturesDir
import prog8tests.helpers.resourcesDir
import prog8tests.ast.helpers.assumeNotExists
import prog8tests.ast.helpers.assumeReadableFile
import prog8tests.ast.helpers.fixturesDir
import prog8tests.ast.helpers.resourcesDir
import kotlin.io.path.Path
import kotlin.test.*

View File

@ -1,4 +1,4 @@
package prog8tests
package prog8tests.ast
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance

View File

@ -1,4 +1,4 @@
package prog8tests.ast
package prog8tests.ast.ast
import org.hamcrest.MatcherAssert.assertThat
@ -12,8 +12,8 @@ import prog8.ast.Program
import prog8.ast.base.Position
import prog8.ast.internedStringsModuleName
import prog8.parser.SourceCode
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.ast.helpers.DummyFunctions
import prog8tests.ast.helpers.DummyMemsizer
import kotlin.test.assertContains
import kotlin.test.assertFailsWith
import kotlin.test.assertSame

View File

@ -1,4 +1,4 @@
package prog8tests.helpers
package prog8tests.ast.helpers
import prog8.ast.IBuiltinFunctions
import prog8.ast.base.Position

View File

@ -1,4 +1,4 @@
package prog8tests.helpers
package prog8tests.ast.helpers
import prog8.ast.base.DataType
import prog8.compiler.IMemSizer

View File

@ -1,4 +1,4 @@
package prog8tests.helpers
package prog8tests.ast.helpers
fun <A, B, R> mapCombinations(dim1: Iterable<A>, dim2: Iterable<B>, combine2: (A, B) -> R) =
sequence {

View File

@ -1,4 +1,4 @@
package prog8tests.helpers
package prog8tests.ast.helpers
import java.nio.file.Path
import kotlin.io.path.*

View File

@ -1,11 +1,11 @@
package prog8tests
package prog8tests.ast
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.`is`
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import prog8tests.helpers.*
import prog8tests.ast.helpers.*
import kotlin.io.path.Path
import kotlin.io.path.div
import kotlin.test.assertFailsWith

View File

@ -1,14 +1,12 @@
package prog8.compiler.functions
package prog8.compilerinterface
import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.VarDecl
import prog8.compilerinterface.CompilerException
import prog8.compiler.IMemSizer
import kotlin.math.*
class FParam(val name: String, val possibleDatatypes: Array<DataType>)
@ -27,11 +25,11 @@ class CallConvention(val params: List<ParamConvention>, val returns: ReturnConve
}
}
val returnConv =
when {
returns.reg!=null -> returns.reg.toString()
returns.floatFac1 -> "floatFAC1"
else -> "<no returnvalue>"
}
when {
returns.reg!=null -> returns.reg.toString()
returns.floatFac1 -> "floatFAC1"
else -> "<no returnvalue>"
}
return "CallConvention[" + paramConvs.joinToString() + " ; returns: $returnConv]"
}
}
@ -52,7 +50,7 @@ class FSignature(val name: String,
else -> {
val paramType = actualParamTypes.first()
if(pure)
// return type depends on arg type
// return type depends on arg type
when(paramType) {
DataType.UBYTE, DataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A, false)
DataType.UWORD, DataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY, false)
@ -87,9 +85,12 @@ class FSignature(val name: String,
}
}
@Suppress("UNUSED_ANONYMOUS_PARAMETER")
private val functionSignatures: List<FSignature> = listOf(
// this set of function have no return value and operate in-place:
// this set of function have no return value and operate in-place:
FSignature("rol" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
FSignature("ror" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
FSignature("rol2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
@ -97,14 +98,14 @@ private val functionSignatures: List<FSignature> = listOf(
FSignature("sort" , false, listOf(FParam("array", ArrayDatatypes)), null),
FSignature("reverse" , false, listOf(FParam("array", ArrayDatatypes)), null),
FSignature("cmp" , false, listOf(FParam("value1", IntegerDatatypes), FParam("value2", NumericDatatypes)), null),
// these few have a return value depending on the argument(s):
// these few have a return value depending on the argument(s):
FSignature("max" , true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg, ct -> collectionArg(a, p, prg, ::builtinMax) }, // type depends on args
FSignature("min" , true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg, ct -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args
FSignature("sum" , true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg, ct -> collectionArg(a, p, prg, ::builtinSum) }, // type depends on args
FSignature("abs" , true, listOf(FParam("value", NumericDatatypes)), null, ::builtinAbs), // type depends on argument
FSignature("len" , true, listOf(FParam("values", IterableDatatypes)), null, ::builtinLen), // type is UBYTE or UWORD depending on actual length
FSignature("sizeof" , true, listOf(FParam("object", DataType.values())), DataType.UBYTE, ::builtinSizeof),
// normal functions follow:
// normal functions follow:
FSignature("sgn" , true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE, ::builtinSgn ),
FSignature("sin" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::sin) },
FSignature("sin8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.BYTE, ::builtinSin8 ),
@ -144,7 +145,7 @@ private val functionSignatures: List<FSignature> = listOf(
FSignature("callfar" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null),
FSignature("callrom" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null),
)
)
val BuiltinFunctions = functionSignatures.associateBy { it.name }
@ -297,7 +298,7 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
val dt = args[0].inferType(program)
if(dt.isKnown) {
val target = (args[0] as IdentifierReference).targetStatement(program)
?: throw CannotEvaluateException("sizeof", "no target")
?: throw CannotEvaluateException("sizeof", "no target")
return when {
dt.isArray -> {
@ -328,7 +329,7 @@ private fun builtinLen(args: List<Expression>, position: Position, program: Prog
if(args[0] !is IdentifierReference)
throw SyntaxError("len argument should be an identifier", position)
val target = (args[0] as IdentifierReference).targetVarDecl(program)
?: throw CannotEvaluateException("len", "no target vardecl")
?: throw CannotEvaluateException("len", "no target vardecl")
return when(target.datatype) {
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F -> {
@ -440,10 +441,10 @@ private fun builtinSgn(args: List<Expression>, position: Position, program: Prog
private fun numericLiteral(value: Number, position: Position): NumericLiteralValue {
val floatNum=value.toDouble()
val tweakedValue: Number =
if(floatNum== floor(floatNum) && (floatNum>=-32768 && floatNum<=65535))
floatNum.toInt() // we have an integer disguised as a float.
else
floatNum
if(floatNum== floor(floatNum) && (floatNum>=-32768 && floatNum<=65535))
floatNum.toInt() // we have an integer disguised as a float.
else
floatNum
return when(tweakedValue) {
is Int -> NumericLiteralValue.optimalInteger(value.toInt(), position)

View File

@ -1,4 +1,4 @@
package prog8.optimizer
package prog8.compilerinterface
import prog8.ast.Module
import prog8.ast.Node
@ -10,7 +10,6 @@ import prog8.ast.expressions.FunctionCall
import prog8.ast.expressions.IdentifierReference
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.compilerinterface.IErrorReporter
class CallGraph(private val program: Program) : IAstVisitor {

View File

@ -14,3 +14,47 @@ interface IErrorReporter {
throw ParsingFailedError("There are $numErrors errors and $numWarnings warnings.")
}
}
class ErrorReporter: IErrorReporter {
private enum class MessageSeverity {
WARNING,
ERROR
}
private class CompilerMessage(val severity: MessageSeverity, val message: String, val position: Position)
private val messages = mutableListOf<CompilerMessage>()
private val alreadyReportedMessages = mutableSetOf<String>()
override fun err(msg: String, position: Position) {
messages.add(CompilerMessage(MessageSeverity.ERROR, msg, position))
}
override fun warn(msg: String, position: Position) {
messages.add(CompilerMessage(MessageSeverity.WARNING, msg, position))
}
override fun report() {
var numErrors = 0
var numWarnings = 0
messages.forEach {
when(it.severity) {
MessageSeverity.ERROR -> System.err.print("\u001b[91m") // bright red
MessageSeverity.WARNING -> System.err.print("\u001b[93m") // bright yellow
}
val msg = "${it.position.toClickableStr()} ${it.severity} ${it.message}".trim()
if(msg !in alreadyReportedMessages) {
System.err.println(msg)
alreadyReportedMessages.add(msg)
when(it.severity) {
MessageSeverity.WARNING -> numWarnings++
MessageSeverity.ERROR -> numErrors++
}
}
System.err.print("\u001b[0m") // reset color
}
messages.clear()
finalizeNumErrors(numErrors, numWarnings)
}
override fun noErrors() = messages.none { it.severity==MessageSeverity.ERROR }
}

View File

@ -1,4 +1,4 @@
package prog8tests
package prog8tests.interfaces
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance

View File

@ -1,4 +1,4 @@
package prog8tests
package prog8tests.interfaces
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance

View File

@ -26,7 +26,6 @@ Future
- add a flood fill routine to gfx2?
- add a diskio.f_seek() routine for the Cx16 that uses its seek dos api?
- make it possible for diskio to read and write from more than one file at the same time (= use multiple io channels)?
- refactor the asmgen into own project submodule
- make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``v_``
- [problematic due to 64tass:] add a compiler option to not remove unused subroutines. this allows for building library programs. But this won't work with 64tass's .proc ...
Perhaps replace all uses of .proc/.pend by .block/.bend will fix that?

View File

@ -2,6 +2,7 @@ include ':parser'
include ':compilerInterfaces'
include ':compilerAst'
include ':codeOptimizers'
include ':codeGeneration'
include ':compiler'
include ':dbusCompilerService'
include ':httpCompilerService'