From 626375bc1f677ba87a181ee104f462c5cb0f8c96 Mon Sep 17 00:00:00 2001 From: Mattia Giambirtone Date: Mon, 15 Aug 2022 22:15:06 +0200 Subject: [PATCH] Added all missing comparison operators and fixed error reporting system --- src/backend/vm.nim | 40 ++++++++++++++ src/frontend/compiler.nim | 40 ++++++++++++++ src/frontend/lexer.nim | 6 +-- src/frontend/meta/bytecode.nim | 41 ++++++++++++++ src/frontend/parser.nim | 1 + src/main.nim | 26 ++++----- tests/comparisons.pn | 41 +++++++++++++- tests/std.pn | 99 ++++++++++++++++++++++++++++++++++ 8 files changed, 276 insertions(+), 18 deletions(-) diff --git a/src/backend/vm.nim b/src/backend/vm.nim index a10eaa0..a8b771b 100644 --- a/src/backend/vm.nim +++ b/src/backend/vm.nim @@ -692,6 +692,46 @@ proc dispatch*(self: PeonVM) = self.push(PeonObject(kind: Bool, boolean: self.pop().halfFloat == self.pop().halfFloat)) of NotEqualFloat32: self.push(PeonObject(kind: Bool, boolean: self.pop().halfFloat != self.pop().halfFloat)) + of GreaterOrEqualInt64: + self.push(PeonObject(kind: Bool, boolean: self.pop().long !>= self.pop().long)) + of LessOrEqualInt64: + self.push(PeonObject(kind: Bool, boolean: self.pop().long <= self.pop().long)) + of GreaterOrEqualUInt64: + self.push(PeonObject(kind: Bool, boolean: self.pop().uLong !>= self.pop().uLong)) + of LessOrEqualUInt64: + self.push(PeonObject(kind: Bool, boolean: self.pop().uLong <= self.pop().uLong)) + of GreaterOrEqualInt32: + self.push(PeonObject(kind: Bool, boolean: self.pop().`int` !>= self.pop().`int`)) + of LessOrEqualInt32: + self.push(PeonObject(kind: Bool, boolean: self.pop().`int` <= self.pop().`int`)) + of GreaterOrEqualUInt32: + self.push(PeonObject(kind: Bool, boolean: self.pop().uInt !>= self.pop().uInt)) + of LessOrEqualUInt32: + self.push(PeonObject(kind: Bool, boolean: self.pop().uInt <= self.pop().uInt)) + of GreaterOrEqualInt16: + self.push(PeonObject(kind: Bool, boolean: self.pop().short !>= self.pop().short)) + of LessOrEqualInt16: + self.push(PeonObject(kind: Bool, boolean: self.pop().short <= self.pop().short)) + of GreaterOrEqualUInt16: + self.push(PeonObject(kind: Bool, boolean: self.pop().uShort !>= self.pop().uShort)) + of LessOrEqualUInt16: + self.push(PeonObject(kind: Bool, boolean: self.pop().uShort <= self.pop().uShort)) + of GreaterOrEqualInt8: + self.push(PeonObject(kind: Bool, boolean: self.pop().tiny !>= self.pop().tiny)) + of LessOrEqualInt8: + self.push(PeonObject(kind: Bool, boolean: self.pop().tiny <= self.pop().tiny)) + of GreaterOrEqualUInt8: + self.push(PeonObject(kind: Bool, boolean: self.pop().uTiny !>= self.pop().uTiny)) + of LessOrEqualUInt8: + self.push(PeonObject(kind: Bool, boolean: self.pop().uTiny <= self.pop().uTiny)) + of GreaterOrEqualFloat64: + self.push(PeonObject(kind: Bool, boolean: self.pop().`float` !>= self.pop().`float`)) + of LessOrEqualFloat64: + self.push(PeonObject(kind: Bool, boolean: self.pop().`float` <= self.pop().`float`)) + of GreaterOrEqualFloat32: + self.push(PeonObject(kind: Bool, boolean: self.pop().halfFloat !>= self.pop().halfFloat)) + of LessOrEqualFloat32: + self.push(PeonObject(kind: Bool, boolean: self.pop().halfFloat <= self.pop().halfFloat)) of SysClock64: # Pushes the value of a monotonic clock # as a 64 bit float onto the operand stack. diff --git a/src/frontend/compiler.nim b/src/frontend/compiler.nim index f1e5d0c..26fcc8b 100644 --- a/src/frontend/compiler.nim +++ b/src/frontend/compiler.nim @@ -1103,6 +1103,46 @@ proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) = self.emitByte(EqualFloat32) of "NotEqualFloat32": self.emitByte(NotEqualFloat32) + of "GreaterOrEqualInt64": + self.emitByte(GreaterOrEqualInt64) + of "LessOrEqualInt64": + self.emitByte(LessOrEqualInt64) + of "GreaterOrEqualUInt64": + self.emitByte(GreaterOrEqualUInt64) + of "LessOrEqualUInt64": + self.emitByte(LessOrEqualUInt64) + of "GreaterOrEqualInt32": + self.emitByte(GreaterOrEqualInt32) + of "LessOrEqualInt32": + self.emitByte(LessOrEqualInt32) + of "GreaterOrEqualUInt32": + self.emitByte(GreaterOrEqualUInt32) + of "LessOrEqualUInt32": + self.emitByte(LessOrEqualUInt32) + of "GreaterOrEqualInt16": + self.emitByte(GreaterOrEqualInt16) + of "LessOrEqualInt16": + self.emitByte(LessOrEqualInt16) + of "GreaterOrEqualUInt16": + self.emitByte(GreaterOrEqualUInt16) + of "LessOrEqualUInt16": + self.emitByte(LessOrEqualUInt16) + of "GreaterOrEqualInt8": + self.emitByte(GreaterOrEqualInt8) + of "LessOrEqualInt8": + self.emitByte(LessOrEqualInt8) + of "GreaterOrEqualUInt8": + self.emitByte(GreaterOrEqualUInt8) + of "LessOrEqualUInt8": + self.emitByte(LessOrEqualUInt8) + of "GreaterOrEqualFloat64": + self.emitByte(GreaterOrEqualFloat64) + of "LessOrEqualFloat64": + self.emitByte(LessOrEqualFloat64) + of "GreaterOrEqualFloat32": + self.emitByte(GreaterOrEqualFloat32) + of "LessOrEqualFloat32": + self.emitByte(LessOrEqualFloat32) of "SysClock64": self.emitByte(SysClock64) else: diff --git a/src/frontend/lexer.nim b/src/frontend/lexer.nim index 6ff1045..e5a655b 100644 --- a/src/frontend/lexer.nim +++ b/src/frontend/lexer.nim @@ -237,7 +237,6 @@ proc peek(self: Lexer, distance: int = 0, length: int = 1): string = proc error(self: Lexer, message: string) = ## Raises a lexing error with info ## for error messages - echo self.source[self.current - 50..self.current] raise LexingError(msg: message, line: self.line, file: self.file, lexeme: self.peek(), lexer: self) @@ -297,9 +296,7 @@ proc createToken(self: Lexer, tokenType: TokenType) = tok.line = self.line tok.spaces = self.spaces self.spaces = 0 - tok.pos = (start: self.start, stop: self.current) - if len(tok.lexeme) != tok.pos.stop - tok.pos.start: - self.error("invalid state: len(tok.lexeme) != tok.pos.stop - tok.pos.start (this is most likely a compiler bug!)") + tok.pos = (start: self.start, stop: self.current - 1) self.tokens.add(tok) @@ -616,6 +613,7 @@ proc next(self: Lexer) = while not (self.match("\n") or self.done()): discard self.step() self.createToken(Comment) + self.incLine() else: self.createToken(Pragma) else: diff --git a/src/frontend/meta/bytecode.nim b/src/frontend/meta/bytecode.nim index a5642bf..0291441 100644 --- a/src/frontend/meta/bytecode.nim +++ b/src/frontend/meta/bytecode.nim @@ -177,6 +177,26 @@ type GreaterThanFloat32, EqualFloat32, NotEqualFloat32, + GreaterOrEqualInt64, + LessOrEqualInt64, + GreaterOrEqualUInt64, + LessOrEqualUInt64, + GreaterOrEqualInt32, + LessOrEqualInt32, + GreaterOrEqualUInt32, + LessOrEqualUInt32, + GreaterOrEqualInt16, + LessOrEqualInt16, + GreaterOrEqualUInt16, + LessOrEqualUInt16, + GreaterOrEqualInt8, + LessOrEqualInt8, + GreaterOrEqualUInt8, + LessOrEqualUInt8, + GreaterOrEqualFloat64, + LessOrEqualFloat64, + GreaterOrEqualFloat32, + LessOrEqualFloat32, SysClock64, ## Basic stack operations Pop, # Pops an element off the stack and discards it @@ -253,6 +273,27 @@ const simpleInstructions* = {Return, LoadNil, NotEqualUInt8, LessThanFloat64, GreaterThanFloat64, EqualFloat64,NotEqualFloat64, LessThanFloat32, GreaterThanFloat32, EqualFloat32, NotEqualFloat32, + GreaterOrEqualInt64, + LessOrEqualInt64, + GreaterOrEqualUInt64, + LessOrEqualUInt64, + GreaterOrEqualInt32, + LessOrEqualInt32, + GreaterOrEqualUInt32, + LessOrEqualUInt32, + GreaterOrEqualInt16, + LessOrEqualInt16, + GreaterOrEqualUInt16, + LessOrEqualUInt16, + GreaterOrEqualInt8, + LessOrEqualInt8, + GreaterOrEqualUInt8, + LessOrEqualUInt8, + GreaterOrEqualFloat64, + LessOrEqualFloat64, + GreaterOrEqualFloat32, + LessOrEqualFloat32, + SysClock64, } # Constant instructions are instructions that operate on the bytecode constant table diff --git a/src/frontend/parser.nim b/src/frontend/parser.nim index 3dc1165..75ebad1 100644 --- a/src/frontend/parser.nim +++ b/src/frontend/parser.nim @@ -208,6 +208,7 @@ proc step(self: Parser, n: int = 1): Token = proc error(self: Parser, message: string, token: Token = nil) {.raises: [ParseError].} = ## Raises a ParseError exception + echo (if token.isNil(): self.getCurrentToken() else: token)[] raise ParseError(msg: message, token: if token.isNil(): self.getCurrentToken() else: token, file: self.file, module: self.getModule(), parser: self) diff --git a/src/main.nim b/src/main.nim index ee701fb..99b7104 100644 --- a/src/main.nim +++ b/src/main.nim @@ -141,11 +141,11 @@ proc repl(vm: PeonVM = newPeonVM()) = except LexingError: input = "" let exc = LexingError(getCurrentException()) - let relPos = tokenizer.getRelPos(exc.line) - let line = tokenizer.getSource().splitLines()[exc.line - 1].strip(chars={'\n'}) + let relPos = exc.lexer.getRelPos(exc.line) + let line = exc.lexer.getSource().splitLines()[exc.line - 1].strip(chars={'\n'}) stderr.styledWriteLine(fgRed, "A fatal error occurred while parsing ", fgYellow, &"'{exc.file}'", fgRed, ", module ", - fgYellow, &"'{exc.file.extractFilename()}'", fgRed, ", line ", fgYellow, $exc.line, fgRed, " at ", fgYellow, &"'{exc.lexeme.escape()}'", - fgRed, ": ", fgGreen , getCurrentExceptionMsg()) + fgYellow, &"'{exc.file.extractFilename()}'", fgRed, ", line ", fgYellow, $exc.line, fgRed, " at ", fgYellow, &"'{exc.lexeme.escape()}'", + fgRed, ": ", fgGreen , getCurrentExceptionMsg()) styledEcho fgBlue, "Source line: " , fgDefault, line styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start) except ParseError: @@ -153,30 +153,30 @@ proc repl(vm: PeonVM = newPeonVM()) = let exc = ParseError(getCurrentException()) let lexeme = exc.token.lexeme let lineNo = exc.token.line - let relPos = tokenizer.getRelPos(lineNo) + let relPos = exc.parser.getRelPos(lineNo) let fn = parser.getCurrentFunction() - let line = tokenizer.getSource().splitLines()[lineNo - 1].strip(chars={'\n'}) + let line = exc.parser.getSource().splitLines()[lineNo - 1].strip(chars={'\n'}) var fnMsg = "" if fn != nil and fn.kind == funDecl: fnMsg &= &"in function '{FunDecl(fn).name.token.lexeme}'" stderr.styledWriteLine(fgRed, "A fatal error occurred while parsing ", fgYellow, &"'{exc.file}'", fgRed, ", module ", - fgYellow, &"'{exc.file}'", fgRed, ", line ", fgYellow, $lineNo, fgRed, " at ", fgYellow, &"'{lexeme}'", - fgRed, ": ", fgGreen , getCurrentExceptionMsg()) + fgYellow, &"'{exc.module}'", fgRed, ", line ", fgYellow, $lineNo, fgRed, " at ", fgYellow, &"'{lexeme}'", + fgRed, ": ", fgGreen , getCurrentExceptionMsg()) styledEcho fgBlue, "Source line: " , fgDefault, line styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start) except CompileError: let exc = CompileError(getCurrentException()) let lexeme = exc.node.token.lexeme let lineNo = exc.node.token.line - let relPos = tokenizer.getRelPos(lineNo) - let line = tokenizer.getSource().splitLines()[lineNo - 1].strip(chars={'\n'}) - var fn = compiler.getCurrentFunction() + let relPos = exc.compiler.getRelPos(lineNo) + let line = exc.compiler.getSource().splitLines()[lineNo - 1].strip(chars={'\n'}) + var fn = exc.compiler.getCurrentFunction() var fnMsg = "" if fn != nil and fn.kind == funDecl: fnMsg &= &"in function '{FunDecl(fn).name.token.lexeme}'" stderr.styledWriteLine(fgRed, "A fatal error occurred while compiling ", fgYellow, &"'{exc.file}'", fgRed, ", module ", - fgYellow, &"'{exc.module}'", fgRed, ", line ", fgYellow, $lineNo, fgRed, " at ", fgYellow, &"'{lexeme}'", - fgRed, ": ", fgGreen , getCurrentExceptionMsg()) + fgYellow, &"'{exc.module}'", fgRed, ", line ", fgYellow, $lineNo, fgRed, " at ", fgYellow, &"'{lexeme}'", + fgRed, ": ", fgGreen , getCurrentExceptionMsg()) styledEcho fgBlue, "Source line: " , fgDefault, line styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start) except SerializationError: diff --git a/tests/comparisons.pn b/tests/comparisons.pn index c15b1b7..954c7f5 100644 --- a/tests/comparisons.pn +++ b/tests/comparisons.pn @@ -1,5 +1,4 @@ import std; - # int64 print(3 > 2); # true print(2 < 3); # true @@ -9,6 +8,10 @@ print(2 != 3); # true print(3 != 2); # true print(3 == 2); # false print(2 == 3); # false +print(2 <= 3); # true +print(3 >= 2); # true +print(2 >= 3); # false +print(3 <= 2); # false # uint64 var x = 3'u64; var y = 2'u64; @@ -20,6 +23,10 @@ print(y != x); # true print(x != y); # true print(x == y); # false print(y == x); # false +print(y <= x); # true +print(x >= y); # true +print(y >= x); # false +print(x <= y); # false # int32 var x1 = 3'i32; var y1 = 2'i32; @@ -31,6 +38,10 @@ print(y1 != x1); # true print(x1 != y1); # true print(x1 == y1); # false print(y1 == x1); # false +print(y1 <= x1); # true +print(x1 >= y1); # true +print(y1 >= x1); # false +print(x1 <= y1); # false # uint32 var x2 = 3'u32; var y2 = 2'u32; @@ -42,6 +53,10 @@ print(y2 != x2); # true print(x2 != y2); # true print(x2 == y2); # false print(y2 == x2); # false +print(y2 <= x2); # true +print(x2 >= y2); # true +print(y2 >= x2); # false +print(x2 <= y2); # false # int16 var x3 = 3'i16; var y3 = 2'i16; @@ -53,6 +68,10 @@ print(y3 != x3); # true print(x3 != y3); # true print(x3 == y3); # false print(y3 == x3); # false +print(y3 <= x3); # true +print(x3 >= y3); # true +print(y3 >= x3); # false +print(x3 <= y3); # false # uint16 var x4 = 3'u16; var y4 = 2'u16; @@ -64,6 +83,10 @@ print(y4 != x4); # true print(x4 != y4); # true print(x4 == y4); # false print(y4 == x4); # false +print(y4 <= x4); # true +print(x4 >= y4); # true +print(y4 >= x4); # false +print(x4 <= y4); # false # int8 var x5 = 3'i8; var y5 = 2'i8; @@ -75,6 +98,10 @@ print(y5 != x5); # true print(x5 != y5); # true print(x5 == y5); # false print(y5 == x5); # false +print(y5 <= x5); # true +print(x5 >= y5); # true +print(y5 >= x5); # false +print(x5 <= y5); # false # uint8 var x6 = 3'u8; var y6 = 2'u8; @@ -86,6 +113,10 @@ print(y6 != x6); # true print(x6 != y6); # true print(x6 == y6); # false print(y6 == x6); # false +print(y6 <= x6); # true +print(x6 >= y6); # true +print(y6 >= x6); # false +print(x6 <= y6); # false # float64 var x7 = 3.0; var y7 = 2.0; @@ -97,6 +128,10 @@ print(y7 != x7); # true print(x7 != y7); # true print(x7 == y7); # false print(y7 == x7); # false +print(y7 <= x7); # true +print(x7 >= y7); # true +print(y7 >= x7); # false +print(x7 <= y7); # false # float32 var x8 = 3'f32; var y8 = 2'f32; @@ -108,3 +143,7 @@ print(y8 != x8); # true print(x8 != y8); # true print(x8 == y8); # false print(y8 == x8); # false +print(y8 <= x8); # true +print(x8 >= y8); # true +print(y8 >= x8); # false +print(x8 <= y8); # false diff --git a/tests/std.pn b/tests/std.pn index 8bd24dc..47ce228 100644 --- a/tests/std.pn +++ b/tests/std.pn @@ -408,6 +408,105 @@ operator `!=`*(a, b: float32): bool { } +operator `>=`*(a, b: int): bool { + #pragma[magic: "GreaterOrEqualInt64", pure] +} + + +operator `<=`*(a, b: int): bool { + #pragma[magic: "LessOrEqualInt64", pure] +} + + +operator `>=`*(a, b: uint64): bool { + #pragma[magic: "GreaterOrEqualUInt64", pure] +} + + +operator `<=`*(a, b: uint64): bool { + #pragma[magic: "LessOrEqualUInt64", pure] +} + + +operator `>=`*(a, b: int32): bool { + #pragma[magic: "GreaterOrEqualInt32", pure] +} + + +operator `<=`*(a, b: int32): bool { + #pragma[magic: "LessOrEqualInt32", pure] +} + + +operator `>=`*(a, b: uint32): bool { + #pragma[magic: "GreaterOrEqualUInt32", pure] +} + + +operator `<=`*(a, b: uint32): bool { + #pragma[magic: "LessOrEqualUInt32", pure] +} + + +operator `>=`*(a, b: int16): bool { + #pragma[magic: "GreaterOrEqualInt16", pure] +} + + +operator `<=`*(a, b: int16): bool { + #pragma[magic: "LessOrEqualInt16", pure] +} + + +operator `>=`*(a, b: uint16): bool { + #pragma[magic: "GreaterOrEqualUInt16", pure] +} + + +operator `<=`*(a, b: uint16): bool { + #pragma[magic: "LessOrEqualUInt16", pure] +} + + +operator `>=`*(a, b: int8): bool { + #pragma[magic: "GreaterOrEqualInt8", pure] +} + + +operator `<=`*(a, b: int8): bool { + #pragma[magic: "LessOrEqualInt8", pure] +} + + +operator `>=`*(a, b: uint8): bool { + #pragma[magic: "GreaterOrEqualUInt8", pure] +} + + +operator `<=`*(a, b: uint8): bool { + #pragma[magic: "LessOrEqualUInt8", pure] +} + + +operator `>=`*(a, b: float): bool { + #pragma[magic: "GreaterOrEqualFloat64", pure] +} + + +operator `<=`*(a, b: float): bool { + #pragma[magic: "LessOrEqualFloat64", pure] +} + + +operator `>=`*(a, b: float32): bool { + #pragma[magic: "GreaterOrEqualFloat32", pure] +} + + +operator `<=`*(a, b: float32): bool { + #pragma[magic: "LessOrEqualFloat32", pure] +} + # Assignment operator # TODO #operator `=`[T](a: var T, b: T) {