split out the code optimizers into own project submodule

This commit is contained in:
Irmen de Jong 2021-10-29 02:42:10 +02:00
parent 2c940de598
commit f21dcaa6fb
75 changed files with 575 additions and 360 deletions

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Kotlin2JvmCompilerArguments">
<option name="jvmTarget" value="11" />
</component>
</project>

View File

@ -0,0 +1,15 @@
<component name="libraryTable">
<library name="KotlinJavaRuntime (2)">
<CLASSES>
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib.jar!/" />
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-reflect.jar!/" />
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-test.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-sources.jar!/" />
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-reflect-sources.jar!/" />
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-test-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -0,0 +1,15 @@
<component name="libraryTable">
<library name="KotlinJavaRuntime (3)">
<CLASSES>
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib.jar!/" />
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-reflect.jar!/" />
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-test.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-sources.jar!/" />
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-reflect-sources.jar!/" />
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-test-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@ -2,8 +2,10 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<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" />
<module fileurl="file://$PROJECT_DIR$/compilerInterfaces/compilerInterfaces.iml" filepath="$PROJECT_DIR$/compilerInterfaces/compilerInterfaces.iml" />
<module fileurl="file://$PROJECT_DIR$/dbusCompilerService/dbusCompilerService.iml" filepath="$PROJECT_DIR$/dbusCompilerService/dbusCompilerService.iml" />
<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" />

View File

@ -0,0 +1,66 @@
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"
}
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,14 @@
<?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="jdk" jdkName="openjdk-11" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime (2)" level="project" />
<orderEntry type="module" module-name="compilerInterfaces" />
<orderEntry type="module" module-name="compilerAst" />
</component>
</module>

View File

@ -9,11 +9,11 @@ import prog8.ast.statements.AssignTarget
import prog8.ast.statements.Assignment
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compiler.astprocessing.isInRegularRAMof
import prog8.compiler.target.ICompilationTarget
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.isInRegularRAMof
internal class BinExprSplitter(private val program: Program, private val compTarget: ICompilationTarget) : AstWalker() {
class BinExprSplitter(private val program: Program, private val compTarget: ICompilationTarget) : AstWalker() {
// override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
// TODO somehow if we do this, the resulting code for some programs (cube3d.p8) gets hundreds of bytes larger...:

View File

@ -10,7 +10,7 @@ import prog8.ast.expressions.FunctionCall
import prog8.ast.expressions.IdentifierReference
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.compiler.IErrorReporter
import prog8.compilerinterface.IErrorReporter
class CallGraph(private val program: Program) : IAstVisitor {

View File

@ -12,7 +12,7 @@ import prog8.ast.walk.IAstModification
import kotlin.math.pow
internal class ConstantFoldingOptimizer(private val program: Program) : AstWalker() {
class ConstantFoldingOptimizer(private val program: Program) : AstWalker() {
override fun before(memread: DirectMemoryRead, parent: Node): Iterable<IAstModification> {
// @( &thing ) --> thing

View File

@ -7,14 +7,14 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compiler.IErrorReporter
import prog8.compiler.astprocessing.size
import prog8.compiler.astprocessing.toConstantIntegerRange
import prog8.compiler.target.ICompilationTarget
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
import prog8.compilerinterface.size
import prog8.compilerinterface.toConstantIntegerRange
// Fix up the literal value's type to match that of the vardecl
// (also check range literal operands types before they get expanded into arrays for instance)
internal class VarConstantValueTypeAdjuster(private val program: Program, private val errors: IErrorReporter) : AstWalker() {
class VarConstantValueTypeAdjuster(private val program: Program, private val errors: IErrorReporter) : AstWalker() {
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {

View File

@ -22,7 +22,7 @@ import kotlin.math.pow
*/
internal class ExpressionSimplifier(private val program: Program) : AstWalker() {
class ExpressionSimplifier(private val program: Program) : AstWalker() {
private val powersOfTwo = (1..16).map { (2.0).pow(it) }.toSet()
private val negativePowersOfTwo = powersOfTwo.map { -it }.toSet()

View File

@ -2,11 +2,11 @@ package prog8.optimizer
import prog8.ast.IBuiltinFunctions
import prog8.ast.Program
import prog8.compiler.IErrorReporter
import prog8.compiler.target.ICompilationTarget
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
internal fun Program.constantFold(errors: IErrorReporter, compTarget: ICompilationTarget) {
fun Program.constantFold(errors: IErrorReporter, compTarget: ICompilationTarget) {
val valuetypefixer = VarConstantValueTypeAdjuster(this, errors)
valuetypefixer.visit(this)
if(errors.noErrors()) {
@ -40,9 +40,10 @@ internal fun Program.constantFold(errors: IErrorReporter, compTarget: ICompilati
}
internal fun Program.optimizeStatements(errors: IErrorReporter,
functions: IBuiltinFunctions,
compTarget: ICompilationTarget): Int {
fun Program.optimizeStatements(errors: IErrorReporter,
functions: IBuiltinFunctions,
compTarget: ICompilationTarget
): Int {
val optimizer = StatementOptimizer(this, errors, functions, compTarget)
optimizer.visit(this)
val optimizationCount = optimizer.applyModifications()
@ -52,13 +53,13 @@ internal fun Program.optimizeStatements(errors: IErrorReporter,
return optimizationCount
}
internal fun Program.simplifyExpressions() : Int {
fun Program.simplifyExpressions() : Int {
val opti = ExpressionSimplifier(this)
opti.visit(this)
return opti.applyModifications()
}
internal fun Program.splitBinaryExpressions(compTarget: ICompilationTarget) : Int {
fun Program.splitBinaryExpressions(compTarget: ICompilationTarget) : Int {
val opti = BinExprSplitter(this, compTarget)
opti.visit(this)
return opti.applyModifications()

View File

@ -10,18 +10,19 @@ import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.ast.walk.IAstVisitor
import prog8.compiler.IErrorReporter
import prog8.compiler.astprocessing.size
import prog8.compiler.target.ICompilationTarget
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
import prog8.compilerinterface.size
import kotlin.math.floor
internal const val retvarName = "prog8_retval"
internal class StatementOptimizer(private val program: Program,
class StatementOptimizer(private val program: Program,
private val errors: IErrorReporter,
private val functions: IBuiltinFunctions,
private val compTarget: ICompilationTarget) : AstWalker() {
private val compTarget: ICompilationTarget
) : AstWalker() {
private val subsThatNeedReturnVariable = mutableSetOf<Triple<IStatementContainer, DataType, Position>>()

View File

@ -9,14 +9,15 @@ import prog8.ast.expressions.TypecastExpression
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compiler.IErrorReporter
import prog8.compiler.astprocessing.isInRegularRAMof
import prog8.compiler.target.ICompilationTarget
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
import prog8.compilerinterface.isInRegularRAMof
internal class UnusedCodeRemover(private val program: Program,
private val errors: IErrorReporter,
private val compTarget: ICompilationTarget): AstWalker() {
class UnusedCodeRemover(private val program: Program,
private val errors: IErrorReporter,
private val compTarget: ICompilationTarget
): AstWalker() {
private val callgraph = CallGraph(program)

View File

@ -18,6 +18,8 @@ repositories {
def prog8version = rootProject.file('compiler/res/version.txt').text.trim()
dependencies {
implementation project(':compilerInterfaces')
implementation project(':codeOptimizers')
implementation project(':compilerAst')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
// implementation "org.jetbrains.kotlin:kotlin-reflect"

View File

@ -22,5 +22,7 @@
<orderEntry type="library" name="jetbrains.kotlinx.cli.jvm" level="project" />
<orderEntry type="library" name="junit.jupiter" level="project" />
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
<orderEntry type="module" module-name="codeOptimizers" />
<orderEntry type="module" module-name="compilerInterfaces" />
</component>
</module>

View File

@ -10,9 +10,11 @@ import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.ast.walk.IAstVisitor
import prog8.compiler.astprocessing.isInRegularRAMof
import prog8.compiler.astprocessing.isSubroutineParameter
import prog8.compiler.target.ICompilationTarget
import prog8.compilerinterface.CompilerException
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
import prog8.compilerinterface.isInRegularRAMof
internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: IErrorReporter, private val compTarget: ICompilationTarget) : AstWalker() {

View File

@ -3,7 +3,6 @@ package prog8.compiler
import com.github.michaelbull.result.*
import prog8.ast.AstToSourceTextConverter
import prog8.ast.IBuiltinFunctions
import prog8.ast.IMemSizer
import prog8.ast.Program
import prog8.ast.base.AstException
import prog8.ast.base.Position
@ -14,8 +13,8 @@ import prog8.compiler.astprocessing.*
import prog8.compiler.functions.*
import prog8.compiler.target.C64Target
import prog8.compiler.target.Cx16Target
import prog8.compiler.target.ICompilationTarget
import prog8.compiler.target.asmGeneratorFor
import prog8.compiler.target.cpu6502.codegen.AsmGen
import prog8.compilerinterface.*
import prog8.optimizer.*
import prog8.parser.ParseError
import prog8.parser.ParsingFailedError
@ -29,38 +28,6 @@ import kotlin.io.path.nameWithoutExtension
import kotlin.system.measureTimeMillis
enum class OutputType {
RAW,
PRG
}
enum class LauncherType {
BASIC,
NONE
}
enum class ZeropageType {
BASICSAFE,
FLOATSAFE,
KERNALSAFE,
FULL,
DONTUSE
}
data class CompilationOptions(val output: OutputType,
val launcher: LauncherType,
val zeropage: ZeropageType,
val zpReserved: List<IntRange>,
val floats: Boolean,
val noSysInit: Boolean,
val compTarget: ICompilationTarget) {
var slowCodegenWarnings = false
var optimize = false
}
class CompilerException(message: String?) : Exception(message)
class CompilationResult(val success: Boolean,
val programAst: Program,
val programName: String,
@ -347,7 +314,8 @@ private sealed class WriteAssemblyResult {
private fun writeAssembly(programAst: Program,
errors: IErrorReporter,
outputDir: Path,
compilerOptions: CompilationOptions): WriteAssemblyResult {
compilerOptions: CompilationOptions
): WriteAssemblyResult {
// asm generation directly from the Ast
programAst.processAstBeforeAsmGeneration(errors, compilerOptions.compTarget)
errors.report()
@ -396,3 +364,16 @@ internal fun loadAsmIncludeFile(filename: String, source: SourceCode): Result<St
Ok(SourceCode.File(Path(filename)).readText())
}
}
internal fun asmGeneratorFor(
compTarget: ICompilationTarget,
program: Program,
errors: IErrorReporter,
zp: Zeropage,
options: CompilationOptions,
outputDir: Path
): IAssemblyGenerator
{
// at the moment we only have one code generation backend (for 6502 and 65c02)
return AsmGen(program, errors, zp, options, compTarget, outputDir)
}

View File

@ -1,19 +1,7 @@
package prog8.compiler
import prog8.ast.base.Position
import prog8.parser.ParsingFailedError
interface IErrorReporter {
fun err(msg: String, position: Position)
fun warn(msg: String, position: Position)
fun noErrors(): Boolean
fun report()
fun finalizeNumErrors(numErrors: Int, numWarnings: Int) {
if(numErrors>0)
throw ParsingFailedError("There are $numErrors errors and $numWarnings warnings.")
}
}
import prog8.compilerinterface.IErrorReporter
internal class ErrorReporter: IErrorReporter {

View File

@ -7,6 +7,7 @@ import prog8.ast.base.Position
import prog8.ast.base.SyntaxError
import prog8.ast.statements.Directive
import prog8.ast.statements.DirectiveArg
import prog8.compilerinterface.IErrorReporter
import prog8.parser.Prog8Parser
import prog8.parser.SourceCode
import java.io.File

View File

@ -8,12 +8,12 @@ import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.compiler.CompilationOptions
import prog8.compiler.IErrorReporter
import prog8.compiler.ZeropageType
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.compiler.target.ICompilationTarget
import java.io.CharConversionException
import java.io.File
import java.util.*

View File

@ -3,65 +3,16 @@ package prog8.compiler.astprocessing
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.DataType
import prog8.ast.base.VarDeclType
import prog8.ast.expressions.*
import prog8.ast.statements.AssignTarget
import prog8.ast.statements.Directive
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compiler.*
import prog8.compiler.BeforeAsmGenerationAstChanger
import prog8.compiler.CompilationOptions
import prog8.compiler.IErrorReporter
import prog8.compiler.IStringEncoding
import prog8.compiler.target.ICompilationTarget
import prog8.compiler.target.IMachineDefinition
import kotlin.math.abs
fun RangeExpr.size(encoding: IStringEncoding): Int? {
val fromLv = (from as? NumericLiteralValue)
val toLv = (to as? NumericLiteralValue)
if(fromLv==null || toLv==null)
return null
return toConstantIntegerRange(encoding)?.count()
}
fun RangeExpr.toConstantIntegerRange(encoding: IStringEncoding): IntProgression? {
val fromVal: Int
val toVal: Int
val fromString = from as? StringLiteralValue
val toString = to as? StringLiteralValue
if(fromString!=null && toString!=null ) {
// string range -> int range over character values
fromVal = encoding.encodeString(fromString.value, fromString.altEncoding)[0].toInt()
toVal = encoding.encodeString(toString.value, fromString.altEncoding)[0].toInt()
} else {
val fromLv = from as? NumericLiteralValue
val toLv = to as? NumericLiteralValue
if(fromLv==null || toLv==null)
return null // non-constant range
// integer range
fromVal = fromLv.number.toInt()
toVal = toLv.number.toInt()
}
val stepVal = (step as? NumericLiteralValue)?.number?.toInt() ?: 1
return makeRange(fromVal, toVal, stepVal)
}
private fun makeRange(fromVal: Int, toVal: Int, stepVal: Int): IntProgression {
return when {
fromVal <= toVal -> when {
stepVal <= 0 -> IntRange.EMPTY
stepVal == 1 -> fromVal..toVal
else -> fromVal..toVal step stepVal
}
else -> when {
stepVal >= 0 -> IntRange.EMPTY
stepVal == -1 -> fromVal downTo toVal
else -> fromVal downTo toVal step abs(stepVal)
}
}
}
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
import prog8.compilerinterface.IStringEncoding
internal fun Program.checkValid(compilerOptions: CompilationOptions, errors: IErrorReporter, compTarget: ICompilationTarget) {
@ -143,7 +94,6 @@ internal fun Program.variousCleanups(program: Program, errors: IErrorReporter) {
process.applyModifications()
}
internal fun Program.moveMainAndStartToFirst() {
// the module containing the program entrypoint is moved to the first in the sequence.
// the "main" block containing the entrypoint is moved to the top in there,
@ -174,51 +124,6 @@ internal fun Program.moveMainAndStartToFirst() {
}
}
internal fun AssignTarget.isInRegularRAMof(machine: IMachineDefinition): Boolean {
val memAddr = memoryAddress
val arrayIdx = arrayindexed
val ident = identifier
when {
memAddr != null -> {
return when (memAddr.addressExpression) {
is NumericLiteralValue -> {
machine.isRegularRAMaddress((memAddr.addressExpression as NumericLiteralValue).number.toInt())
}
is IdentifierReference -> {
val program = definingModule.program
val decl = (memAddr.addressExpression as IdentifierReference).targetVarDecl(program)
if ((decl?.type == VarDeclType.VAR || decl?.type == VarDeclType.CONST) && decl.value is NumericLiteralValue)
machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt())
else
false
}
else -> false
}
}
arrayIdx != null -> {
val program = definingModule.program
val targetStmt = arrayIdx.arrayvar.targetVarDecl(program)
return if (targetStmt?.type == VarDeclType.MEMORY) {
val addr = targetStmt.value as? NumericLiteralValue
if (addr != null)
machine.isRegularRAMaddress(addr.number.toInt())
else
false
} else true
}
ident != null -> {
val program = definingModule.program
val decl = ident.targetVarDecl(program)!!
return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteralValue)
machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt())
else
true
}
else -> return true
}
}
internal fun IdentifierReference.isSubroutineParameter(program: Program): Boolean {
val vardecl = this.targetVarDecl(program)
if(vardecl!=null && vardecl.autogeneratedDontRemove) {

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.compiler.IErrorReporter
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
import prog8.compiler.functions.BuiltinFunctions
import prog8.compiler.target.ICompilationTarget
internal class AstIdentifiersChecker(private val errors: IErrorReporter, private val compTarget: ICompilationTarget) : IAstVisitor {
private var blocks = mutableMapOf<String, Block>()

View File

@ -10,7 +10,7 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compiler.IErrorReporter
import prog8.compilerinterface.IErrorReporter
import prog8.compiler.functions.BuiltinFunctions

View File

@ -8,7 +8,7 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compiler.IErrorReporter
import prog8.compilerinterface.IErrorReporter
import prog8.compiler.functions.BuiltinFunctions

View File

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

View File

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

View File

@ -1,11 +1,11 @@
package prog8.compiler.functions
import prog8.ast.IMemSizer
import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.VarDecl
import prog8.compiler.CompilerException
import prog8.compilerinterface.CompilerException
import prog8.compiler.IMemSizer
import kotlin.math.*

View File

@ -0,0 +1,35 @@
package prog8.compiler.target
import com.github.michaelbull.result.fold
import prog8.ast.base.ByteDatatypes
import prog8.ast.base.DataType
import prog8.ast.base.PassByReferenceDatatypes
import prog8.ast.base.WordDatatypes
import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.cbm.Petscii
import prog8.compilerinterface.*
internal object C64Target: ICompilationTarget {
override val name = "c64"
override val machine = C64MachineDefinition
override fun encodeString(str: String, altEncoding: Boolean): List<Short> {
val coded = if (altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
return coded.fold(
failure = { throw it },
success = { it }
)
}
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
override fun memorySize(dt: DataType): Int {
return when(dt) {
in ByteDatatypes -> 1
in WordDatatypes -> 2
DataType.FLOAT -> machine.FLOAT_MEM_SIZE
in PassByReferenceDatatypes -> machine.POINTER_MEM_SIZE
else -> -9999999
}
}
}

View File

@ -0,0 +1,36 @@
package prog8.compiler.target
import com.github.michaelbull.result.fold
import prog8.ast.base.ByteDatatypes
import prog8.ast.base.DataType
import prog8.ast.base.PassByReferenceDatatypes
import prog8.ast.base.WordDatatypes
import prog8.compiler.target.cbm.Petscii
import prog8.compiler.target.cx16.CX16MachineDefinition
import prog8.compilerinterface.*
internal object Cx16Target: ICompilationTarget {
override val name = "cx16"
override val machine = CX16MachineDefinition
override fun encodeString(str: String, altEncoding: Boolean): List<Short> {
val coded= if (altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
return coded.fold(
failure = { throw it },
success = { it }
)
}
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
override fun memorySize(dt: DataType): Int {
return when(dt) {
in ByteDatatypes -> 1
in WordDatatypes -> 2
DataType.FLOAT -> machine.FLOAT_MEM_SIZE
in PassByReferenceDatatypes -> machine.POINTER_MEM_SIZE
else -> -9999999
}
}
}

View File

@ -1,17 +0,0 @@
package prog8.compiler.target
import prog8.compiler.CompilationOptions
internal interface IAssemblyGenerator {
fun compileToAssembly(): IAssemblyProgram
}
internal const val generatedLabelPrefix = "_prog8_label_"
internal const val subroutineFloatEvalResultVar1 = "_prog8_float_eval_result1"
internal const val subroutineFloatEvalResultVar2 = "_prog8_float_eval_result2"
internal interface IAssemblyProgram {
val valid: Boolean
val name: String
fun assemble(options: CompilationOptions): Int
}

View File

@ -1,89 +0,0 @@
package prog8.compiler.target
import com.github.michaelbull.result.fold
import prog8.ast.IMemSizer
import prog8.ast.Program
import prog8.ast.base.ByteDatatypes
import prog8.ast.base.DataType
import prog8.ast.base.PassByReferenceDatatypes
import prog8.ast.base.WordDatatypes
import prog8.compiler.CompilationOptions
import prog8.compiler.IErrorReporter
import prog8.compiler.IStringEncoding
import prog8.compiler.Zeropage
import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.cbm.Petscii
import prog8.compiler.target.cpu6502.codegen.AsmGen
import prog8.compiler.target.cx16.CX16MachineDefinition
import java.nio.file.Path
interface ICompilationTarget: IStringEncoding, IMemSizer {
val name: String
val machine: IMachineDefinition
override fun encodeString(str: String, altEncoding: Boolean): List<Short>
override fun decodeString(bytes: List<Short>, altEncoding: Boolean): String
}
internal object C64Target: ICompilationTarget {
override val name = "c64"
override val machine = C64MachineDefinition
override fun encodeString(str: String, altEncoding: Boolean): List<Short> {
val coded = if (altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
return coded.fold(
failure = { throw it },
success = { it }
)
}
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
override fun memorySize(dt: DataType): Int {
return when(dt) {
in ByteDatatypes -> 1
in WordDatatypes -> 2
DataType.FLOAT -> machine.FLOAT_MEM_SIZE
in PassByReferenceDatatypes -> machine.POINTER_MEM_SIZE
else -> -9999999
}
}
}
internal object Cx16Target: ICompilationTarget {
override val name = "cx16"
override val machine = CX16MachineDefinition
override fun encodeString(str: String, altEncoding: Boolean): List<Short> {
val coded= if (altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true)
return coded.fold(
failure = { throw it },
success = { it }
)
}
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
override fun memorySize(dt: DataType): Int {
return when(dt) {
in ByteDatatypes -> 1
in WordDatatypes -> 2
DataType.FLOAT -> machine.FLOAT_MEM_SIZE
in PassByReferenceDatatypes -> machine.POINTER_MEM_SIZE
else -> -9999999
}
}
}
internal fun asmGeneratorFor(
compTarget: ICompilationTarget,
program: Program,
errors: IErrorReporter,
zp: Zeropage,
options: CompilationOptions,
outputDir: Path
): IAssemblyGenerator
{
// at the moment we only have one code generation backend (for 6502 and 65c02)
return AsmGen(program, errors, zp, options, compTarget, outputDir)
}

View File

@ -1,10 +1,8 @@
package prog8.compiler.target.c64
import prog8.compiler.*
import prog8.compiler.target.CpuType
import prog8.compiler.target.IMachineDefinition
import prog8.compiler.target.IMachineFloat
import prog8.compiler.target.cbm.viceMonListPostfix
import prog8.compilerinterface.*
import java.io.IOException
import java.nio.file.Path
import kotlin.math.absoluteValue
@ -30,7 +28,7 @@ internal object C64MachineDefinition: IMachineDefinition {
override fun getFloat(num: Number) = Mflpt5.fromNumber(num)
override fun importLibs(compilerOptions: CompilationOptions,compilationTargetName: String): List<String> {
override fun importLibs(compilerOptions: CompilationOptions, compilationTargetName: String): List<String> {
return if (compilerOptions.launcher == LauncherType.BASIC || compilerOptions.output == OutputType.PRG)
listOf("syslib")
else
@ -125,7 +123,7 @@ internal object C64MachineDefinition: IMachineDefinition {
))
}
if(options.zeropage!=ZeropageType.DONTUSE) {
if(options.zeropage!= ZeropageType.DONTUSE) {
// add the free Zp addresses
// these are valid for the C-64 but allow BASIC to keep running fully *as long as you don't use tape I/O*
free.addAll(listOf(0x04, 0x05, 0x06, 0x0a, 0x0e,
@ -146,7 +144,8 @@ internal object C64MachineDefinition: IMachineDefinition {
}
}
internal data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, val b4: Short): IMachineFloat {
internal data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, val b4: Short):
IMachineFloat {
companion object {
val zero = Mflpt5(0, 0, 0, 0, 0)

View File

@ -1,9 +1,9 @@
package prog8.compiler.target.cbm
import prog8.compiler.CompilationOptions
import prog8.compiler.OutputType
import prog8.compiler.target.IAssemblyProgram
import prog8.compiler.target.generatedLabelPrefix
import prog8.compilerinterface.CompilationOptions
import prog8.compilerinterface.IAssemblyProgram
import prog8.compilerinterface.OutputType
import prog8.compilerinterface.generatedLabelPrefix
import java.nio.file.Path

View File

@ -13,6 +13,7 @@ import prog8.compiler.target.*
import prog8.compiler.target.cbm.AssemblyProgram
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

View File

@ -11,11 +11,11 @@ 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.CpuType
import prog8.compiler.target.Cx16Target
import prog8.compiler.target.cpu6502.codegen.assignment.*
import prog8.compiler.target.subroutineFloatEvalResultVar2
import prog8.compilerinterface.subroutineFloatEvalResultVar2
internal class BuiltinFunctionsAsmGen(private val program: Program, private val asmgen: AsmGen, private val assignAsmGen: AssignmentAsmGen) {
@ -785,7 +785,6 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
&& (firstOffset is NumericLiteralValue || firstOffset is IdentifierReference || firstOffset is TypecastExpression)
&& (secondOffset is NumericLiteralValue || secondOffset is IdentifierReference || secondOffset is TypecastExpression)
) {
val pointerVar = firstExpr.left as IdentifierReference
if(firstOffset is NumericLiteralValue && secondOffset is NumericLiteralValue) {
if(firstOffset!=secondOffset) {
swapArrayValues(

View File

@ -8,9 +8,9 @@ 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.CpuType
import prog8.compiler.target.subroutineFloatEvalResultVar1
import prog8.compilerinterface.subroutineFloatEvalResultVar1
import kotlin.math.absoluteValue
internal class ExpressionsAsmGen(private val program: Program, private val asmgen: AsmGen) {

View File

@ -9,7 +9,7 @@ import prog8.ast.expressions.RangeExpr
import prog8.ast.statements.ForLoop
import prog8.ast.toHex
import prog8.compiler.AssemblyError
import prog8.compiler.astprocessing.toConstantIntegerRange
import prog8.compilerinterface.toConstantIntegerRange
import kotlin.math.absoluteValue
internal class ForLoopsAsmGen(private val program: Program, private val asmgen: AsmGen) {

View File

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

View File

@ -1,11 +1,11 @@
package prog8.compiler.target.cpu6502.codegen.assignment
import prog8.ast.IMemSizer
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.cpu6502.codegen.AsmGen

View File

@ -6,9 +6,9 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.toHex
import prog8.compiler.AssemblyError
import prog8.compilerinterface.CpuType
import prog8.compiler.functions.BuiltinFunctions
import prog8.compiler.functions.builtinFunctionReturnType
import prog8.compiler.target.CpuType
import prog8.compiler.target.cpu6502.codegen.AsmGen
import prog8.compiler.target.cpu6502.codegen.ExpressionsAsmGen

View File

@ -6,7 +6,7 @@ import prog8.ast.expressions.*
import prog8.ast.statements.Subroutine
import prog8.ast.toHex
import prog8.compiler.AssemblyError
import prog8.compiler.target.CpuType
import prog8.compilerinterface.CpuType
import prog8.compiler.target.cpu6502.codegen.AsmGen
import prog8.compiler.target.cpu6502.codegen.ExpressionsAsmGen

View File

@ -1,13 +1,13 @@
package prog8.compiler.target.cx16
import prog8.compiler.*
import prog8.compiler.target.CpuType
import prog8.compiler.target.IMachineDefinition
import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.cbm.viceMonListPostfix
import prog8.compilerinterface.*
import java.io.IOException
import java.nio.file.Path
internal object CX16MachineDefinition: IMachineDefinition {
override val cpu = CpuType.CPU65c02

View File

@ -18,6 +18,10 @@ 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.parser.SourceCode
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer

View File

@ -9,7 +9,7 @@ import org.hamcrest.core.Is
import org.junit.jupiter.api.*
import prog8.ast.Program
import prog8.ast.internedStringsModuleName
import prog8.compiler.IErrorReporter
import prog8.compilerinterface.IErrorReporter
import prog8.compiler.ModuleImporter
import prog8.parser.ParseError
import prog8.parser.SourceCode

View File

@ -4,10 +4,10 @@ import org.junit.jupiter.api.DynamicTest
import org.junit.jupiter.api.DynamicTest.dynamicTest
import org.junit.jupiter.api.TestFactory
import org.junit.jupiter.api.TestInstance
import prog8.compilerinterface.ICompilationTarget
import prog8.compiler.compileProgram
import prog8.compiler.target.C64Target
import prog8.compiler.target.Cx16Target
import prog8.compiler.target.ICompilationTarget
import prog8tests.helpers.*
import kotlin.io.path.absolute
import kotlin.io.path.exists

View File

@ -9,10 +9,10 @@ import prog8.ast.expressions.*
import prog8.ast.statements.ForLoop
import prog8.ast.statements.Subroutine
import prog8.ast.statements.VarDecl
import prog8.compiler.astprocessing.size
import prog8.compiler.astprocessing.toConstantIntegerRange
import prog8.compilerinterface.size
import prog8.compiler.target.C64Target
import prog8.compiler.target.Cx16Target
import prog8.compilerinterface.toConstantIntegerRange
import prog8tests.helpers.*
import kotlin.test.assertContains
import kotlin.test.assertEquals

View File

@ -4,7 +4,7 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import prog8.ast.internedStringsModuleName
import prog8.compiler.ErrorReporter
import prog8.compiler.ZeropageType
import prog8.compilerinterface.ZeropageType
import prog8.compiler.determineCompilationOptions
import prog8.compiler.parseImports
import prog8.compiler.target.C64Target

View File

@ -12,7 +12,7 @@ import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.expressions.PrefixExpression
import prog8.ast.statements.*
import prog8.compiler.astprocessing.isInRegularRAMof
import prog8.compilerinterface.isInRegularRAMof
import prog8.compiler.target.C64Target
import prog8.parser.SourceCode
import prog8tests.helpers.DummyFunctions

View File

@ -6,7 +6,7 @@ import org.hamcrest.Matchers.equalTo
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import prog8.ast.toHex
import prog8.compiler.CompilerException
import prog8.compilerinterface.CompilerException
import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_NEGATIVE
import prog8.compiler.target.c64.C64MachineDefinition.FLOAT_MAX_POSITIVE
import prog8.compiler.target.c64.C64MachineDefinition.Mflpt5

View File

@ -8,6 +8,7 @@ import prog8.compiler.target.C64Target
import prog8.compiler.target.Cx16Target
import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage
import prog8.compiler.target.cx16.CX16MachineDefinition.CX16Zeropage
import prog8.compilerinterface.*
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse

View File

@ -1,7 +1,7 @@
package prog8tests.helpers
import prog8.ast.base.Position
import prog8.compiler.IErrorReporter
import prog8.compilerinterface.IErrorReporter
class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: Boolean=true): IErrorReporter {

View File

@ -1,10 +1,8 @@
package prog8tests.helpers
import prog8.compiler.CompilationResult
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.compileProgram
import prog8.compiler.target.ICompilationTarget
import prog8.compiler.*
import prog8.compilerinterface.ICompilationTarget
import prog8.compilerinterface.IErrorReporter
import java.nio.file.Path
import kotlin.io.path.name
import kotlin.test.assertFalse

View File

@ -7,6 +7,7 @@ import prog8.ast.expressions.StringLiteralValue
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstVisitor
import prog8.compiler.IMemSizer
import prog8.parser.SourceCode
const val internedStringsModuleName = "prog8_interned_strings"
@ -286,7 +287,8 @@ interface Node {
class Program(val name: String,
val builtinFunctions: IBuiltinFunctions,
val memsizer: IMemSizer): Node {
val memsizer: IMemSizer
): Node {
private val _modules = mutableListOf<Module>()
val modules: List<Module> = _modules

View File

@ -4,10 +4,11 @@ import prog8.ast.base.Position
import prog8.ast.expressions.Expression
import prog8.ast.expressions.InferredTypes
import prog8.ast.expressions.NumericLiteralValue
import prog8.compiler.IMemSizer
interface IBuiltinFunctions {
val names: Set<String>
val purefunctionNames: Set<String>
fun constValue(name: String, args: List<Expression>, position: Position, memsizer: IMemSizer): NumericLiteralValue?
fun returnType(name: String, args: MutableList<Expression>): InferredTypes.InferredType
}
}

View File

@ -6,6 +6,7 @@ import prog8.ast.base.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstVisitor
import prog8.compiler.IMemSizer
import java.util.*

View File

@ -1,7 +1,7 @@
package prog8.ast
package prog8.compiler
import prog8.ast.base.DataType
interface IMemSizer {
fun memorySize(dt: DataType): Int
}
}

View File

@ -1,11 +1,11 @@
package prog8tests.helpers
import prog8.ast.IBuiltinFunctions
import prog8.ast.IMemSizer
import prog8.ast.base.Position
import prog8.ast.expressions.Expression
import prog8.ast.expressions.InferredTypes
import prog8.ast.expressions.NumericLiteralValue
import prog8.compiler.IMemSizer
val DummyFunctions = object : IBuiltinFunctions {
override val names: Set<String> = emptySet()
@ -18,4 +18,4 @@ val DummyFunctions = object : IBuiltinFunctions {
): NumericLiteralValue? = null
override fun returnType(name: String, args: MutableList<Expression>) = InferredTypes.InferredType.unknown()
}
}

View File

@ -1,8 +1,8 @@
package prog8tests.helpers
import prog8.ast.IMemSizer
import prog8.ast.base.DataType
import prog8.compiler.IMemSizer
val DummyMemsizer = object : IMemSizer {
override fun memorySize(dt: DataType): Int = 0
}
}

View File

@ -0,0 +1,66 @@
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(':compilerAst')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
// implementation "org.jetbrains.kotlin:kotlin-reflect"
}
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,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="jdk" jdkName="openjdk-11" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime (3)" level="project" />
<orderEntry type="module" module-name="compilerAst" />
</component>
</module>

View File

@ -0,0 +1,99 @@
package prog8.compilerinterface
import prog8.ast.base.VarDeclType
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.expressions.RangeExpr
import prog8.ast.expressions.StringLiteralValue
import prog8.ast.statements.AssignTarget
import kotlin.math.abs
fun AssignTarget.isInRegularRAMof(machine: IMachineDefinition): Boolean {
val memAddr = memoryAddress
val arrayIdx = arrayindexed
val ident = identifier
when {
memAddr != null -> {
return when (memAddr.addressExpression) {
is NumericLiteralValue -> {
machine.isRegularRAMaddress((memAddr.addressExpression as NumericLiteralValue).number.toInt())
}
is IdentifierReference -> {
val program = definingModule.program
val decl = (memAddr.addressExpression as IdentifierReference).targetVarDecl(program)
if ((decl?.type == VarDeclType.VAR || decl?.type == VarDeclType.CONST) && decl.value is NumericLiteralValue)
machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt())
else
false
}
else -> false
}
}
arrayIdx != null -> {
val program = definingModule.program
val targetStmt = arrayIdx.arrayvar.targetVarDecl(program)
return if (targetStmt?.type == VarDeclType.MEMORY) {
val addr = targetStmt.value as? NumericLiteralValue
if (addr != null)
machine.isRegularRAMaddress(addr.number.toInt())
else
false
} else true
}
ident != null -> {
val program = definingModule.program
val decl = ident.targetVarDecl(program)!!
return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteralValue)
machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt())
else
true
}
else -> return true
}
}
fun RangeExpr.toConstantIntegerRange(encoding: IStringEncoding): IntProgression? {
fun makeRange(fromVal: Int, toVal: Int, stepVal: Int): IntProgression {
return when {
fromVal <= toVal -> when {
stepVal <= 0 -> IntRange.EMPTY
stepVal == 1 -> fromVal..toVal
else -> fromVal..toVal step stepVal
}
else -> when {
stepVal >= 0 -> IntRange.EMPTY
stepVal == -1 -> fromVal downTo toVal
else -> fromVal downTo toVal step abs(stepVal)
}
}
}
val fromVal: Int
val toVal: Int
val fromString = from as? StringLiteralValue
val toString = to as? StringLiteralValue
if(fromString!=null && toString!=null ) {
// string range -> int range over character values
fromVal = encoding.encodeString(fromString.value, fromString.altEncoding)[0].toInt()
toVal = encoding.encodeString(toString.value, fromString.altEncoding)[0].toInt()
} else {
val fromLv = from as? NumericLiteralValue
val toLv = to as? NumericLiteralValue
if(fromLv==null || toLv==null)
return null // non-constant range
// integer range
fromVal = fromLv.number.toInt()
toVal = toLv.number.toInt()
}
val stepVal = (step as? NumericLiteralValue)?.number?.toInt() ?: 1
return makeRange(fromVal, toVal, stepVal)
}
fun RangeExpr.size(encoding: IStringEncoding): Int? {
val fromLv = (from as? NumericLiteralValue)
val toLv = (to as? NumericLiteralValue)
if(fromLv==null || toLv==null)
return null
return toConstantIntegerRange(encoding)?.count()
}

View File

@ -0,0 +1,31 @@
package prog8.compilerinterface
enum class OutputType {
RAW,
PRG
}
enum class LauncherType {
BASIC,
NONE
}
enum class ZeropageType {
BASICSAFE,
FLOATSAFE,
KERNALSAFE,
FULL,
DONTUSE
}
data class CompilationOptions(val output: OutputType,
val launcher: LauncherType,
val zeropage: ZeropageType,
val zpReserved: List<IntRange>,
val floats: Boolean,
val noSysInit: Boolean,
val compTarget: ICompilationTarget
) {
var slowCodegenWarnings = false
var optimize = false
}

View File

@ -0,0 +1,3 @@
package prog8.compilerinterface
class CompilerException(message: String?) : Exception(message)

View File

@ -0,0 +1,15 @@
package prog8.compilerinterface
interface IAssemblyGenerator {
fun compileToAssembly(): IAssemblyProgram
}
const val generatedLabelPrefix = "_prog8_label_"
const val subroutineFloatEvalResultVar1 = "_prog8_float_eval_result1"
const val subroutineFloatEvalResultVar2 = "_prog8_float_eval_result2"
interface IAssemblyProgram {
val valid: Boolean
val name: String
fun assemble(options: CompilationOptions): Int
}

View File

@ -0,0 +1,10 @@
package prog8.compilerinterface
import prog8.compiler.IMemSizer
interface ICompilationTarget: IStringEncoding, IMemSizer {
val name: String
val machine: IMachineDefinition
override fun encodeString(str: String, altEncoding: Boolean): List<Short>
override fun decodeString(bytes: List<Short>, altEncoding: Boolean): String
}

View File

@ -0,0 +1,16 @@
package prog8.compilerinterface
import prog8.ast.base.Position
import prog8.parser.ParsingFailedError
interface IErrorReporter {
fun err(msg: String, position: Position)
fun warn(msg: String, position: Position)
fun noErrors(): Boolean
fun report()
fun finalizeNumErrors(numErrors: Int, numWarnings: Int) {
if(numErrors>0)
throw ParsingFailedError("There are $numErrors errors and $numWarnings warnings.")
}
}

View File

@ -1,7 +1,5 @@
package prog8.compiler.target
package prog8.compilerinterface
import prog8.compiler.CompilationOptions
import prog8.compiler.Zeropage
import java.nio.file.Path

View File

@ -1,6 +1,6 @@
package prog8.compiler
package prog8.compilerinterface
interface IStringEncoding {
fun encodeString(str: String, altEncoding: Boolean): List<Short>
fun decodeString(bytes: List<Short>, altEncoding: Boolean): String
}
}

View File

@ -1,4 +1,4 @@
package prog8.compiler
package prog8.compilerinterface
import prog8.ast.base.*
@ -19,10 +19,10 @@ abstract class Zeropage(protected val options: CompilationOptions) {
val allowedDatatypes = NumericDatatypes
fun availableBytes() = if(options.zeropage==ZeropageType.DONTUSE) 0 else free.size
fun hasByteAvailable() = if(options.zeropage==ZeropageType.DONTUSE) false else free.isNotEmpty()
fun availableBytes() = if(options.zeropage== ZeropageType.DONTUSE) 0 else free.size
fun hasByteAvailable() = if(options.zeropage== ZeropageType.DONTUSE) false else free.isNotEmpty()
fun availableWords(): Int {
if(options.zeropage==ZeropageType.DONTUSE)
if(options.zeropage== ZeropageType.DONTUSE)
return 0
val words = free.windowed(2).filter { it[0] == it[1]-1 }
@ -37,7 +37,7 @@ abstract class Zeropage(protected val options: CompilationOptions) {
return nonOverlappingWordsCount
}
fun hasWordAvailable(): Boolean {
if(options.zeropage==ZeropageType.DONTUSE)
if(options.zeropage== ZeropageType.DONTUSE)
return false
return free.windowed(2).any { it[0] == it[1] - 1 }
@ -46,7 +46,7 @@ abstract class Zeropage(protected val options: CompilationOptions) {
fun allocate(scopedname: String, datatype: DataType, position: Position?, errors: IErrorReporter): Int {
assert(scopedname.isEmpty() || !allocations.values.any { it.first==scopedname } ) {"scopedname can't be allocated twice"}
if(options.zeropage==ZeropageType.DONTUSE)
if(options.zeropage== ZeropageType.DONTUSE)
throw CompilerException("zero page usage has been disabled")
val size =

View File

@ -27,7 +27,6 @@ Future
- 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
- refactor the compiler optimizers 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

@ -16,6 +16,7 @@ repositories {
}
dependencies {
implementation project(':compilerInterfaces')
implementation project(':compiler')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
// implementation "org.jetbrains.kotlin:kotlin-reflect"

View File

@ -14,5 +14,6 @@
<orderEntry type="library" name="glassfish.javax.json" level="project" />
<orderEntry type="library" name="takes" level="project" />
<orderEntry type="library" name="slf4j.simple" level="project" />
<orderEntry type="module" module-name="compilerInterfaces" />
</component>
</module>

View File

@ -1,5 +1,7 @@
include ':parser'
include ':compilerInterfaces'
include ':compilerAst'
include ':codeOptimizers'
include ':compiler'
include ':dbusCompilerService'
include ':httpCompilerService'