Improve code quality
This commit is contained in:
parent
5edad332cd
commit
3f260e7ffd
11 changed files with 95 additions and 45 deletions
10
cli/main.go
10
cli/main.go
|
|
@ -116,7 +116,10 @@ func (cmd *RunCmd) Run(ctx *Context) error {
|
||||||
if ctx.Debug {
|
if ctx.Debug {
|
||||||
log.Println("Compiling parse tree")
|
log.Println("Compiling parse tree")
|
||||||
}
|
}
|
||||||
c.Compile(tree)
|
err = c.Compile(tree)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
chunk = c.Chunk
|
chunk = c.Chunk
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -219,7 +222,10 @@ func (cmd *CompileCmd) Run(ctx *Context) error {
|
||||||
log.Println("Compiling parse tree")
|
log.Println("Compiling parse tree")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Compile(tree)
|
err = c.Compile(tree)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if ctx.Debug {
|
if ctx.Debug {
|
||||||
log.Println("Registering GOB types")
|
log.Println("Registering GOB types")
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,10 @@ func TestAll(t *testing.T) {
|
||||||
c := NewCompiler()
|
c := NewCompiler()
|
||||||
|
|
||||||
t.Log("Compiling parse tree")
|
t.Log("Compiling parse tree")
|
||||||
c.Compile(tree)
|
err = c.Compile(tree)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Compiler had an error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
printChunk(t, name, c.Chunk)
|
printChunk(t, name, c.Chunk)
|
||||||
|
|
||||||
|
|
@ -108,7 +111,7 @@ func BenchmarkAll(b *testing.B) {
|
||||||
tree, _ := p.Parse()
|
tree, _ := p.Parse()
|
||||||
|
|
||||||
c := NewCompiler()
|
c := NewCompiler()
|
||||||
c.Compile(tree)
|
_ = c.Compile(tree)
|
||||||
|
|
||||||
vm := NewVM(c.Chunk, 256, 256)
|
vm := NewVM(c.Chunk, 256, 256)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,10 @@ func (c *Compiler) Compile(tree Node) error {
|
||||||
c.addConstant(v)
|
c.addConstant(v)
|
||||||
} else {
|
} else {
|
||||||
for _, n := range l.items {
|
for _, n := range l.items {
|
||||||
c.Compile(n)
|
err := c.Compile(n)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c.add(InstructionFormList)
|
c.add(InstructionFormList)
|
||||||
c.addU16(uint16(len(l.items)))
|
c.addU16(uint16(len(l.items)))
|
||||||
|
|
@ -102,7 +105,10 @@ func (c *Compiler) Compile(tree Node) error {
|
||||||
c.getVar(tree.(*ReferenceNode).name)
|
c.getVar(tree.(*ReferenceNode).name)
|
||||||
|
|
||||||
case BinaryNodeType:
|
case BinaryNodeType:
|
||||||
c.compileBinary(tree.(*BinaryNode))
|
err := c.compileBinary(tree.(*BinaryNode))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
case BooleanNodeType:
|
case BooleanNodeType:
|
||||||
if tree.(*BooleanNode).value {
|
if tree.(*BooleanNode).value {
|
||||||
|
|
@ -117,7 +123,10 @@ func (c *Compiler) Compile(tree Node) error {
|
||||||
case BlockNodeType:
|
case BlockNodeType:
|
||||||
c.descend()
|
c.descend()
|
||||||
for _, n := range tree.(*BlockNode).statements {
|
for _, n := range tree.(*BlockNode).statements {
|
||||||
c.Compile(n)
|
err := c.Compile(n)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c.ascend()
|
c.ascend()
|
||||||
|
|
||||||
|
|
@ -125,7 +134,10 @@ func (c *Compiler) Compile(tree Node) error {
|
||||||
n := tree.(*ConditionalNode)
|
n := tree.(*ConditionalNode)
|
||||||
|
|
||||||
// the stack should have whether the condition was truthful
|
// the stack should have whether the condition was truthful
|
||||||
c.Compile(n.condition)
|
err := c.Compile(n.condition)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// if the condition equated to true, we should jump over the body
|
// if the condition equated to true, we should jump over the body
|
||||||
c.add(InstructionJumpFalse)
|
c.add(InstructionJumpFalse)
|
||||||
|
|
@ -135,7 +147,10 @@ func (c *Compiler) Compile(tree Node) error {
|
||||||
c.advance(2)
|
c.advance(2)
|
||||||
|
|
||||||
// this part would be executed if the value was true
|
// this part would be executed if the value was true
|
||||||
c.Compile(n.do)
|
err = c.Compile(n.do)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// we store the position of the jump over the else code here
|
// we store the position of the jump over the else code here
|
||||||
var jumpOverElse Pos
|
var jumpOverElse Pos
|
||||||
|
|
@ -150,7 +165,10 @@ func (c *Compiler) Compile(tree Node) error {
|
||||||
c.putU16(jumpByPos, uint16(c.ip-jumpByPos-2))
|
c.putU16(jumpByPos, uint16(c.ip-jumpByPos-2))
|
||||||
|
|
||||||
if n.otherwise != nil {
|
if n.otherwise != nil {
|
||||||
c.Compile(n.otherwise)
|
err := c.Compile(n.otherwise)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
c.putU16(jumpOverElse, uint16(c.ip-jumpOverElse-2))
|
c.putU16(jumpOverElse, uint16(c.ip-jumpOverElse-2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,13 +176,19 @@ func (c *Compiler) Compile(tree Node) error {
|
||||||
n := tree.(*LoopNode)
|
n := tree.(*LoopNode)
|
||||||
|
|
||||||
conditionPos := c.ip
|
conditionPos := c.ip
|
||||||
c.Compile(n.condition)
|
err := c.Compile(n.condition)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
c.add(InstructionJumpFalse)
|
c.add(InstructionJumpFalse)
|
||||||
jumpValuePos := c.ip
|
jumpValuePos := c.ip
|
||||||
c.advance(2)
|
c.advance(2)
|
||||||
|
|
||||||
c.Compile(n.do)
|
err = c.Compile(n.do)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
c.add(InstructionLoop)
|
c.add(InstructionLoop)
|
||||||
// condition pos < ip
|
// condition pos < ip
|
||||||
|
|
@ -177,20 +201,32 @@ func (c *Compiler) Compile(tree Node) error {
|
||||||
|
|
||||||
if n.name == "_" {
|
if n.name == "_" {
|
||||||
// allow non-ish statements
|
// allow non-ish statements
|
||||||
c.Compile(n.value)
|
err := c.Compile(n.value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
c.add(InstructionPop)
|
c.add(InstructionPop)
|
||||||
} else {
|
} else {
|
||||||
c.setVar(n.name, n.value, n.declare)
|
err := c.setVar(n.name, n.value, n.declare)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case CallNodeType:
|
case CallNodeType:
|
||||||
n := tree.(*CallNode)
|
n := tree.(*CallNode)
|
||||||
|
|
||||||
for _, arg := range n.args {
|
for _, arg := range n.args {
|
||||||
c.Compile(arg)
|
err := c.Compile(arg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Compile(n.source)
|
err := c.Compile(n.source)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
c.add(InstructionCall)
|
c.add(InstructionCall)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"conditional_welse_false": {
|
"conditional_else_false": {
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
|
|
@ -164,7 +164,7 @@ func GetCompileTestData() map[string]CompileTestData {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"conditional_welse_true": {
|
"conditional_else_true": {
|
||||||
&BlockNode{
|
&BlockNode{
|
||||||
[]Node{
|
[]Node{
|
||||||
&AssignNode{
|
&AssignNode{
|
||||||
|
|
@ -363,7 +363,10 @@ func TestCompile(t *testing.T) {
|
||||||
c := NewCompiler()
|
c := NewCompiler()
|
||||||
|
|
||||||
t.Log("Compiling node tree")
|
t.Log("Compiling node tree")
|
||||||
c.Compile(testCase.tree)
|
err := c.Compile(testCase.tree)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Compiling failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
t.Log("Initializing vm")
|
t.Log("Initializing vm")
|
||||||
vm := NewVM(c.Chunk, 256, 256)
|
vm := NewVM(c.Chunk, 256, 256)
|
||||||
|
|
@ -387,7 +390,7 @@ func BenchmarkCompile(b *testing.B) {
|
||||||
b.Run(name, func(b *testing.B) {
|
b.Run(name, func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
c := NewCompiler()
|
c := NewCompiler()
|
||||||
c.Compile(testCase.tree)
|
_ = c.Compile(testCase.tree)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -426,16 +429,15 @@ func TestCompiler_CleanStack(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean statements
|
// clean statements
|
||||||
case BlockNodeType:
|
default:
|
||||||
case ConditionalNodeType:
|
|
||||||
case LoopNodeType:
|
|
||||||
case AssignNodeType:
|
|
||||||
case FunctionNodeType:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
c := NewCompiler()
|
c := NewCompiler()
|
||||||
c.Compile(tc.tree)
|
err := c.Compile(tc.tree)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Compiling failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
vm := NewVM(c.Chunk, 256, 256)
|
vm := NewVM(c.Chunk, 256, 256)
|
||||||
for vm.Next() {
|
for vm.Next() {
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ func (l *Lexer) NextToken() (Token, error) {
|
||||||
|
|
||||||
l.start = l.current
|
l.start = l.current
|
||||||
|
|
||||||
var c = []rune(l.src)[l.current]
|
var c = l.src[l.current]
|
||||||
l.advance()
|
l.advance()
|
||||||
|
|
||||||
switch c {
|
switch c {
|
||||||
|
|
|
||||||
|
|
@ -182,14 +182,14 @@ func TestNewLexer(t *testing.T) {
|
||||||
|
|
||||||
// lexer NextToken provides an error when it comes across an invalid token
|
// lexer NextToken provides an error when it comes across an invalid token
|
||||||
func TestLexer_NextTokenErrors(t *testing.T) {
|
func TestLexer_NextTokenErrors(t *testing.T) {
|
||||||
invalid_codes := []string{
|
invalidCodes := []string{
|
||||||
// Invalid tokens
|
// Invalid tokens
|
||||||
"^", "@", "$&", "¨",
|
"^", "@", "$&", "¨",
|
||||||
// Non-ending string (in same line)
|
// Non-ending string (in same line)
|
||||||
"\"", "Hini minit \"mini moe", "\"this is some test\ncontent\"", "\n\"Hello world",
|
"\"", "Hini minit \"mini moe", "\"this is some test\ncontent\"", "\n\"Hello world",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, code := range invalid_codes {
|
for _, code := range invalidCodes {
|
||||||
lex := NewLexer(code)
|
lex := NewLexer(code)
|
||||||
tok, err := lex.NextToken()
|
tok, err := lex.NextToken()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ func (n NilNode) String() string {
|
||||||
return "nil"
|
return "nil"
|
||||||
}
|
}
|
||||||
|
|
||||||
// block node with statements
|
// BlockNode block node with statements
|
||||||
type BlockNode struct {
|
type BlockNode struct {
|
||||||
statements []Node
|
statements []Node
|
||||||
}
|
}
|
||||||
|
|
@ -284,7 +284,7 @@ func (n ConditionalNode) String() string {
|
||||||
return fmt.Sprintf("if %s then %s otheriwise %s", n.condition.String(), n.do.String(), n.otherwise.String())
|
return fmt.Sprintf("if %s then %s otheriwise %s", n.condition.String(), n.do.String(), n.otherwise.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loops (for/while)
|
// LoopNode Loops (for/while)
|
||||||
type LoopNode struct {
|
type LoopNode struct {
|
||||||
condition Node
|
condition Node
|
||||||
do Node
|
do Node
|
||||||
|
|
@ -298,7 +298,7 @@ func (n LoopNode) String() string {
|
||||||
return fmt.Sprintf("while %s loop %s", n.condition.String(), n.do.String())
|
return fmt.Sprintf("while %s loop %s", n.condition.String(), n.do.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// assignment
|
// AssignNode assignment
|
||||||
type AssignNode struct {
|
type AssignNode struct {
|
||||||
name string
|
name string
|
||||||
value Node
|
value Node
|
||||||
|
|
@ -313,7 +313,7 @@ func (n AssignNode) String() string {
|
||||||
return fmt.Sprintf("set %s to %s", n.name, n.value)
|
return fmt.Sprintf("set %s to %s", n.name, n.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// function call
|
// CallNode function call
|
||||||
type CallNode struct {
|
type CallNode struct {
|
||||||
source Node
|
source Node
|
||||||
args []Node
|
args []Node
|
||||||
|
|
@ -328,7 +328,7 @@ func (n CallNode) String() string {
|
||||||
return fmt.Sprintf("call %s with args (%s)", n.source.String(), n.args)
|
return fmt.Sprintf("call %s with args (%s)", n.source.String(), n.args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// definition of function
|
// FunctionNode definition of function
|
||||||
type FunctionNode struct {
|
type FunctionNode struct {
|
||||||
name string
|
name string
|
||||||
params []string
|
params []string
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ func (p *ParsingError) Error() string {
|
||||||
return p.Description
|
return p.Description
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print a rich and informative error
|
// Format Print a rich and informative error
|
||||||
func (p *ParsingError) Format(src []rune) string {
|
func (p *ParsingError) Format(src []rune) string {
|
||||||
builder := strings.Builder{}
|
builder := strings.Builder{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -667,9 +667,9 @@ func NodeEquality(t *testing.T, n1 Node, n2 Node) {
|
||||||
|
|
||||||
func TestParser_Parse(t *testing.T) {
|
func TestParser_Parse(t *testing.T) {
|
||||||
t.Logf("Getting test data")
|
t.Logf("Getting test data")
|
||||||
token_data := GetTokenTestData()
|
tokenData := GetTokenTestData()
|
||||||
|
|
||||||
for name, data := range token_data {
|
for name, data := range tokenData {
|
||||||
if name != "empty_block" && name != "lambda" {
|
if name != "empty_block" && name != "lambda" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -692,9 +692,9 @@ func TestParser_Parse(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkParser_Parse(b *testing.B) {
|
func BenchmarkParser_Parse(b *testing.B) {
|
||||||
token_data := GetTokenTestData()
|
tokenData := GetTokenTestData()
|
||||||
|
|
||||||
for name, data := range token_data {
|
for name, data := range tokenData {
|
||||||
b.Run(name, func(b *testing.B) {
|
b.Run(name, func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
p := NewParser(data.tokens)
|
p := NewParser(data.tokens)
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ func (v *BoolValue) Equals(other Value) bool {
|
||||||
return other.Type() == BoolValueType && other.(*BoolValue).bool == v.bool
|
return other.Type() == BoolValueType && other.(*BoolValue).bool == v.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *BoolValue) Get(key string) (Value, error) {
|
func (v *BoolValue) Get(_ string) (Value, error) {
|
||||||
return nil, errors.New("booleans have no properties")
|
return nil, errors.New("booleans have no properties")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -254,7 +254,7 @@ func (v *NumberValue) Equals(other Value) bool {
|
||||||
return other.Type() == NumberValueType && other.(*NumberValue).float64 == v.float64
|
return other.Type() == NumberValueType && other.(*NumberValue).float64 == v.float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *NumberValue) Get(key string) (Value, error) {
|
func (v *NumberValue) Get(_ string) (Value, error) {
|
||||||
// TODO maybe add standard functions for number values?
|
// TODO maybe add standard functions for number values?
|
||||||
return nil, errors.New("numbers have no properties")
|
return nil, errors.New("numbers have no properties")
|
||||||
}
|
}
|
||||||
|
|
@ -489,7 +489,7 @@ type BuiltinFunctionValue struct {
|
||||||
Parent Value
|
Parent Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v BuiltinFunctionValue) Type() ValueType {
|
func (v *BuiltinFunctionValue) Type() ValueType {
|
||||||
return BuiltinFunctionValueType
|
return BuiltinFunctionValueType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func jsErrorOfString(err string) interface{} {
|
||||||
return errorObject
|
return errorObject
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(this js.Value, args []js.Value) interface{} {
|
func run(_ js.Value, args []js.Value) interface{} {
|
||||||
source := args[0].String()
|
source := args[0].String()
|
||||||
outputHandler := args[1]
|
outputHandler := args[1]
|
||||||
resolver := args[2]
|
resolver := args[2]
|
||||||
|
|
@ -89,9 +89,12 @@ func run(this js.Value, args []js.Value) interface{} {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
compiler.Compile(tree)
|
err = compiler.Compile(tree)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("Compiled tree (into %i instructions)", len(compiler.Chunk.Bytecode))
|
log.Printf("Compiled tree (into %v instructions)", len(compiler.Chunk.Bytecode))
|
||||||
|
|
||||||
vm := core.NewVM(compiler.Chunk, 256, 256)
|
vm := core.NewVM(compiler.Chunk, 256, 256)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue