Made exception handling in main.nim module-aware and did some minor refactoring
This commit is contained in:
parent
39a84182b0
commit
edef50deca
|
@ -176,10 +176,20 @@ type
|
||||||
frames: seq[int]
|
frames: seq[int]
|
||||||
# Compiler procedures called by pragmas
|
# Compiler procedures called by pragmas
|
||||||
compilerProcs: TableRef[string, proc (self: Compiler, pragma: Pragma, node: ASTNode)]
|
compilerProcs: TableRef[string, proc (self: Compiler, pragma: Pragma, node: ASTNode)]
|
||||||
|
# Stores line data
|
||||||
|
lines: seq[tuple[start, stop: int]]
|
||||||
|
# The source of the current module
|
||||||
|
source: string
|
||||||
|
CompileError* = ref object of PeonException
|
||||||
|
compiler*: Compiler
|
||||||
|
node*: ASTNode
|
||||||
|
file*: string
|
||||||
|
module*: string
|
||||||
|
|
||||||
|
|
||||||
## Forward declarations
|
## Forward declarations
|
||||||
proc compile*(self: Compiler, ast: seq[Declaration], file: string): Chunk
|
proc compile*(self: Compiler, ast: seq[Declaration], file: string, lines: seq[tuple[start, stop: int]], source: string, chunk: Chunk = nil,
|
||||||
|
standalone: bool = true): Chunk
|
||||||
proc expression(self: Compiler, node: Expression)
|
proc expression(self: Compiler, node: Expression)
|
||||||
proc statement(self: Compiler, node: Statement)
|
proc statement(self: Compiler, node: Statement)
|
||||||
proc declaration(self: Compiler, node: Declaration)
|
proc declaration(self: Compiler, node: Declaration)
|
||||||
|
@ -207,6 +217,8 @@ proc newCompiler*(enableOptimizations: bool = true, replMode: bool = false): Com
|
||||||
result.file = ""
|
result.file = ""
|
||||||
result.names = @[]
|
result.names = @[]
|
||||||
result.scopeDepth = 0
|
result.scopeDepth = 0
|
||||||
|
result.frames = @[0]
|
||||||
|
result.lines = @[]
|
||||||
result.currentFunction = nil
|
result.currentFunction = nil
|
||||||
result.enableOptimizations = enableOptimizations
|
result.enableOptimizations = enableOptimizations
|
||||||
result.replMode = replMode
|
result.replMode = replMode
|
||||||
|
@ -214,7 +226,7 @@ proc newCompiler*(enableOptimizations: bool = true, replMode: bool = false): Com
|
||||||
result.compilerProcs = newTable[string, proc (self: Compiler, pragma: Pragma, node: ASTNode)]()
|
result.compilerProcs = newTable[string, proc (self: Compiler, pragma: Pragma, node: ASTNode)]()
|
||||||
result.compilerProcs["magic"] = handleMagicPragma
|
result.compilerProcs["magic"] = handleMagicPragma
|
||||||
result.compilerProcs["pure"] = handlePurePragma
|
result.compilerProcs["pure"] = handlePurePragma
|
||||||
|
result.source = ""
|
||||||
|
|
||||||
proc compileModule(self: Compiler, filename: string)
|
proc compileModule(self: Compiler, filename: string)
|
||||||
|
|
||||||
|
@ -225,7 +237,9 @@ proc getCurrentNode*(self: Compiler): ASTNode = (if self.current >=
|
||||||
proc getCurrentFunction*(self: Compiler): Declaration {.inline.} = (if self.currentFunction.isNil(): nil else: self.currentFunction.fun)
|
proc getCurrentFunction*(self: Compiler): Declaration {.inline.} = (if self.currentFunction.isNil(): nil else: self.currentFunction.fun)
|
||||||
proc getFile*(self: Compiler): string {.inline.} = self.file
|
proc getFile*(self: Compiler): string {.inline.} = self.file
|
||||||
proc getModule*(self: Compiler): string {.inline.} = self.currentModule
|
proc getModule*(self: Compiler): string {.inline.} = self.currentModule
|
||||||
|
proc getLines*(self: Compiler): seq[tuple[start, stop: int]] = self.lines
|
||||||
|
proc getSource*(self: Compiler): string = self.source
|
||||||
|
proc getRelPos*(self: Compiler, line: int): tuple[start, stop: int] = self.lines[line - 1]
|
||||||
|
|
||||||
## Utility functions
|
## Utility functions
|
||||||
|
|
||||||
|
@ -249,7 +263,7 @@ proc done(self: Compiler): bool {.inline.} =
|
||||||
|
|
||||||
proc error(self: Compiler, message: string, node: ASTNode = nil) {.raises: [CompileError], inline.} =
|
proc error(self: Compiler, message: string, node: ASTNode = nil) {.raises: [CompileError], inline.} =
|
||||||
## Raises a CompileError exception
|
## Raises a CompileError exception
|
||||||
raise CompileError(msg: message, node: if node.isNil(): self.getCurrentNode() else: node, file: self.file, module: self.currentModule)
|
raise CompileError(msg: message, node: if node.isNil(): self.getCurrentNode() else: node, file: self.file, module: self.currentModule, compiler: self)
|
||||||
|
|
||||||
|
|
||||||
proc step(self: Compiler): ASTNode {.inline.} =
|
proc step(self: Compiler): ASTNode {.inline.} =
|
||||||
|
@ -329,7 +343,7 @@ proc emitConstant(self: Compiler, obj: Expression, kind: Type) =
|
||||||
let str = LiteralExpr(obj).literal.lexeme
|
let str = LiteralExpr(obj).literal.lexeme
|
||||||
if str.len() >= 16777216:
|
if str.len() >= 16777216:
|
||||||
self.error("string constants cannot be larger than 16777215 bytes")
|
self.error("string constants cannot be larger than 16777215 bytes")
|
||||||
self.emitBytes(LiteralExpr(obj).literal.lexeme.len().toTriple())
|
self.emitBytes(str.len().toTriple())
|
||||||
of Float32:
|
of Float32:
|
||||||
self.emitByte(LoadFloat32)
|
self.emitByte(LoadFloat32)
|
||||||
of Float64:
|
of Float64:
|
||||||
|
@ -550,6 +564,8 @@ proc toIntrinsic(name: string): Type =
|
||||||
return Type(kind: Bool)
|
return Type(kind: Bool)
|
||||||
elif name == "typevar":
|
elif name == "typevar":
|
||||||
return Type(kind: Typevar)
|
return Type(kind: Typevar)
|
||||||
|
elif name == "string":
|
||||||
|
return Type(kind: String)
|
||||||
else:
|
else:
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
@ -591,6 +607,8 @@ proc inferType(self: Compiler, node: LiteralExpr): Type =
|
||||||
return Type(kind: TypeKind.Nan)
|
return Type(kind: TypeKind.Nan)
|
||||||
of infExpr:
|
of infExpr:
|
||||||
return Type(kind: TypeKind.Inf)
|
return Type(kind: TypeKind.Inf)
|
||||||
|
of strExpr:
|
||||||
|
return Type(kind: String)
|
||||||
else:
|
else:
|
||||||
discard # TODO
|
discard # TODO
|
||||||
|
|
||||||
|
@ -1519,6 +1537,8 @@ proc importStmt(self: Compiler, node: ImportStmt) =
|
||||||
self.compileModule(filename)
|
self.compileModule(filename)
|
||||||
except IOError:
|
except IOError:
|
||||||
self.error(&"""could not import '{filename}': {getCurrentExceptionMsg()}""")
|
self.error(&"""could not import '{filename}': {getCurrentExceptionMsg()}""")
|
||||||
|
except OSError:
|
||||||
|
self.error(&"""could not import '{filename}': {getCurrentExceptionMsg()} [errno {osLastError()}]""")
|
||||||
|
|
||||||
|
|
||||||
proc statement(self: Compiler, node: Statement) =
|
proc statement(self: Compiler, node: Statement) =
|
||||||
|
@ -1797,43 +1817,22 @@ proc declaration(self: Compiler, node: Declaration) =
|
||||||
self.statement(Statement(node))
|
self.statement(Statement(node))
|
||||||
|
|
||||||
|
|
||||||
proc compileModule(self: Compiler, filename: string) =
|
proc terminateProgram(self: Compiler, pos: int) =
|
||||||
## Compiles an imported module into an existing chunk.
|
## Utility to terminate a peon program
|
||||||
## A temporary compiler object is initialized internally
|
## compiled as the main module
|
||||||
## and its state is copied from the self argument
|
self.endScope()
|
||||||
var lexer = newLexer()
|
self.patchReturnAddress(pos)
|
||||||
var parser = newParser()
|
self.emitByte(OpCode.Return)
|
||||||
var compiler = newCompiler()
|
self.emitByte(0) # Entry point has no return value (TODO: Add easter eggs, cuz why not)
|
||||||
lexer.fillSymbolTable()
|
|
||||||
compiler.chunk = self.chunk
|
|
||||||
compiler.ast = parser.parse(lexer.lex(readFile(filename), filename), filename)
|
|
||||||
compiler.file = filename
|
|
||||||
compiler.names = @[]
|
|
||||||
compiler.scopeDepth = 0
|
|
||||||
compiler.currentFunction = nil
|
|
||||||
compiler.currentModule = compiler.file.extractFilename()
|
|
||||||
compiler.current = 0
|
|
||||||
compiler.frames = @[0]
|
|
||||||
while not compiler.done():
|
|
||||||
compiler.declaration(Declaration(compiler.step()))
|
|
||||||
self.names &= compiler.names
|
|
||||||
self.closedOver &= compiler.closedOver
|
|
||||||
compiler.endScope()
|
|
||||||
|
|
||||||
|
|
||||||
|
proc beginProgram(self: Compiler): int =
|
||||||
|
## Utility to begin a peon program
|
||||||
|
## compiled as the main module.
|
||||||
|
## Returns a dummy return address of
|
||||||
|
## the implicit main to be patched by
|
||||||
|
## terminateProgram
|
||||||
|
|
||||||
proc compile*(self: Compiler, ast: seq[Declaration], file: string): Chunk =
|
|
||||||
## Compiles a sequence of AST nodes into a chunk
|
|
||||||
## object
|
|
||||||
self.chunk = newChunk()
|
|
||||||
self.ast = ast
|
|
||||||
self.file = file
|
|
||||||
self.names = @[]
|
|
||||||
self.scopeDepth = 0
|
|
||||||
self.currentFunction = nil
|
|
||||||
self.currentModule = self.file.extractFilename()
|
|
||||||
self.current = 0
|
|
||||||
self.frames = @[0]
|
|
||||||
# Every peon program has a hidden entry point in
|
# Every peon program has a hidden entry point in
|
||||||
# which user code is wrapped. Think of it as if
|
# which user code is wrapped. Think of it as if
|
||||||
# peon is implicitly writing the main() function
|
# peon is implicitly writing the main() function
|
||||||
|
@ -1863,14 +1862,51 @@ proc compile*(self: Compiler, ast: seq[Declaration], file: string): Chunk =
|
||||||
self.emitByte(LoadFunction)
|
self.emitByte(LoadFunction)
|
||||||
self.emitBytes(main.codePos.toTriple())
|
self.emitBytes(main.codePos.toTriple())
|
||||||
self.emitByte(LoadReturnAddress)
|
self.emitByte(LoadReturnAddress)
|
||||||
let pos = self.chunk.code.len()
|
result = self.chunk.code.len()
|
||||||
self.emitBytes(0.toQuad())
|
self.emitBytes(0.toQuad())
|
||||||
self.emitByte(Call)
|
self.emitByte(Call)
|
||||||
self.emitBytes(0.toTriple())
|
self.emitBytes(0.toTriple())
|
||||||
|
|
||||||
|
|
||||||
|
proc compile*(self: Compiler, ast: seq[Declaration], file: string, lines: seq[tuple[start, stop: int]], source: string, chunk: Chunk = nil,
|
||||||
|
standalone: bool = true): Chunk =
|
||||||
|
## Compiles a sequence of AST nodes into a chunk
|
||||||
|
## object
|
||||||
|
if chunk.isNil():
|
||||||
|
self.chunk = newChunk()
|
||||||
|
else:
|
||||||
|
self.chunk = chunk
|
||||||
|
self.ast = ast
|
||||||
|
self.file = file
|
||||||
|
self.names = @[]
|
||||||
|
self.scopeDepth = 0
|
||||||
|
self.currentFunction = nil
|
||||||
|
self.currentModule = self.file.extractFilename()
|
||||||
|
self.current = 0
|
||||||
|
self.frames = @[0]
|
||||||
|
self.lines = lines
|
||||||
|
self.source = source
|
||||||
|
var pos: int
|
||||||
|
if standalone:
|
||||||
|
pos = self.beginProgram()
|
||||||
while not self.done():
|
while not self.done():
|
||||||
self.declaration(Declaration(self.step()))
|
self.declaration(Declaration(self.step()))
|
||||||
self.endScope()
|
if standalone:
|
||||||
self.patchReturnAddress(pos)
|
self.terminateProgram(pos)
|
||||||
self.emitByte(OpCode.Return)
|
|
||||||
self.emitByte(0) # Entry point has no return value (TODO: Add easter eggs, cuz why not)
|
|
||||||
result = self.chunk
|
result = self.chunk
|
||||||
|
|
||||||
|
|
||||||
|
proc compileModule(self: Compiler, filename: string) =
|
||||||
|
## Compiles an imported module into an existing chunk.
|
||||||
|
## A temporary compiler object is initialized internally
|
||||||
|
var lexer = newLexer()
|
||||||
|
var parser = newParser()
|
||||||
|
var compiler = newCompiler()
|
||||||
|
lexer.fillSymbolTable()
|
||||||
|
let source = readFile(joinPath(splitPath(self.file).head, filename))
|
||||||
|
let tokens = lexer.lex(source, filename)
|
||||||
|
let ast = parser.parse(tokens, filename, lexer.getLines(), source)
|
||||||
|
discard compiler.compile(ast, filename, lexer.getLines(), source, standalone=false)
|
||||||
|
self.names &= compiler.names
|
||||||
|
self.closedOver &= compiler.closedOver
|
||||||
|
compiler.endScope()
|
|
@ -52,6 +52,12 @@ type
|
||||||
lines: seq[tuple[start, stop: int]]
|
lines: seq[tuple[start, stop: int]]
|
||||||
lastLine: int
|
lastLine: int
|
||||||
spaces: int
|
spaces: int
|
||||||
|
LexingError* = ref object of PeonException
|
||||||
|
## A lexing error
|
||||||
|
lexer*: Lexer
|
||||||
|
file*: string
|
||||||
|
lexeme*: string
|
||||||
|
line*: int
|
||||||
|
|
||||||
|
|
||||||
proc newSymbolTable: SymbolTable =
|
proc newSymbolTable: SymbolTable =
|
||||||
|
@ -154,6 +160,7 @@ proc getStart*(self: Lexer): int = self.start
|
||||||
proc getFile*(self: Lexer): string = self.file
|
proc getFile*(self: Lexer): string = self.file
|
||||||
proc getCurrent*(self: Lexer): int = self.current
|
proc getCurrent*(self: Lexer): int = self.current
|
||||||
proc getLine*(self: Lexer): int = self.line
|
proc getLine*(self: Lexer): int = self.line
|
||||||
|
proc getLines*(self: Lexer): seq[tuple[start, stop: int]] = self.lines
|
||||||
proc getSource*(self: Lexer): string = self.source
|
proc getSource*(self: Lexer): string = self.source
|
||||||
proc getRelPos*(self: Lexer, line: int): tuple[start, stop: int] =
|
proc getRelPos*(self: Lexer, line: int): tuple[start, stop: int] =
|
||||||
if self.tokens.len() == 0 or self.tokens[^1].kind != EndOfFile:
|
if self.tokens.len() == 0 or self.tokens[^1].kind != EndOfFile:
|
||||||
|
@ -186,9 +193,9 @@ proc done(self: Lexer): bool =
|
||||||
|
|
||||||
proc incLine(self: Lexer) =
|
proc incLine(self: Lexer) =
|
||||||
## Increments the lexer's line
|
## Increments the lexer's line
|
||||||
## and updates internal line
|
## counter and updates internal
|
||||||
## metadata
|
## line metadata
|
||||||
self.lines.add((self.lastLine, self.current))
|
self.lines.add((self.lastLine, self.current - 1))
|
||||||
self.lastLine = self.current
|
self.lastLine = self.current
|
||||||
self.line += 1
|
self.line += 1
|
||||||
|
|
||||||
|
@ -230,7 +237,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 info
|
## Raises a lexing error with info
|
||||||
## for error messages
|
## for error messages
|
||||||
raise LexingError(msg: message, line: self.line, file: self.file, lexeme: self.peek())
|
raise LexingError(msg: message, line: self.line, file: self.file, lexeme: self.peek(), lexer: self)
|
||||||
|
|
||||||
|
|
||||||
proc check(self: Lexer, s: string, distance: int = 0): bool =
|
proc check(self: Lexer, s: string, distance: int = 0): bool =
|
||||||
|
|
|
@ -11,24 +11,10 @@
|
||||||
# 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* = ref object of CatchableError
|
PeonException* = ref object of CatchableError
|
||||||
LexingError* = ref object of PeonException
|
|
||||||
file*: string
|
|
||||||
lexeme*: string
|
|
||||||
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
|
SerializationError* = ref object of PeonException
|
||||||
file*: string
|
file*: string
|
||||||
|
|
|
@ -89,6 +89,15 @@ type
|
||||||
operators: OperatorTable
|
operators: OperatorTable
|
||||||
# The AST node
|
# The AST node
|
||||||
tree: seq[Declaration]
|
tree: seq[Declaration]
|
||||||
|
# Stores line data
|
||||||
|
lines: seq[tuple[start, stop: int]]
|
||||||
|
# The source of the current module
|
||||||
|
source: string
|
||||||
|
ParseError* = ref object of PeonException
|
||||||
|
parser*: Parser
|
||||||
|
file*: string
|
||||||
|
token*: Token
|
||||||
|
module*: string
|
||||||
|
|
||||||
|
|
||||||
proc newOperatorTable: OperatorTable =
|
proc newOperatorTable: OperatorTable =
|
||||||
|
@ -146,6 +155,7 @@ proc newParser*: Parser =
|
||||||
result.scopeDepth = 0
|
result.scopeDepth = 0
|
||||||
result.operators = newOperatorTable()
|
result.operators = newOperatorTable()
|
||||||
result.tree = @[]
|
result.tree = @[]
|
||||||
|
result.source = ""
|
||||||
|
|
||||||
|
|
||||||
# Public getters for improved error formatting
|
# Public getters for improved error formatting
|
||||||
|
@ -155,8 +165,10 @@ 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()
|
proc getModule*(self: Parser): string {.inline.} = self.getFile().splitFile().name
|
||||||
|
proc getLines*(self: Parser): seq[tuple[start, stop: int]] = self.lines
|
||||||
|
proc getSource*(self: Parser): string = self.source
|
||||||
|
proc getRelPos*(self: Parser, line: int): tuple[start, stop: int] = self.lines[line - 1]
|
||||||
template endOfFile: Token = Token(kind: EndOfFile, lexeme: "", line: -1)
|
template endOfFile: Token = Token(kind: EndOfFile, lexeme: "", line: -1)
|
||||||
template endOfLine(msg: string) = self.expect(Semicolon, msg)
|
template endOfLine(msg: string) = self.expect(Semicolon, msg)
|
||||||
|
|
||||||
|
@ -196,7 +208,7 @@ proc step(self: Parser, n: int = 1): Token =
|
||||||
|
|
||||||
proc error(self: Parser, message: string, token: Token = nil) {.raises: [ParseError].} =
|
proc error(self: Parser, message: string, token: Token = nil) {.raises: [ParseError].} =
|
||||||
## Raises a ParseError exception
|
## Raises a ParseError exception
|
||||||
raise ParseError(msg: message, token: if token.isNil(): self.getCurrentToken() else: token, file: self.file, module: self.getModule())
|
raise ParseError(msg: message, token: if token.isNil(): self.getCurrentToken() else: token, file: self.file, module: self.getModule(), parser: self)
|
||||||
|
|
||||||
|
|
||||||
# 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:
|
||||||
|
@ -664,7 +676,7 @@ proc forEachStmt(self: Parser): Statement =
|
||||||
self.currentLoop = enclosingLoop
|
self.currentLoop = enclosingLoop
|
||||||
|
|
||||||
|
|
||||||
proc parse*(self: Parser, tokens: seq[Token], file: string): seq[Declaration]
|
proc parse*(self: Parser, tokens: seq[Token], file: string, lines: seq[tuple[start, stop: int]], source: string): seq[Declaration]
|
||||||
proc findOperators(self: Parser, tokens: seq[Token])
|
proc findOperators(self: Parser, tokens: seq[Token])
|
||||||
|
|
||||||
|
|
||||||
|
@ -684,12 +696,15 @@ proc importStmt(self: Parser, fromStmt: bool = false): Statement =
|
||||||
var filename = ImportStmt(result).moduleName.token.lexeme & ".pn"
|
var filename = ImportStmt(result).moduleName.token.lexeme & ".pn"
|
||||||
var lexer = newLexer()
|
var lexer = newLexer()
|
||||||
lexer.fillSymbolTable()
|
lexer.fillSymbolTable()
|
||||||
|
let path = joinPath(splitPath(self.file).head, filename)
|
||||||
# TODO: This is obviously horrible. It's just a test
|
# TODO: This is obviously horrible. It's just a test
|
||||||
try:
|
try:
|
||||||
self.findOperators(lexer.lex(readFile(filename), filename))
|
self.findOperators(lexer.lex(readFile(path), filename))
|
||||||
except IOError:
|
except IOError:
|
||||||
self.error(&"""could not import '{filename}': {getCurrentExceptionMsg()}""")
|
self.error(&"""could not import '{filename}': {getCurrentExceptionMsg()}""")
|
||||||
|
except OSError:
|
||||||
|
self.error(&"""could not import '{filename}': {getCurrentExceptionMsg()} [errno {osLastError()}]""")
|
||||||
|
|
||||||
|
|
||||||
proc tryStmt(self: Parser): Statement =
|
proc tryStmt(self: Parser): Statement =
|
||||||
## Parses try/except/else/finally blocks
|
## Parses try/except/else/finally blocks
|
||||||
|
@ -1223,7 +1238,7 @@ proc findOperators(self: Parser, tokens: seq[Token]) =
|
||||||
self.error("invalid state: found malformed tokenizer input while looking for operators (missing EOF)", token)
|
self.error("invalid state: found malformed tokenizer input while looking for operators (missing EOF)", token)
|
||||||
|
|
||||||
|
|
||||||
proc parse*(self: Parser, tokens: seq[Token], file: string): seq[Declaration] =
|
proc parse*(self: Parser, tokens: seq[Token], file: string, lines: seq[tuple[start, stop: int]], source: string): seq[Declaration] =
|
||||||
## Parses a sequence of tokens into a sequence of AST nodes
|
## Parses a sequence of tokens into a sequence of AST nodes
|
||||||
self.tokens = tokens
|
self.tokens = tokens
|
||||||
self.file = file
|
self.file = file
|
||||||
|
@ -1233,6 +1248,8 @@ proc parse*(self: Parser, tokens: seq[Token], file: string): seq[Declaration] =
|
||||||
self.scopeDepth = 0
|
self.scopeDepth = 0
|
||||||
self.operators = newOperatorTable()
|
self.operators = newOperatorTable()
|
||||||
self.tree = @[]
|
self.tree = @[]
|
||||||
|
self.source = source
|
||||||
|
self.lines = lines
|
||||||
self.findOperators(tokens)
|
self.findOperators(tokens)
|
||||||
while not self.done():
|
while not self.done():
|
||||||
self.tree.add(self.declaration())
|
self.tree.add(self.declaration())
|
||||||
|
|
24
src/main.nim
24
src/main.nim
|
@ -95,7 +95,7 @@ proc repl(vm: PeonVM = newPeonVM()) =
|
||||||
break
|
break
|
||||||
styledEcho fgGreen, "\t", $token
|
styledEcho fgGreen, "\t", $token
|
||||||
echo ""
|
echo ""
|
||||||
tree = parser.parse(tokens, "stdin")
|
tree = parser.parse(tokens, "stdin", tokenizer.getLines(), input)
|
||||||
if tree.len() == 0:
|
if tree.len() == 0:
|
||||||
continue
|
continue
|
||||||
when debugParser:
|
when debugParser:
|
||||||
|
@ -103,7 +103,7 @@ proc repl(vm: PeonVM = newPeonVM()) =
|
||||||
for node in tree:
|
for node in tree:
|
||||||
styledEcho fgGreen, "\t", $node
|
styledEcho fgGreen, "\t", $node
|
||||||
echo ""
|
echo ""
|
||||||
compiled = compiler.compile(tree, "stdin")
|
compiled = compiler.compile(tree, "stdin", tokenizer.getLines(), input)
|
||||||
when debugCompiler:
|
when debugCompiler:
|
||||||
styledEcho fgCyan, "Compilation step:\n"
|
styledEcho fgCyan, "Compilation step:\n"
|
||||||
debugger.disassembleChunk(compiled, "stdin")
|
debugger.disassembleChunk(compiled, "stdin")
|
||||||
|
@ -218,7 +218,7 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
|
||||||
break
|
break
|
||||||
styledEcho fgGreen, "\t", $token
|
styledEcho fgGreen, "\t", $token
|
||||||
echo ""
|
echo ""
|
||||||
tree = parser.parse(tokens, f)
|
tree = parser.parse(tokens, f, tokenizer.getLines(), input)
|
||||||
if tree.len() == 0:
|
if tree.len() == 0:
|
||||||
return
|
return
|
||||||
when debugParser:
|
when debugParser:
|
||||||
|
@ -226,7 +226,7 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
|
||||||
for node in tree:
|
for node in tree:
|
||||||
styledEcho fgGreen, "\t", $node
|
styledEcho fgGreen, "\t", $node
|
||||||
echo ""
|
echo ""
|
||||||
compiled = compiler.compile(tree, f)
|
compiled = compiler.compile(tree, f, tokenizer.getLines(), input)
|
||||||
when debugCompiler:
|
when debugCompiler:
|
||||||
styledEcho fgCyan, "Compilation step:\n"
|
styledEcho fgCyan, "Compilation step:\n"
|
||||||
debugger.disassembleChunk(compiled, f)
|
debugger.disassembleChunk(compiled, f)
|
||||||
|
@ -267,8 +267,8 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
|
||||||
except LexingError:
|
except LexingError:
|
||||||
input = ""
|
input = ""
|
||||||
let exc = LexingError(getCurrentException())
|
let exc = LexingError(getCurrentException())
|
||||||
let relPos = tokenizer.getRelPos(exc.line)
|
let relPos = exc.lexer.getRelPos(exc.line)
|
||||||
let line = tokenizer.getSource().splitLines()[exc.line - 1].strip(chars={'\n'})
|
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 ",
|
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()}'",
|
fgYellow, &"'{exc.file.extractFilename()}'", fgRed, ", line ", fgYellow, $exc.line, fgRed, " at ", fgYellow, &"'{exc.lexeme.escape()}'",
|
||||||
fgRed, ": ", fgGreen , getCurrentExceptionMsg())
|
fgRed, ": ", fgGreen , getCurrentExceptionMsg())
|
||||||
|
@ -279,14 +279,14 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
|
||||||
let exc = ParseError(getCurrentException())
|
let exc = ParseError(getCurrentException())
|
||||||
let lexeme = exc.token.lexeme
|
let lexeme = exc.token.lexeme
|
||||||
let lineNo = exc.token.line
|
let lineNo = exc.token.line
|
||||||
let relPos = tokenizer.getRelPos(lineNo)
|
let relPos = exc.parser.getRelPos(lineNo)
|
||||||
let fn = parser.getCurrentFunction()
|
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 = ""
|
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, &"'{exc.file}'", fgRed, ", module ",
|
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}'",
|
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)
|
||||||
|
@ -294,9 +294,9 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
|
||||||
let exc = CompileError(getCurrentException())
|
let exc = CompileError(getCurrentException())
|
||||||
let lexeme = exc.node.token.lexeme
|
let lexeme = exc.node.token.lexeme
|
||||||
let lineNo = exc.node.token.line
|
let lineNo = exc.node.token.line
|
||||||
let relPos = tokenizer.getRelPos(lineNo)
|
let relPos = exc.compiler.getRelPos(lineNo)
|
||||||
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip(chars={'\n'})
|
let line = exc.compiler.getSource().splitLines()[lineNo - 1].strip(chars={'\n'})
|
||||||
var fn = compiler.getCurrentFunction()
|
var fn = exc.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}'"
|
||||||
|
|
|
@ -36,4 +36,3 @@ fn print*(x: float) {
|
||||||
fn print*(x: int) {
|
fn print*(x: int) {
|
||||||
#pragma[magic: "GenericPrint"]
|
#pragma[magic: "GenericPrint"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue