diff --git a/src/build/ast/Count.go b/src/build/ast/Count.go index 0c0c4a8..031a5fc 100644 --- a/src/build/ast/Count.go +++ b/src/build/ast/Count.go @@ -15,7 +15,7 @@ func Count(body AST, buffer []byte, kind token.Kind, name string) uint8 { count += node.Expression.Count(buffer, kind, name) case *Define: - count += node.Value.Count(buffer, kind, name) + count += node.Expression.Count(buffer, kind, name) case *Return: if node.Value != nil { diff --git a/src/build/ast/Define.go b/src/build/ast/Define.go index 64f0c15..551c9b7 100644 --- a/src/build/ast/Define.go +++ b/src/build/ast/Define.go @@ -2,11 +2,9 @@ package ast import ( "git.akyoto.dev/cli/q/src/build/expression" - "git.akyoto.dev/cli/q/src/build/token" ) // Define represents a variable definition. type Define struct { - Value *expression.Expression - Name token.Token + Expression *expression.Expression } diff --git a/src/build/ast/Parse.go b/src/build/ast/Parse.go index a7c0e0e..4db7cca 100644 --- a/src/build/ast/Parse.go +++ b/src/build/ast/Parse.go @@ -83,9 +83,7 @@ func toASTNode(tokens token.List, buffer []byte) (Node, error) { return nil, errors.New(errors.MissingOperand, nil, expr.Token.End()) } - name := expr.Children[0].Token - value := expr.Children[1] - return &Define{Name: name, Value: value}, nil + return &Define{Expression: expr}, nil case IsAssignment(expr): if len(expr.Children) < 2 { diff --git a/src/build/core/CompileAssignDivision.go b/src/build/core/CompileAssignDivision.go index de383c9..177b008 100644 --- a/src/build/core/CompileAssignDivision.go +++ b/src/build/core/CompileAssignDivision.go @@ -29,11 +29,14 @@ func (f *Function) CompileAssignDivision(node *ast.Assign) error { } dividend := right.Children[0] - name = dividend.Token.Text(f.File.Bytes) - dividendVariable := f.VariableByName(name) + dividendRegister, err := f.Evaluate(dividend) + + if err != nil { + return err + } divisor := right.Children[1] - err := f.Execute(right.Token, dividendVariable.Register, divisor) + err = f.Execute(right.Token, dividendRegister, divisor) f.RegisterRegister(asm.MOVE, quotientVariable.Register, x64.RAX) f.RegisterRegister(asm.MOVE, remainderVariable.Register, x64.RDX) return err diff --git a/src/build/core/CompileDefinition.go b/src/build/core/CompileDefinition.go index 6e1943f..75241ba 100644 --- a/src/build/core/CompileDefinition.go +++ b/src/build/core/CompileDefinition.go @@ -9,20 +9,22 @@ import ( // CompileDefinition compiles a variable definition. func (f *Function) CompileDefinition(node *ast.Define) error { - name := node.Name.Text(f.File.Bytes) + left := node.Expression.Children[0] + right := node.Expression.Children[1] + name := left.Token.Text(f.File.Bytes) if f.IdentifierExists(name) { - return errors.New(&errors.VariableAlreadyExists{Name: name}, f.File, node.Name.Position) + return errors.New(&errors.VariableAlreadyExists{Name: name}, f.File, left.Token.Position) } uses := token.Count(f.Body, f.File.Bytes, token.Identifier, name) - 1 if uses == 0 { - return errors.New(&errors.UnusedVariable{Name: name}, f.File, node.Name.Position) + return errors.New(&errors.UnusedVariable{Name: name}, f.File, left.Token.Position) } register := f.NewRegister() - err := f.ExpressionToRegister(node.Value, register) + err := f.ExpressionToRegister(right, register) f.AddVariable(&scope.Variable{ Name: name, diff --git a/src/build/core/Evaluate.go b/src/build/core/Evaluate.go new file mode 100644 index 0000000..f7d601a --- /dev/null +++ b/src/build/core/Evaluate.go @@ -0,0 +1,24 @@ +package core + +import ( + "git.akyoto.dev/cli/q/src/build/cpu" + "git.akyoto.dev/cli/q/src/build/expression" + "git.akyoto.dev/cli/q/src/build/token" +) + +// Evaluate evaluates an expression and returns a register that contains the value of the expression. +func (f *Function) Evaluate(expr *expression.Expression) (cpu.Register, error) { + if expr.Token.Kind == token.Identifier { + name := expr.Token.Text(f.File.Bytes) + variable := f.VariableByName(name) + + if variable.Alive == 1 { + f.UseVariable(variable) + return variable.Register, nil + } + } + + tmp := f.NewRegister() + err := f.ExpressionToRegister(expr, tmp) + return tmp, err +} diff --git a/tests/programs/division-split.q b/tests/programs/division-split.q new file mode 100644 index 0000000..e44e409 --- /dev/null +++ b/tests/programs/division-split.q @@ -0,0 +1,22 @@ +main() { + quotient := 0 + remainder := 0 + dividend := 256 + divisor := 100 + + quotient, remainder = 256 / 100 + assert quotient == 2 + assert remainder == 56 + + quotient, remainder = dividend / 100 + assert quotient == 2 + assert remainder == 56 + + quotient, remainder = 256 / divisor + assert quotient == 2 + assert remainder == 56 + + quotient, remainder = dividend / divisor + assert quotient == 2 + assert remainder == 56 +} \ No newline at end of file diff --git a/tests/programs/modulo-assign.q b/tests/programs/modulo-assign.q new file mode 100644 index 0000000..8fa9671 --- /dev/null +++ b/tests/programs/modulo-assign.q @@ -0,0 +1,8 @@ +main() { + x := 256 + x %= 100 + assert x == 56 + + x %= 10 + assert x == 6 +} \ No newline at end of file diff --git a/tests/programs/modulo.q b/tests/programs/modulo.q new file mode 100644 index 0000000..c6e0a59 --- /dev/null +++ b/tests/programs/modulo.q @@ -0,0 +1,9 @@ +main() { + assert 0 % 1 == 0 + assert 1 % 1 == 0 + assert 2 % 1 == 0 + assert 0 % 2 == 0 + assert 1 % 2 == 1 + assert 2 % 2 == 0 + assert 3 % 2 == 1 +} \ No newline at end of file diff --git a/tests/programs/remainder.q b/tests/programs/remainder.q deleted file mode 100644 index 2bbe4f5..0000000 --- a/tests/programs/remainder.q +++ /dev/null @@ -1,46 +0,0 @@ -import sys - -main() { - if 0 % 1 != 0 { - sys.exit(1) - } - - if 1 % 1 != 0 { - sys.exit(1) - } - - if 2 % 1 != 0 { - sys.exit(1) - } - - if 0 % 2 != 0 { - sys.exit(1) - } - - if 1 % 2 != 1 { - sys.exit(1) - } - - if 2 % 2 != 0 { - sys.exit(1) - } - - if 3 % 2 != 1 { - sys.exit(1) - } - - x := 256 - x %= 100 - - if x != 56 { - sys.exit(1) - } - - x %= 10 - - if x != 6 { - sys.exit(1) - } - - sys.exit(0) -} \ No newline at end of file diff --git a/tests/programs_test.go b/tests/programs_test.go index 204f314..46e2a1b 100644 --- a/tests/programs_test.go +++ b/tests/programs_test.go @@ -33,14 +33,16 @@ var programs = []struct { {"branch-and", "", "", 0}, {"branch-or", "", "", 0}, {"branch-both", "", "", 0}, + {"jump-near", "", "", 0}, + {"loop", "", "", 0}, + {"loop-lifetime", "", "", 0}, {"bitwise-and", "", "", 0}, {"bitwise-or", "", "", 0}, {"bitwise-xor", "", "", 0}, {"shift", "", "", 0}, - {"remainder", "", "", 0}, - {"jump-near", "", "", 0}, - {"loop", "", "", 0}, - {"loop-lifetime", "", "", 0}, + {"modulo", "", "", 0}, + {"modulo-assign", "", "", 0}, + {"division-split", "", "", 0}, {"assert", "", "", 1}, {"negative", "", "", 32}, {"negation", "", "", 32},