Improved variable definitions

This commit is contained in:
Eduard Urbach 2024-06-22 20:18:13 +02:00
parent 2f7319e6a0
commit 4f6750dc8e
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
7 changed files with 48 additions and 22 deletions

View File

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

View File

@ -3,8 +3,9 @@ main() {
}
hello() {
write := 1
stdout := 1
one := 1
write := one
stdout := one
address := 4194305
length := 3

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,3 @@
main() {
x := x
}