Improve code quality

This commit is contained in:
Neemek 2025-03-16 21:16:12 +01:00
parent 5edad332cd
commit 3f260e7ffd
Signed by: neemek
GPG key ID: 28360A8951CD0E9B
11 changed files with 95 additions and 45 deletions

View file

@ -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")

View file

@ -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)

View file

@ -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)

View file

@ -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() {

View file

@ -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 {

View file

@ -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()

View file

@ -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

View file

@ -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{}

View file

@ -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)

View file

@ -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
} }

View file

@ -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)