diff --git a/examples/hello/hello.q b/examples/hello/hello.q index 1a3745e..a49c249 100644 --- a/examples/hello/hello.q +++ b/examples/hello/hello.q @@ -11,6 +11,7 @@ hello() { address += 4194304 address += 1 + length = 0 length += 50 length -= 20 length *= 10 diff --git a/src/build/Assignment.go b/src/build/Assignment.go new file mode 100644 index 0000000..a5a91bb --- /dev/null +++ b/src/build/Assignment.go @@ -0,0 +1,38 @@ +package build + +import ( + "strconv" + + "git.akyoto.dev/cli/q/src/build/asm" + "git.akyoto.dev/cli/q/src/build/expression" + "git.akyoto.dev/cli/q/src/errors" +) + +// CompileAssignment compiles an assignment. +func (f *Function) CompileAssignment(expr *expression.Expression) error { + name := expr.Children[0].Token.Text() + number, _ := strconv.Atoi(expr.Children[1].Token.Text()) + register := f.Variables[name].Register + + switch expr.Token.Text() { + case "=": + f.ExpressionToRegister(expr.Children[1], register) + + case "+=": + f.Assembler.RegisterNumber(asm.ADD, register, number) + + case "-=": + f.Assembler.RegisterNumber(asm.SUB, register, number) + + case "*=": + f.Assembler.RegisterNumber(asm.MUL, register, number) + + case "/=": + f.Assembler.RegisterNumber(asm.DIV, register, number) + + default: + return errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text()}, f.File, expr.Token.Position) + } + + return nil +} diff --git a/src/build/Function.go b/src/build/Function.go index 141c210..5d7666d 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -109,37 +109,32 @@ func (f *Function) CompileInstruction(line token.List) error { return f.CompileVariableDefinition(expr) } + if isAssignment(expr) { + return f.CompileAssignment(expr) + } + if isFunctionCall(expr) { return f.CompileFunctionCall(expr) } - if expr.Token.Kind == token.Operator { - name := expr.Children[0].Token.Text() - number, _ := strconv.Atoi(expr.Children[1].Token.Text()) - register := f.Variables[name].Register - - switch expr.Token.Text() { - case "+=": - f.Assembler.RegisterNumber(asm.ADD, register, number) - return nil - - case "-=": - f.Assembler.RegisterNumber(asm.SUB, register, number) - return nil - - case "*=": - f.Assembler.RegisterNumber(asm.MUL, register, number) - return nil - - case "/=": - f.Assembler.RegisterNumber(asm.DIV, register, number) - return nil - } - } - return errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text()}, f.File, expr.Token.Position) } +// isAssignment returns true if the expression is an assignment. +func isAssignment(expr *expression.Expression) bool { + return expr.Token.Kind == token.Operator && expr.Token.Bytes[len(expr.Token.Bytes)-1] == '=' +} + +// isFunctionCall returns true if the expression is a function call. +func isFunctionCall(expr *expression.Expression) bool { + return expr.Token.Kind == token.Operator && expr.Token.Text() == "λ" +} + +// isVariableDefinition returns true if the expression is a variable definition. +func isVariableDefinition(expr *expression.Expression) bool { + return expr.Token.Kind == token.Operator && expr.Token.Text() == ":=" +} + // ExpressionToRegister moves the result of an expression into the given register. func (f *Function) ExpressionToRegister(root *expression.Expression, register cpu.Register) error { if root.IsLeaf() { diff --git a/src/build/FunctionCall.go b/src/build/FunctionCall.go index 1857a82..9c90ee7 100644 --- a/src/build/FunctionCall.go +++ b/src/build/FunctionCall.go @@ -2,7 +2,6 @@ package build import ( "git.akyoto.dev/cli/q/src/build/expression" - "git.akyoto.dev/cli/q/src/build/token" ) // CompileFunctionCall compiles a top-level function call. @@ -26,8 +25,3 @@ func (f *Function) CompileFunctionCall(expr *expression.Expression) error { return nil } - -// isFunctionCall returns true if the expression is a function call. -func isFunctionCall(expr *expression.Expression) bool { - return expr.Token.Kind == token.Operator && expr.Token.Text() == "λ" -} diff --git a/src/build/VariableDefinition.go b/src/build/VariableDefinition.go index 9eca8e9..1043143 100644 --- a/src/build/VariableDefinition.go +++ b/src/build/VariableDefinition.go @@ -48,8 +48,3 @@ func (f *Function) CompileVariableDefinition(expr *expression.Expression) error return nil } - -// isVariableDefinition returns true if the expression is a variable definition. -func isVariableDefinition(expr *expression.Expression) bool { - return expr.Token.Kind == token.Operator && expr.Token.Text() == ":=" -}