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"}},
|
{"InvalidInstructionIdentifier.q", &errors.InvalidInstruction{Instruction: "abc"}},
|
||||||
{"InvalidInstructionNumber.q", &errors.InvalidInstruction{Instruction: "123"}},
|
{"InvalidInstructionNumber.q", &errors.InvalidInstruction{Instruction: "123"}},
|
||||||
{"InvalidExpression.q", errors.InvalidExpression},
|
{"InvalidExpression.q", errors.InvalidExpression},
|
||||||
|
{"InvalidOperator.q", &errors.InvalidOperator{Operator: "+++"}},
|
||||||
{"MissingAssignValue.q", errors.MissingAssignValue},
|
{"MissingAssignValue.q", errors.MissingAssignValue},
|
||||||
{"MissingBlockEnd.q", errors.MissingBlockEnd},
|
{"MissingBlockEnd.q", errors.MissingBlockEnd},
|
||||||
{"MissingBlockStart.q", errors.MissingBlockStart},
|
{"MissingBlockStart.q", errors.MissingBlockStart},
|
||||||
{"MissingGroupEnd.q", errors.MissingGroupEnd},
|
{"MissingGroupEnd.q", errors.MissingGroupEnd},
|
||||||
{"MissingGroupStart.q", errors.MissingGroupStart},
|
{"MissingGroupStart.q", errors.MissingGroupStart},
|
||||||
{"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "a"}},
|
{"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "x"}},
|
||||||
{"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}},
|
{"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}},
|
||||||
{"UnknownIdentifier2.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)
|
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])
|
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)
|
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.
|
// TokenToRegister moves a token into a register.
|
||||||
// It only works with identifiers, numbers and strings.
|
// It only works with identifiers, numbers and strings.
|
||||||
func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
|
func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package expression
|
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.
|
// Operator represents an operator for mathematical expressions.
|
||||||
type Operator struct {
|
type Operator struct {
|
||||||
@ -12,35 +16,35 @@ type Operator struct {
|
|||||||
// Operators defines the operators used in the language.
|
// Operators defines the operators used in the language.
|
||||||
// The number corresponds to the operator priority and can not be zero.
|
// The number corresponds to the operator priority and can not be zero.
|
||||||
var Operators = map[string]*Operator{
|
var Operators = map[string]*Operator{
|
||||||
".": {".", 14, 2},
|
".": {".", 13, 2},
|
||||||
"λ": {"λ", 13, 1},
|
"λ": {"λ", 12, 1},
|
||||||
"!": {"!", 12, 1},
|
"!": {"!", 11, 1},
|
||||||
"*": {"*", 11, 2},
|
"*": {"*", 10, 2},
|
||||||
"/": {"/", 11, 2},
|
"/": {"/", 10, 2},
|
||||||
"%": {"%", 11, 2},
|
"%": {"%", 10, 2},
|
||||||
"+": {"+", 10, 2},
|
"+": {"+", 9, 2},
|
||||||
"-": {"-", 10, 2},
|
"-": {"-", 9, 2},
|
||||||
">>": {">>", 9, 2},
|
">>": {">>", 8, 2},
|
||||||
"<<": {"<<", 9, 2},
|
"<<": {"<<", 8, 2},
|
||||||
">": {">", 8, 2},
|
">": {">", 7, 2},
|
||||||
"<": {"<", 8, 2},
|
"<": {"<", 7, 2},
|
||||||
">=": {">=", 8, 2},
|
">=": {">=", 7, 2},
|
||||||
"<=": {"<=", 8, 2},
|
"<=": {"<=", 7, 2},
|
||||||
"==": {"==", 7, 2},
|
"==": {"==", 6, 2},
|
||||||
"!=": {"!=", 7, 2},
|
"!=": {"!=", 6, 2},
|
||||||
"&": {"&", 6, 2},
|
"&": {"&", 5, 2},
|
||||||
"^": {"^", 5, 2},
|
"^": {"^", 4, 2},
|
||||||
"|": {"|", 4, 2},
|
"|": {"|", 3, 2},
|
||||||
"&&": {"&&", 3, 2},
|
"&&": {"&&", 2, 2},
|
||||||
"||": {"||", 2, 2},
|
"||": {"||", 1, 2},
|
||||||
"=": {"=", 1, 2},
|
"=": {"=", math.MinInt, 2},
|
||||||
":=": {":=", 1, 2},
|
":=": {":=", math.MinInt, 2},
|
||||||
"+=": {"+=", 1, 2},
|
"+=": {"+=", math.MinInt, 2},
|
||||||
"-=": {"-=", 1, 2},
|
"-=": {"-=", math.MinInt, 2},
|
||||||
"*=": {"*=", 1, 2},
|
"*=": {"*=", math.MinInt, 2},
|
||||||
"/=": {"/=", 1, 2},
|
"/=": {"/=", math.MinInt, 2},
|
||||||
">>=": {">>=", 1, 2},
|
">>=": {">>=", math.MinInt, 2},
|
||||||
"<<=": {"<<=", 1, 2},
|
"<<=": {"<<=", math.MinInt, 2},
|
||||||
}
|
}
|
||||||
|
|
||||||
func isComplete(expr *Expression) bool {
|
func isComplete(expr *Expression) bool {
|
||||||
@ -60,9 +64,21 @@ func isComplete(expr *Expression) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func numOperands(symbol string) int {
|
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 {
|
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() {
|
main() {
|
||||||
a :=
|
x :=
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
main() {
|
main() {
|
||||||
a := 1
|
x := 1
|
||||||
a := 2
|
x := 2
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user