diff --git a/src/build/Function.go b/src/build/Function.go index 4bd2a94..7a2b103 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -74,8 +74,6 @@ func (f *Function) CompileTokens(body token.List) error { if err != nil { return err } - - start = -1 } start = i + 1 diff --git a/src/build/compile.go b/src/build/compile.go index 325bcd5..c028a68 100644 --- a/src/build/compile.go +++ b/src/build/compile.go @@ -51,30 +51,11 @@ func compile(functions <-chan *Function, errors <-chan error) (Result, error) { result.Used = append(result.Used, main) delete(result.Unused, "main") - result.findCalls(main) + result.findAliveCode(main) return result, nil } -func (result *Result) findCalls(f *Function) { - for _, x := range f.Assembler.Instructions { - if x.Mnemonic != asm.CALL { - continue - } - - name := x.Data.(*asm.Label).Name - called, exists := result.Unused[name] - - if !exists { - continue - } - - result.Used = append(result.Used, called) - delete(result.Unused, name) - result.findCalls(called) - } -} - // compileFunctions starts a goroutine for each function compilation and waits for completion. func compileFunctions(functions map[string]*Function) { wg := sync.WaitGroup{} @@ -90,3 +71,23 @@ func compileFunctions(functions map[string]*Function) { wg.Wait() } + +// findAliveCode recursively finds all the calls to external functions and marks them as required. +func (result *Result) findAliveCode(f *Function) { + for _, x := range f.Assembler.Instructions { + if x.Mnemonic != asm.CALL { + continue + } + + name := x.Data.(*asm.Label).Name + called, exists := result.Unused[name] + + if !exists { + continue + } + + result.Used = append(result.Used, called) + delete(result.Unused, name) + result.findAliveCode(called) + } +} diff --git a/src/build/expression/Expression_test.go b/src/build/expression/Expression_test.go index c0fe259..e267a60 100644 --- a/src/build/expression/Expression_test.go +++ b/src/build/expression/Expression_test.go @@ -102,14 +102,15 @@ func TestEachLeaf(t *testing.T) { expr := expression.Parse(tokens) leaves := []string{} - expr.EachLeaf(func(leaf *expression.Expression) error { + err := expr.EachLeaf(func(leaf *expression.Expression) error { leaves = append(leaves, leaf.Token.Text()) return nil }) + assert.Nil(t, err) assert.DeepEqual(t, leaves, []string{"1", "2", "3", "4", "5", "6", "7", "8"}) - err := expr.EachLeaf(func(leaf *expression.Expression) error { + err = expr.EachLeaf(func(leaf *expression.Expression) error { return fmt.Errorf("error") }) diff --git a/src/build/expression/List.go b/src/build/expression/List.go index 2bb4b56..75c44d0 100644 --- a/src/build/expression/List.go +++ b/src/build/expression/List.go @@ -4,8 +4,8 @@ import ( "git.akyoto.dev/cli/q/src/build/token" ) -// List generates a list of expressions from comma separated parameters. -func List(tokens token.List) []*Expression { +// NewList generates a list of expressions from comma separated parameters. +func NewList(tokens token.List) []*Expression { var list []*Expression EachParameter(tokens, func(parameter token.List) error { diff --git a/src/build/expression/Parse.go b/src/build/expression/Parse.go index 536718b..072dfe4 100644 --- a/src/build/expression/Parse.go +++ b/src/build/expression/Parse.go @@ -38,7 +38,7 @@ func Parse(tokens token.List) *Expression { isFunctionCall := isComplete(cursor) if isFunctionCall { - parameters := List(tokens[groupPosition:i]) + parameters := NewList(tokens[groupPosition:i]) node := New() node.Token.Kind = token.Operator diff --git a/src/build/fs/Walk_test.go b/src/build/fs/Walk_test.go index ae55b3d..d3f6e17 100644 --- a/src/build/fs/Walk_test.go +++ b/src/build/fs/Walk_test.go @@ -10,10 +10,11 @@ import ( func TestWalk(t *testing.T) { var files []string - fs.Walk(".", func(file string) { + err := fs.Walk(".", func(file string) { files = append(files, file) }) + assert.Nil(t, err) assert.Contains(t, files, "Walk.go") assert.Contains(t, files, "Walk_test.go") }