Enforced consistent naming
This commit is contained in:
parent
d1a3ffb1a5
commit
94151773a5
@ -21,12 +21,13 @@ func TestErrors(t *testing.T) {
|
||||
{"InvalidInstructionIdentifier.q", &errors.InvalidInstruction{Instruction: "abc"}},
|
||||
{"InvalidInstructionNumber.q", &errors.InvalidInstruction{Instruction: "123"}},
|
||||
{"InvalidExpression.q", errors.InvalidExpression},
|
||||
{"InvalidOperator.q", &errors.InvalidOperator{Operator: "+++"}},
|
||||
{"MissingAssignValue.q", errors.MissingAssignValue},
|
||||
{"MissingBlockEnd.q", errors.MissingBlockEnd},
|
||||
{"MissingBlockStart.q", errors.MissingBlockStart},
|
||||
{"MissingGroupEnd.q", errors.MissingGroupEnd},
|
||||
{"MissingGroupStart.q", errors.MissingGroupStart},
|
||||
{"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "a"}},
|
||||
{"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "x"}},
|
||||
{"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}},
|
||||
{"UnknownIdentifier2.q", &errors.UnknownIdentifier{Name: "x"}},
|
||||
}
|
||||
|
@ -14,15 +14,5 @@ func (f *Function) CompileAssignment(expr *expression.Expression) error {
|
||||
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, expr.Children[0].Token.Position)
|
||||
}
|
||||
|
||||
if expr.Token.Text() == "=" {
|
||||
return f.ExpressionToRegister(expr.Children[1], variable.Register)
|
||||
}
|
||||
|
||||
right := expr.Children[1]
|
||||
|
||||
if right.IsLeaf() {
|
||||
return f.Calculate(variable.Register, expr.Token, right.Token)
|
||||
}
|
||||
|
||||
return f.Execute(expr.Token, variable.Register, expr.Children[1])
|
||||
}
|
||||
|
@ -1,81 +0,0 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// Calculate performs an operation on a register with the given operand.
|
||||
func (f *Function) Calculate(register cpu.Register, operation token.Token, operand token.Token) error {
|
||||
switch operand.Kind {
|
||||
case token.Number:
|
||||
value := operand.Text()
|
||||
number, err := strconv.Atoi(value)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.CalculateRegisterNumber(operation, register, number)
|
||||
|
||||
case token.Identifier:
|
||||
name := operand.Text()
|
||||
variable, exists := f.Variables[name]
|
||||
|
||||
if !exists {
|
||||
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, operand.Position)
|
||||
}
|
||||
|
||||
return f.CalculateRegisterRegister(operation, register, variable.Register)
|
||||
}
|
||||
|
||||
return errors.New(errors.NotImplemented, f.File, operation.Position)
|
||||
}
|
||||
|
||||
// CalculateRegisterNumber performs an operation on a register and a number.
|
||||
func (f *Function) CalculateRegisterNumber(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)
|
||||
|
||||
default:
|
||||
return errors.New(errors.NotImplemented, f.File, operation.Position)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CalculateRegisterRegister performs an operation on two registers.
|
||||
func (f *Function) CalculateRegisterRegister(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)
|
||||
|
||||
default:
|
||||
return errors.New(errors.NotImplemented, f.File, operation.Position)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
111
src/build/Execute.go
Normal file
111
src/build/Execute.go
Normal file
@ -0,0 +1,111 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/build/asm"
|
||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||
"git.akyoto.dev/cli/q/src/build/expression"
|
||||
"git.akyoto.dev/cli/q/src/build/token"
|
||||
"git.akyoto.dev/cli/q/src/errors"
|
||||
)
|
||||
|
||||
// Execute executes an operation on a register with a value operand.
|
||||
func (f *Function) Execute(operation token.Token, register cpu.Register, value *expression.Expression) error {
|
||||
if value.IsLeaf() {
|
||||
return f.ExecuteLeaf(operation, register, value.Token)
|
||||
}
|
||||
|
||||
temporary, found := f.CPU.FindFree(f.CPU.General)
|
||||
|
||||
if !found {
|
||||
panic("no free registers")
|
||||
}
|
||||
|
||||
f.CPU.Use(temporary)
|
||||
defer f.CPU.Free(temporary)
|
||||
err := f.ExpressionToRegister(value, temporary)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.ExecuteRegisterRegister(operation, register, temporary)
|
||||
}
|
||||
|
||||
// ExecuteLeaf performs an operation on a register with the given leaf operand.
|
||||
func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, operand token.Token) error {
|
||||
switch operand.Kind {
|
||||
case token.Number:
|
||||
value := operand.Text()
|
||||
number, err := strconv.Atoi(value)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.ExecuteRegisterNumber(operation, register, number)
|
||||
|
||||
case token.Identifier:
|
||||
name := operand.Text()
|
||||
variable, exists := f.Variables[name]
|
||||
|
||||
if !exists {
|
||||
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, operand.Position)
|
||||
}
|
||||
|
||||
return f.ExecuteRegisterRegister(operation, register, variable.Register)
|
||||
}
|
||||
|
||||
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 "=":
|
||||
f.Assembler.RegisterRegister(asm.MOVE, destination, source)
|
||||
|
||||
default:
|
||||
return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -140,29 +140,6 @@ func (f *Function) ExpressionToRegister(root *expression.Expression, register cp
|
||||
return f.Execute(operation, register, right)
|
||||
}
|
||||
|
||||
// Execute executes an operation on a register with a value operand.
|
||||
func (f *Function) Execute(operation token.Token, register cpu.Register, value *expression.Expression) error {
|
||||
if value.IsLeaf() {
|
||||
return f.Calculate(register, operation, value.Token)
|
||||
}
|
||||
|
||||
temporary, found := f.CPU.FindFree(f.CPU.General)
|
||||
|
||||
if !found {
|
||||
panic("no free registers")
|
||||
}
|
||||
|
||||
f.CPU.Use(temporary)
|
||||
defer f.CPU.Free(temporary)
|
||||
err := f.ExpressionToRegister(value, temporary)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.CalculateRegisterRegister(operation, register, temporary)
|
||||
}
|
||||
|
||||
// TokenToRegister moves a token into a register.
|
||||
// It only works with identifiers, numbers and strings.
|
||||
func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
|
||||
|
@ -1,6 +1,10 @@
|
||||
package expression
|
||||
|
||||
import "git.akyoto.dev/cli/q/src/build/token"
|
||||
import (
|
||||
"math"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/build/token"
|
||||
)
|
||||
|
||||
// Operator represents an operator for mathematical expressions.
|
||||
type Operator struct {
|
||||
@ -12,35 +16,35 @@ type Operator struct {
|
||||
// Operators defines the operators used in the language.
|
||||
// The number corresponds to the operator priority and can not be zero.
|
||||
var Operators = map[string]*Operator{
|
||||
".": {".", 14, 2},
|
||||
"λ": {"λ", 13, 1},
|
||||
"!": {"!", 12, 1},
|
||||
"*": {"*", 11, 2},
|
||||
"/": {"/", 11, 2},
|
||||
"%": {"%", 11, 2},
|
||||
"+": {"+", 10, 2},
|
||||
"-": {"-", 10, 2},
|
||||
">>": {">>", 9, 2},
|
||||
"<<": {"<<", 9, 2},
|
||||
">": {">", 8, 2},
|
||||
"<": {"<", 8, 2},
|
||||
">=": {">=", 8, 2},
|
||||
"<=": {"<=", 8, 2},
|
||||
"==": {"==", 7, 2},
|
||||
"!=": {"!=", 7, 2},
|
||||
"&": {"&", 6, 2},
|
||||
"^": {"^", 5, 2},
|
||||
"|": {"|", 4, 2},
|
||||
"&&": {"&&", 3, 2},
|
||||
"||": {"||", 2, 2},
|
||||
"=": {"=", 1, 2},
|
||||
":=": {":=", 1, 2},
|
||||
"+=": {"+=", 1, 2},
|
||||
"-=": {"-=", 1, 2},
|
||||
"*=": {"*=", 1, 2},
|
||||
"/=": {"/=", 1, 2},
|
||||
">>=": {">>=", 1, 2},
|
||||
"<<=": {"<<=", 1, 2},
|
||||
".": {".", 13, 2},
|
||||
"λ": {"λ", 12, 1},
|
||||
"!": {"!", 11, 1},
|
||||
"*": {"*", 10, 2},
|
||||
"/": {"/", 10, 2},
|
||||
"%": {"%", 10, 2},
|
||||
"+": {"+", 9, 2},
|
||||
"-": {"-", 9, 2},
|
||||
">>": {">>", 8, 2},
|
||||
"<<": {"<<", 8, 2},
|
||||
">": {">", 7, 2},
|
||||
"<": {"<", 7, 2},
|
||||
">=": {">=", 7, 2},
|
||||
"<=": {"<=", 7, 2},
|
||||
"==": {"==", 6, 2},
|
||||
"!=": {"!=", 6, 2},
|
||||
"&": {"&", 5, 2},
|
||||
"^": {"^", 4, 2},
|
||||
"|": {"|", 3, 2},
|
||||
"&&": {"&&", 2, 2},
|
||||
"||": {"||", 1, 2},
|
||||
"=": {"=", math.MinInt, 2},
|
||||
":=": {":=", math.MinInt, 2},
|
||||
"+=": {"+=", math.MinInt, 2},
|
||||
"-=": {"-=", math.MinInt, 2},
|
||||
"*=": {"*=", math.MinInt, 2},
|
||||
"/=": {"/=", math.MinInt, 2},
|
||||
">>=": {">>=", math.MinInt, 2},
|
||||
"<<=": {"<<=", math.MinInt, 2},
|
||||
}
|
||||
|
||||
func isComplete(expr *Expression) bool {
|
||||
@ -60,9 +64,21 @@ func isComplete(expr *Expression) bool {
|
||||
}
|
||||
|
||||
func numOperands(symbol string) int {
|
||||
return Operators[symbol].Operands
|
||||
operator, exists := Operators[symbol]
|
||||
|
||||
if !exists {
|
||||
return -1
|
||||
}
|
||||
|
||||
return operator.Operands
|
||||
}
|
||||
|
||||
func precedence(symbol string) int {
|
||||
return Operators[symbol].Precedence
|
||||
operator, exists := Operators[symbol]
|
||||
|
||||
if !exists {
|
||||
return -1
|
||||
}
|
||||
|
||||
return operator.Precedence
|
||||
}
|
||||
|
13
src/errors/InvalidOperator.go
Normal file
13
src/errors/InvalidOperator.go
Normal file
@ -0,0 +1,13 @@
|
||||
package errors
|
||||
|
||||
import "fmt"
|
||||
|
||||
// InvalidOperator error is created when an operator is not valid.
|
||||
type InvalidOperator struct {
|
||||
Operator string
|
||||
}
|
||||
|
||||
// Error generates the string representation.
|
||||
func (err *InvalidOperator) Error() string {
|
||||
return fmt.Sprintf("Invalid operator '%s'", err.Operator)
|
||||
}
|
3
tests/errors/InvalidOperator.q
Normal file
3
tests/errors/InvalidOperator.q
Normal file
@ -0,0 +1,3 @@
|
||||
main() {
|
||||
x := 123 +++ 456
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
main() {
|
||||
a :=
|
||||
x :=
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
main() {
|
||||
a := 1
|
||||
a := 2
|
||||
x := 1
|
||||
x := 2
|
||||
}
|
Loading…
Reference in New Issue
Block a user