Fixed bug with calling a call
This commit is contained in:
parent
da2cfefe75
commit
33066d3b9b
|
@ -188,7 +188,7 @@ 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 findByName(self: Compiler, name: string): seq[Name]
|
||||||
proc findByType(self: Compiler, name: string, kind: Type): seq[Name]
|
proc findByType(self: Compiler, name: string, kind: Type, depth: int = -1): seq[Name]
|
||||||
proc compareTypes(self: Compiler, a, b: Type): bool
|
proc compareTypes(self: Compiler, a, b: Type): bool
|
||||||
proc patchReturnAddress(self: Compiler, pos: int)
|
proc patchReturnAddress(self: Compiler, pos: int)
|
||||||
proc handleMagicPragma(self: Compiler, pragma: Pragma, node: ASTnode)
|
proc handleMagicPragma(self: Compiler, pragma: Pragma, node: ASTnode)
|
||||||
|
@ -456,7 +456,8 @@ proc detectClosureVariable(self: Compiler, name: var Name, depth: int = self.sco
|
||||||
for i, b in self.closedOver.high().toTriple():
|
for i, b in self.closedOver.high().toTriple():
|
||||||
self.chunk.code[name.codePos + i + 1] = b
|
self.chunk.code[name.codePos + i + 1] = b
|
||||||
else:
|
else:
|
||||||
self.error("it is currently not possible to close over function arguments")
|
discard
|
||||||
|
# self.error("it is currently not possible to close over function arguments")
|
||||||
|
|
||||||
|
|
||||||
proc compareTypes(self: Compiler, a, b: Type): bool =
|
proc compareTypes(self: Compiler, a, b: Type): bool =
|
||||||
|
@ -639,12 +640,12 @@ proc inferType(self: Compiler, node: Expression): Type =
|
||||||
let resolved = self.resolve(IdentExpr(node.callee))
|
let resolved = self.resolve(IdentExpr(node.callee))
|
||||||
if not resolved.isNil():
|
if not resolved.isNil():
|
||||||
result = resolved.valueType.returnType
|
result = resolved.valueType.returnType
|
||||||
if result.isNil():
|
|
||||||
result = Type(kind: Any)
|
|
||||||
else:
|
else:
|
||||||
result = nil
|
result = nil
|
||||||
of lambdaExpr:
|
of lambdaExpr:
|
||||||
result = self.inferType(LambdaExpr(node.callee).returnType)
|
result = self.inferType(LambdaExpr(node.callee).returnType)
|
||||||
|
of callExpr:
|
||||||
|
result = self.inferType(CallExpr(node.callee).callee)
|
||||||
else:
|
else:
|
||||||
discard # Unreachable
|
discard # Unreachable
|
||||||
of varExpr:
|
of varExpr:
|
||||||
|
@ -719,11 +720,12 @@ proc findByName(self: Compiler, name: string): seq[Name] =
|
||||||
result.add(obj)
|
result.add(obj)
|
||||||
|
|
||||||
|
|
||||||
proc findByType(self: Compiler, name: string, kind: Type): seq[Name] =
|
proc findByType(self: Compiler, name: string, kind: Type, depth: int = -1): seq[Name] =
|
||||||
## Looks for objects that have already been declared
|
## Looks for objects that have already been declared
|
||||||
## with the given name and type
|
## with the given name and type. If depth is not -1,
|
||||||
|
## it also compares the name's scope depth
|
||||||
for obj in self.findByName(name):
|
for obj in self.findByName(name):
|
||||||
if self.compareTypes(obj.valueType, kind):
|
if self.compareTypes(obj.valueType, kind) and depth == -1 or depth == obj.depth:
|
||||||
result.add(obj)
|
result.add(obj)
|
||||||
|
|
||||||
#[
|
#[
|
||||||
|
@ -751,7 +753,7 @@ proc matchImpl(self: Compiler, name: string, kind: Type): Name =
|
||||||
msg &= "s"
|
msg &= "s"
|
||||||
msg &= ": "
|
msg &= ": "
|
||||||
for name in names:
|
for name in names:
|
||||||
msg &= &"\n - '{name.name.token.lexeme}' of type '{self.typeToStr(name.valueType)}'"
|
msg &= &"\n - in module '{name.owner}' at line {name.name.token.line} of type '{self.typeToStr(name.valueType)}'"
|
||||||
if name.valueType.kind != Function:
|
if name.valueType.kind != Function:
|
||||||
msg &= ", not a callable"
|
msg &= ", not a callable"
|
||||||
elif kind.args.len() != name.valueType.args.len():
|
elif kind.args.len() != name.valueType.args.len():
|
||||||
|
@ -1004,7 +1006,7 @@ proc handleBuiltinFunction(self: Compiler, fn: Name, args: seq[Expression]) =
|
||||||
self.error(&"unknown built-in: '{fn.valueType.builtinOp}'")
|
self.error(&"unknown built-in: '{fn.valueType.builtinOp}'")
|
||||||
|
|
||||||
|
|
||||||
proc generateCall(self: Compiler, fn: Name, args: seq[Expression]) =
|
proc generateCall(self: Compiler, fn: Name, args: seq[Expression], onStack: bool = false) =
|
||||||
## Small wrapper that abstracts emitting a call instruction
|
## Small wrapper that abstracts emitting a call instruction
|
||||||
## for a given function
|
## for a given function
|
||||||
if fn.valueType.isBuiltinFunction:
|
if fn.valueType.isBuiltinFunction:
|
||||||
|
@ -1013,11 +1015,8 @@ proc generateCall(self: Compiler, fn: Name, args: seq[Expression]) =
|
||||||
# them differently
|
# them differently
|
||||||
self.handleBuiltinFunction(fn, args)
|
self.handleBuiltinFunction(fn, args)
|
||||||
return
|
return
|
||||||
if any(fn.valueType.args, proc (arg: tuple[name: string, kind: Type]): bool = arg[1].kind == Generic):
|
if not onStack:
|
||||||
# The function has generic arguments! We need to compile a version
|
self.emitFunction(fn)
|
||||||
# of it with the right type data
|
|
||||||
self.funDecl(nil, fn, args)
|
|
||||||
self.emitFunction(fn)
|
|
||||||
self.emitByte(LoadReturnAddress)
|
self.emitByte(LoadReturnAddress)
|
||||||
let pos = self.chunk.code.len()
|
let pos = self.chunk.code.len()
|
||||||
# We initially emit a dummy return
|
# We initially emit a dummy return
|
||||||
|
@ -1177,7 +1176,7 @@ proc identifier(self: Compiler, node: IdentExpr) =
|
||||||
self.emitConstant(node, self.inferType(node))
|
self.emitConstant(node, self.inferType(node))
|
||||||
else:
|
else:
|
||||||
self.detectClosureVariable(s)
|
self.detectClosureVariable(s)
|
||||||
if s.valueType.kind == Function:
|
if s.valueType.kind == Function and s.isFunDecl:
|
||||||
# Functions have no runtime
|
# Functions have no runtime
|
||||||
# representation, so we need
|
# representation, so we need
|
||||||
# to create one on the fly
|
# to create one on the fly
|
||||||
|
@ -1242,24 +1241,29 @@ proc endScope(self: Compiler) =
|
||||||
self.error("cannot call endScope with scopeDepth < 0 (This is an internal error and most likely a bug)")
|
self.error("cannot call endScope with scopeDepth < 0 (This is an internal error and most likely a bug)")
|
||||||
dec(self.scopeDepth)
|
dec(self.scopeDepth)
|
||||||
var names: seq[Name] = @[]
|
var names: seq[Name] = @[]
|
||||||
|
var popCount = 0
|
||||||
for name in self.names:
|
for name in self.names:
|
||||||
if name.depth > self.scopeDepth and name.valueType.kind notin {Generic, CustomType} and not name.isFunDecl:
|
if name.depth > self.scopeDepth:
|
||||||
names.add(name)
|
names.add(name)
|
||||||
if len(names) > 1:
|
if name.valueType.kind notin {Generic, CustomType} and not name.isFunDecl:
|
||||||
|
# We don't increase the pop count for these kinds of objects
|
||||||
|
# because they're not stored the same way as regular variables
|
||||||
|
inc(popCount)
|
||||||
|
if popCount > 1:
|
||||||
# If we're popping less than 65535 variables, then
|
# If we're popping less than 65535 variables, then
|
||||||
# we can emit a PopN instruction. This is true for
|
# we can emit a PopN instruction. This is true for
|
||||||
# 99.99999% of the use cases of the language (who the
|
# 99.99999% of the use cases of the language (who the
|
||||||
# hell is going to use 65 THOUSAND local variables?), but
|
# hell is going to use 65 THOUSAND variables?), but
|
||||||
# if you'll ever use more then Peon will emit a PopN instruction
|
# if you'll ever use more then Peon will emit a PopN instruction
|
||||||
# for the first 65 thousand and change local variables and then
|
# for the first 65 thousand and change local variables and then
|
||||||
# emit another batch of plain ol' Pop instructions for the rest
|
# emit another batch of plain ol' Pop instructions for the rest
|
||||||
self.emitByte(PopN)
|
self.emitByte(PopN)
|
||||||
self.emitBytes(len(names).toDouble())
|
self.emitBytes(popCount.toDouble())
|
||||||
if len(names) > uint16.high().int():
|
if popCount > uint16.high().int():
|
||||||
for i in countdown(self.names.high(), len(names) - uint16.high().int()):
|
for i in countdown(self.names.high(), popCount - uint16.high().int()):
|
||||||
if self.names[i].depth > self.scopeDepth:
|
if self.names[i].depth > self.scopeDepth:
|
||||||
self.emitByte(PopC)
|
self.emitByte(PopC)
|
||||||
elif len(names) == 1:
|
elif popCount == 1:
|
||||||
# We only emit PopN if we're popping more than one value
|
# We only emit PopN if we're popping more than one value
|
||||||
self.emitByte(PopC)
|
self.emitByte(PopC)
|
||||||
# This seems *really* slow, but
|
# This seems *really* slow, but
|
||||||
|
@ -1274,7 +1278,6 @@ proc endScope(self: Compiler) =
|
||||||
inc(idx)
|
inc(idx)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc blockStmt(self: Compiler, node: BlockStmt) =
|
proc blockStmt(self: Compiler, node: BlockStmt) =
|
||||||
## Compiles block statements, which create a new
|
## Compiles block statements, which create a new
|
||||||
## local scope
|
## local scope
|
||||||
|
@ -1321,15 +1324,17 @@ proc whileStmt(self: Compiler, node: WhileStmt) =
|
||||||
|
|
||||||
|
|
||||||
proc checkCallIsPure(self: Compiler, node: ASTnode): bool =
|
proc checkCallIsPure(self: Compiler, node: ASTnode): bool =
|
||||||
## Checks if a call has any side effects
|
## Checks if a call has any side effects. Returns
|
||||||
|
## true if it doesn't and false otherwise
|
||||||
return true # TODO
|
return true # TODO
|
||||||
|
|
||||||
|
|
||||||
proc callExpr(self: Compiler, node: CallExpr) =
|
proc callExpr(self: Compiler, node: CallExpr): Name {.discardable.} =
|
||||||
## Compiles code to call a function
|
## Compiles code to call a function
|
||||||
var args: seq[tuple[name: string, kind: Type]] = @[]
|
var args: seq[tuple[name: string, kind: Type]] = @[]
|
||||||
var argExpr: seq[Expression] = @[]
|
var argExpr: seq[Expression] = @[]
|
||||||
var kind: Type
|
var kind: Type
|
||||||
|
var onStack = false
|
||||||
# TODO: Keyword arguments
|
# TODO: Keyword arguments
|
||||||
for i, argument in node.arguments.positionals:
|
for i, argument in node.arguments.positionals:
|
||||||
kind = self.inferType(argument)
|
kind = self.inferType(argument)
|
||||||
|
@ -1340,6 +1345,7 @@ proc callExpr(self: Compiler, node: CallExpr) =
|
||||||
args.add(("", kind))
|
args.add(("", kind))
|
||||||
argExpr.add(argument)
|
argExpr.add(argument)
|
||||||
for argument in node.arguments.keyword:
|
for argument in node.arguments.keyword:
|
||||||
|
# TODO
|
||||||
discard
|
discard
|
||||||
if args.len() >= 16777216:
|
if args.len() >= 16777216:
|
||||||
self.error(&"cannot pass more than 16777215 arguments")
|
self.error(&"cannot pass more than 16777215 arguments")
|
||||||
|
@ -1348,28 +1354,19 @@ proc callExpr(self: Compiler, node: CallExpr) =
|
||||||
of identExpr:
|
of identExpr:
|
||||||
funct = self.matchImpl(IdentExpr(node.callee).name.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: args))
|
funct = self.matchImpl(IdentExpr(node.callee).name.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: args))
|
||||||
of NodeKind.callExpr:
|
of NodeKind.callExpr:
|
||||||
var node = node.callee
|
funct = self.callExpr(CallExpr(node.callee))
|
||||||
while node.kind == callExpr:
|
funct = Name(valueType: Type(kind: Function, returnType: Type(kind: Any), args: args))
|
||||||
self.callExpr(CallExpr(node))
|
onStack = true
|
||||||
node = CallExpr(node).callee
|
# TODO: Calling lambdas on-the-fly (i.e. on the same line)
|
||||||
# funct = self.matchImpl(IdentExpr(node.callee).name.lexeme, Type(kind: Function, returnType: Type(kind: Any), args: args))
|
|
||||||
# TODO: Calling lambdas
|
|
||||||
else:
|
else:
|
||||||
let typ = self.inferType(node)
|
let typ = self.inferType(node)
|
||||||
if typ.isNil():
|
if typ.isNil():
|
||||||
self.error(&"expression has no type")
|
self.error(&"expression has no type")
|
||||||
else:
|
else:
|
||||||
self.error(&"object of type '{self.typeToStr(typ)}' is not callable")
|
self.error(&"object of type '{self.typeToStr(typ)}' is not callable")
|
||||||
if any(funct.valueType.args, proc (arg: tuple[name: string, kind: Type]): bool = arg[1].kind == Generic):
|
result = funct
|
||||||
# The function has generic arguments! We need to compile a version
|
self.generateCall(funct, argExpr, onStack)
|
||||||
# of it with the right type data
|
if not self.checkCallIsPure(node.callee):
|
||||||
self.funDecl(nil, funct, argExpr)
|
|
||||||
# TODO: What next?
|
|
||||||
elif funct.valueType.isBuiltinFunction:
|
|
||||||
self.handleBuiltinFunction(funct, argExpr)
|
|
||||||
else:
|
|
||||||
self.generateCall(funct, argExpr)
|
|
||||||
if self.scopeDepth > 0 and not self.checkCallIsPure(node.callee):
|
|
||||||
if self.currentFunction.name != "":
|
if self.currentFunction.name != "":
|
||||||
self.error(&"cannot make sure that calls to '{self.currentFunction.name}' are side-effect free")
|
self.error(&"cannot make sure that calls to '{self.currentFunction.name}' are side-effect free")
|
||||||
else:
|
else:
|
||||||
|
@ -1688,14 +1685,14 @@ proc fixGenericFunc(self: Compiler, name: Name, args: seq[Expression]): Type =
|
||||||
|
|
||||||
proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression] = @[]) =
|
proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression] = @[]) =
|
||||||
## Compiles function declarations
|
## Compiles function declarations
|
||||||
if not node.isNil():
|
#[if not node.isNil():
|
||||||
if node.generics.len() > 0 and fn.isNil() and args.len() == 0:
|
if node.generics.len() > 0 and fn.isNil() and args.len() == 0:
|
||||||
# Generic function! We can't compile it right now
|
# Generic function! We can't compile it right now
|
||||||
self.declareName(node)
|
self.declareName(node)
|
||||||
self.dispatchPragmas(node)
|
self.dispatchPragmas(node)
|
||||||
return
|
return]#
|
||||||
self.declareName(node)
|
self.declareName(node)
|
||||||
self.dispatchPragmas(node)
|
self.dispatchPragmas(node)
|
||||||
var node = node
|
var node = node
|
||||||
var fn = if fn.isNil(): self.names[^(node.arguments.len() + 1)] else: fn
|
var fn = if fn.isNil(): self.names[^(node.arguments.len() + 1)] else: fn
|
||||||
if fn.valueType.isBuiltinFunction:
|
if fn.valueType.isBuiltinFunction:
|
||||||
|
@ -1729,14 +1726,14 @@ proc funDecl(self: Compiler, node: FunDecl, fn: Name = nil, args: seq[Expression
|
||||||
self.error("cannot declare function with empty body")
|
self.error("cannot declare function with empty body")
|
||||||
else:
|
else:
|
||||||
discard # TODO: Forward declarations
|
discard # TODO: Forward declarations
|
||||||
let impl = self.findByType(fn.name.token.lexeme, fn.valueType)
|
let impl = self.findByType(fn.name.token.lexeme, fn.valueType, self.scopeDepth)
|
||||||
if impl.len() > 1:
|
if impl.len() > 1:
|
||||||
# We found more than one (public) implementation of
|
# We found more than one (public) implementation of
|
||||||
# the same function with the same name: this is an
|
# the same function with the same name: this is an
|
||||||
# error, as it would raise ambiguity when calling them
|
# error, as it would raise ambiguity when calling them
|
||||||
var msg = &"multiple matching implementations of '{fn.name.token.lexeme}' found:\n"
|
var msg = &"multiple matching implementations of '{fn.name.token.lexeme}' found:\n"
|
||||||
for f in reversed(impl):
|
for f in reversed(impl):
|
||||||
msg &= &"- '{f.name.token.lexeme}' at line {f.line} of type {self.typeToStr(f.valueType)}\n"
|
msg &= &"- in module '{f.owner}' at line {f.line} of type {self.typeToStr(f.valueType)}\n"
|
||||||
self.error(msg)
|
self.error(msg)
|
||||||
# Since the deferred array is a linear
|
# Since the deferred array is a linear
|
||||||
# sequence of instructions and we want
|
# sequence of instructions and we want
|
||||||
|
|
|
@ -55,6 +55,7 @@ type
|
||||||
|
|
||||||
|
|
||||||
proc newSymbolTable: SymbolTable =
|
proc newSymbolTable: SymbolTable =
|
||||||
|
## Initializes a new symbol table
|
||||||
new(result)
|
new(result)
|
||||||
result.keywords = newTable[string, TokenType]()
|
result.keywords = newTable[string, TokenType]()
|
||||||
result.symbols = newTable[string, TokenType]()
|
result.symbols = newTable[string, TokenType]()
|
||||||
|
@ -144,6 +145,7 @@ proc isAlphaNumeric(s: string): bool =
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
# Forward declaration
|
||||||
proc incLine(self: Lexer)
|
proc incLine(self: Lexer)
|
||||||
|
|
||||||
# Simple public getters used for error
|
# Simple public getters used for error
|
||||||
|
@ -213,7 +215,8 @@ proc peek(self: Lexer, distance: int = 0, length: int = 1): string =
|
||||||
## previously consumed tokens. If the
|
## previously consumed tokens. If the
|
||||||
## distance and/or the length are beyond
|
## distance and/or the length are beyond
|
||||||
## EOF (even partially), the resulting string
|
## EOF (even partially), the resulting string
|
||||||
## will be shorter than length bytes
|
## will be shorter than length bytes. The string
|
||||||
|
## may be empty
|
||||||
var i = distance
|
var i = distance
|
||||||
while len(result) < length:
|
while len(result) < length:
|
||||||
if self.done() or self.current + i > self.source.high() or
|
if self.done() or self.current + i > self.source.high() or
|
||||||
|
@ -225,8 +228,8 @@ 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 info
|
||||||
## error message
|
## 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())
|
||||||
|
|
||||||
|
|
||||||
|
@ -299,7 +302,7 @@ proc parseEscape(self: Lexer) =
|
||||||
# likely be soon. Another notable limitation is that
|
# likely be soon. Another notable limitation is that
|
||||||
# \xhhh and \nnn are limited to the size of a char
|
# \xhhh and \nnn are limited to the size of a char
|
||||||
# (i.e. uint8, or 256 values)
|
# (i.e. uint8, or 256 values)
|
||||||
case self.peek()[0]: # We use a char instead of a string because of how case statements handle ranges with strings
|
case self.peek()[0]: # We use a char instead of a string because of how case statements handle ranges with strings
|
||||||
# (i.e. not well, given they crash the C code generator)
|
# (i.e. not well, given they crash the C code generator)
|
||||||
of 'a':
|
of 'a':
|
||||||
self.source[self.current] = cast[char](0x07)
|
self.source[self.current] = cast[char](0x07)
|
||||||
|
|
|
@ -183,7 +183,7 @@ type
|
||||||
returnType*: Expression
|
returnType*: Expression
|
||||||
hasExplicitReturn*: bool
|
hasExplicitReturn*: bool
|
||||||
freeVars*: seq[IdentExpr]
|
freeVars*: seq[IdentExpr]
|
||||||
|
depth*: int
|
||||||
|
|
||||||
SliceExpr* = ref object of Expression
|
SliceExpr* = ref object of Expression
|
||||||
expression*: Expression
|
expression*: Expression
|
||||||
|
@ -265,6 +265,7 @@ type
|
||||||
returnType*: Expression
|
returnType*: Expression
|
||||||
hasExplicitReturn*: bool
|
hasExplicitReturn*: bool
|
||||||
freeVars*: seq[IdentExpr]
|
freeVars*: seq[IdentExpr]
|
||||||
|
depth*: int
|
||||||
|
|
||||||
TypeDecl* = ref object of Declaration
|
TypeDecl* = ref object of Declaration
|
||||||
name*: IdentExpr
|
name*: IdentExpr
|
||||||
|
@ -411,10 +412,11 @@ proc newGroupingExpr*(expression: Expression, token: Token): GroupingExpr =
|
||||||
result.token = token
|
result.token = token
|
||||||
|
|
||||||
|
|
||||||
proc newLambdaExpr*(arguments: seq[tuple[name: IdentExpr, valueType: Expression]],
|
proc newLambdaExpr*(arguments: seq[tuple[name: IdentExpr, valueType: Expression]], defaults: seq[Expression],
|
||||||
defaults: seq[Expression], body: Statement, isGenerator: bool,
|
body: Statement, isAsync, isGenerator: bool,
|
||||||
isAsync: bool, token: Token, returnType: Expression, pragmas: seq[Pragma],
|
token: Token, depth: int, pragmas: seq[Pragma] = @[],
|
||||||
generics: seq[tuple[name: IdentExpr, cond: Expression]], freeVars: seq[IdentExpr] = @[]): LambdaExpr =
|
returnType: Expression, generics: seq[tuple[name: IdentExpr, cond: Expression]] = @[],
|
||||||
|
freeVars: seq[IdentExpr] = @[]): LambdaExpr =
|
||||||
result = LambdaExpr(kind: lambdaExpr)
|
result = LambdaExpr(kind: lambdaExpr)
|
||||||
result.body = body
|
result.body = body
|
||||||
result.arguments = arguments
|
result.arguments = arguments
|
||||||
|
@ -427,6 +429,7 @@ proc newLambdaExpr*(arguments: seq[tuple[name: IdentExpr, valueType: Expression]
|
||||||
result.pragmas = pragmas
|
result.pragmas = pragmas
|
||||||
result.generics = generics
|
result.generics = generics
|
||||||
result.freeVars = freeVars
|
result.freeVars = freeVars
|
||||||
|
result.depth = depth
|
||||||
|
|
||||||
|
|
||||||
proc newGetItemExpr*(obj: Expression, name: IdentExpr,
|
proc newGetItemExpr*(obj: Expression, name: IdentExpr,
|
||||||
|
@ -615,8 +618,9 @@ proc newVarDecl*(name: IdentExpr, value: Expression, isConst: bool = false,
|
||||||
|
|
||||||
proc newFunDecl*(name: IdentExpr, arguments: seq[tuple[name: IdentExpr, valueType: Expression]], defaults: seq[Expression],
|
proc newFunDecl*(name: IdentExpr, arguments: seq[tuple[name: IdentExpr, valueType: Expression]], defaults: seq[Expression],
|
||||||
body: Statement, isAsync, isGenerator: bool,
|
body: Statement, isAsync, isGenerator: bool,
|
||||||
isPrivate: bool, token: Token, pragmas: seq[Pragma],
|
isPrivate: bool, token: Token, depth: int,
|
||||||
returnType: Expression, generics: seq[tuple[name: IdentExpr, cond: Expression]], freeVars: seq[IdentExpr] = @[]): FunDecl =
|
pragmas: seq[Pragma] = @[], returnType: Expression,
|
||||||
|
generics: seq[tuple[name: IdentExpr, cond: Expression]] = @[], freeVars: seq[IdentExpr] = @[]): FunDecl =
|
||||||
result = FunDecl(kind: funDecl)
|
result = FunDecl(kind: funDecl)
|
||||||
result.name = name
|
result.name = name
|
||||||
result.arguments = arguments
|
result.arguments = arguments
|
||||||
|
@ -631,6 +635,7 @@ proc newFunDecl*(name: IdentExpr, arguments: seq[tuple[name: IdentExpr, valueTyp
|
||||||
result.isPure = false
|
result.isPure = false
|
||||||
result.generics = generics
|
result.generics = generics
|
||||||
result.freeVars = freeVars
|
result.freeVars = freeVars
|
||||||
|
result.depth = depth
|
||||||
|
|
||||||
|
|
||||||
proc newTypeDecl*(name: IdentExpr, fields: seq[tuple[name: IdentExpr, valueType: Expression, isPrivate: bool]],
|
proc newTypeDecl*(name: IdentExpr, fields: seq[tuple[name: IdentExpr, valueType: Expression, isPrivate: bool]],
|
||||||
|
@ -730,13 +735,13 @@ proc `$`*(self: ASTNode): string =
|
||||||
result &= &"Var(name={self.name}, value={self.value}, const={self.isConst}, private={self.isPrivate}, type={self.valueType}, pragmas={self.pragmas})"
|
result &= &"Var(name={self.name}, value={self.value}, const={self.isConst}, private={self.isPrivate}, type={self.valueType}, pragmas={self.pragmas})"
|
||||||
of funDecl:
|
of funDecl:
|
||||||
var self = FunDecl(self)
|
var self = FunDecl(self)
|
||||||
result &= &"""FunDecl(name={self.name}, body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], generics=[{self.generics.join(", ")}], async={self.isAsync}, generator={self.isGenerator}, private={self.isPrivate}, pragmas={self.pragmas})"""
|
result &= &"""FunDecl(name={self.name}, body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], generics=[{self.generics.join(", ")}], async={self.isAsync}, generator={self.isGenerator}, private={self.isPrivate}, pragmas={self.pragmas}, vars=[{self.freeVars.join(", ")}])"""
|
||||||
of typeDecl:
|
of typeDecl:
|
||||||
var self = TypeDecl(self)
|
var self = TypeDecl(self)
|
||||||
result &= &"""TypeDecl(name={self.name}, fields={self.fields}, defaults={self.defaults}, private={self.isPrivate}, pragmas={self.pragmas}, generics={self.generics}, pragmas={self.pragmas}, type={self.valueType})"""
|
result &= &"""TypeDecl(name={self.name}, fields={self.fields}, defaults={self.defaults}, private={self.isPrivate}, pragmas={self.pragmas}, generics={self.generics}, pragmas={self.pragmas}, type={self.valueType})"""
|
||||||
of lambdaExpr:
|
of lambdaExpr:
|
||||||
var self = LambdaExpr(self)
|
var self = LambdaExpr(self)
|
||||||
result &= &"""Lambda(body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], generator={self.isGenerator}, async={self.isAsync}, pragmas={self.pragmas})"""
|
result &= &"""Lambda(body={self.body}, type={self.returnType}, arguments=[{self.arguments.join(", ")}], defaults=[{self.defaults.join(", ")}], generator={self.isGenerator}, async={self.isAsync}, pragmas={self.pragmas}, vars=[{self.freeVars.join(", ")}])"""
|
||||||
of deferStmt:
|
of deferStmt:
|
||||||
var self = DeferStmt(self)
|
var self = DeferStmt(self)
|
||||||
result &= &"Defer({self.expression})"
|
result &= &"Defer({self.expression})"
|
||||||
|
|
|
@ -79,7 +79,7 @@ type
|
||||||
proc `$`*(self: Token): string =
|
proc `$`*(self: Token): string =
|
||||||
## Strinfifies
|
## Strinfifies
|
||||||
if self != nil:
|
if self != nil:
|
||||||
result = &"Token(kind={self.kind}, lexeme={($self.lexeme).escape()}, line={self.line}, pos=({self.pos.start}, {self.pos.stop}), spaces={self.spaces})"
|
result = &"Token(kind={self.kind}, lexeme={self.lexeme.escape()}, line={self.line}, pos=({self.pos.start}, {self.pos.stop}), spaces={self.spaces})"
|
||||||
else:
|
else:
|
||||||
result = "nil"
|
result = "nil"
|
||||||
|
|
||||||
|
|
|
@ -192,9 +192,9 @@ proc step(self: Parser, n: int = 1): Token =
|
||||||
self.current += 1
|
self.current += 1
|
||||||
|
|
||||||
|
|
||||||
proc error(self: Parser, message: string) {.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: self.getCurrentToken(), file: self.file, module: self.getModule())
|
raise ParseError(msg: message, token: if token.isNil(): self.getCurrentToken() else: token, 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:
|
||||||
|
@ -306,6 +306,16 @@ proc primary(self: Parser): Expression =
|
||||||
result = newIntExpr(self.step())
|
result = newIntExpr(self.step())
|
||||||
of Identifier:
|
of Identifier:
|
||||||
result = newIdentExpr(self.step(), self.scopeDepth)
|
result = newIdentExpr(self.step(), self.scopeDepth)
|
||||||
|
if not self.currentFunction.isNil() and self.scopeDepth > 0:
|
||||||
|
case self.currentFunction.kind:
|
||||||
|
of NodeKind.funDecl:
|
||||||
|
if FunDecl(self.currentFunction).depth != self.scopeDepth:
|
||||||
|
FunDecl(self.currentFunction).freeVars.add(IdentExpr(result))
|
||||||
|
of NodeKind.lambdaExpr:
|
||||||
|
if LambdaExpr(self.currentFunction).depth != self.scopeDepth:
|
||||||
|
LambdaExpr(self.currentFunction).freeVars.add(IdentExpr(result))
|
||||||
|
else:
|
||||||
|
discard # Unreachable
|
||||||
of LeftParen:
|
of LeftParen:
|
||||||
let tok = self.step()
|
let tok = self.step()
|
||||||
result = newGroupingExpr(self.expression(), tok)
|
result = newGroupingExpr(self.expression(), tok)
|
||||||
|
@ -313,10 +323,10 @@ proc primary(self: Parser): Expression =
|
||||||
of Yield:
|
of Yield:
|
||||||
let tok = self.step()
|
let tok = self.step()
|
||||||
if self.currentFunction.isNil():
|
if self.currentFunction.isNil():
|
||||||
self.error("'yield' cannot be used outside functions")
|
self.error("'yield' cannot be used outside functions", tok)
|
||||||
elif self.currentFunction.token.kind != Generator:
|
elif self.currentFunction.token.kind != Generator:
|
||||||
# It's easier than doing conversions for lambda/funDecl
|
# It's easier than doing conversions for lambda/funDecl
|
||||||
self.error("'yield' cannot be used outside generators")
|
self.error("'yield' cannot be used outside generators", tok)
|
||||||
if not self.check([RightBrace, RightBracket, RightParen, Comma, Semicolon]):
|
if not self.check([RightBrace, RightBracket, RightParen, Comma, Semicolon]):
|
||||||
# Expression delimiters
|
# Expression delimiters
|
||||||
result = newYieldExpr(self.expression(), tok)
|
result = newYieldExpr(self.expression(), tok)
|
||||||
|
@ -326,9 +336,9 @@ proc primary(self: Parser): Expression =
|
||||||
of Await:
|
of Await:
|
||||||
let tok = self.step()
|
let tok = self.step()
|
||||||
if self.currentFunction.isNil():
|
if self.currentFunction.isNil():
|
||||||
self.error("'await' cannot be used outside functions")
|
self.error("'await' cannot be used outside functions", tok)
|
||||||
if self.currentFunction.token.kind != Coroutine:
|
if self.currentFunction.token.kind != Coroutine:
|
||||||
self.error("'await' can only be used inside coroutines")
|
self.error("'await' can only be used inside coroutines", tok)
|
||||||
result = newAwaitExpr(self.expression(), tok)
|
result = newAwaitExpr(self.expression(), tok)
|
||||||
of RightParen, RightBracket, RightBrace:
|
of RightParen, RightBracket, RightBrace:
|
||||||
# This is *technically* unnecessary: the parser would
|
# This is *technically* unnecessary: the parser would
|
||||||
|
@ -502,7 +512,7 @@ proc parseAssign(self: Parser): Expression =
|
||||||
of getItemExpr:
|
of getItemExpr:
|
||||||
result = newSetItemExpr(GetItemExpr(result).obj, GetItemExpr(result).name, value, tok)
|
result = newSetItemExpr(GetItemExpr(result).obj, GetItemExpr(result).name, value, tok)
|
||||||
else:
|
else:
|
||||||
self.error("invalid assignment target")
|
self.error("invalid assignment target", tok)
|
||||||
|
|
||||||
|
|
||||||
proc parseArrow(self: Parser): Expression =
|
proc parseArrow(self: Parser): Expression =
|
||||||
|
@ -568,8 +578,8 @@ proc deferStmt(self: Parser): Statement =
|
||||||
let tok = self.peek(-1)
|
let tok = self.peek(-1)
|
||||||
if self.currentFunction.isNil():
|
if self.currentFunction.isNil():
|
||||||
self.error("'defer' cannot be used outside functions")
|
self.error("'defer' cannot be used outside functions")
|
||||||
result = newDeferStmt(self.expression(), tok)
|
|
||||||
endOfLine("missing statement terminator after 'defer'")
|
endOfLine("missing statement terminator after 'defer'")
|
||||||
|
result = newDeferStmt(self.expression(), tok)
|
||||||
|
|
||||||
|
|
||||||
proc continueStmt(self: Parser): Statement =
|
proc continueStmt(self: Parser): Statement =
|
||||||
|
@ -622,8 +632,8 @@ proc awaitStmt(self: Parser): Statement =
|
||||||
self.error("'await' cannot be used outside functions")
|
self.error("'await' cannot be used outside functions")
|
||||||
if self.currentFunction.token.kind != Coroutine:
|
if self.currentFunction.token.kind != Coroutine:
|
||||||
self.error("'await' can only be used inside coroutines")
|
self.error("'await' can only be used inside coroutines")
|
||||||
result = newAwaitStmt(self.expression(), tok)
|
|
||||||
endOfLine("missing statement terminator after 'await'")
|
endOfLine("missing statement terminator after 'await'")
|
||||||
|
result = newAwaitStmt(self.expression(), tok)
|
||||||
|
|
||||||
|
|
||||||
proc raiseStmt(self: Parser): Statement =
|
proc raiseStmt(self: Parser): Statement =
|
||||||
|
@ -661,8 +671,8 @@ proc importStmt(self: Parser, fromStmt: bool = false): Statement =
|
||||||
tok = self.peek(-1)
|
tok = self.peek(-1)
|
||||||
# TODO: New AST node
|
# TODO: New AST node
|
||||||
self.expect(Identifier, "expecting module name(s) after import statement")
|
self.expect(Identifier, "expecting module name(s) after import statement")
|
||||||
result = newImportStmt(newIdentExpr(self.peek(-1), self.scopeDepth), tok)
|
|
||||||
endOfLine("missing statement terminator after 'import'")
|
endOfLine("missing statement terminator after 'import'")
|
||||||
|
result = newImportStmt(newIdentExpr(self.peek(-1), self.scopeDepth), tok)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -687,10 +697,10 @@ proc tryStmt(self: Parser): Statement =
|
||||||
if self.match(Finally):
|
if self.match(Finally):
|
||||||
finallyClause = self.statement()
|
finallyClause = self.statement()
|
||||||
if handlers.len() == 0 and elseClause.isNil() and finallyClause.isNil():
|
if handlers.len() == 0 and elseClause.isNil() and finallyClause.isNil():
|
||||||
self.error("expecting 'except', 'finally' or 'else' statement after 'try' block")
|
self.error("expecting 'except', 'finally' or 'else' statement after 'try' block", tok)
|
||||||
for i, handler in handlers:
|
for i, handler in handlers:
|
||||||
if handler.exc.isNil() and i != handlers.high():
|
if handler.exc.isNil() and i != handlers.high():
|
||||||
self.error("catch-all exception handler with bare 'except' must come last in try statement")
|
self.error("catch-all exception handler with bare 'except' must come last in try statement", handler.exc.token)
|
||||||
result = newTryStmt(body, handlers, finallyClause, elseClause, tok)
|
result = newTryStmt(body, handlers, finallyClause, elseClause, tok)
|
||||||
|
|
||||||
|
|
||||||
|
@ -807,15 +817,15 @@ proc parsePragmas(self: Parser): seq[Pragma] =
|
||||||
while not self.match(")") and not self.done():
|
while not self.match(")") and not self.done():
|
||||||
exp = self.primary()
|
exp = self.primary()
|
||||||
if not exp.isLiteral():
|
if not exp.isLiteral():
|
||||||
self.error("pragma arguments can only be literals")
|
self.error("pragma arguments can only be literals", exp.token)
|
||||||
args.add(LiteralExpr(exp))
|
args.add(LiteralExpr(exp))
|
||||||
if not self.match(","):
|
if not self.match(","):
|
||||||
break
|
break
|
||||||
self.expect(")", "unterminated parenthesis in pragma arguments")
|
self.expect(LeftParen, "unterminated parenthesis in pragma arguments")
|
||||||
else:
|
else:
|
||||||
exp = self.primary()
|
exp = self.primary()
|
||||||
if not exp.isLiteral():
|
if not exp.isLiteral():
|
||||||
self.error("pragma arguments can only be literals")
|
self.error("pragma arguments can only be literals", exp.token)
|
||||||
args.add(LiteralExpr(exp))
|
args.add(LiteralExpr(exp))
|
||||||
result.add(newPragma(name, args))
|
result.add(newPragma(name, args))
|
||||||
if self.match(","):
|
if self.match(","):
|
||||||
|
@ -866,7 +876,7 @@ proc varDecl(self: Parser, isLet: bool = false,
|
||||||
else:
|
else:
|
||||||
discard # Unreachable
|
discard # Unreachable
|
||||||
if not hasInit and VarDecl(result).valueType.isNil():
|
if not hasInit and VarDecl(result).valueType.isNil():
|
||||||
self.error("expecting initializer or explicit type declaration, but neither was found")
|
self.error("expecting initializer or explicit type annotation, but neither was found", result.token)
|
||||||
result.pragmas = pragmas
|
result.pragmas = pragmas
|
||||||
|
|
||||||
|
|
||||||
|
@ -876,7 +886,7 @@ proc parseDeclArguments(self: Parser, arguments: var seq[tuple[name: IdentExpr,
|
||||||
## Helper to parse declaration arguments and avoid code duplication
|
## Helper to parse declaration arguments and avoid code duplication
|
||||||
while not self.check(RightParen):
|
while not self.check(RightParen):
|
||||||
if arguments.len > 255:
|
if arguments.len > 255:
|
||||||
self.error("cannot have more than 255 arguments in function declaration")
|
self.error("cannot have more than 255 arguments in function declaration", self.peek(-1))
|
||||||
self.expect(Identifier, "expecting parameter name")
|
self.expect(Identifier, "expecting parameter name")
|
||||||
parameter.name = newIdentExpr(self.peek(-1), self.scopeDepth)
|
parameter.name = newIdentExpr(self.peek(-1), self.scopeDepth)
|
||||||
if self.match(":"):
|
if self.match(":"):
|
||||||
|
@ -888,12 +898,12 @@ proc parseDeclArguments(self: Parser, arguments: var seq[tuple[name: IdentExpr,
|
||||||
else:
|
else:
|
||||||
parameter.valueType = nil
|
parameter.valueType = nil
|
||||||
if parameter in arguments:
|
if parameter in arguments:
|
||||||
self.error("duplicate parameter name in function declaration")
|
self.error("duplicate parameter name in function declaration", parameter.name.token)
|
||||||
arguments.add(parameter)
|
arguments.add(parameter)
|
||||||
if self.match("="):
|
if self.match("="):
|
||||||
defaults.add(self.expression())
|
defaults.add(self.expression())
|
||||||
elif defaults.len() > 0:
|
elif defaults.len() > 0:
|
||||||
self.error("positional argument cannot follow default argument in function declaration")
|
self.error("positional argument cannot follow default argument in function declaration", parameter.name.token)
|
||||||
if not self.match(Comma):
|
if not self.match(Comma):
|
||||||
break
|
break
|
||||||
self.expect(RightParen)
|
self.expect(RightParen)
|
||||||
|
@ -910,7 +920,7 @@ proc parseFunExpr(self: Parser): LambdaExpr =
|
||||||
var defaults: seq[Expression] = @[]
|
var defaults: seq[Expression] = @[]
|
||||||
result = newLambdaExpr(arguments, defaults, nil, isGenerator=self.peek(-1).kind == Generator,
|
result = newLambdaExpr(arguments, defaults, nil, isGenerator=self.peek(-1).kind == Generator,
|
||||||
isAsync=self.peek(-1).kind == Coroutine, token=self.peek(-1),
|
isAsync=self.peek(-1).kind == Coroutine, token=self.peek(-1),
|
||||||
returnType=nil, pragmas=(@[]), generics=(@[]))
|
returnType=nil, depth=self.scopeDepth)
|
||||||
var parameter: tuple[name: IdentExpr, valueType: Expression]
|
var parameter: tuple[name: IdentExpr, valueType: Expression]
|
||||||
if self.match(LeftParen):
|
if self.match(LeftParen):
|
||||||
self.parseDeclArguments(arguments, parameter, defaults)
|
self.parseDeclArguments(arguments, parameter, defaults)
|
||||||
|
@ -956,9 +966,9 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
||||||
isAsync=isAsync,
|
isAsync=isAsync,
|
||||||
isGenerator=isGenerator,
|
isGenerator=isGenerator,
|
||||||
isPrivate=true,
|
isPrivate=true,
|
||||||
token=tok, pragmas=(@[]),
|
token=tok,
|
||||||
returnType=nil,
|
returnType=nil,
|
||||||
generics=(@[]))
|
depth=self.scopeDepth)
|
||||||
if self.match("*"):
|
if self.match("*"):
|
||||||
FunDecl(self.currentFunction).isPrivate = false
|
FunDecl(self.currentFunction).isPrivate = false
|
||||||
self.checkDecl(FunDecl(self.currentFunction).isPrivate)
|
self.checkDecl(FunDecl(self.currentFunction).isPrivate)
|
||||||
|
@ -978,8 +988,8 @@ proc funDecl(self: Parser, isAsync: bool = false, isGenerator: bool = false,
|
||||||
self.currentFunction = enclosingFunction
|
self.currentFunction = enclosingFunction
|
||||||
return result
|
return result
|
||||||
elif isLambda:
|
elif isLambda:
|
||||||
self.currentFunction = newLambdaExpr(arguments, defaults, newBlockStmt(@[], Token()), isGenerator = isGenerator, isAsync = isAsync, token = tok,
|
self.currentFunction = newLambdaExpr(arguments, defaults, newBlockStmt(@[], Token()), isGenerator=isGenerator, isAsync=isAsync, token=tok,
|
||||||
returnType = nil, pragmas = (@[]), generics=(@[]))
|
returnType=nil, depth=self.scopeDepth)
|
||||||
if self.match(":"):
|
if self.match(":"):
|
||||||
# Function has explicit return type
|
# Function has explicit return type
|
||||||
if self.match([Function, Coroutine, Generator]):
|
if self.match([Function, Coroutine, Generator]):
|
||||||
|
@ -1198,12 +1208,12 @@ proc parse*(self: Parser, tokens: seq[Token], file: string): seq[Declaration] =
|
||||||
# with an EOF token
|
# with an EOF token
|
||||||
if token.kind == Operator:
|
if token.kind == Operator:
|
||||||
if i == self.tokens.high():
|
if i == self.tokens.high():
|
||||||
self.error("invalid state: found malformed tokenizer input while looking for operators (missing EOF)")
|
self.error("invalid state: found malformed tokenizer input while looking for operators (missing EOF)", token)
|
||||||
self.operators.addOperator(self.tokens[i + 1].lexeme)
|
self.operators.addOperator(self.tokens[i + 1].lexeme)
|
||||||
if i == self.tokens.high() and token.kind != EndOfFile:
|
if i == self.tokens.high() and token.kind != EndOfFile:
|
||||||
# Since we're iterating this list anyway might as
|
# Since we're iterating this list anyway might as
|
||||||
# well perform some extra checks
|
# well perform some extra checks
|
||||||
self.error("invalid state: found malformed tokenizer input while looking for operators (missing EOF)")
|
self.error("invalid state: found malformed tokenizer input while looking for operators (missing EOF)", token)
|
||||||
while not self.done():
|
while not self.done():
|
||||||
self.tree.add(self.declaration())
|
self.tree.add(self.declaration())
|
||||||
if self.tree[^1] == nil:
|
if self.tree[^1] == nil:
|
||||||
|
|
22
src/main.nim
22
src/main.nim
|
@ -142,9 +142,9 @@ proc repl(vm: PeonVM = newPeonVM()) =
|
||||||
input = ""
|
input = ""
|
||||||
let exc = LexingError(getCurrentException())
|
let exc = LexingError(getCurrentException())
|
||||||
let relPos = tokenizer.getRelPos(exc.line)
|
let relPos = tokenizer.getRelPos(exc.line)
|
||||||
let line = tokenizer.getSource().splitLines()[exc.line - 1].strip()
|
let line = tokenizer.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}'",
|
fgYellow, &"'{exc.file.extractFilename()}'", fgRed, ", line ", fgYellow, $exc.line, fgRed, " at ", fgYellow, &"'{exc.lexeme.escape()}'",
|
||||||
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)
|
||||||
|
@ -155,7 +155,7 @@ proc repl(vm: PeonVM = newPeonVM()) =
|
||||||
let lineNo = exc.token.line
|
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(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}'"
|
||||||
|
@ -169,7 +169,7 @@ proc repl(vm: PeonVM = newPeonVM()) =
|
||||||
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 = tokenizer.getRelPos(lineNo)
|
||||||
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip(chars={'\n'})
|
||||||
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:
|
||||||
|
@ -265,21 +265,23 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
|
||||||
styledEcho fgCyan, "\n\nExecution step: "
|
styledEcho fgCyan, "\n\nExecution step: "
|
||||||
vm.run(serialized.chunk)
|
vm.run(serialized.chunk)
|
||||||
except LexingError:
|
except LexingError:
|
||||||
|
input = ""
|
||||||
let exc = LexingError(getCurrentException())
|
let exc = LexingError(getCurrentException())
|
||||||
let relPos = tokenizer.getRelPos(exc.line)
|
let relPos = tokenizer.getRelPos(exc.line)
|
||||||
let line = tokenizer.getSource().splitLines()[exc.line - 1].strip()
|
let line = tokenizer.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}'", 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())
|
||||||
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:
|
||||||
|
input = ""
|
||||||
let exc = ParseError(getCurrentException())
|
let exc = ParseError(getCurrentException())
|
||||||
let lexeme = exc.token.lexeme.escape()
|
let lexeme = exc.token.lexeme
|
||||||
let lineNo = exc.token.line
|
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(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}'"
|
||||||
|
@ -290,10 +292,10 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
|
||||||
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 exc = CompileError(getCurrentException())
|
let exc = CompileError(getCurrentException())
|
||||||
let lexeme = exc.node.token.lexeme.escape()
|
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 = tokenizer.getRelPos(lineNo)
|
||||||
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
let line = tokenizer.getSource().splitLines()[lineNo - 1].strip(chars={'\n'})
|
||||||
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:
|
||||||
|
|
|
@ -138,7 +138,7 @@ proc callInstruction(self: Debugger, instruction: OpCode) =
|
||||||
## Debugs function calls
|
## Debugs function calls
|
||||||
var size = [self.chunk.code[self.current + 1], self.chunk.code[self.current + 2], self.chunk.code[self.current + 3]].fromTriple()
|
var size = [self.chunk.code[self.current + 1], self.chunk.code[self.current + 2], self.chunk.code[self.current + 3]].fromTriple()
|
||||||
printInstruction(instruction)
|
printInstruction(instruction)
|
||||||
styledEcho fgGreen, &", creates frame of size ", fgYellow, $size
|
styledEcho fgGreen, &", creates frame of size ", fgYellow, $(size + 2)
|
||||||
self.current += 4
|
self.current += 4
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,5 @@ fn makeClosure(n: int): fn: int {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var closure = makeClosure(1);
|
var closure = makeClosure(1)();
|
||||||
closure();
|
closure;
|
Loading…
Reference in New Issue