Improved variable definitions
This commit is contained in:
parent
2f7319e6a0
commit
4f6750dc8e
@ -28,6 +28,7 @@ func TestErrors(t *testing.T) {
|
|||||||
{"MissingGroupStart.q", errors.MissingGroupStart},
|
{"MissingGroupStart.q", errors.MissingGroupStart},
|
||||||
{"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "a"}},
|
{"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "a"}},
|
||||||
{"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}},
|
{"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}},
|
||||||
|
{"UnknownIdentifier2.q", &errors.UnknownIdentifier{Name: "x"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
@ -3,8 +3,9 @@ main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hello() {
|
hello() {
|
||||||
write := 1
|
one := 1
|
||||||
stdout := 1
|
write := one
|
||||||
|
stdout := one
|
||||||
address := 4194305
|
address := 4194305
|
||||||
length := 3
|
length := 3
|
||||||
|
|
||||||
|
@ -137,19 +137,35 @@ func (f *Function) CompileVariableDefinition(expr *expression.Expression) error
|
|||||||
|
|
||||||
value := expr.Children[1]
|
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.
|
// All expressions are returned to the memory pool.
|
||||||
// To avoid losing variable values, we will detach it from the expression.
|
// To avoid losing variable values, we will detach it from the expression.
|
||||||
expr.RemoveChild(value)
|
expr.RemoveChild(value)
|
||||||
|
|
||||||
f.Variables[name] = &Variable{
|
f.Variables[name] = &Variable{
|
||||||
Name: name,
|
Name: name,
|
||||||
Value: value,
|
Value: value,
|
||||||
IsConst: true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Function) identifierExists(name string) bool {
|
||||||
|
_, exists := f.Variables[name]
|
||||||
|
return exists
|
||||||
|
}
|
||||||
|
|
||||||
// CompileFunctionCall compiles a function call.
|
// CompileFunctionCall compiles a function call.
|
||||||
func (f *Function) CompileFunctionCall(expr *expression.Expression) error {
|
func (f *Function) CompileFunctionCall(expr *expression.Expression) error {
|
||||||
funcName := expr.Children[0].Token.Text()
|
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)
|
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, t.Position)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !variable.IsConst {
|
return f.ExpressionToRegister(variable.Value, register)
|
||||||
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
|
|
||||||
|
|
||||||
case token.Number:
|
case token.Number:
|
||||||
value := t.Text()
|
value := t.Text()
|
||||||
|
@ -4,7 +4,6 @@ import "git.akyoto.dev/cli/q/src/build/expression"
|
|||||||
|
|
||||||
// Variable represents a variable in a function.
|
// Variable represents a variable in a function.
|
||||||
type Variable struct {
|
type Variable struct {
|
||||||
Name string
|
Name string
|
||||||
Value *expression.Expression
|
Value *expression.Expression
|
||||||
IsConst bool
|
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,23 @@ func (expr *Expression) Close() {
|
|||||||
pool.Put(expr)
|
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.
|
// RemoveChild removes a child from the expression.
|
||||||
func (expr *Expression) RemoveChild(child *Expression) {
|
func (expr *Expression) RemoveChild(child *Expression) {
|
||||||
for i, c := range expr.Children {
|
for i, c := range expr.Children {
|
||||||
|
@ -11,8 +11,8 @@ type UnknownIdentifier struct {
|
|||||||
// Error generates the string representation.
|
// Error generates the string representation.
|
||||||
func (err *UnknownIdentifier) Error() string {
|
func (err *UnknownIdentifier) Error() string {
|
||||||
if err.CorrectName != "" {
|
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)
|
||||||
}
|
}
|
||||||
|
3
tests/errors/UnknownIdentifier2.q
Normal file
3
tests/errors/UnknownIdentifier2.q
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
main() {
|
||||||
|
x := x
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user