Added more tests
This commit is contained in:
parent
23b4e6442d
commit
9f341a6146
@ -2,6 +2,7 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.akyoto.dev/cli/q/src/build/asm"
|
"git.akyoto.dev/cli/q/src/build/asm"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/errors"
|
||||||
"git.akyoto.dev/cli/q/src/build/expression"
|
"git.akyoto.dev/cli/q/src/build/expression"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -11,9 +12,18 @@ import (
|
|||||||
// After the function call, they must be restored in reverse order.
|
// After the function call, they must be restored in reverse order.
|
||||||
func (f *Function) CompileCall(root *expression.Expression) error {
|
func (f *Function) CompileCall(root *expression.Expression) error {
|
||||||
funcName := root.Children[0].Token.Text()
|
funcName := root.Children[0].Token.Text()
|
||||||
|
isSyscall := funcName == "syscall"
|
||||||
|
|
||||||
|
if !isSyscall {
|
||||||
|
_, exists := f.functions[funcName]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return errors.New(&errors.UnknownFunction{Name: funcName}, f.File, root.Children[0].Token.Position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parameters := root.Children[1:]
|
parameters := root.Children[1:]
|
||||||
registers := f.cpu.Input[:len(parameters)]
|
registers := f.cpu.Input[:len(parameters)]
|
||||||
isSyscall := funcName == "syscall"
|
|
||||||
|
|
||||||
if isSyscall {
|
if isSyscall {
|
||||||
registers = f.cpu.Syscall[:len(parameters)]
|
registers = f.cpu.Syscall[:len(parameters)]
|
||||||
|
@ -9,25 +9,15 @@ import (
|
|||||||
|
|
||||||
// CompileIf compiles a branch instruction.
|
// CompileIf compiles a branch instruction.
|
||||||
func (f *Function) CompileIf(branch *ast.If) error {
|
func (f *Function) CompileIf(branch *ast.If) error {
|
||||||
condition := branch.Condition
|
err := f.Evaluate(branch.Condition)
|
||||||
tmp := f.cpu.MustFindFree(f.cpu.General)
|
|
||||||
err := f.ExpressionToRegister(condition.Children[0], tmp)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
f.cpu.Use(tmp)
|
|
||||||
err = f.Execute(condition.Token, tmp, condition.Children[1])
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
f.cpu.Free(tmp)
|
|
||||||
endLabel := fmt.Sprintf("%s_end_if_%d", f.Name, f.count.branch)
|
endLabel := fmt.Sprintf("%s_end_if_%d", f.Name, f.count.branch)
|
||||||
|
|
||||||
switch condition.Token.Text() {
|
switch branch.Condition.Token.Text() {
|
||||||
case "==":
|
case "==":
|
||||||
f.assembler.Label(asm.JNE, endLabel)
|
f.assembler.Label(asm.JNE, endLabel)
|
||||||
case "!=":
|
case "!=":
|
||||||
|
41
src/build/core/Evaluate.go
Normal file
41
src/build/core/Evaluate.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.akyoto.dev/cli/q/src/build/ast"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/expression"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Evaluate evaluates an expression.
|
||||||
|
func (f *Function) Evaluate(value *expression.Expression) error {
|
||||||
|
left := value.Children[0]
|
||||||
|
right := value.Children[1]
|
||||||
|
|
||||||
|
if left.IsLeaf() && left.Token.Kind == token.Identifier {
|
||||||
|
variable := f.variables[left.Token.Text()]
|
||||||
|
register := variable.Register
|
||||||
|
defer f.useVariable(variable)
|
||||||
|
return f.Execute(value.Token, register, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ast.IsFunctionCall(left) && right.IsLeaf() {
|
||||||
|
err := f.CompileCall(left)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.Execute(value.Token, f.cpu.Output[0], right)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp := f.cpu.MustFindFree(f.cpu.General)
|
||||||
|
err := f.ExpressionToRegister(left, tmp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.cpu.Use(tmp)
|
||||||
|
defer f.cpu.Free(tmp)
|
||||||
|
return f.Execute(value.Token, tmp, right)
|
||||||
|
}
|
18
src/build/errors/UnknownFunction.go
Normal file
18
src/build/errors/UnknownFunction.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package errors
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// UnknownFunction represents unknown function errors.
|
||||||
|
type UnknownFunction struct {
|
||||||
|
Name string
|
||||||
|
CorrectName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error generates the string representation.
|
||||||
|
func (err *UnknownFunction) Error() string {
|
||||||
|
if err.CorrectName != "" {
|
||||||
|
return fmt.Sprintf("Unknown function '%s', did you mean '%s'?", err.Name, err.CorrectName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("Unknown function '%s'", err.Name)
|
||||||
|
}
|
3
tests/errors/UnknownFunction.q
Normal file
3
tests/errors/UnknownFunction.q
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
main() {
|
||||||
|
unknown()
|
||||||
|
}
|
@ -33,6 +33,7 @@ var errs = []struct {
|
|||||||
{"MissingOperand.q", errors.MissingOperand},
|
{"MissingOperand.q", errors.MissingOperand},
|
||||||
{"MissingOperand2.q", errors.MissingOperand},
|
{"MissingOperand2.q", errors.MissingOperand},
|
||||||
{"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "x"}},
|
{"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "x"}},
|
||||||
|
{"UnknownFunction.q", &errors.UnknownFunction{Name: "unknown"}},
|
||||||
{"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}},
|
{"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}},
|
||||||
{"UnknownIdentifier2.q", &errors.UnknownIdentifier{Name: "x"}},
|
{"UnknownIdentifier2.q", &errors.UnknownIdentifier{Name: "x"}},
|
||||||
{"UnknownIdentifier3.q", &errors.UnknownIdentifier{Name: "f"}},
|
{"UnknownIdentifier3.q", &errors.UnknownIdentifier{Name: "f"}},
|
||||||
|
81
tests/programs/branch.q
Normal file
81
tests/programs/branch.q
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
main() {
|
||||||
|
x := 0
|
||||||
|
|
||||||
|
if x != 0 {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x > 0 {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x < 0 {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 != x {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 > x {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 < x {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x >= 1 {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if 1 <= x {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x == inc(x) {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x == dec(x) {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if inc(0) == x {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dec(0) == x {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if inc(x) == dec(x) {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x + 1 != inc(x) {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x + 1 != x + 1 {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x == 0 {
|
||||||
|
exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(x) {
|
||||||
|
syscall(60, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
inc(x) {
|
||||||
|
return x + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
dec(x) {
|
||||||
|
return x - 1
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user