diff --git a/examples/prime/prime.q b/examples/prime/prime.q index 7d639a2..f29c701 100644 --- a/examples/prime/prime.q +++ b/examples/prime/prime.q @@ -9,7 +9,7 @@ main() { return } - if isPrime(i) == 1 { + if isPrime(i) { if i != 2 { io.out(" ") } @@ -23,22 +23,22 @@ main() { isPrime(x int) -> bool { if x == 2 { - return 1 + return true } if x % 2 == 0 { - return 0 + return false } i := 3 loop { if i * i > x { - return 1 + return true } if x % i == 0 { - return 0 + return false } i += 2 diff --git a/lib/mem/free_unix.q b/lib/mem/free_unix.q index 2c61b78..8acf0df 100644 --- a/lib/mem/free_unix.q +++ b/lib/mem/free_unix.q @@ -1,5 +1,5 @@ import sys -free(address []any) -> int { - return sys.munmap(address-8, len(address)+8) +free(address []any) { + sys.munmap(address-8, len(address)+8) } \ No newline at end of file diff --git a/lib/mem/free_windows.q b/lib/mem/free_windows.q index 1bb258a..3cf8a91 100644 --- a/lib/mem/free_windows.q +++ b/lib/mem/free_windows.q @@ -2,6 +2,6 @@ extern kernel32 { VirtualFree(address *any, size uint, type uint32) -> bool } -free(address []any) -> int { - return kernel32.VirtualFree(address-8, len(address)+8, mem.decommit) +free(address []any) { + kernel32.VirtualFree(address-8, len(address)+8, mem.decommit) } \ No newline at end of file diff --git a/src/core/CompileCondition.go b/src/core/CompileCondition.go index a0c8ffe..0e41f82 100644 --- a/src/core/CompileCondition.go +++ b/src/core/CompileCondition.go @@ -1,8 +1,11 @@ package core import ( + "git.urbach.dev/cli/q/src/asm" + "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/expression" "git.urbach.dev/cli/q/src/token" + "git.urbach.dev/cli/q/src/types" ) // CompileCondition inserts code to jump to the start label or end label depending on the truth of the condition. @@ -62,7 +65,26 @@ func (f *Function) CompileCondition(condition *expression.Expression, successLab return err - default: + case token.Call: + typ, err := f.CompileCall(condition) + + if err != nil { + return err + } + + if len(typ) == 0 { + return errors.New(errors.UntypedExpression, f.File, condition.Token.Position) + } + + if !types.Is(typ[0], types.Bool) { + return errors.New(&errors.TypeMismatch{Encountered: typ[0].Name(), Expected: types.Bool.Name()}, f.File, condition.Token.Position) + } + + f.RegisterNumber(asm.COMPARE, f.CPU.Output[0], 0) + f.Jump(asm.JE, failLabel) + return nil + + case token.Equal, token.NotEqual, token.Greater, token.Less, token.GreaterEqual, token.LessEqual: err := f.Compare(condition) if condition.Parent == nil { @@ -70,5 +92,8 @@ func (f *Function) CompileCondition(condition *expression.Expression, successLab } return err + + default: + return errors.New(errors.InvalidCondition, f.File, condition.Token.Position) } } diff --git a/src/core/Evaluate.go b/src/core/Evaluate.go index 5e36fec..7189cf6 100644 --- a/src/core/Evaluate.go +++ b/src/core/Evaluate.go @@ -1,6 +1,7 @@ package core import ( + "git.urbach.dev/cli/q/src/ast" "git.urbach.dev/cli/q/src/cpu" "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/expression" @@ -24,6 +25,16 @@ func (f *Function) Evaluate(expr *expression.Expression) (types.Type, cpu.Regist } } + if ast.IsFunctionCall(expr) { + types, err := f.CompileCall(expr) + + if err != nil { + return nil, 0, false, err + } + + return types[0], f.CPU.Output[0], false, nil + } + tmp := f.NewRegister() typ, err := f.ExpressionToRegister(expr, tmp) return typ, tmp, true, err diff --git a/src/core/TokenToRegister.go b/src/core/TokenToRegister.go index a8128eb..e05d9e8 100644 --- a/src/core/TokenToRegister.go +++ b/src/core/TokenToRegister.go @@ -16,6 +16,17 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) (types. switch t.Kind { case token.Identifier: name := t.Text(f.File.Bytes) + + if name == "true" { + f.RegisterNumber(asm.MOVE, register, 1) + return types.Bool, nil + } + + if name == "false" { + f.RegisterNumber(asm.MOVE, register, 0) + return types.Bool, nil + } + variable, function := f.Identifier(name) if variable != nil { diff --git a/src/errors/Common.go b/src/errors/Common.go index 3b1d665..f5f4f50 100644 --- a/src/errors/Common.go +++ b/src/errors/Common.go @@ -10,6 +10,7 @@ var ( ExpectedStructName = &Base{"Expected struct name"} ExpectedDLLName = &Base{"Expected DLL name"} InvalidNumber = &Base{"Invalid number"} + InvalidCondition = &Base{"Invalid condition"} InvalidExpression = &Base{"Invalid expression"} InvalidRune = &Base{"Invalid rune"} MissingBlockStart = &Base{"Missing '{'"} diff --git a/src/types/Common.go b/src/types/Common.go index 3d2a870..8cab280 100644 --- a/src/types/Common.go +++ b/src/types/Common.go @@ -4,6 +4,7 @@ var ( Any = &Base{name: "any", size: 0} AnyArray = &Array{Of: Any} AnyPointer = &Pointer{To: Any} + Bool = &Base{name: "bool", size: 1} Int64 = &Base{name: "int64", size: 8} Int32 = &Base{name: "int32", size: 4} Int16 = &Base{name: "int16", size: 2} @@ -14,7 +15,6 @@ var ( ) var ( - Bool = Int Byte = UInt8 Int = Int64 Float = Float64 diff --git a/src/types/Is.go b/src/types/Is.go index 4134701..1629454 100644 --- a/src/types/Is.go +++ b/src/types/Is.go @@ -25,8 +25,12 @@ func Is(a Type, b Type) bool { return true } - // Temporary hack for implicit casts - if a.Size() > b.Size() { + // Temporary hacks + if a == Int32 && b == Int64 { + return true + } + + if a == Int64 && b == Int32 { return true } diff --git a/tests/errors/InvalidCondition.q b/tests/errors/InvalidCondition.q new file mode 100644 index 0000000..8d76be8 --- /dev/null +++ b/tests/errors/InvalidCondition.q @@ -0,0 +1,3 @@ +main() { + if 42 {} +} \ No newline at end of file diff --git a/tests/errors_test.go b/tests/errors_test.go index c31056e..6b10e3f 100644 --- a/tests/errors_test.go +++ b/tests/errors_test.go @@ -22,6 +22,7 @@ var errs = []struct { {"ExpectedIfBeforeElse2.q", errors.ExpectedIfBeforeElse}, {"ExpectedStructName.q", errors.ExpectedStructName}, {"ExpectedPackageName.q", errors.ExpectedPackageName}, + {"InvalidCondition.q", errors.InvalidCondition}, {"InvalidInstructionCall.q", &errors.InvalidInstruction{Instruction: "sys.write"}}, {"InvalidInstructionExpression.q", &errors.InvalidInstruction{Instruction: "2+3"}}, {"InvalidInstructionIdentifier.q", &errors.InvalidInstruction{Instruction: "abc"}},