diff --git a/src/build/core/ExecuteRegisterNumber.go b/src/build/core/ExecuteRegisterNumber.go index e2e4171..c78fe66 100644 --- a/src/build/core/ExecuteRegisterNumber.go +++ b/src/build/core/ExecuteRegisterNumber.go @@ -9,6 +9,10 @@ import ( // ExecuteRegisterNumber performs an operation on a register and a number. func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Register, number int) error { + if !operation.IsAssignment() && !operation.IsComparison() { + f.SaveRegister(register) + } + switch operation.Kind { case token.Add, token.AddAssign: f.RegisterNumber(asm.ADD, register, number) @@ -40,12 +44,12 @@ func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Reg case token.Shr, token.ShrAssign: f.RegisterNumber(asm.SHIFTRS, register, number) - case token.Equal, token.NotEqual, token.Less, token.LessEqual, token.Greater, token.GreaterEqual: - f.RegisterNumber(asm.COMPARE, register, number) - case token.Assign: f.RegisterNumber(asm.MOVE, register, number) + case token.Equal, token.NotEqual, token.Less, token.LessEqual, token.Greater, token.GreaterEqual: + f.RegisterNumber(asm.COMPARE, register, number) + default: return errors.New(&errors.InvalidOperator{Operator: operation.Text(f.File.Bytes)}, f.File, operation.Position) } diff --git a/src/build/core/ExecuteRegisterRegister.go b/src/build/core/ExecuteRegisterRegister.go index aa8006f..129d452 100644 --- a/src/build/core/ExecuteRegisterRegister.go +++ b/src/build/core/ExecuteRegisterRegister.go @@ -9,6 +9,10 @@ import ( // ExecuteRegisterRegister performs an operation on two registers. func (f *Function) ExecuteRegisterRegister(operation token.Token, register cpu.Register, operand cpu.Register) error { + if !operation.IsAssignment() && !operation.IsComparison() { + f.SaveRegister(register) + } + switch operation.Kind { case token.Add, token.AddAssign: f.RegisterRegister(asm.ADD, register, operand) @@ -34,12 +38,12 @@ func (f *Function) ExecuteRegisterRegister(operation token.Token, register cpu.R case token.Xor, token.XorAssign: f.RegisterRegister(asm.XOR, register, operand) - case token.Equal, token.NotEqual, token.Less, token.LessEqual, token.Greater, token.GreaterEqual: - f.RegisterRegister(asm.COMPARE, register, operand) - case token.Assign: f.RegisterRegister(asm.MOVE, register, operand) + case token.Equal, token.NotEqual, token.Less, token.LessEqual, token.Greater, token.GreaterEqual: + f.RegisterRegister(asm.COMPARE, register, operand) + default: return errors.New(&errors.InvalidOperator{Operator: operation.Text(f.File.Bytes)}, f.File, operation.Position) } diff --git a/src/build/core/ExpressionToRegister.go b/src/build/core/ExpressionToRegister.go index 1956932..e115758 100644 --- a/src/build/core/ExpressionToRegister.go +++ b/src/build/core/ExpressionToRegister.go @@ -12,6 +12,7 @@ import ( // ExpressionToRegister puts the result of an expression into the specified register. func (f *Function) ExpressionToRegister(node *expression.Expression, register cpu.Register) error { if node.IsFolded { + f.SaveRegister(register) f.RegisterNumber(asm.MOVE, register, node.Value) return nil } @@ -24,6 +25,7 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp err := f.CompileCall(node) if register != f.CPU.Output[0] { + f.SaveRegister(register) f.RegisterRegister(asm.MOVE, register, f.CPU.Output[0]) } @@ -68,6 +70,7 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp err = f.Execute(node.Token, register, right) if register != final { + f.SaveRegister(final) f.RegisterRegister(asm.MOVE, final, register) f.FreeRegister(register) } diff --git a/src/build/core/TokenToRegister.go b/src/build/core/TokenToRegister.go index a7e32f3..3335daf 100644 --- a/src/build/core/TokenToRegister.go +++ b/src/build/core/TokenToRegister.go @@ -20,6 +20,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error { } f.UseVariable(variable) + f.SaveRegister(register) f.RegisterRegister(asm.MOVE, register, variable.Register) return nil @@ -30,6 +31,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error { return err } + f.SaveRegister(register) f.RegisterNumber(asm.MOVE, register, number) return nil @@ -37,6 +39,7 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error { data := t.Bytes(f.File.Bytes) data = String(data) label := f.AddBytes(data) + f.SaveRegister(register) f.RegisterLabel(asm.MOVE, register, label) return nil diff --git a/src/build/register/RegisterLabel.go b/src/build/register/RegisterLabel.go index 7778e5a..70690bc 100644 --- a/src/build/register/RegisterLabel.go +++ b/src/build/register/RegisterLabel.go @@ -6,10 +6,6 @@ import ( ) func (f *Machine) RegisterLabel(mnemonic asm.Mnemonic, register cpu.Register, label string) { - if f.RegisterIsUsed(register) && isDestructive(mnemonic) { - f.SaveRegister(register) - } - f.Assembler.RegisterLabel(mnemonic, register, label) if mnemonic == asm.MOVE { diff --git a/src/build/register/RegisterNumber.go b/src/build/register/RegisterNumber.go index a6b5aa6..32b552b 100644 --- a/src/build/register/RegisterNumber.go +++ b/src/build/register/RegisterNumber.go @@ -7,10 +7,6 @@ import ( ) func (f *Machine) RegisterNumber(mnemonic asm.Mnemonic, a cpu.Register, b int) { - if f.RegisterIsUsed(a) && isDestructive(mnemonic) { - f.SaveRegister(a) - } - // The `MOVE` operation is very flexible and works with any type of immediate number. if mnemonic == asm.MOVE { f.Assembler.RegisterNumber(mnemonic, a, b) diff --git a/src/build/register/RegisterRegister.go b/src/build/register/RegisterRegister.go index a969ca5..5f87783 100644 --- a/src/build/register/RegisterRegister.go +++ b/src/build/register/RegisterRegister.go @@ -10,10 +10,6 @@ func (f *Machine) RegisterRegister(mnemonic asm.Mnemonic, a cpu.Register, b cpu. return } - if f.RegisterIsUsed(a) && isDestructive(mnemonic) { - f.SaveRegister(a) - } - f.Assembler.RegisterRegister(mnemonic, a, b) if mnemonic == asm.MOVE { diff --git a/src/build/register/isDestructive.go b/src/build/register/isDestructive.go deleted file mode 100644 index 9305367..0000000 --- a/src/build/register/isDestructive.go +++ /dev/null @@ -1,12 +0,0 @@ -package register - -import "git.akyoto.dev/cli/q/src/build/asm" - -func isDestructive(mnemonic asm.Mnemonic) bool { - switch mnemonic { - case asm.MOVE, asm.ADD, asm.SUB, asm.MUL, asm.DIV, asm.MODULO, asm.AND, asm.OR, asm.XOR, asm.SHIFTL, asm.SHIFTRS, asm.NEGATE: - return true - default: - return false - } -} diff --git a/src/build/token/Kind.go b/src/build/token/Kind.go index 6bbaff8..1b45363 100644 --- a/src/build/token/Kind.go +++ b/src/build/token/Kind.go @@ -31,12 +31,14 @@ const ( Shr // >> LogicalAnd // && LogicalOr // || + _comparisons // Equal // == + NotEqual // != Less // < Greater // > - NotEqual // != LessEqual // <= GreaterEqual // >= + _comparisonsEnd // Define // := Period // . Call // x() diff --git a/src/build/token/Token.go b/src/build/token/Token.go index 3885218..0476cbd 100644 --- a/src/build/token/Token.go +++ b/src/build/token/Token.go @@ -28,6 +28,11 @@ func (t Token) IsAssignment() bool { return t.Kind > _assignments && t.Kind < _assignmentsEnd } +// IsComparison returns true if the token is a comparison operator. +func (t Token) IsComparison() bool { + return t.Kind > _comparisons && t.Kind < _comparisonsEnd +} + // IsExpressionStart returns true if the token starts an expression. func (t Token) IsExpressionStart() bool { return t.Kind == GroupStart || t.Kind == ArrayStart || t.Kind == BlockStart diff --git a/tests/programs/op-assign.q b/tests/programs/op-assign.q new file mode 100644 index 0000000..496b3a5 --- /dev/null +++ b/tests/programs/op-assign.q @@ -0,0 +1,9 @@ +main() { + f(10) +} + +f(new) { + old := new + new -= 1 + assert new != old +} \ No newline at end of file diff --git a/tests/programs_test.go b/tests/programs_test.go index 043dbe9..4f2be2d 100644 --- a/tests/programs_test.go +++ b/tests/programs_test.go @@ -26,6 +26,7 @@ var programs = []struct { {"return", "", "", 0}, {"math", "", "", 0}, {"precedence", "", "", 0}, + {"op-assign", "", "", 0}, {"binary", "", "", 0}, {"octal", "", "", 0}, {"hexadecimal", "", "", 0},