var type checking, fix importing, fix creating empty lists, repl command, dynamic stacks
This commit is contained in:
parent
f633a02c32
commit
5bcab07681
11 changed files with 407 additions and 284 deletions
|
|
@ -157,7 +157,6 @@ func (c *Compiler) addConstant(value Value) {
|
|||
|
||||
func (c *Compiler) Compile(p *Program) error {
|
||||
c.fileStack.Push(p.Path)
|
||||
defer c.fileStack.Pop()
|
||||
|
||||
for _, i := range p.Imports {
|
||||
if err := c.resolveImport(i); err != nil {
|
||||
|
|
@ -171,6 +170,8 @@ func (c *Compiler) Compile(p *Program) error {
|
|||
}
|
||||
}
|
||||
|
||||
c.fileStack.Pop()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -451,7 +452,8 @@ func (c *Compiler) compile(tree Node) error {
|
|||
c.registerVar(p.Name, p.Signature)
|
||||
}
|
||||
|
||||
if err := c.affirmReturnSignature(n.logic, n.yield); err != nil {
|
||||
err = c.affirmReturnSignature(n.logic, n.yield)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -585,7 +587,7 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
|
|||
case ListNodeType:
|
||||
n := tree.(*ListNode)
|
||||
|
||||
var contents TypeSignature
|
||||
contents := n.content
|
||||
// check for contents type
|
||||
for _, v := range n.items {
|
||||
sig, err := c.deduceSignature(v)
|
||||
|
|
@ -596,8 +598,7 @@ func (c *Compiler) deduceSignature(tree Node) (TypeSignature, error) {
|
|||
if contents == nil {
|
||||
contents = sig
|
||||
} else if !contents.Matches(sig) {
|
||||
contents = &AnySignature{}
|
||||
break
|
||||
return nil, c.error(fmt.Sprintf("non-conforming item type"), v)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -804,7 +805,7 @@ func (c *Compiler) affirmReturnSignature(tree Node, sig TypeSignature) error {
|
|||
}
|
||||
|
||||
if !sig.Matches(v) {
|
||||
return c.error(fmt.Sprintf("function cannot return a value with type %s. defined to be %s", v, sig), n.value)
|
||||
return c.error(fmt.Sprintf("function cannot return a value with type %s. defined to be %s", v, sig), n)
|
||||
}
|
||||
|
||||
case ConditionalNodeType:
|
||||
|
|
@ -842,7 +843,7 @@ func (c *Compiler) affirmReturnSignature(tree Node, sig TypeSignature) error {
|
|||
}
|
||||
|
||||
if !sig.Matches(prev) {
|
||||
return c.error(fmt.Sprintf("cannot assign value of type %s to variable of type %s", prev, sig), n.value)
|
||||
return c.error(fmt.Sprintf("cannot assign value of type %s to variable %s of type %s", sig, n.name, prev), n.value)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -891,14 +892,24 @@ func (c *Compiler) addSetVar(name string, value Node, declare bool) error {
|
|||
return err
|
||||
}
|
||||
|
||||
t, err := c.deduceSignature(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if declare {
|
||||
c.add(InstructionDeclareLocal)
|
||||
t, err := c.deduceSignature(value)
|
||||
c.registerVar(name, t)
|
||||
} else {
|
||||
vt, err := c.getVarSignature(name, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.registerVar(name, t)
|
||||
} else {
|
||||
|
||||
if !vt.Matches(t) {
|
||||
return c.error(fmt.Sprintf("cannot assign value of type %s to variable %s of type %s", t, name, vt), value)
|
||||
}
|
||||
|
||||
c.add(InstructionSetLocal)
|
||||
}
|
||||
|
||||
|
|
@ -1090,10 +1101,7 @@ func (c *Compiler) ascend() {
|
|||
|
||||
func (c *Compiler) addAscend() {
|
||||
c.ascend()
|
||||
|
||||
if c.scope != 0 {
|
||||
c.add(InstructionAscend)
|
||||
}
|
||||
c.add(InstructionAscend)
|
||||
}
|
||||
|
||||
func (c *Compiler) descend() {
|
||||
|
|
@ -1102,9 +1110,7 @@ func (c *Compiler) descend() {
|
|||
|
||||
func (c *Compiler) addDescend() {
|
||||
c.descend()
|
||||
if c.scope != 1 {
|
||||
c.add(InstructionDescend)
|
||||
}
|
||||
c.add(InstructionDescend)
|
||||
}
|
||||
|
||||
func (c *Compiler) error(msg string, causer Node) CompilerError {
|
||||
|
|
@ -1169,6 +1175,10 @@ func (c *Compiler) SetImportsResolver(resolver ImportsResolver) {
|
|||
c.resolver = resolver
|
||||
}
|
||||
|
||||
func (c *Compiler) SetSource(src string) {
|
||||
c.source = []rune(src)
|
||||
}
|
||||
|
||||
func (c *Compiler) advance(amount Pos) {
|
||||
c.ip += amount
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,58 +28,80 @@ func BenchmarkNewCompiler(b *testing.B) {
|
|||
}
|
||||
|
||||
type CompileTestData struct {
|
||||
tree Node
|
||||
program *Program
|
||||
expectedStack []Value
|
||||
}
|
||||
|
||||
func GetCompileTestData() map[string]CompileTestData {
|
||||
return map[string]CompileTestData{
|
||||
"constant_string": {
|
||||
&StringNode{
|
||||
"Hello world!",
|
||||
"\"Hello world!\"",
|
||||
0, 0,
|
||||
&Program{
|
||||
[]string{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&StringNode{
|
||||
"Hello world!",
|
||||
"\"Hello world!\"",
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
"",
|
||||
},
|
||||
[]Value{
|
||||
&StringValue{"Hello world!"},
|
||||
&VariableValue{
|
||||
"a",
|
||||
&StringValue{"Hello world!"},
|
||||
0,
|
||||
},
|
||||
},
|
||||
},
|
||||
"conditional_false": {
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
0,
|
||||
&Program{
|
||||
[]string{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
0,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
&ConditionalNode{
|
||||
&BooleanNode{
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
1,
|
||||
&ConditionalNode{
|
||||
&BooleanNode{
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
1,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
"",
|
||||
},
|
||||
[]Value{
|
||||
&VariableValue{
|
||||
|
|
@ -90,41 +112,45 @@ func GetCompileTestData() map[string]CompileTestData {
|
|||
},
|
||||
},
|
||||
"conditional_true": {
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
0,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
&ConditionalNode{
|
||||
&BooleanNode{
|
||||
&Program{
|
||||
[]string{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
0,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
1,
|
||||
&ConditionalNode{
|
||||
&BooleanNode{
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
1,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
"",
|
||||
},
|
||||
[]Value{
|
||||
&VariableValue{
|
||||
|
|
@ -135,54 +161,58 @@ func GetCompileTestData() map[string]CompileTestData {
|
|||
},
|
||||
},
|
||||
"conditional_else_false": {
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
0,
|
||||
&Program{
|
||||
[]string{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
0,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
&ConditionalNode{
|
||||
&BooleanNode{
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
1,
|
||||
&ConditionalNode{
|
||||
&BooleanNode{
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
1,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
2,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
2,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
"",
|
||||
},
|
||||
[]Value{
|
||||
&VariableValue{
|
||||
|
|
@ -193,54 +223,58 @@ func GetCompileTestData() map[string]CompileTestData {
|
|||
},
|
||||
},
|
||||
"conditional_else_true": {
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
0,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
&ConditionalNode{
|
||||
&BooleanNode{
|
||||
&Program{
|
||||
[]string{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
0,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
1,
|
||||
&ConditionalNode{
|
||||
&BooleanNode{
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
1,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
2,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&NumberNode{
|
||||
2,
|
||||
0, 0,
|
||||
},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
"",
|
||||
},
|
||||
[]Value{
|
||||
&VariableValue{
|
||||
|
|
@ -251,67 +285,89 @@ func GetCompileTestData() map[string]CompileTestData {
|
|||
},
|
||||
},
|
||||
"addition": {
|
||||
&BinaryNode{
|
||||
BinaryAddition,
|
||||
&NumberNode{
|
||||
1,
|
||||
&Program{
|
||||
[]string{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&BinaryNode{
|
||||
BinaryAddition,
|
||||
&NumberNode{
|
||||
1,
|
||||
0, 0,
|
||||
},
|
||||
&NumberNode{
|
||||
2,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
&NumberNode{
|
||||
2,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
"",
|
||||
},
|
||||
[]Value{
|
||||
&NumberValue{3},
|
||||
&VariableValue{
|
||||
"a",
|
||||
&NumberValue{3},
|
||||
0,
|
||||
},
|
||||
},
|
||||
},
|
||||
"sum_function": {
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"sum",
|
||||
&FunctionNode{
|
||||
&Program{
|
||||
[]string{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"sum",
|
||||
[]FunctionParameter{
|
||||
{
|
||||
"a",
|
||||
&NumberSignature{},
|
||||
&FunctionNode{
|
||||
"sum",
|
||||
[]FunctionParameter{
|
||||
{
|
||||
"a",
|
||||
&NumberSignature{},
|
||||
},
|
||||
{
|
||||
"b",
|
||||
&NumberSignature{},
|
||||
},
|
||||
},
|
||||
{
|
||||
"b",
|
||||
&NumberSignature{},
|
||||
},
|
||||
},
|
||||
&NumberSignature{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&ReturnNode{
|
||||
&BinaryNode{
|
||||
BinaryAddition,
|
||||
&ReferenceNode{
|
||||
"a",
|
||||
0, 0,
|
||||
},
|
||||
&ReferenceNode{
|
||||
"b",
|
||||
&NumberSignature{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&ReturnNode{
|
||||
&BinaryNode{
|
||||
BinaryAddition,
|
||||
&ReferenceNode{
|
||||
"a",
|
||||
0, 0,
|
||||
},
|
||||
&ReferenceNode{
|
||||
"b",
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
"",
|
||||
},
|
||||
[]Value{
|
||||
&VariableValue{
|
||||
|
|
@ -350,51 +406,55 @@ func GetCompileTestData() map[string]CompileTestData {
|
|||
},
|
||||
},
|
||||
"remove_func_vars": {
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
&FunctionNode{
|
||||
&Program{
|
||||
[]string{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"a",
|
||||
[]FunctionParameter{},
|
||||
&NumberSignature{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"b",
|
||||
&NumberNode{
|
||||
1,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
&ReturnNode{
|
||||
&ReferenceNode{
|
||||
&FunctionNode{
|
||||
"a",
|
||||
[]FunctionParameter{},
|
||||
&NumberSignature{},
|
||||
&BlockNode{
|
||||
[]Node{
|
||||
&AssignNode{
|
||||
"b",
|
||||
&NumberNode{
|
||||
1,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
&ReturnNode{
|
||||
&ReferenceNode{
|
||||
"b",
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
0, 0,
|
||||
},
|
||||
&CallNode{
|
||||
&ReferenceNode{
|
||||
"a",
|
||||
&CallNode{
|
||||
&ReferenceNode{
|
||||
"a",
|
||||
0, 0,
|
||||
},
|
||||
[]Node{},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
[]Node{},
|
||||
false,
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
},
|
||||
0, 0,
|
||||
"",
|
||||
},
|
||||
[]Value{
|
||||
&VariableValue{
|
||||
|
|
@ -423,29 +483,33 @@ func GetCompileTestData() map[string]CompileTestData {
|
|||
},
|
||||
},
|
||||
"two_lists": {
|
||||
tree: &BlockNode{
|
||||
statements: []Node{
|
||||
&AssignNode{
|
||||
name: "a",
|
||||
value: &ListNode{
|
||||
items: []Node{
|
||||
&NumberNode{value: 1},
|
||||
&NumberNode{value: 2},
|
||||
program: &Program{
|
||||
[]string{},
|
||||
&BlockNode{
|
||||
statements: []Node{
|
||||
&AssignNode{
|
||||
name: "a",
|
||||
value: &ListNode{
|
||||
items: []Node{
|
||||
&NumberNode{value: 1},
|
||||
&NumberNode{value: 2},
|
||||
},
|
||||
},
|
||||
declare: true,
|
||||
},
|
||||
declare: true,
|
||||
},
|
||||
&AssignNode{
|
||||
name: "b",
|
||||
value: &ListNode{
|
||||
items: []Node{
|
||||
&StringNode{value: "Hello"},
|
||||
&StringNode{value: "world"},
|
||||
&AssignNode{
|
||||
name: "b",
|
||||
value: &ListNode{
|
||||
items: []Node{
|
||||
&StringNode{value: "Hello"},
|
||||
&StringNode{value: "world"},
|
||||
},
|
||||
},
|
||||
declare: true,
|
||||
},
|
||||
declare: true,
|
||||
},
|
||||
},
|
||||
"",
|
||||
},
|
||||
expectedStack: []Value{
|
||||
&VariableValue{
|
||||
|
|
@ -499,10 +563,10 @@ func TestCompile(t *testing.T) {
|
|||
for name, testCase := range data {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Log("Initializing compiler")
|
||||
c := NewCompiler([]rune(testCase.tree.String()))
|
||||
c := NewCompiler([]rune(testCase.program.String()))
|
||||
|
||||
t.Log("Compiling node tree")
|
||||
err := c.compile(testCase.tree)
|
||||
err := c.Compile(testCase.program)
|
||||
if err != nil {
|
||||
t.Fatalf("Compiling failed: %v", err)
|
||||
}
|
||||
|
|
@ -529,7 +593,7 @@ func BenchmarkCompile(b *testing.B) {
|
|||
b.Run(name, func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
c := NewCompiler([]rune{})
|
||||
_ = c.compile(testCase.tree)
|
||||
_ = c.Compile(testCase.program)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -556,24 +620,9 @@ func TestCompiler_CleanStack(t *testing.T) {
|
|||
cases := GetCompileTestData()
|
||||
|
||||
for name, tc := range cases {
|
||||
switch tc.tree.Type() {
|
||||
// skip all expected unclean nodes
|
||||
case StringNodeType, NumberNodeType, ReferenceNodeType, BooleanNodeType, NilNodeType, BinaryNodeType, ReturnNodeType:
|
||||
continue
|
||||
|
||||
case CallNodeType:
|
||||
if tc.tree.(*CallNode).keep {
|
||||
// if we know it should be unclean, skip it
|
||||
continue
|
||||
}
|
||||
|
||||
// clean statements
|
||||
default:
|
||||
}
|
||||
|
||||
t.Run(name, func(t *testing.T) {
|
||||
c := NewCompiler([]rune(tc.tree.String()))
|
||||
err := c.compile(tc.tree)
|
||||
c := NewCompiler([]rune(tc.program.String()))
|
||||
err := c.Compile(tc.program)
|
||||
if err != nil {
|
||||
t.Fatalf("Compiling failed: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,7 +137,8 @@ func (n NumberNode) Bounds() (Pos, Pos) {
|
|||
|
||||
// ListNode a list or sequence of values (items)
|
||||
type ListNode struct {
|
||||
items []Node
|
||||
items []Node
|
||||
content TypeSignature
|
||||
|
||||
start Pos
|
||||
end Pos
|
||||
|
|
|
|||
|
|
@ -253,9 +253,21 @@ func (p *Parser) factor() (Node, error) {
|
|||
|
||||
case TokenOpenBracket:
|
||||
p.advance()
|
||||
|
||||
start := p.prev.Start
|
||||
|
||||
if p.accept(TokenCloseBracket) {
|
||||
s, err := p.parseSignature()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ListNode{
|
||||
[]Node{},
|
||||
s,
|
||||
start,
|
||||
p.prev.Start + p.prev.Length,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var values []Node
|
||||
for !p.accept(TokenCloseBracket) {
|
||||
if len(values) > 0 {
|
||||
|
|
@ -275,6 +287,7 @@ func (p *Parser) factor() (Node, error) {
|
|||
|
||||
return &ListNode{
|
||||
values,
|
||||
nil,
|
||||
start,
|
||||
p.prev.Start + p.prev.Length,
|
||||
}, nil
|
||||
|
|
@ -386,9 +399,7 @@ func (p *Parser) factor() (Node, error) {
|
|||
return v, nil
|
||||
|
||||
default:
|
||||
err := p.error("invalid factor", p.curr)
|
||||
p.advance()
|
||||
return nil, err
|
||||
return nil, p.error("invalid factor", p.curr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -688,10 +699,10 @@ func (p *Parser) statement() (Node, error) {
|
|||
start,
|
||||
p.prev.Start + p.prev.Length,
|
||||
}, nil
|
||||
} else {
|
||||
return p.condition()
|
||||
}
|
||||
|
||||
return nil, p.error("invalid statement", p.curr)
|
||||
|
||||
case TokenFunc:
|
||||
p.advance()
|
||||
|
||||
|
|
|
|||
|
|
@ -630,9 +630,11 @@ func GetTokenTestData() map[string]TokenTestData {
|
|||
0, 0,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
0, 0,
|
||||
},
|
||||
true,
|
||||
|
|
|
|||
|
|
@ -1,25 +1,28 @@
|
|||
package core
|
||||
|
||||
type Stack[T any] struct {
|
||||
Current Pos
|
||||
Size Pos
|
||||
Current Pos
|
||||
Capacity Pos
|
||||
|
||||
items []T
|
||||
}
|
||||
|
||||
func NewStack[T any](size Pos) *Stack[T] {
|
||||
func NewStack[T any](capacity Pos) *Stack[T] {
|
||||
return &Stack[T]{
|
||||
items: make([]T, size),
|
||||
Size: size,
|
||||
Current: 0,
|
||||
items: make([]T, 16),
|
||||
Capacity: capacity,
|
||||
Current: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Stack[T]) Push(items ...T) {
|
||||
for _, item := range items {
|
||||
if s.Current >= s.Size {
|
||||
if s.Current >= s.Capacity {
|
||||
panic("stack overflow")
|
||||
}
|
||||
if int(s.Current) == len(s.items) {
|
||||
s.items = append(s.items, item)
|
||||
}
|
||||
|
||||
s.items[s.Current] = item
|
||||
s.Current++
|
||||
|
|
@ -45,7 +48,7 @@ func (s *Stack[T]) Peek() T {
|
|||
|
||||
// check whether the stack is invalid (stack over-/underflow)
|
||||
func (s *Stack[T]) check() {
|
||||
if s.Current >= s.Size {
|
||||
if s.Current >= s.Capacity {
|
||||
panic("stack underflow")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,16 +25,10 @@ func TestNewStack(t *testing.T) {
|
|||
|
||||
s := NewStack[any](Pos(size))
|
||||
|
||||
if s.Size != Pos(size) {
|
||||
t.Errorf("Stack size (%d) does not match expected size (%d)", s.Size, size)
|
||||
if s.Capacity != Pos(size) {
|
||||
t.Errorf("Stack size (%d) does not match expected size (%d)", s.Capacity, size)
|
||||
} else {
|
||||
t.Logf("Stack size is expected size (%d)", s.Size)
|
||||
}
|
||||
|
||||
if len(s.items) != size {
|
||||
t.Errorf("internal items slice size (%d) does not match expected size (%d)", len(s.items), size)
|
||||
} else {
|
||||
t.Logf("internal items slice size is as expected (%d)", len(s.items))
|
||||
t.Logf("Stack size is expected size (%d)", s.Capacity)
|
||||
}
|
||||
|
||||
if s.Current != 0 {
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ func (v *ObjectValue) String() string {
|
|||
out += ", "
|
||||
}
|
||||
|
||||
out += fmt.Sprintf("%q=%s", key, value.String())
|
||||
out += fmt.Sprintf("%q=%s", key, value.DebugString())
|
||||
}
|
||||
out += "}"
|
||||
|
||||
|
|
|
|||
|
|
@ -826,6 +826,10 @@ func (vm *VM) Call(v Value, args []Value) (Value, error) {
|
|||
return nil, errors.New(fmt.Sprintf("value is not a function (%s)", v.DebugString()))
|
||||
}
|
||||
|
||||
func (vm *VM) SetChunk(c *Chunk) {
|
||||
vm.chunk = c
|
||||
}
|
||||
|
||||
func (vm *VM) TryNextByte() (Bytecode, error) {
|
||||
if !vm.HasNext() {
|
||||
return 0, errors.New("there are no more instructions")
|
||||
|
|
|
|||
|
|
@ -76,13 +76,13 @@ func TestNewVM(t *testing.T) {
|
|||
}
|
||||
|
||||
// should have given stack size
|
||||
if vm.stack.Size != stackSize {
|
||||
t.Errorf("vm.stack.Size = %d, want %d", vm.stack.Size, stackSize)
|
||||
if vm.stack.Capacity != stackSize {
|
||||
t.Errorf("vm.stack.Capacity = %d, want %d", vm.stack.Capacity, stackSize)
|
||||
}
|
||||
|
||||
// should have given call stack size
|
||||
if vm.call.Size != callstackSize {
|
||||
t.Errorf("vm.call.Size = %d, want %d", vm.call.Size, callstackSize)
|
||||
if vm.call.Capacity != callstackSize {
|
||||
t.Errorf("vm.call.Capacity = %d, want %d", vm.call.Capacity, callstackSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue