2022-03-04 22:25:26 +00:00
|
|
|
package prog8tests
|
|
|
|
|
2023-02-09 21:49:34 +00:00
|
|
|
import io.kotest.assertions.fail
|
|
|
|
import io.kotest.core.spec.style.FunSpec
|
|
|
|
import io.kotest.matchers.shouldBe
|
|
|
|
import io.kotest.matchers.shouldNotBe
|
|
|
|
import io.kotest.matchers.types.shouldBeSameInstanceAs
|
|
|
|
import prog8.code.*
|
|
|
|
import prog8.code.ast.*
|
|
|
|
import prog8.code.core.DataType
|
|
|
|
import prog8.code.core.Position
|
|
|
|
import prog8.code.core.SourceCode
|
|
|
|
import prog8.code.core.ZeropageWish
|
|
|
|
import prog8tests.helpers.DummyMemsizer
|
|
|
|
import prog8tests.helpers.DummyStringEncoder
|
2022-03-04 22:25:26 +00:00
|
|
|
|
2023-02-03 23:02:50 +00:00
|
|
|
|
2022-03-04 22:25:26 +00:00
|
|
|
class TestSymbolTable: FunSpec({
|
|
|
|
test("empty symboltable") {
|
2023-02-09 21:49:34 +00:00
|
|
|
val astNode = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
|
|
|
val st = SymbolTable(astNode)
|
|
|
|
st.name shouldBe "test"
|
2022-03-04 22:25:26 +00:00
|
|
|
st.type shouldBe StNodeType.GLOBAL
|
|
|
|
st.children shouldBe mutableMapOf()
|
2023-02-09 21:49:34 +00:00
|
|
|
st.astNode shouldBeSameInstanceAs astNode
|
|
|
|
st.astNode.position shouldBe Position.DUMMY
|
2022-03-04 22:25:26 +00:00
|
|
|
}
|
|
|
|
|
2022-03-06 17:05:38 +00:00
|
|
|
test("symboltable flatten") {
|
2022-03-04 22:25:26 +00:00
|
|
|
val st = makeSt()
|
2022-12-31 13:27:14 +00:00
|
|
|
st.flat["zzzzz"] shouldBe null
|
|
|
|
st.flat.getValue("msb").type shouldBe StNodeType.BUILTINFUNC
|
|
|
|
st.flat.getValue("block2").type shouldBe StNodeType.BLOCK
|
|
|
|
st.flat.getValue("block2.sub2.subsub.label").type shouldBe StNodeType.LABEL
|
|
|
|
st.flat["block2.sub2.subsub.label.zzzz"] shouldBe null
|
2022-03-06 17:05:38 +00:00
|
|
|
}
|
2022-03-04 22:25:26 +00:00
|
|
|
|
2022-03-06 17:05:38 +00:00
|
|
|
test("symboltable global lookups") {
|
|
|
|
val st = makeSt()
|
2022-12-31 13:27:14 +00:00
|
|
|
st.lookupUnscoped("undefined") shouldBe null
|
2022-12-30 18:01:00 +00:00
|
|
|
st.lookup("undefined") shouldBe null
|
2022-12-31 13:27:14 +00:00
|
|
|
st.lookup("undefined.undefined") shouldBe null
|
2023-02-09 21:49:34 +00:00
|
|
|
var default = st.lookupUnscopedOrElse("undefined") { StNode("default", StNodeType.LABEL, PtIdentifier("default", DataType.BYTE, Position.DUMMY)) }
|
2022-03-04 22:25:26 +00:00
|
|
|
default.name shouldBe "default"
|
2023-02-09 21:49:34 +00:00
|
|
|
default = st.lookupUnscopedOrElse("undefined") { StNode("default", StNodeType.LABEL, PtIdentifier("default", DataType.BYTE, Position.DUMMY)) }
|
2022-03-04 22:25:26 +00:00
|
|
|
default.name shouldBe "default"
|
|
|
|
|
2022-12-31 13:27:14 +00:00
|
|
|
val msbFunc = st.lookupUnscopedOrElse("msb") { fail("msb must be found") }
|
2022-04-15 20:38:32 +00:00
|
|
|
msbFunc.type shouldBe StNodeType.BUILTINFUNC
|
2022-03-04 22:25:26 +00:00
|
|
|
|
2022-12-31 13:27:14 +00:00
|
|
|
val variable = st.lookupOrElse("block1.sub2.v2") { fail("v2 must be found") }
|
2022-03-04 22:25:26 +00:00
|
|
|
variable.type shouldBe StNodeType.STATICVAR
|
|
|
|
}
|
|
|
|
|
|
|
|
test("symboltable nested lookups") {
|
|
|
|
val st = makeSt()
|
|
|
|
|
2022-12-31 13:27:14 +00:00
|
|
|
val sub1 = st.lookupOrElse("block1.sub1") { fail("should find sub1") }
|
2022-03-04 22:25:26 +00:00
|
|
|
sub1.name shouldBe "sub1"
|
2022-12-30 18:01:00 +00:00
|
|
|
sub1.scopedName shouldBe "block1.sub1"
|
2022-03-04 22:25:26 +00:00
|
|
|
sub1.type shouldBe StNodeType.SUBROUTINE
|
2023-03-04 14:35:54 +00:00
|
|
|
sub1.children.size shouldBe 4
|
2022-03-04 22:25:26 +00:00
|
|
|
|
2022-12-31 13:27:14 +00:00
|
|
|
val v1 = sub1.lookupUnscopedOrElse("v1") { fail("v1 must be found") } as StStaticVariable
|
2022-03-04 22:25:26 +00:00
|
|
|
v1.type shouldBe StNodeType.STATICVAR
|
|
|
|
v1.name shouldBe "v1"
|
|
|
|
v1.dt shouldBe DataType.BYTE
|
|
|
|
|
2022-12-31 13:27:14 +00:00
|
|
|
val blockc = sub1.lookupUnscopedOrElse("blockc") { fail("blockc") } as StConstant
|
2022-03-04 22:25:26 +00:00
|
|
|
blockc.type shouldBe StNodeType.CONSTANT
|
|
|
|
blockc.value shouldBe 999.0
|
|
|
|
|
2022-12-31 13:27:14 +00:00
|
|
|
val subsub = st.lookupOrElse("block2.sub2.subsub") { fail("should find subsub") }
|
|
|
|
subsub.lookupUnscoped("blockc") shouldBe null
|
|
|
|
subsub.lookupUnscoped("label") shouldNotBe null
|
2022-03-04 22:25:26 +00:00
|
|
|
}
|
2023-02-09 21:49:34 +00:00
|
|
|
|
2023-03-04 14:35:54 +00:00
|
|
|
test("symboltable collections") {
|
|
|
|
val st= makeSt()
|
|
|
|
|
|
|
|
st.allVariables.size shouldBe 4
|
|
|
|
st.allMemMappedVariables.single().scopedName shouldBe "block1.sub1.v3"
|
|
|
|
st.allMemorySlabs.single().scopedName shouldBe "block1.sub1.slab1"
|
|
|
|
}
|
2023-02-09 21:49:34 +00:00
|
|
|
|
2022-03-04 22:25:26 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
private fun makeSt(): SymbolTable {
|
2023-02-09 21:49:34 +00:00
|
|
|
|
|
|
|
// first build the AST
|
|
|
|
val astProgram = PtProgram("test", DummyMemsizer, DummyStringEncoder)
|
|
|
|
val astBlock1 = PtBlock("block1", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("block1"), Position.DUMMY)
|
|
|
|
val astConstant1 = PtConstant("c1", DataType.UWORD, 12345.0, Position.DUMMY)
|
|
|
|
val astConstant2 = PtConstant("blockc", DataType.UWORD, 999.0, Position.DUMMY)
|
|
|
|
astBlock1.add(astConstant1)
|
|
|
|
astBlock1.add(astConstant2)
|
|
|
|
val astSub1 = PtSub("sub1", emptyList(), null, Position.DUMMY)
|
|
|
|
val astSub2 = PtSub("sub2", emptyList(), null, Position.DUMMY)
|
2023-02-11 14:14:37 +00:00
|
|
|
val astSub1v1 = PtVariable("v1", DataType.BYTE, ZeropageWish.DONTCARE, null, null, Position.DUMMY)
|
|
|
|
val astSub1v2 = PtVariable("v2", DataType.BYTE, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
|
2023-03-04 14:35:54 +00:00
|
|
|
val astSub1v3 = PtVariable("v3", DataType.FLOAT, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
|
|
|
|
val astSub1v4 = PtVariable("slab1", DataType.UWORD, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
|
2023-02-11 14:14:37 +00:00
|
|
|
val astSub2v1 = PtVariable("v1", DataType.BYTE, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
|
|
|
|
val astSub2v2 = PtVariable("v2", DataType.BYTE, ZeropageWish.DONTCARE,null, null, Position.DUMMY)
|
2023-02-09 21:49:34 +00:00
|
|
|
astSub1.add(astSub1v1)
|
|
|
|
astSub1.add(astSub1v2)
|
2023-03-04 14:35:54 +00:00
|
|
|
astSub1.add(astSub1v3)
|
|
|
|
astSub1.add(astSub1v4)
|
2023-02-09 21:49:34 +00:00
|
|
|
astSub2.add(astSub2v2)
|
|
|
|
astSub2.add(astSub2v2)
|
|
|
|
astBlock1.add(astSub1)
|
|
|
|
astBlock1.add(astSub2)
|
|
|
|
val astBfunc = PtIdentifier("msb", DataType.UBYTE, Position.DUMMY)
|
|
|
|
astBlock1.add(astBfunc)
|
|
|
|
val astBlock2 = PtBlock("block2", null, false, false, PtBlock.BlockAlignment.NONE, SourceCode.Generated("block2"), Position.DUMMY)
|
|
|
|
val astSub21 = PtSub("sub1", emptyList(), null, Position.DUMMY)
|
|
|
|
val astSub22 = PtSub("sub2", emptyList(), null, Position.DUMMY)
|
|
|
|
val astSub221 = PtSub("subsub", emptyList(), null, Position.DUMMY)
|
|
|
|
val astLabel = PtLabel("label", Position.DUMMY)
|
|
|
|
astSub221.add(astLabel)
|
|
|
|
astSub22.add(astSub221)
|
|
|
|
astBlock2.add(astSub21)
|
|
|
|
astBlock2.add(astSub22)
|
|
|
|
astProgram.add(astBlock1)
|
|
|
|
astProgram.add(astBlock2)
|
|
|
|
|
|
|
|
// now hook up the SymbolTable on that AST
|
|
|
|
val st = SymbolTable(astProgram)
|
|
|
|
val block1 = StNode("block1", StNodeType.BLOCK, astBlock1)
|
|
|
|
val sub11 = StNode("sub1", StNodeType.SUBROUTINE, astSub1)
|
|
|
|
val sub12 = StNode("sub2", StNodeType.SUBROUTINE, astSub2)
|
2022-03-04 22:25:26 +00:00
|
|
|
block1.add(sub11)
|
|
|
|
block1.add(sub12)
|
2023-02-09 21:49:34 +00:00
|
|
|
block1.add(StConstant("c1", DataType.UWORD, 12345.0, astConstant1))
|
|
|
|
block1.add(StConstant("blockc", DataType.UWORD, 999.0, astConstant2))
|
2023-02-19 14:23:57 +00:00
|
|
|
sub11.add(StStaticVariable("v1", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, astSub1v1))
|
|
|
|
sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, astSub1v2))
|
2023-03-04 14:35:54 +00:00
|
|
|
sub11.add(StMemVar("v3", DataType.FLOAT, 12345u, null, astSub1v3))
|
|
|
|
sub11.add(StMemorySlab("slab1", 200u, 64u, astSub1v4))
|
2023-02-19 14:23:57 +00:00
|
|
|
sub12.add(StStaticVariable("v1", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, astSub2v1))
|
|
|
|
sub12.add(StStaticVariable("v2", DataType.BYTE, null, null, null, null, ZeropageWish.DONTCARE, astSub2v2))
|
2023-02-09 21:49:34 +00:00
|
|
|
val block2 = StNode("block2", StNodeType.BLOCK, astBlock2)
|
|
|
|
val sub21 = StNode("sub1", StNodeType.SUBROUTINE, astSub21)
|
|
|
|
val sub22 = StNode("sub2", StNodeType.SUBROUTINE, astSub22)
|
2022-03-04 22:25:26 +00:00
|
|
|
block2.add(sub21)
|
|
|
|
block2.add(sub22)
|
2023-02-09 21:49:34 +00:00
|
|
|
val sub221 = StNode("subsub", StNodeType.SUBROUTINE, astSub221)
|
|
|
|
sub221.add(StNode("label", StNodeType.LABEL, astLabel))
|
2022-03-04 22:25:26 +00:00
|
|
|
sub22.add(sub221)
|
|
|
|
|
2023-02-09 21:49:34 +00:00
|
|
|
val builtinfunc = StNode("msb", StNodeType.BUILTINFUNC, astBfunc)
|
2022-03-04 22:25:26 +00:00
|
|
|
st.add(block1)
|
|
|
|
st.add(block2)
|
|
|
|
st.add(builtinfunc)
|
|
|
|
return st
|
2023-02-09 21:49:34 +00:00
|
|
|
}
|