working on vm and new ast

This commit is contained in:
Irmen de Jong 2022-03-21 01:01:21 +01:00
parent 9b16d7c786
commit ff57c5e9d3
27 changed files with 161 additions and 76 deletions

View File

@ -6,8 +6,9 @@ import java.nio.file.Path
// New (work-in-progress) simplified AST for the code generator.
sealed class PtNode(val position: Position, val children: MutableList<PtNode> = mutableListOf()) {
sealed class PtNode(val position: Position) {
val children = mutableListOf<PtNode>()
lateinit var parent: PtNode
protected fun printIndented(indent: Int) {
@ -32,7 +33,7 @@ sealed class PtNode(val position: Position, val children: MutableList<PtNode> =
}
class PtNodeGroup: PtNode(Position.DUMMY) {
class PtNodeGroup : PtNode(Position.DUMMY) {
override fun printProperties() {}
}
@ -109,4 +110,14 @@ class PtIncludeBinary(val file: Path, val offset: UInt?, val length: UInt?, posi
class PtNop(position: Position): PtNode(position) {
override fun printProperties() {}
}
class PtScopeVarsDecls(position: Position): PtNode(position) {
override fun printProperties() {}
}
class PtScopeVarsInit(position: Position): PtNode(position) {
override fun printProperties() {}
}

View File

@ -1,4 +1,4 @@
package prog8.parser
package prog8.code.core
import java.io.File
import java.io.IOException
@ -6,6 +6,10 @@ import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.readText
const val internedStringsModuleName = "prog8_interned_strings"
/**
* Encapsulates - and ties together - actual source code (=text) and its [origin].
*/

View File

@ -10,7 +10,7 @@ import prog8.code.core.*
import prog8.codegen.cpu6502.assignment.*
import prog8.compiler.BuiltinFunctions
import prog8.compiler.builtinFunctionReturnType
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import java.util.*
import kotlin.io.path.Path
import kotlin.io.path.writeLines

View File

@ -4,7 +4,7 @@ import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
import com.github.michaelbull.result.mapError
import prog8.code.core.*
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import java.io.File
import java.nio.file.Path
import kotlin.io.path.Path

View File

@ -186,11 +186,27 @@ class AstToXmlConverter(internal val program: PtProgram,
is PtLabel -> write(it)
is PtNop -> {}
is PtBreakpoint -> write(it)
is PtScopeVarsDecls -> write(it)
is PtScopeVarsInit -> write(it)
is PtNodeGroup -> it.children.forEach { writeNode(it) }
else -> TODO("$it")
}
}
private fun write(vars: PtScopeVarsDecls) {
xml.elt("vars")
xml.startChildren()
vars.children.forEach { writeNode(it) }
xml.endElt()
}
private fun write(inits: PtScopeVarsInit) {
xml.elt("varsinit")
xml.startChildren()
inits.children.forEach { writeNode(it) }
xml.endElt()
}
private fun write(breakPt: PtBreakpoint) {
xml.elt("breakpoint")
xml.pos(breakPt.position)
@ -236,10 +252,8 @@ class AstToXmlConverter(internal val program: PtProgram,
xml.startChildren()
writeNode(rept.count)
xml.endElt()
xml.elt("statements")
writeNode(rept.statements)
xml.endElt()
xml.endElt()
}
private fun write(branch: PtConditionalBranch) {
@ -303,11 +317,8 @@ class AstToXmlConverter(internal val program: PtProgram,
xml.startChildren()
writeNode(forLoop.iterable)
xml.endElt()
xml.elt("statements")
xml.startChildren()
writeNode(forLoop.statements)
xml.endElt()
xml.endElt()
}
private fun write(membyte: PtMemoryByte) {
@ -348,11 +359,8 @@ class AstToXmlConverter(internal val program: PtProgram,
writeNode(choice.values)
xml.endElt()
}
xml.elt("statements")
xml.startChildren()
writeNode(choice.statements)
xml.endElt()
xml.endElt()
}
private fun write(inlineAsm: PtInlineAssembly) {
@ -570,11 +578,8 @@ class AstToXmlConverter(internal val program: PtProgram,
sub.parameters.forEach { write(it) }
xml.endElt()
}
xml.elt("statements")
xml.startChildren()
sub.children.forEach { writeNode(it) }
xml.endElt()
xml.endElt()
}
private fun write(parameter: PtSubroutineParameter, registerOrStatusflag: RegisterOrStatusflag? = null) {

View File

@ -1,15 +1,10 @@
package prog8.codegen.virtual
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
import com.github.michaelbull.result.mapError
import prog8.code.SymbolTable
import prog8.code.ast.*
import prog8.code.core.*
import prog8.vm.Instruction
import java.io.File
import kotlin.io.path.Path
import kotlin.io.path.isRegularFile
import prog8.vm.Opcode
class CodeGen(internal val program: PtProgram,
internal val symbolTable: SymbolTable,
@ -19,11 +14,30 @@ class CodeGen(internal val program: PtProgram,
private val instructions = mutableListOf<String>()
init {
if(options.dontReinitGlobals)
TODO("support no globals re-init in vm")
}
override fun compileToAssembly(): IAssemblyProgram? {
instructions.clear()
val allocations = VariableAllocator(symbolTable, program, errors)
for (block in program.allBlocks())
outComment("GLOBAL VARS INITS")
program.allBlocks().forEach {
it.children
.singleOrNull { node->node is PtScopeVarsInit }
?.let { inits->
translateNode(inits)
it.children.remove(inits)
}
}
outComment("PROGRAM CODE")
for (block in program.allBlocks()) {
translateNode(block)
}
return AssemblyProgram(program.name, allocations, instructions)
}
@ -31,21 +45,22 @@ class CodeGen(internal val program: PtProgram,
instructions.add(ins.toString())
}
private fun out(ins: String) {
instructions.add(ins)
private fun outComment(ins: String) {
instructions.add("; $ins")
}
private fun translateNode(node: PtNode) {
when(node) {
is PtBlock -> translate(node)
is PtSub -> translate(node)
is PtScopeVarsDecls -> { /* vars should be looked up via symbol table */ }
is PtVariable -> { /* var should be looked up via symbol table */ }
is PtMemMapped -> { /* memmapped var should be looked up via symbol table */ }
is PtConstant -> { /* constants have all been folded into the code */ }
is PtAsmSub -> translate(node)
is PtAssignTarget -> TODO()
is PtAssignment -> translate(node)
is PtBreakpoint -> TODO()
is PtScopeVarsInit -> translate(node)
is PtBreakpoint -> translate(node)
is PtConditionalBranch -> TODO()
is PtAddressOf -> TODO()
is PtArrayIndexer -> TODO()
@ -76,28 +91,42 @@ class CodeGen(internal val program: PtProgram,
is PtSubroutineParameter -> TODO()
is PtWhen -> TODO()
is PtWhenChoice -> TODO()
is PtAsmSub -> throw AssemblyError("asmsub not supported on virtual machine target")
is PtInlineAssembly -> throw AssemblyError("inline assembly not supported on virtual machine target")
else -> TODO("missing codegen for $node")
}
}
private fun translate(sub: PtSub) {
out("; SUB: ${sub.scopedName} -> ${sub.returntype}")
private fun translate(breakpoint: PtBreakpoint) {
out(Instruction(Opcode.BREAKPOINT))
}
private fun translate(asmsub: PtAsmSub) {
out("; ASMSUB: ${asmsub.scopedName} = ${asmsub.address} -> ${asmsub.retvalRegisters}")
private fun translate(init: PtScopeVarsInit) {
init.children.forEach { translateNode(it) }
}
private fun translate(sub: PtSub) {
outComment("SUB: ${sub.scopedName} -> ${sub.returntype}")
sub.children
.singleOrNull { it is PtScopeVarsInit }
?.let { inits ->
sub.children.remove(inits)
translateNode(inits)
}
// TODO rest
outComment("SUB-END ${sub.scopedName}\n")
}
private fun translate(assign: PtAssignment) {
out("; ASSIGN: ${assign.target.identifier?.targetName} = ${assign.value}")
outComment("ASSIGN: ${assign.target.identifier?.targetName} = ${assign.value}")
}
private fun translate(block: PtBlock) {
out("\n; BLOCK '${block.name}' addr=${block.address} lib=${block.library}")
outComment("BLOCK '${block.name}' addr=${block.address} lib=${block.library}")
for (child in block.children) {
translateNode(child)
}
out("; BLOCK-END '${block.name}'\n")
outComment("BLOCK-END '${block.name}'\n")
}
}

View File

@ -8,6 +8,7 @@ import prog8.ast.walk.IAstModification
import prog8.code.core.DataType
import prog8.code.core.ICompilationTarget
import prog8.code.core.IErrorReporter
import prog8.code.core.internedStringsModuleName
import prog8.compiler.CallGraph

View File

@ -10,7 +10,8 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.code.ast.*
import prog8.code.core.DataType
import prog8.parser.SourceCode
import prog8.code.core.Position
import prog8.code.core.SourceCode
import java.io.File
import kotlin.io.path.Path
import kotlin.io.path.isRegularFile
@ -122,14 +123,34 @@ class IntermediateAstMaker(val program: Program) {
}
private fun transform(srcBlock: Block): PtBlock {
val (vardecls, statements) = srcBlock.statements.partition { it is VarDecl }
val (varinits, actualStatements) = statements.partition { (it as? Assignment)?.origin==AssignmentOrigin.VARINIT }
val block = PtBlock(srcBlock.name, srcBlock.address, srcBlock.isInLibrary, srcBlock.position)
for (stmt in srcBlock.statements)
if(vardecls.isNotEmpty()) block.add(makeScopeVarsDecls(vardecls, srcBlock.position))
if(varinits.isNotEmpty()) block.add(makeScopeVarInitializers(varinits, srcBlock.position))
for (stmt in actualStatements)
block.add(transformStatement(stmt))
return block
}
private fun makeScopeVarsDecls(vardecls: List<Statement>, position: Position): PtNode {
val decls = PtScopeVarsDecls(position)
vardecls.forEach {
decls.add(transformStatement(it as VarDecl))
}
return decls
}
private fun makeScopeVarInitializers(varinits: List<Statement>, position: Position): PtScopeVarsInit {
val init = PtScopeVarsInit(position)
varinits.forEach {
init.add(transformStatement(it as Assignment))
}
return init
}
private fun transform(srcNode: BuiltinFunctionCallStatement): PtBuiltinFunctionCall {
val type = builtinFunctionReturnType(srcNode.name, srcNode.args, program).getOr(DataType.UNDEFINED)
val call = PtBuiltinFunctionCall(srcNode.name, true, type, srcNode.position)
@ -294,13 +315,17 @@ class IntermediateAstMaker(val program: Program) {
}
private fun transformSub(srcSub: Subroutine): PtSub {
val (vardecls, statements) = srcSub.statements.partition { it is VarDecl }
val (varinits, actualStatements) = statements.partition { (it as? Assignment)?.origin==AssignmentOrigin.VARINIT }
val sub = PtSub(srcSub.name,
srcSub.parameters.map { PtSubroutineParameter(it.name, it.type, it.position) },
srcSub.returntypes.singleOrNull(),
srcSub.inline,
srcSub.position)
for (statement in srcSub.statements)
if(vardecls.isNotEmpty()) sub.add(makeScopeVarsDecls(vardecls, sub.position))
if(varinits.isNotEmpty()) sub.add(makeScopeVarInitializers(varinits, srcSub.position))
for (statement in actualStatements)
sub.add(transformStatement(statement))
return sub

View File

@ -9,7 +9,7 @@ import prog8.ast.statements.DirectiveArg
import prog8.code.core.IErrorReporter
import prog8.code.core.Position
import prog8.parser.Prog8Parser
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import java.io.File
import java.nio.file.Path
import kotlin.io.path.*

View File

@ -10,11 +10,11 @@ import io.kotest.matchers.collections.shouldBeIn
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldContain
import prog8.ast.Program
import prog8.ast.internedStringsModuleName
import prog8.code.core.IErrorReporter
import prog8.compiler.ModuleImporter
import prog8.parser.ParseError
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import prog8.code.core.internedStringsModuleName
import prog8tests.helpers.*
import kotlin.io.path.*

View File

@ -12,7 +12,7 @@ import prog8.ast.statements.Subroutine
import prog8.code.target.C64Target
import prog8.compiler.CallGraph
import prog8.parser.Prog8Parser.parseModule
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import prog8tests.helpers.*
class TestCallgraph: FunSpec({

View File

@ -4,8 +4,8 @@ import io.kotest.assertions.withClue
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldStartWith
import prog8.ast.internedStringsModuleName
import prog8.code.core.ZeropageType
import prog8.code.core.internedStringsModuleName
import prog8.code.target.C64Target
import prog8.compiler.determineCompilationOptions
import prog8.compiler.parseImports

View File

@ -15,7 +15,7 @@ import prog8.code.core.Position
import prog8.code.core.ZeropageWish
import prog8.code.target.C64Target
import prog8.compiler.printProgram
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder

View File

@ -16,7 +16,7 @@ import prog8.code.core.Position
import prog8.code.target.C64Target
import prog8.compiler.astprocessing.AstPreprocessor
import prog8.parser.Prog8Parser.parseModule
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import prog8tests.helpers.*

View File

@ -6,10 +6,10 @@ import io.kotest.matchers.string.shouldContain
import prog8.ast.AstToSourceTextConverter
import prog8.ast.Module
import prog8.ast.Program
import prog8.ast.internedStringsModuleName
import prog8.parser.ParseError
import prog8.parser.Prog8Parser.parseModule
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import prog8.code.core.internedStringsModuleName
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder

View File

@ -11,7 +11,7 @@ import prog8.ast.expressions.PrefixExpression
import prog8.ast.statements.*
import prog8.code.core.Position
import prog8.parser.Prog8Parser
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder

View File

@ -4,10 +4,9 @@ import io.kotest.assertions.fail
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.ints.shouldBeGreaterThan
import io.kotest.matchers.shouldBe
import prog8.code.ast.PtAssignment
import prog8.code.ast.PtPipe
import prog8.code.ast.PtVariable
import prog8.code.ast.*
import prog8.code.core.DataType
import prog8.code.core.Position
import prog8.code.target.C64Target
import prog8.compiler.IntermediateAstMaker
import prog8tests.helpers.compileText
@ -32,21 +31,29 @@ class TestIntermediateAst: FunSpec({
ast.name shouldBe result.program.name
ast.allBlocks().any() shouldBe true
val entry = ast.entrypoint() ?: fail("no main.start() found")
entry.children.size shouldBe 5
entry.children.size shouldBe 4
entry.name shouldBe "start"
entry.scopedName shouldBe listOf("main", "start")
val blocks = ast.allBlocks().toList()
blocks.size shouldBeGreaterThan 1
blocks[0].name shouldBe "main"
blocks[0].scopedName shouldBe listOf("main")
val ccdecl = entry.children[0] as PtVariable
val vars = entry.children[0] as PtScopeVarsDecls
val inits = entry.children[1] as PtScopeVarsInit
inits.children.size shouldBe 1
val ccdecl = vars.children[0] as PtVariable
ccdecl.name shouldBe "cc"
ccdecl.scopedName shouldBe listOf("main", "start", "cc")
ccdecl.type shouldBe DataType.UBYTE
val arraydecl = entry.children[2] as PtVariable
val arraydecl = vars.children[1] as PtVariable
arraydecl.name shouldBe "array"
arraydecl.type shouldBe DataType.ARRAY_UB
val pipe = (entry.children[4] as PtAssignment).value as PtPipe
val containment = (entry.children[2] as PtAssignment).value as PtContainmentCheck
(containment.element as PtNumber).number shouldBe 11.0
val pipe = (entry.children[3] as PtAssignment).value as PtPipe
pipe.void shouldBe false
pipe.type shouldBe DataType.UBYTE
ast.print()

View File

@ -25,7 +25,7 @@ import prog8.code.target.C64Target
import prog8.code.target.cbm.PetsciiEncoding
import prog8.parser.ParseError
import prog8.parser.Prog8Parser.parseModule
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import prog8tests.helpers.*
import kotlin.io.path.Path
import kotlin.io.path.isRegularFile
@ -70,14 +70,16 @@ class TestProg8Parser: FunSpec( {
test("is required between two Blocks or Directives - #47") {
// block and block
shouldThrow<ParseError>{ parseModule(SourceCode.Text("""
shouldThrow<ParseError>{ parseModule(
SourceCode.Text("""
blockA {
} blockB {
}
""")) }
// block and directive
shouldThrow<ParseError>{ parseModule(SourceCode.Text("""
shouldThrow<ParseError>{ parseModule(
SourceCode.Text("""
blockB {
} %import textio
""")) }
@ -86,12 +88,14 @@ class TestProg8Parser: FunSpec( {
// Leaving them in anyways.
// dir and block
shouldThrow<ParseError>{ parseModule(SourceCode.Text("""
shouldThrow<ParseError>{ parseModule(
SourceCode.Text("""
%import textio blockB {
}
""")) }
shouldThrow<ParseError>{ parseModule(SourceCode.Text("""
shouldThrow<ParseError>{ parseModule(
SourceCode.Text("""
%import textio %import syslib
""")) }
}
@ -563,7 +567,8 @@ class TestProg8Parser: FunSpec( {
context("Ranges") {
test("in for-loops") {
val module = parseModule(SourceCode.Text("""
val module = parseModule(
SourceCode.Text("""
main {
sub start() {
ubyte ub
@ -758,7 +763,7 @@ class TestProg8Parser: FunSpec( {
}
test("inferred type for typecasted expressions with logical operators") {
val src=SourceCode.Text("""
val src= SourceCode.Text("""
main {
ubyte bb
uword ww

View File

@ -9,9 +9,9 @@ import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.types.shouldBeSameInstanceAs
import prog8.ast.Module
import prog8.ast.Program
import prog8.ast.internedStringsModuleName
import prog8.code.core.Position
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import prog8.code.core.internedStringsModuleName
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder

View File

@ -4,8 +4,8 @@ import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.AnnotationSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldContain
import prog8.parser.SourceCode
import prog8.parser.SourceCode.Companion.libraryFilePrefix
import prog8.code.core.SourceCode
import prog8.code.core.SourceCode.Companion.libraryFilePrefix
import prog8tests.helpers.assumeNotExists
import prog8tests.helpers.assumeReadableFile
import prog8tests.helpers.fixturesDir
@ -26,7 +26,7 @@ class TestSourceCode: AnnotationSpec() {
src.text shouldBe text
src.isFromResources shouldBe false
src.isFromFilesystem shouldBe false
src.toString().startsWith("prog8.parser.SourceCode") shouldBe true
src.toString().startsWith("prog8.code.core.SourceCode") shouldBe true
}
@Test

View File

@ -6,7 +6,7 @@ import prog8.ast.statements.Block
import prog8.ast.statements.Subroutine
import prog8.code.core.DataType
import prog8.parser.Prog8Parser.parseModule
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
class TestSubroutines: AnnotationSpec() {

View File

@ -13,7 +13,7 @@ import prog8.code.target.C64Target
import prog8.code.target.c64.C64Zeropage
import prog8.codegen.cpu6502.AsmGen
import prog8.compiler.astprocessing.SymbolTableMaker
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder

View File

@ -9,9 +9,7 @@ import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstVisitor
import prog8.code.core.DataType
import prog8.code.core.Position
import prog8.parser.SourceCode
const val internedStringsModuleName = "prog8_interned_strings"
import prog8.code.core.SourceCode
object ParentSentinel : Node {
@ -275,7 +273,8 @@ inline fun <reified T> findParentNode(node: Node): T? {
open class Module(final override var statements: MutableList<Statement>,
final override val position: Position,
val source: SourceCode) : Node, INameScope {
val source: SourceCode
) : Node, INameScope {
override lateinit var parent: Node
lateinit var program: Program

View File

@ -6,7 +6,7 @@ import prog8.ast.expressions.StringLiteral
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.code.core.*
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
/*********** Everything starts from here, the Program; zero or more modules *************/

View File

@ -8,7 +8,7 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.code.core.*
import prog8.parser.Prog8ANTLRParser
import prog8.parser.SourceCode
import prog8.code.core.SourceCode
import java.nio.file.Path
import kotlin.io.path.isRegularFile

View File

@ -6,6 +6,7 @@ import prog8.ast.antlr.toAst
import prog8.ast.statements.Block
import prog8.ast.statements.Directive
import prog8.code.core.Position
import prog8.code.core.SourceCode
class ParseError(override var message: String, val position: Position, cause: RuntimeException): Exception(message, cause)

View File

@ -4,8 +4,6 @@ TODO
For next release
^^^^^^^^^^^^^^^^
- move prog8_lib.pattern_match to string module
- move SourceCode class?
- move internedStringsModuleName ?
...