diff --git a/errors_test.go b/errors_test.go index 38e1cdb..efd2ae7 100644 --- a/errors_test.go +++ b/errors_test.go @@ -28,6 +28,7 @@ func TestErrors(t *testing.T) { {"MissingGroupStart.q", errors.MissingGroupStart}, {"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "a"}}, {"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}}, + {"UnknownIdentifier2.q", &errors.UnknownIdentifier{Name: "x"}}, } for _, test := range tests { diff --git a/examples/hello/hello.q b/examples/hello/hello.q index 60f65e4..d3e8c5c 100644 --- a/examples/hello/hello.q +++ b/examples/hello/hello.q @@ -3,8 +3,9 @@ main() { } hello() { - write := 1 - stdout := 1 + one := 1 + write := one + stdout := one address := 4194305 length := 3 diff --git a/src/build/Function.go b/src/build/Function.go index 671c4e0..3ec442f 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -137,19 +137,35 @@ func (f *Function) CompileVariableDefinition(expr *expression.Expression) error value := expr.Children[1] + err := value.EachLeaf(func(leaf *expression.Expression) error { + if leaf.Token.Kind == token.Identifier && !f.identifierExists(leaf.Token.Text()) { + return errors.New(&errors.UnknownIdentifier{Name: leaf.Token.Text()}, f.File, leaf.Token.Position) + } + + return nil + }) + + if err != nil { + return err + } + // All expressions are returned to the memory pool. // To avoid losing variable values, we will detach it from the expression. expr.RemoveChild(value) f.Variables[name] = &Variable{ - Name: name, - Value: value, - IsConst: true, + Name: name, + Value: value, } return nil } +func (f *Function) identifierExists(name string) bool { + _, exists := f.Variables[name] + return exists +} + // CompileFunctionCall compiles a function call. func (f *Function) CompileFunctionCall(expr *expression.Expression) error { funcName := expr.Children[0].Token.Text() @@ -193,18 +209,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error { return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, t.Position) } - if !variable.IsConst { - return errors.New(errors.NotImplemented, f.File, t.Position) - } - - n, err := strconv.Atoi(variable.Value.Token.Text()) - - if err != nil { - return err - } - - f.Assembler.MoveRegisterNumber(register, uint64(n)) - return nil + return f.ExpressionToRegister(variable.Value, register) case token.Number: value := t.Text() diff --git a/src/build/Variable.go b/src/build/Variable.go index b5f7338..a37b2b5 100644 --- a/src/build/Variable.go +++ b/src/build/Variable.go @@ -4,7 +4,6 @@ import "git.akyoto.dev/cli/q/src/build/expression" // Variable represents a variable in a function. type Variable struct { - Name string - Value *expression.Expression - IsConst bool + Name string + Value *expression.Expression } diff --git a/src/build/expression/Expression.go b/src/build/expression/Expression.go index 3cfbb97..37b7719 100644 --- a/src/build/expression/Expression.go +++ b/src/build/expression/Expression.go @@ -54,6 +54,23 @@ func (expr *Expression) Close() { pool.Put(expr) } +// EachLeaf iterates through all leaves in the tree. +func (expr *Expression) EachLeaf(callBack func(*Expression) error) error { + if expr.IsLeaf() { + return callBack(expr) + } + + for _, child := range expr.Children { + err := child.EachLeaf(callBack) + + if err != nil { + return err + } + } + + return nil +} + // RemoveChild removes a child from the expression. func (expr *Expression) RemoveChild(child *Expression) { for i, c := range expr.Children { diff --git a/src/errors/UnknownIdentifier.go b/src/errors/UnknownIdentifier.go index d6f8dc8..fe1fc1f 100644 --- a/src/errors/UnknownIdentifier.go +++ b/src/errors/UnknownIdentifier.go @@ -11,8 +11,8 @@ type UnknownIdentifier struct { // Error generates the string representation. func (err *UnknownIdentifier) Error() string { if err.CorrectName != "" { - return fmt.Sprintf("Unknown variable '%s', did you mean '%s'?", err.Name, err.CorrectName) + return fmt.Sprintf("Unknown identifier '%s', did you mean '%s'?", err.Name, err.CorrectName) } - return fmt.Sprintf("Unknown variable '%s'", err.Name) + return fmt.Sprintf("Unknown identifier '%s'", err.Name) } diff --git a/tests/errors/UnknownIdentifier2.q b/tests/errors/UnknownIdentifier2.q new file mode 100644 index 0000000..4c60d29 --- /dev/null +++ b/tests/errors/UnknownIdentifier2.q @@ -0,0 +1,3 @@ +main() { + x := x +} \ No newline at end of file