diff --git a/src/asmc/call.go b/src/asmc/call.go index 7a4f51a..3bdc411 100644 --- a/src/asmc/call.go +++ b/src/asmc/call.go @@ -1,6 +1,8 @@ package asmc import ( + "fmt" + "git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/x86" ) @@ -21,7 +23,7 @@ func (c *compiler) call(x asm.Instruction) { destination, exists := c.codeLabels[data.Name] if !exists { - panic("unknown jump label") + panic(fmt.Sprintf("unknown jump label %s", data.Name)) } distance := destination - (pointer.Position + Address(pointer.Size)) diff --git a/src/asmc/jump.go b/src/asmc/jump.go index 853bd81..9964c8b 100644 --- a/src/asmc/jump.go +++ b/src/asmc/jump.go @@ -1,6 +1,8 @@ package asmc import ( + "fmt" + "git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/x86" ) @@ -36,7 +38,7 @@ func (c *compiler) jump(x asm.Instruction) { destination, exists := c.codeLabels[label.Name] if !exists { - panic("unknown jump label") + panic(fmt.Sprintf("unknown jump label %s", label.Name)) } distance := destination - (pointer.Position + Address(pointer.Size)) diff --git a/src/compiler/Compile.go b/src/compiler/Compile.go index ae3c437..6fd88c1 100644 --- a/src/compiler/Compile.go +++ b/src/compiler/Compile.go @@ -82,6 +82,20 @@ func Compile(constants <-chan *core.Constant, files <-chan *fs.File, functions < } } + // Check for existence of `init` + init, exists := all.Functions["core.init"] + + if !exists { + return result, errors.MissingInitFunction + } + + // Check for existence of `main` + main, exists := all.Functions["main.main"] + + if !exists { + return result, errors.MissingMainFunction + } + // Start parallel compilation CompileFunctions(all.Functions) @@ -104,20 +118,6 @@ func Compile(constants <-chan *core.Constant, files <-chan *fs.File, functions < } } - // Check for existence of `init` - init, exists := all.Functions["core.init"] - - if !exists { - return result, errors.MissingInitFunction - } - - // Check for existence of `main` - main, exists := all.Functions["main.main"] - - if !exists { - return result, errors.MissingMainFunction - } - result.Init = init result.Main = main result.Functions = all.Functions diff --git a/src/compiler/eachFunction.go b/src/compiler/eachFunction.go index f3d6215..44bc00e 100644 --- a/src/compiler/eachFunction.go +++ b/src/compiler/eachFunction.go @@ -1,37 +1,20 @@ package compiler import ( - "git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/core" ) -// eachFunction recursively finds all the calls to external functions. +// eachFunction recursively finds all the calls to other functions. // It avoids calling the same function twice with the help of a hashmap. func (r *Result) eachFunction(caller *core.Function, traversed map[*core.Function]bool, call func(*core.Function)) { call(caller) traversed[caller] = true - for _, x := range caller.Assembler.Instructions { - if x.Mnemonic != asm.CALL { + for _, function := range caller.Dependencies { + if traversed[function] { continue } - label, isLabel := x.Data.(*asm.Label) - - if !isLabel { - continue - } - - callee, exists := r.Functions[label.Name] - - if !exists { - continue - } - - if traversed[callee] { - continue - } - - r.eachFunction(callee, traversed, call) + r.eachFunction(function, traversed, call) } } diff --git a/src/core/CompileCall.go b/src/core/CompileCall.go index 9d94c2b..de531e7 100644 --- a/src/core/CompileCall.go +++ b/src/core/CompileCall.go @@ -43,16 +43,7 @@ func (f *Function) CompileCall(root *expression.Expression) ([]types.Type, error switch value := value.(type) { case *eval.Label: - fn, exists := f.All.Functions[value.Label] - - if !exists { - if value.Label == "main.main" && f.UniqueName == "core.init" { - f.Label(asm.CALL, "main.main") - return nil, nil - } - - return nil, errors.New(&errors.UnknownIdentifier{Name: value.Label}, f.File, root.Children[0].Token.Position) - } + fn := f.All.Functions[value.Label] if len(parameters) != len(fn.Input) { return nil, errors.New(&errors.ParameterCountMismatch{Function: fn.Name, Count: len(parameters), ExpectedCount: len(fn.Input)}, f.File, root.Children[0].Token.End()) diff --git a/src/core/CompileDelete.go b/src/core/CompileDelete.go index ad01ee7..8100b6f 100644 --- a/src/core/CompileDelete.go +++ b/src/core/CompileDelete.go @@ -22,6 +22,8 @@ func (f *Function) CompileDelete(root *expression.Expression) error { f.SaveRegister(f.CPU.Input[1]) f.RegisterRegister(asm.MOVE, f.CPU.Input[0], variable.Value.Register) f.RegisterNumber(asm.MOVE, f.CPU.Input[1], variable.Value.Typ.(*types.Pointer).To.Size()) - f.CallSafe(f.All.Functions["mem.free"], f.CPU.Input[:2]) + free := f.All.Functions["mem.free"] + f.CallSafe(free, f.CPU.Input[:2]) + f.Dependencies = append(f.Dependencies, free) return nil } diff --git a/src/core/CompileNew.go b/src/core/CompileNew.go index 52a1649..26a47ac 100644 --- a/src/core/CompileNew.go +++ b/src/core/CompileNew.go @@ -45,6 +45,8 @@ func (f *Function) CompileNew(root *expression.Expression) (types.Type, error) { f.SaveRegister(f.CPU.Input[0]) f.RegisterNumber(asm.MOVE, f.CPU.Input[0], typ.Size()) - f.CallSafe(f.All.Functions["mem.alloc"], f.CPU.Input[:1]) + alloc := f.All.Functions["mem.alloc"] + f.CallSafe(alloc, f.CPU.Input[:1]) + f.Dependencies = append(f.Dependencies, alloc) return &types.Pointer{To: typ}, nil } diff --git a/src/core/EvaluateDot.go b/src/core/EvaluateDot.go index 69f078c..52738b3 100644 --- a/src/core/EvaluateDot.go +++ b/src/core/EvaluateDot.go @@ -42,7 +42,8 @@ func (f *Function) EvaluateDot(expr *expression.Expression) (eval.Value, error) return value, nil } - constant, isConst := f.All.Constants[f.Package+"."+leftText+"."+rightText] + label := fmt.Sprintf("%s.%s", leftText, rightText) + constant, isConst := f.All.Constants[f.Package+"."+label] if isConst { number, err := ToNumber(constant.Token, constant.File) @@ -73,10 +74,18 @@ func (f *Function) EvaluateDot(expr *expression.Expression) (eval.Value, error) } } - value := &eval.Label{ - Typ: types.AnyPointer, - Label: fmt.Sprintf("%s.%s", leftText, rightText), + function, exists := f.All.Functions[label] + + if exists { + f.Dependencies = append(f.Dependencies, function) + + value := &eval.Label{ + Typ: types.AnyPointer, + Label: label, + } + + return value, nil } - return value, nil + return nil, errors.New(&errors.UnknownIdentifier{Name: label}, f.File, left.Token.Position) } diff --git a/src/core/EvaluateToken.go b/src/core/EvaluateToken.go index f2e7c9d..459aa2a 100644 --- a/src/core/EvaluateToken.go +++ b/src/core/EvaluateToken.go @@ -41,6 +41,8 @@ func (f *Function) EvaluateToken(t token.Token) (eval.Value, error) { } if function != nil { + f.Dependencies = append(f.Dependencies, function) + value := &eval.Label{ Typ: types.AnyPointer, Label: function.UniqueName, diff --git a/src/core/Function.go b/src/core/Function.go index dca269e..ac09a62 100644 --- a/src/core/Function.go +++ b/src/core/Function.go @@ -11,17 +11,18 @@ import ( // Function represents the smallest unit of code. type Function struct { register.Machine - Package string - Name string - UniqueName string - All *Environment - File *fs.File - Body token.List - Input []*Parameter - Output []*Parameter - OutputTypes []types.Type - DLLs dll.List - Err error - deferred []func() - count count + Package string + Name string + UniqueName string + All *Environment + File *fs.File + Body token.List + Input []*Parameter + Output []*Parameter + OutputTypes []types.Type + Dependencies []*Function + DLLs dll.List + Err error + deferred []func() + count count } diff --git a/tests/programs/function-pointer-field.q b/tests/programs/function-pointer-field.q index 89894b9..8a8611a 100644 --- a/tests/programs/function-pointer-field.q +++ b/tests/programs/function-pointer-field.q @@ -1,4 +1,4 @@ -import core +import sys struct Struct { func *any @@ -6,6 +6,11 @@ struct Struct { main() { s := new(Struct) - s.func = core.exit + s.func = f s.func() + sys.exit(1) +} + +f() { + sys.exit(0) } \ No newline at end of file diff --git a/tests/programs/function-pointer.q b/tests/programs/function-pointer.q index 20f8c8a..784fa85 100644 --- a/tests/programs/function-pointer.q +++ b/tests/programs/function-pointer.q @@ -1,6 +1,13 @@ import core +import sys main() { + func := f + func() + sys.exit(1) +} + +f() { exit := core.exit exit() } \ No newline at end of file