diff --git a/src/build/Call.go b/src/build/Call.go index 2051499..ee813fc 100644 --- a/src/build/Call.go +++ b/src/build/Call.go @@ -6,6 +6,9 @@ import ( ) // CompileFunctionCall executes a function call. +// All call registers must hold the correct parameter values before the function invocation. +// Registers that are in use must be saved if they are modified by the function. +// After the function call, they must be restored in reverse order. func (f *Function) CompileFunctionCall(expr *expression.Expression) error { funcName := expr.Children[0].Token.Text() diff --git a/src/build/Execute.go b/src/build/Execute.go index 3bdc61e..4903ef7 100644 --- a/src/build/Execute.go +++ b/src/build/Execute.go @@ -73,58 +73,6 @@ func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, ope return errors.New(errors.NotImplemented, f.File, operation.Position) } -// ExecuteRegisterNumber performs an operation on a register and a number. -func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Register, number int) error { - switch operation.Text() { - 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) - - case "=": - f.assembler.RegisterNumber(asm.MOVE, register, number) - - default: - return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position) - } - - return nil -} - -// ExecuteRegisterRegister performs an operation on two registers. -func (f *Function) ExecuteRegisterRegister(operation token.Token, destination cpu.Register, source cpu.Register) error { - switch operation.Text() { - case "+", "+=": - f.assembler.RegisterRegister(asm.ADD, destination, source) - - case "-", "-=": - f.assembler.RegisterRegister(asm.SUB, destination, source) - - case "*", "*=": - f.assembler.RegisterRegister(asm.MUL, destination, source) - - case "/", "/=": - f.assembler.RegisterRegister(asm.DIV, destination, source) - - case "=": - if destination != source { - f.assembler.RegisterRegister(asm.MOVE, destination, source) - } - - default: - return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position) - } - - return nil -} - // ExpressionToRegister moves the result of an expression into the given register. func (f *Function) ExpressionToRegister(root *expression.Expression, register cpu.Register) error { if config.Verbose { diff --git a/src/build/Function.go b/src/build/Function.go index d58afc2..d615a90 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -7,7 +7,6 @@ import ( "git.akyoto.dev/cli/q/src/build/expression" "git.akyoto.dev/cli/q/src/build/fs" "git.akyoto.dev/cli/q/src/build/token" - "git.akyoto.dev/cli/q/src/errors" ) // Function represents a function. @@ -82,39 +81,6 @@ func (f *Function) CompileTokens(body token.List) error { return nil } -// CompileInstruction compiles a single instruction. -func (f *Function) CompileInstruction(line token.List) error { - if len(line) == 0 { - return nil - } - - if line[0].Kind == token.Keyword { - return f.CompileKeyword(line) - } - - expr := expression.Parse(line) - - if expr == nil { - return nil - } - - defer expr.Close() - - switch true { - case isVariableDefinition(expr): - return f.CompileVariableDefinition(expr) - - case isAssignment(expr): - return f.CompileAssignment(expr) - - case isFunctionCall(expr): - return f.CompileFunctionCall(expr) - - default: - return errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text()}, f.File, expr.Token.Position) - } -} - // Logf formats a message for verbose output. func (f *Function) Logf(format string, data ...any) { fmt.Printf("[%s @ %d] %s\n", f, len(f.assembler.Instructions), fmt.Sprintf(format, data...)) diff --git a/src/build/Instruction.go b/src/build/Instruction.go new file mode 100644 index 0000000..c668258 --- /dev/null +++ b/src/build/Instruction.go @@ -0,0 +1,36 @@ +package build + +import ( + "git.akyoto.dev/cli/q/src/build/expression" + "git.akyoto.dev/cli/q/src/build/token" + "git.akyoto.dev/cli/q/src/errors" +) + +// CompileInstruction compiles a single instruction. +func (f *Function) CompileInstruction(instruction token.List) error { + if instruction[0].Kind == token.Keyword { + return f.CompileKeyword(instruction) + } + + expr := expression.Parse(instruction) + + if expr == nil { + return nil + } + + defer expr.Close() + + switch true { + case isVariableDefinition(expr): + return f.CompileVariableDefinition(expr) + + case isAssignment(expr): + return f.CompileAssignment(expr) + + case isFunctionCall(expr): + return f.CompileFunctionCall(expr) + + default: + return errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text()}, f.File, expr.Token.Position) + } +} diff --git a/src/build/Math.go b/src/build/Math.go new file mode 100644 index 0000000..b02d42d --- /dev/null +++ b/src/build/Math.go @@ -0,0 +1,60 @@ +package build + +import ( + "git.akyoto.dev/cli/q/src/build/asm" + "git.akyoto.dev/cli/q/src/build/cpu" + "git.akyoto.dev/cli/q/src/build/token" + "git.akyoto.dev/cli/q/src/errors" +) + +// ExecuteRegisterNumber performs an operation on a register and a number. +func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Register, number int) error { + switch operation.Text() { + 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) + + case "=": + f.assembler.RegisterNumber(asm.MOVE, register, number) + + default: + return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position) + } + + return nil +} + +// ExecuteRegisterRegister performs an operation on two registers. +func (f *Function) ExecuteRegisterRegister(operation token.Token, destination cpu.Register, source cpu.Register) error { + switch operation.Text() { + case "+", "+=": + f.assembler.RegisterRegister(asm.ADD, destination, source) + + case "-", "-=": + f.assembler.RegisterRegister(asm.SUB, destination, source) + + case "*", "*=": + f.assembler.RegisterRegister(asm.MUL, destination, source) + + case "/", "/=": + f.assembler.RegisterRegister(asm.DIV, destination, source) + + case "=": + if destination != source { + f.assembler.RegisterRegister(asm.MOVE, destination, source) + } + + default: + return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position) + } + + return nil +}