Initial work on call resolution, added support for running files
This commit is contained in:
parent
6d6ae3ee7a
commit
42ab1d4c6e
|
@ -23,6 +23,7 @@ import algorithm
|
||||||
import parseutils
|
import parseutils
|
||||||
import strutils
|
import strutils
|
||||||
import sequtils
|
import sequtils
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
export ast
|
export ast
|
||||||
|
@ -43,9 +44,11 @@ type
|
||||||
node*: ASTNode
|
node*: ASTNode
|
||||||
case kind*: TypeKind:
|
case kind*: TypeKind:
|
||||||
of Function:
|
of Function:
|
||||||
|
args*: seq[tuple[name: IdentExpr, kind: Type]]
|
||||||
returnType*: Type
|
returnType*: Type
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
# This way we don't have recursive dependency issues
|
# This way we don't have recursive dependency issues
|
||||||
import meta/bytecode
|
import meta/bytecode
|
||||||
export bytecode
|
export bytecode
|
||||||
|
@ -158,6 +161,8 @@ proc identifier(self: Compiler, node: IdentExpr)
|
||||||
proc varDecl(self: Compiler, node: VarDecl)
|
proc varDecl(self: Compiler, node: VarDecl)
|
||||||
proc inferType(self: Compiler, node: LiteralExpr): Type
|
proc inferType(self: Compiler, node: LiteralExpr): Type
|
||||||
proc inferType(self: Compiler, node: Expression): Type
|
proc inferType(self: Compiler, node: Expression): Type
|
||||||
|
proc findByName(self: Compiler, name: string): seq[Name]
|
||||||
|
proc findByType(self: Compiler, name: string, kind: Type): seq[Name]
|
||||||
## End of forward declarations
|
## End of forward declarations
|
||||||
|
|
||||||
## Public getter for nicer error formatting
|
## Public getter for nicer error formatting
|
||||||
|
@ -190,7 +195,7 @@ proc done(self: Compiler): bool =
|
||||||
|
|
||||||
proc error(self: Compiler, message: string) {.raises: [CompileError].} =
|
proc error(self: Compiler, message: string) {.raises: [CompileError].} =
|
||||||
## Raises a CompileError exception
|
## Raises a CompileError exception
|
||||||
raise newException(CompileError, message)
|
raise CompileError(msg: message, node: self.getCurrentNode(), file: self.file, module: self.currentModule)
|
||||||
|
|
||||||
|
|
||||||
proc step(self: Compiler): ASTNode =
|
proc step(self: Compiler): ASTNode =
|
||||||
|
@ -201,7 +206,7 @@ proc step(self: Compiler): ASTNode =
|
||||||
self.current += 1
|
self.current += 1
|
||||||
|
|
||||||
|
|
||||||
proc emitByte(self: Compiler, byt: OpCode|uint8) =
|
proc emitByte(self: Compiler, byt: OpCode | uint8) =
|
||||||
## Emits a single byte, writing it to
|
## Emits a single byte, writing it to
|
||||||
## the current chunk being compiled
|
## the current chunk being compiled
|
||||||
when DEBUG_TRACE_COMPILER:
|
when DEBUG_TRACE_COMPILER:
|
||||||
|
@ -209,23 +214,8 @@ proc emitByte(self: Compiler, byt: OpCode|uint8) =
|
||||||
self.chunk.write(uint8 byt, self.peek().token.line)
|
self.chunk.write(uint8 byt, self.peek().token.line)
|
||||||
|
|
||||||
|
|
||||||
proc emitBytes(self: Compiler, byt1: OpCode|uint8, byt2: OpCode|uint8) =
|
proc emitBytes(self: Compiler, bytarr: openarray[OpCode | uint8]) =
|
||||||
## Emits multiple bytes instead of a single one. This is useful
|
## Handy helper method to write arbitrary bytes into
|
||||||
## to emit operators along with their operands or for multi-byte
|
|
||||||
## instructions that are longer than one byte
|
|
||||||
self.emitByte(uint8 byt1)
|
|
||||||
self.emitByte(uint8 byt2)
|
|
||||||
|
|
||||||
|
|
||||||
proc emitBytes(self: Compiler, bytarr: array[2, uint8]) =
|
|
||||||
## Handy helper method to write an array of 2 bytes into
|
|
||||||
## the current chunk, calling emitByte on each of its
|
|
||||||
## elements
|
|
||||||
self.emitBytes(bytarr[0], bytarr[1])
|
|
||||||
|
|
||||||
|
|
||||||
proc emitBytes(self: Compiler, bytarr: openarray[uint8]) =
|
|
||||||
## Handy helper method to write an array of 3 bytes into
|
|
||||||
## the current chunk, calling emitByte on each of its
|
## the current chunk, calling emitByte on each of its
|
||||||
## elements
|
## elements
|
||||||
for b in bytarr:
|
for b in bytarr:
|
||||||
|
@ -390,6 +380,30 @@ proc detectClosureVariable(self: Compiler, name: IdentExpr,
|
||||||
self.chunk.code[entry.codePos + 2] = idx[1]
|
self.chunk.code[entry.codePos + 2] = idx[1]
|
||||||
self.chunk.code[entry.codePos + 3] = idx[2]
|
self.chunk.code[entry.codePos + 3] = idx[2]
|
||||||
|
|
||||||
|
proc compareTypes(self: Compiler, a, b: Type): bool
|
||||||
|
|
||||||
|
proc compareTypesWithNullNode(self: Compiler, a, b: Type): bool =
|
||||||
|
## Compares two types without using information from
|
||||||
|
## AST nodes
|
||||||
|
if a == nil:
|
||||||
|
return b == nil
|
||||||
|
elif b == nil:
|
||||||
|
return a == nil
|
||||||
|
if a.kind != b.kind:
|
||||||
|
return false
|
||||||
|
case a.kind:
|
||||||
|
of Function:
|
||||||
|
if a.args.len() != b.args.len():
|
||||||
|
return false
|
||||||
|
elif not self.compareTypes(a.returnType, b.returnType):
|
||||||
|
return false
|
||||||
|
for (argA, argB) in zip(a.args, b.args):
|
||||||
|
if not self.compareTypes(argA.kind, argB.kind):
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
|
||||||
proc compareTypes(self: Compiler, a, b: Type): bool =
|
proc compareTypes(self: Compiler, a, b: Type): bool =
|
||||||
## Compares two type objects
|
## Compares two type objects
|
||||||
|
@ -406,6 +420,8 @@ proc compareTypes(self: Compiler, a, b: Type): bool =
|
||||||
Char, Byte, String, Nil, Nan, Bool, Inf:
|
Char, Byte, String, Nil, Nan, Bool, Inf:
|
||||||
return true
|
return true
|
||||||
of Function:
|
of Function:
|
||||||
|
if a.node == nil or b.node == nil:
|
||||||
|
return self.compareTypesWithNullNode(a, b)
|
||||||
let
|
let
|
||||||
a = FunDecl(a.node)
|
a = FunDecl(a.node)
|
||||||
b = FunDecl(b.node)
|
b = FunDecl(b.node)
|
||||||
|
@ -413,8 +429,7 @@ proc compareTypes(self: Compiler, a, b: Type): bool =
|
||||||
return false
|
return false
|
||||||
elif a.arguments.len() != b.arguments.len():
|
elif a.arguments.len() != b.arguments.len():
|
||||||
return false
|
return false
|
||||||
elif not self.compareTypes(self.inferType(a.returnType),
|
elif not self.compareTypes(self.inferType(a.returnType), self.inferType(b.returnType)):
|
||||||
self.inferType(b.returnType)):
|
|
||||||
return false
|
return false
|
||||||
for (argA, argB) in zip(a.arguments, b.arguments):
|
for (argA, argB) in zip(a.arguments, b.arguments):
|
||||||
if argA.mutable != argB.mutable:
|
if argA.mutable != argB.mutable:
|
||||||
|
@ -423,8 +438,7 @@ proc compareTypes(self: Compiler, a, b: Type): bool =
|
||||||
return false
|
return false
|
||||||
elif argA.isPtr != argB.isPtr:
|
elif argA.isPtr != argB.isPtr:
|
||||||
return false
|
return false
|
||||||
elif not self.compareTypes(self.inferType(argA.valueType),
|
elif not self.compareTypes(self.inferType(argA.valueType), self.inferType(argB.valueType)):
|
||||||
self.inferType(argB.valueType)):
|
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
else:
|
else:
|
||||||
|
@ -702,7 +716,10 @@ proc unary(self: Compiler, node: UnaryExpr) =
|
||||||
## Compiles unary expressions such as decimal
|
## Compiles unary expressions such as decimal
|
||||||
## and bitwise negation
|
## and bitwise negation
|
||||||
self.expression(node.a) # Pushes the operand onto the stack
|
self.expression(node.a) # Pushes the operand onto the stack
|
||||||
|
let valueType = self.inferType(node.a)
|
||||||
|
let impl = self.findByType(node.token.lexeme, Type(kind: Function, returnType: valueType, node: nil))
|
||||||
|
if impl.len() == 0:
|
||||||
|
self.error(&"cannot find a suitable implementation for '{node.token.lexeme}'")
|
||||||
|
|
||||||
|
|
||||||
proc binary(self: Compiler, node: BinaryExpr) =
|
proc binary(self: Compiler, node: BinaryExpr) =
|
||||||
|
@ -772,10 +789,12 @@ proc declareName(self: Compiler, node: Declaration) =
|
||||||
owner: self.currentModule,
|
owner: self.currentModule,
|
||||||
valueType: Type(kind: Function, node: node,
|
valueType: Type(kind: Function, node: node,
|
||||||
returnType: self.inferType(
|
returnType: self.inferType(
|
||||||
node.returnType)),
|
node.returnType),
|
||||||
|
args: @[]),
|
||||||
codePos: self.chunk.code.len(),
|
codePos: self.chunk.code.len(),
|
||||||
name: node.name,
|
name: node.name,
|
||||||
isLet: false))
|
isLet: false))
|
||||||
|
let fn = self.names[^1]
|
||||||
for argument in node.arguments:
|
for argument in node.arguments:
|
||||||
if self.names.high() > 16777215:
|
if self.names.high() > 16777215:
|
||||||
self.error("cannot declare more than 16777216 variables at a time")
|
self.error("cannot declare more than 16777216 variables at a time")
|
||||||
|
@ -789,6 +808,7 @@ proc declareName(self: Compiler, node: Declaration) =
|
||||||
isLet: false))
|
isLet: false))
|
||||||
self.names[^1].valueType = self.inferType(argument.valueType)
|
self.names[^1].valueType = self.inferType(argument.valueType)
|
||||||
self.names[^1].valueType.node = argument.name
|
self.names[^1].valueType.node = argument.name
|
||||||
|
fn.valueType.args.add((node.name, self.names[^1].valueType))
|
||||||
self.emitByte(LoadVar)
|
self.emitByte(LoadVar)
|
||||||
self.emitBytes(self.names.high().toTriple())
|
self.emitBytes(self.names.high().toTriple())
|
||||||
else:
|
else:
|
||||||
|
@ -1274,7 +1294,7 @@ proc compile*(self: Compiler, ast: seq[Declaration], file: string): Chunk =
|
||||||
self.names = @[]
|
self.names = @[]
|
||||||
self.scopeDepth = 0
|
self.scopeDepth = 0
|
||||||
self.currentFunction = nil
|
self.currentFunction = nil
|
||||||
self.currentModule = self.file
|
self.currentModule = self.file.extractFilename()
|
||||||
self.current = 0
|
self.current = 0
|
||||||
while not self.done():
|
while not self.done():
|
||||||
self.declaration(Declaration(self.step()))
|
self.declaration(Declaration(self.step()))
|
||||||
|
|
|
@ -19,7 +19,6 @@ import strutils
|
||||||
import parseutils
|
import parseutils
|
||||||
import strformat
|
import strformat
|
||||||
import tables
|
import tables
|
||||||
import terminal
|
|
||||||
|
|
||||||
|
|
||||||
import meta/token
|
import meta/token
|
||||||
|
@ -203,7 +202,7 @@ proc step(self: Lexer, n: int = 1): string =
|
||||||
inc(self.current)
|
inc(self.current)
|
||||||
|
|
||||||
|
|
||||||
proc peek*(self: Lexer, distance: int = 0, length: int = 1): string =
|
proc peek(self: Lexer, distance: int = 0, length: int = 1): string =
|
||||||
## Returns a stream of characters of
|
## Returns a stream of characters of
|
||||||
## at most length bytes from the source
|
## at most length bytes from the source
|
||||||
## file, starting at the given distance,
|
## file, starting at the given distance,
|
||||||
|
@ -226,7 +225,7 @@ proc peek*(self: Lexer, distance: int = 0, length: int = 1): string =
|
||||||
proc error(self: Lexer, message: string) =
|
proc error(self: Lexer, message: string) =
|
||||||
## Raises a lexing error with a formatted
|
## Raises a lexing error with a formatted
|
||||||
## error message
|
## error message
|
||||||
raise newException(LexingError, message)
|
raise LexingError(msg: message, line: self.line, file: self.file, lexeme: self.peek())
|
||||||
|
|
||||||
|
|
||||||
proc check(self: Lexer, s: string, distance: int = 0): bool =
|
proc check(self: Lexer, s: string, distance: int = 0): bool =
|
||||||
|
|
|
@ -11,12 +11,24 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
import token
|
||||||
|
import ast
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
## Nim exceptions for internal Peon failures
|
## Nim exceptions for internal Peon failures
|
||||||
PeonException* = object of CatchableError
|
PeonException* = ref object of CatchableError
|
||||||
LexingError* = object of PeonException
|
LexingError* = ref object of PeonException
|
||||||
ParseError* = object of PeonException
|
file*: string
|
||||||
CompileError* = object of PeonException
|
lexeme*: string
|
||||||
SerializationError* = object of PeonException
|
line*: int
|
||||||
|
ParseError* = ref object of PeonException
|
||||||
|
file*: string
|
||||||
|
token*: Token
|
||||||
|
module*: string
|
||||||
|
CompileError* = ref object of PeonException
|
||||||
|
node*: ASTNode
|
||||||
|
file*: string
|
||||||
|
module*: string
|
||||||
|
SerializationError* = ref object of PeonException
|
||||||
|
file*: string
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
import strformat
|
import strformat
|
||||||
import strutils
|
import strutils
|
||||||
import tables
|
import tables
|
||||||
|
import os
|
||||||
|
|
||||||
import meta/token
|
import meta/token
|
||||||
import meta/ast
|
import meta/ast
|
||||||
|
@ -152,6 +153,7 @@ proc getCurrentToken*(self: Parser): Token {.inline.} = (if self.getCurrent() >=
|
||||||
self.getCurrent() - 1 < 0: self.tokens[^1] else: self.tokens[self.current - 1])
|
self.getCurrent() - 1 < 0: self.tokens[^1] else: self.tokens[self.current - 1])
|
||||||
proc getCurrentFunction*(self: Parser): Declaration {.inline.} = self.currentFunction
|
proc getCurrentFunction*(self: Parser): Declaration {.inline.} = self.currentFunction
|
||||||
proc getFile*(self: Parser): string {.inline.} = self.file
|
proc getFile*(self: Parser): string {.inline.} = self.file
|
||||||
|
proc getModule*(self: Parser): string {.inline.} = self.getFile().extractFilename()
|
||||||
|
|
||||||
# Handy templates to make our life easier, thanks nim!
|
# Handy templates to make our life easier, thanks nim!
|
||||||
template endOfFile: Token = Token(kind: EndOfFile, lexeme: "", line: -1)
|
template endOfFile: Token = Token(kind: EndOfFile, lexeme: "", line: -1)
|
||||||
|
@ -192,7 +194,7 @@ proc step(self: Parser, n: int = 1): Token =
|
||||||
|
|
||||||
proc error(self: Parser, message: string) {.raises: [ParseError].} =
|
proc error(self: Parser, message: string) {.raises: [ParseError].} =
|
||||||
## Raises a ParseError exception
|
## Raises a ParseError exception
|
||||||
raise newException(ParseError, message)
|
raise ParseError(msg: message, token: self.getCurrentToken(), file: self.file, module: self.getModule())
|
||||||
|
|
||||||
|
|
||||||
# Why do we allow strings or enum members of TokenType? Well, it's simple:
|
# Why do we allow strings or enum members of TokenType? Well, it's simple:
|
||||||
|
|
104
src/main.nim
104
src/main.nim
|
@ -2,6 +2,7 @@
|
||||||
import strformat
|
import strformat
|
||||||
import strutils
|
import strutils
|
||||||
import terminal
|
import terminal
|
||||||
|
import os
|
||||||
# Thanks art <3
|
# Thanks art <3
|
||||||
import jale/editor as ed
|
import jale/editor as ed
|
||||||
import jale/templates
|
import jale/templates
|
||||||
|
@ -18,7 +19,6 @@ import frontend/compiler as c
|
||||||
import backend/vm as v
|
import backend/vm as v
|
||||||
import util/serializer as s
|
import util/serializer as s
|
||||||
|
|
||||||
|
|
||||||
# Forward declarations
|
# Forward declarations
|
||||||
proc fillSymbolTable(tokenizer: Lexer)
|
proc fillSymbolTable(tokenizer: Lexer)
|
||||||
proc getLineEditor: LineEditor
|
proc getLineEditor: LineEditor
|
||||||
|
@ -38,8 +38,8 @@ when debugCompiler:
|
||||||
import util/debugger
|
import util/debugger
|
||||||
|
|
||||||
|
|
||||||
when isMainModule:
|
proc repl =
|
||||||
setControlCHook(proc () {.noconv.} = quit(0))
|
styledEcho fgMagenta, "Welcome into the peon REPL!"
|
||||||
var
|
var
|
||||||
keep = true
|
keep = true
|
||||||
tokens: seq[Token] = @[]
|
tokens: seq[Token] = @[]
|
||||||
|
@ -121,50 +121,116 @@ when isMainModule:
|
||||||
when debugRuntime:
|
when debugRuntime:
|
||||||
styledEcho fgCyan, "\n\nExecution step: "
|
styledEcho fgCyan, "\n\nExecution step: "
|
||||||
vm.run(serialized.chunk)
|
vm.run(serialized.chunk)
|
||||||
# TODO: The code for error reporting completely
|
|
||||||
# breaks down with multiline input, fix it
|
|
||||||
except LexingError:
|
except LexingError:
|
||||||
let lineNo = tokenizer.getLine()
|
let exc = LexingError(getCurrentException())
|
||||||
let relPos = tokenizer.getRelPos(lineNo)
|
let relPos = tokenizer.getRelPos(exc.line)
|
||||||
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
let line = tokenizer.getSource().splitLines()[exc.line - 1].strip()
|
||||||
stderr.styledWriteLine(fgRed, "A fatal error occurred while parsing ", fgYellow, &"'{tokenizer.getFile()}'", fgRed, ", module ",
|
stderr.styledWriteLine(fgRed, "A fatal error occurred while parsing ", fgYellow, &"'{exc.file}'", fgRed, ", module ",
|
||||||
fgYellow, &"'{tokenizer.getFile()}'", fgRed, ", line ", fgYellow, $lineNo, fgRed, " at ", fgYellow, &"'{tokenizer.peek()}'",
|
fgYellow, &"'{exc.file.extractFilename()}'", fgRed, ", line ", fgYellow, $exc.line, fgRed, " at ", fgYellow, &"'{exc.lexeme}'",
|
||||||
fgRed, ": ", fgGreen , getCurrentExceptionMsg())
|
fgRed, ": ", fgGreen , getCurrentExceptionMsg())
|
||||||
styledEcho fgBlue, "Source line: " , fgDefault, line
|
styledEcho fgBlue, "Source line: " , fgDefault, line
|
||||||
styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start)
|
styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start)
|
||||||
except ParseError:
|
except ParseError:
|
||||||
let lexeme = parser.getCurrentToken().lexeme
|
let exc = ParseError(getCurrentException())
|
||||||
let lineNo = parser.getCurrentToken().line
|
let lexeme = exc.token.lexeme
|
||||||
|
let lineNo = exc.token.line
|
||||||
let relPos = tokenizer.getRelPos(lineNo)
|
let relPos = tokenizer.getRelPos(lineNo)
|
||||||
let fn = parser.getCurrentFunction()
|
let fn = parser.getCurrentFunction()
|
||||||
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||||
var fnMsg = ""
|
var fnMsg = ""
|
||||||
if fn != nil and fn.kind == funDecl:
|
if fn != nil and fn.kind == funDecl:
|
||||||
fnMsg &= &"in function '{FunDecl(fn).name.token.lexeme}'"
|
fnMsg &= &"in function '{FunDecl(fn).name.token.lexeme}'"
|
||||||
stderr.styledWriteLine(fgRed, "A fatal error occurred while parsing ", fgYellow, &"'{parser.getFile()}'", fgRed, ", module ",
|
stderr.styledWriteLine(fgRed, "A fatal error occurred while parsing ", fgYellow, &"'{exc.file}'", fgRed, ", module ",
|
||||||
fgYellow, &"'{parser.getFile()}'", fgRed, ", line ", fgYellow, $lineNo, fgRed, " at ", fgYellow, &"'{lexeme}'",
|
fgYellow, &"'{exc.file}'", fgRed, ", line ", fgYellow, $lineNo, fgRed, " at ", fgYellow, &"'{lexeme}'",
|
||||||
fgRed, ": ", fgGreen , getCurrentExceptionMsg())
|
fgRed, ": ", fgGreen , getCurrentExceptionMsg())
|
||||||
styledEcho fgBlue, "Source line: " , fgDefault, line
|
styledEcho fgBlue, "Source line: " , fgDefault, line
|
||||||
styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start)
|
styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start)
|
||||||
except CompileError:
|
except CompileError:
|
||||||
let lexeme = compiler.getCurrentNode().token.lexeme
|
let exc = CompileError(getCurrentException())
|
||||||
let lineNo = compiler.getCurrentNode().token.line
|
let lexeme = exc.node.token.lexeme
|
||||||
|
let lineNo = exc.node.token.line
|
||||||
let relPos = tokenizer.getRelPos(lineNo)
|
let relPos = tokenizer.getRelPos(lineNo)
|
||||||
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||||
var fn = compiler.getCurrentFunction()
|
var fn = compiler.getCurrentFunction()
|
||||||
var fnMsg = ""
|
var fnMsg = ""
|
||||||
if fn != nil and fn.kind == funDecl:
|
if fn != nil and fn.kind == funDecl:
|
||||||
fnMsg &= &"in function '{FunDecl(fn).name.token.lexeme}'"
|
fnMsg &= &"in function '{FunDecl(fn).name.token.lexeme}'"
|
||||||
stderr.styledWriteLine(fgRed, "A fatal error occurred while compiling ", fgYellow, &"'{compiler.getFile()}'", fgRed, ", module ",
|
stderr.styledWriteLine(fgRed, "A fatal error occurred while compiling ", fgYellow, &"'{exc.file}'", fgRed, ", module ",
|
||||||
fgYellow, &"'{compiler.getModule()}'", fgRed, ", line ", fgYellow, $lineNo, fgRed, " at ", fgYellow, &"'{lexeme}'",
|
fgYellow, &"'{exc.module}'", fgRed, ", line ", fgYellow, $lineNo, fgRed, " at ", fgYellow, &"'{lexeme}'",
|
||||||
fgRed, ": ", fgGreen , getCurrentExceptionMsg())
|
fgRed, ": ", fgGreen , getCurrentExceptionMsg())
|
||||||
styledEcho fgBlue, "Source line: " , fgDefault, line
|
styledEcho fgBlue, "Source line: " , fgDefault, line
|
||||||
styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start)
|
styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start)
|
||||||
except SerializationError:
|
except SerializationError:
|
||||||
stderr.styledWriteLine(fgRed, getCurrentExceptionMsg())
|
let exc = SerializationError(getCurrentException())
|
||||||
|
stderr.styledWriteLine(fgRed, "A fatal error occurred while (de-)serializing", fgYellow, &"'{exc.file}'", fgGreen, ": ", getCurrentExceptionMsg())
|
||||||
quit(0)
|
quit(0)
|
||||||
|
|
||||||
|
|
||||||
|
proc runFile(f: string) =
|
||||||
|
var
|
||||||
|
tokenizer = newLexer()
|
||||||
|
parser = newParser()
|
||||||
|
compiler = newCompiler()
|
||||||
|
vm = newPeonVM()
|
||||||
|
tokenizer.fillSymbolTable()
|
||||||
|
try:
|
||||||
|
vm.run(compiler.compile(parser.parse(tokenizer.lex(readFile(f), f), f), f))
|
||||||
|
except LexingError:
|
||||||
|
let exc = LexingError(getCurrentException())
|
||||||
|
let relPos = tokenizer.getRelPos(exc.line)
|
||||||
|
let line = tokenizer.getSource().splitLines()[exc.line - 1].strip()
|
||||||
|
stderr.styledWriteLine(fgRed, "A fatal error occurred while parsing ", fgYellow, &"'{exc.file}'", fgRed, ", module ",
|
||||||
|
fgYellow, &"'{exc.file}'", fgRed, ", line ", fgYellow, $exc.line, fgRed, " at ", fgYellow, &"'{exc.lexeme}'",
|
||||||
|
fgRed, ": ", fgGreen , getCurrentExceptionMsg())
|
||||||
|
styledEcho fgBlue, "Source line: " , fgDefault, line
|
||||||
|
styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start)
|
||||||
|
except ParseError:
|
||||||
|
let exc = ParseError(getCurrentException())
|
||||||
|
let lexeme = exc.token.lexeme
|
||||||
|
let lineNo = exc.token.line
|
||||||
|
let relPos = tokenizer.getRelPos(lineNo)
|
||||||
|
let fn = parser.getCurrentFunction()
|
||||||
|
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||||
|
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())
|
||||||
|
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()
|
||||||
|
var fn = 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())
|
||||||
|
styledEcho fgBlue, "Source line: " , fgDefault, line
|
||||||
|
styledEcho fgCyan, " ".repeat(len("Source line: ")) & "^".repeat(relPos.stop - relPos.start)
|
||||||
|
except SerializationError:
|
||||||
|
let exc = SerializationError(getCurrentException())
|
||||||
|
stderr.styledWriteLine(fgRed, "A fatal error occurred while (de-)serializing", fgYellow, &"'{exc.file}'", fgGreen, ": ", getCurrentExceptionMsg())
|
||||||
|
except IOError:
|
||||||
|
stderr.styledWriteLine("An error occurred while trying to read ", fgYellow, &"'{f}'", fgRed, &": {getCurrentExceptionMsg()}")
|
||||||
|
except OSError:
|
||||||
|
stderr.styledWriteLine("An error occurred while trying to read ", fgYellow, &"'{f}'", fgRed, &": {osErrorMsg(osLastError())} [errno {osLastError()}]")
|
||||||
|
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
setControlCHook(proc () {.noconv.} = quit(0))
|
||||||
|
let args = commandLineParams()
|
||||||
|
if args.len() == 0:
|
||||||
|
repl()
|
||||||
|
else:
|
||||||
|
runFile(args[0])
|
||||||
|
|
||||||
|
|
||||||
proc fillSymbolTable(tokenizer: Lexer) =
|
proc fillSymbolTable(tokenizer: Lexer) =
|
||||||
## Initializes the Lexer's symbol
|
## Initializes the Lexer's symbol
|
||||||
|
|
|
@ -0,0 +1,193 @@
|
||||||
|
## Builtin arithmetic operators for Peon
|
||||||
|
|
||||||
|
|
||||||
|
operator `+`(a, b: int): int {
|
||||||
|
#pragma[magic: AddInt64, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `+`(a, b: uint): uint {
|
||||||
|
#pragma[magic: AddUInt64, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `+`(a, b: int32): int32 {
|
||||||
|
#pragma[magic: AddInt32, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `+`(a, b: uint32): uint32 {
|
||||||
|
#pragma[magic: AddUInt32, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `+`(a, b: int16): int16 {
|
||||||
|
#pragma[magic: AddInt16, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `+`(a, b: uint16): uint16 {
|
||||||
|
#pragma[magic: AddUInt16, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `+`(a, b: int8): int8 {
|
||||||
|
#pragma[magic: AddInt8, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `+`(a, b: uint8): uint8 {
|
||||||
|
#pragma[magic: AddUInt8, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `-`(a, b: int): int {
|
||||||
|
#pragma[magic: SubInt64, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `-`(a, b: uint): uint {
|
||||||
|
#pragma[magic: SubUInt64, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `-`(a, b: int32): int32 {
|
||||||
|
#pragma[magic: SubInt32, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `-`(a, b: uint32): uint32 {
|
||||||
|
#pragma[magic: SubUInt32, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `-`(a, b: int16): int16 {
|
||||||
|
#pragma[magic: SubInt16, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `-`(a, b: uint16): uint16 {
|
||||||
|
#pragma[magic: SubUInt16, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `-`(a, b: int8): int8 {
|
||||||
|
#pragma[magic: SubInt8, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `-`(a, b: uint8): uint8 {
|
||||||
|
#pragma[magic: SubUInt8, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `*`(a, b: int): int {
|
||||||
|
#pragma[magic: MulInt64, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `*`(a, b: uint): uint {
|
||||||
|
#pragma[magic: MulUInt64, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `*`(a, b: int32): int32 {
|
||||||
|
#pragma[magic: MulInt32, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `*`(a, b: uint32): uint32 {
|
||||||
|
#pragma[magic: MulUInt32, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `*`(a, b: int16): int16 {
|
||||||
|
#pragma[magic: MulInt16, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `*`(a, b: uint16): uint16 {
|
||||||
|
#pragma[magic: MulUInt16, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `*`(a, b: int8): int8 {
|
||||||
|
#pragma[magic: MulInt8, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `*`(a, b: uint8): uint8 {
|
||||||
|
#pragma[magic: MulUInt8, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `/`(a, b: int): int {
|
||||||
|
#pragma[magic: DivInt64, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `/`(a, b: uint): uint {
|
||||||
|
#pragma[magic: DivUInt64, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `/`(a, b: int32): int32 {
|
||||||
|
#pragma[magic: DivInt32, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `/`(a, b: uint32): uint32 {
|
||||||
|
#pragma[magic: DivUInt32, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `/`(a, b: int16): int16 {
|
||||||
|
#pragma[magic: DivInt16, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `/`(a, b: uint16): uint16 {
|
||||||
|
#pragma[magic: DivUInt16, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `/`(a, b: int8): int8 {
|
||||||
|
#pragma[magic: DivInt8, pure]
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
operator `/`(a, b: uint8): uint8 {
|
||||||
|
#pragma[magic: DivUInt8, pure]
|
||||||
|
return;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
operator `+`(a: int): int {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
+1;
|
|
@ -49,8 +49,7 @@ proc `$`*(self: Serialized): string =
|
||||||
|
|
||||||
proc error(self: Serializer, message: string) =
|
proc error(self: Serializer, message: string) =
|
||||||
## Raises a formatted SerializationError exception
|
## Raises a formatted SerializationError exception
|
||||||
raise newException(SerializationError,
|
raise SerializationError(msg: message, file: self.filename)
|
||||||
&"A fatal error occurred while (de)serializing '{self.filename}' -> {message}")
|
|
||||||
|
|
||||||
|
|
||||||
proc newSerializer*(self: Serializer = nil): Serializer =
|
proc newSerializer*(self: Serializer = nil): Serializer =
|
||||||
|
|
Loading…
Reference in New Issue