Fixed various bugs and added more tests. Also added nim.cfg
parent
6f444582a4
commit
3dead5a555
|
@ -194,7 +194,7 @@ type
|
|||
# List of closed-over variables
|
||||
closures: seq[Name]
|
||||
# Compiler procedures called by pragmas
|
||||
compilerProcs: TableRef[string, proc (self: Compiler, pragma: Pragma, node: ASTNode, name: Name)]
|
||||
compilerProcs: TableRef[string, proc (self: Compiler, pragma: Pragma, name: Name)]
|
||||
# Stores line data for error reporting
|
||||
lines: seq[tuple[start, stop: int]]
|
||||
# The source of the current module,
|
||||
|
@ -237,9 +237,9 @@ proc findByModule(self: Compiler, name: string): seq[Name]
|
|||
proc findByType(self: Compiler, name: string, kind: Type, depth: int = -1): seq[Name]
|
||||
proc compare(self: Compiler, a, b: Type): bool
|
||||
proc patchReturnAddress(self: Compiler, pos: int)
|
||||
proc handleMagicPragma(self: Compiler, pragma: Pragma, node: ASTnode, name: Name)
|
||||
proc handlePurePragma(self: Compiler, pragma: Pragma, node: ASTnode, name: Name)
|
||||
proc dispatchPragmas(self: Compiler, node: ASTnode, name: Name)
|
||||
proc handleMagicPragma(self: Compiler, pragma: Pragma, name: Name)
|
||||
proc handlePurePragma(self: Compiler, pragma: Pragma, name: Name)
|
||||
proc dispatchPragmas(self: Compiler, name: Name)
|
||||
proc funDecl(self: Compiler, node: FunDecl, name: Name)
|
||||
proc typeDecl(self: Compiler, node: TypeDecl, name: Name)
|
||||
proc compileModule(self: Compiler, moduleName: string)
|
||||
|
@ -260,7 +260,7 @@ proc newCompiler*(replMode: bool = false): Compiler =
|
|||
result.currentFunction = nil
|
||||
result.replMode = replMode
|
||||
result.currentModule = ""
|
||||
result.compilerProcs = newTable[string, proc (self: Compiler, pragma: Pragma, node: ASTNode, name: Name)]()
|
||||
result.compilerProcs = newTable[string, proc (self: Compiler, pragma: Pragma, name: Name)]()
|
||||
result.compilerProcs["magic"] = handleMagicPragma
|
||||
result.compilerProcs["pure"] = handlePurePragma
|
||||
result.source = ""
|
||||
|
@ -491,10 +491,12 @@ proc resolve(self: Compiler, name: string): Name =
|
|||
## Traverses all existing namespaces and returns
|
||||
## the first object with the given name. Returns
|
||||
## nil when the name can't be found. Note that
|
||||
## when a declaration is first resolved, it is
|
||||
## also compiled on-the-fly
|
||||
## when a type or function declaration is first
|
||||
## resolved, it is also compiled on-the-fly
|
||||
for obj in reversed(self.names):
|
||||
if obj.ident.token.lexeme == name:
|
||||
if obj.kind == NameKind.Argument and obj.belongsTo != self.currentFunction:
|
||||
continue
|
||||
if obj.owner != self.currentModule:
|
||||
# We don't own this name, but we
|
||||
# may still have access to it
|
||||
|
@ -573,21 +575,28 @@ proc getStackPos(self: Compiler, name: Name): int =
|
|||
# Argument of a function we haven't compiled yet (or one that we're
|
||||
# not in). Ignore it, as it won't exist at runtime
|
||||
continue
|
||||
elif not variable.belongsTo.isNil() and variable.belongsTo.valueType.isBuiltinFunction:
|
||||
# Builtin functions don't exist at runtime either, so variables belonging to them
|
||||
# are not present in the stack
|
||||
continue
|
||||
elif not variable.valueType.isNil() and variable.valueType.kind == Generic:
|
||||
# Generics are also a purely compile-time construct and are therefore
|
||||
# ignored as far as stack positioning goes
|
||||
continue
|
||||
elif not variable.belongsTo.isNil():
|
||||
if variable.belongsTo.valueType.isBuiltinFunction:
|
||||
# Builtin functions don't exist at runtime either, so variables belonging to them
|
||||
# are not present in the stack
|
||||
continue
|
||||
elif variable.valueType.kind == Generic:
|
||||
# Generics are also a purely compile-time construct and are therefore
|
||||
# ignored as far as stack positioning goes
|
||||
continue
|
||||
elif variable.belongsTo != name.belongsTo:
|
||||
# Since referencing a function immediately compiles it, this means
|
||||
# that if there's a function A with an argument x that calls another
|
||||
# function B with an argument also named x, that second "x" would
|
||||
# shadow the first one, leading to an incorrect stack offset
|
||||
continue
|
||||
elif variable.owner != self.currentModule:
|
||||
# We don't own this variable, so we check
|
||||
# if the owner exported it to us. If not,
|
||||
# we skip it and pretend it doesn't exist
|
||||
if variable.isPrivate or not variable.exported:
|
||||
continue
|
||||
elif name == variable:
|
||||
if name == variable:
|
||||
# After all of these checks, we can
|
||||
# finally check whether the two names
|
||||
# match (note: this also includes scope
|
||||
|
@ -931,20 +940,35 @@ proc typeToStr(self: Compiler, typ: Type): string =
|
|||
|
||||
proc findByName(self: Compiler, name: string): seq[Name] =
|
||||
## Looks for objects that have been already declared
|
||||
## with the given name. Returns all objects that apply
|
||||
## with the given name. Returns all objects that apply.
|
||||
## As with resolve(), this will cause type and function
|
||||
## declarations to be compiled on-the-fly
|
||||
|
||||
for obj in reversed(self.names):
|
||||
if obj.ident.token.lexeme == name:
|
||||
if obj.owner != self.currentModule:
|
||||
if obj.isPrivate or not obj.exported:
|
||||
continue
|
||||
result.add(obj)
|
||||
for n in result:
|
||||
if n.resolved:
|
||||
continue
|
||||
n.resolved = true
|
||||
case n.kind:
|
||||
of NameKind.CustomType:
|
||||
self.typeDecl(TypeDecl(n.node), n)
|
||||
of NameKind.Function:
|
||||
if not n.valueType.isGeneric:
|
||||
self.funDecl(FunDecl(n.node), n)
|
||||
else:
|
||||
discard
|
||||
|
||||
|
||||
proc findByModule(self: Compiler, name: string): seq[Name] =
|
||||
## Looks for objects that have been already declared AS
|
||||
## public within the given module. Returns all objects that apply
|
||||
for obj in reversed(self.names):
|
||||
if obj.owner == name:
|
||||
if not obj.isPrivate and obj.owner == name:
|
||||
result.add(obj)
|
||||
|
||||
|
||||
|
@ -1134,8 +1158,6 @@ proc endScope(self: Compiler) =
|
|||
return
|
||||
for name in self.names:
|
||||
if name.depth > self.depth:
|
||||
if not name.belongsTo.isNil() and not name.belongsTo.resolved:
|
||||
continue
|
||||
names.add(name)
|
||||
#[if not name.resolved:
|
||||
# TODO: Emit a warning?
|
||||
|
@ -1148,7 +1170,7 @@ proc endScope(self: Compiler) =
|
|||
if name.kind == NameKind.Var:
|
||||
inc(popCount)
|
||||
elif name.kind == NameKind.Argument:
|
||||
if not name.belongsTo.valueType.isBuiltinFunction and name.belongsTo.resolved:
|
||||
if not name.belongsTo.valueType.isBuiltinFunction and name.belongsTo.resolved and not name.belongsTo.valueType.isGeneric:
|
||||
# We don't pop arguments to builtin functions because those don't
|
||||
# actually have scopes: their arguments are temporaries on the stack
|
||||
inc(popCount)
|
||||
|
@ -1202,7 +1224,6 @@ proc endScope(self: Compiler) =
|
|||
inc(idx)
|
||||
|
||||
|
||||
|
||||
proc unpackGenerics(self: Compiler, condition: Expression, list: var seq[tuple[match: bool, kind: Type]], accept: bool = true) =
|
||||
## Recursively unpacks a type constraint in a generic type
|
||||
case condition.kind:
|
||||
|
@ -1227,7 +1248,7 @@ proc unpackGenerics(self: Compiler, condition: Expression, list: var seq[tuple[m
|
|||
self.error("invalid type constraint in generic declaration", condition)
|
||||
|
||||
|
||||
proc declareName(self: Compiler, node: ASTNode, mutable: bool = false): Name =
|
||||
proc declareName(self: Compiler, node: ASTNode, mutable: bool = false) =
|
||||
## Statically declares a name into the current scope.
|
||||
## "Declaring" a name only means updating our internal
|
||||
## list of identifiers so that further calls to resolve()
|
||||
|
@ -1235,15 +1256,16 @@ proc declareName(self: Compiler, node: ASTNode, mutable: bool = false): Name =
|
|||
## declare a variable at runtime: the value is already
|
||||
## on the stack
|
||||
var declaredName: string = ""
|
||||
var n: Name
|
||||
case node.kind:
|
||||
of NodeKind.varDecl:
|
||||
var node = VarDecl(node)
|
||||
# Creates a new Name entry so that self.identifier emits the proper stack offset
|
||||
if self.names.high() > 16777215:
|
||||
# If someone ever hits this limit in real-world scenarios, I swear I'll
|
||||
# slap myself 100 times with a sign saying "I'm dumb". Mark my words
|
||||
self.error("cannot declare more than 16777215 variables at a time")
|
||||
declaredName = node.name.token.lexeme
|
||||
# Creates a new Name entry so that self.identifier emits the proper stack offset
|
||||
self.names.add(Name(depth: self.depth,
|
||||
ident: node.name,
|
||||
isPrivate: node.isPrivate,
|
||||
|
@ -1256,12 +1278,13 @@ proc declareName(self: Compiler, node: ASTNode, mutable: bool = false): Name =
|
|||
kind: NameKind.Var,
|
||||
node: node
|
||||
))
|
||||
n = self.names[^1]
|
||||
if mutable:
|
||||
self.names[^1].valueType.mutable = true
|
||||
result = self.names[^1]
|
||||
of NodeKind.funDecl:
|
||||
var node = FunDecl(node)
|
||||
result = Name(depth: self.depth,
|
||||
declaredName = node.name.token.lexeme
|
||||
var fn = Name(depth: self.depth,
|
||||
isPrivate: node.isPrivate,
|
||||
isConst: false,
|
||||
owner: self.currentModule,
|
||||
|
@ -1276,31 +1299,32 @@ proc declareName(self: Compiler, node: ASTNode, mutable: bool = false): Name =
|
|||
line: node.token.line,
|
||||
kind: NameKind.Function,
|
||||
belongsTo: self.currentFunction)
|
||||
n = fn
|
||||
# First we declare the function's generics, if it has any.
|
||||
# This is because the function's return type may in itself
|
||||
# be a generic, so it needs to exist first
|
||||
var constraints: seq[tuple[match: bool, kind: Type]] = @[]
|
||||
for gen in node.generics:
|
||||
self.unpackGenerics(gen.cond, constraints)
|
||||
self.names.add(Name(depth: result.depth + 1,
|
||||
self.names.add(Name(depth: fn.depth + 1,
|
||||
isPrivate: true,
|
||||
valueType: Type(kind: Generic, name: gen.name.token.lexeme, mutable: false, cond: constraints),
|
||||
codePos: 0,
|
||||
isLet: false,
|
||||
line: result.node.token.line,
|
||||
belongsTo: result,
|
||||
line: fn.node.token.line,
|
||||
belongsTo: fn,
|
||||
ident: gen.name,
|
||||
owner: self.currentModule))
|
||||
constraints = @[]
|
||||
if not node.returnType.isNil():
|
||||
result.valueType.returnType = self.inferOrError(node.returnType, allowGeneric=true)
|
||||
self.names.add(result)
|
||||
fn.valueType.returnType = self.inferOrError(node.returnType, allowGeneric=true)
|
||||
self.names.add(fn)
|
||||
# We now declare and typecheck the function's
|
||||
# arguments
|
||||
for argument in FunDecl(result.node).arguments:
|
||||
for argument in FunDecl(fn.node).arguments:
|
||||
if self.names.high() > 16777215:
|
||||
self.error("cannot declare more than 16777215 variables at a time")
|
||||
self.names.add(Name(depth: result.depth + 1,
|
||||
self.names.add(Name(depth: fn.depth + 1,
|
||||
isPrivate: true,
|
||||
owner: self.currentModule,
|
||||
isConst: false,
|
||||
|
@ -1309,12 +1333,12 @@ proc declareName(self: Compiler, node: ASTNode, mutable: bool = false): Name =
|
|||
codePos: 0,
|
||||
isLet: false,
|
||||
line: argument.name.token.line,
|
||||
belongsTo: result,
|
||||
belongsTo: fn,
|
||||
kind: NameKind.Argument
|
||||
))
|
||||
result.valueType.args.add((self.names[^1].ident.token.lexeme, self.names[^1].valueType))
|
||||
fn.valueType.args.add((self.names[^1].ident.token.lexeme, self.names[^1].valueType))
|
||||
if node.generics.len() > 0:
|
||||
result.valueType.isGeneric = true
|
||||
fn.valueType.isGeneric = true
|
||||
of NodeKind.importStmt:
|
||||
var node = ImportStmt(node)
|
||||
var name = node.moduleName.token.lexeme.extractFilename().replace(".pn", "")
|
||||
|
@ -1326,11 +1350,12 @@ proc declareName(self: Compiler, node: ASTNode, mutable: bool = false): Name =
|
|||
kind: NameKind.Module,
|
||||
isPrivate: false
|
||||
))
|
||||
result = self.names[^1]
|
||||
n = self.names[^1]
|
||||
else:
|
||||
discard # TODO: Types, enums
|
||||
self.dispatchPragmas(n)
|
||||
for name in self.findByName(declaredName):
|
||||
if name == result:
|
||||
if name == n:
|
||||
continue
|
||||
elif (name.kind == NameKind.Var and name.depth == self.depth) or name.kind in [NameKind.Module, NameKind.CustomType, NameKind.Enum]:
|
||||
self.error(&"attempt to redeclare '{name.ident.token.lexeme}', which was previously defined in '{name.owner}' at line {name.line}")
|
||||
|
@ -1357,47 +1382,49 @@ proc patchBreaks(self: Compiler) =
|
|||
self.patchJump(brk)
|
||||
|
||||
|
||||
proc handleMagicPragma(self: Compiler, pragma: Pragma, node: ASTNode, name: Name) =
|
||||
proc handleMagicPragma(self: Compiler, pragma: Pragma, name: Name) =
|
||||
## Handles the "magic" pragma. Assumes the given name is already
|
||||
## declared
|
||||
if pragma.args.len() != 1:
|
||||
self.error("'magic' pragma: wrong number of arguments")
|
||||
elif pragma.args[0].kind != strExpr:
|
||||
self.error("'magic' pragma: wrong type of argument (constant string expected)")
|
||||
elif node.kind != NodeKind.funDecl:
|
||||
elif name.node.kind != NodeKind.funDecl:
|
||||
self.error("'magic' pragma is not valid in this context")
|
||||
var node = FunDecl(node)
|
||||
var node = FunDecl(name.node)
|
||||
name.valueType.isBuiltinFunction = true
|
||||
name.valueType.builtinOp = pragma.args[0].token.lexeme[1..^2]
|
||||
# The magic pragma ignores the function's body
|
||||
node.body = nil
|
||||
|
||||
|
||||
proc handlePurePragma(self: Compiler, pragma: Pragma, node: ASTNode, name: Name) =
|
||||
proc handlePurePragma(self: Compiler, pragma: Pragma, name: Name) =
|
||||
## Handles the "pure" pragma
|
||||
case node.kind:
|
||||
case name.node.kind:
|
||||
of NodeKind.funDecl:
|
||||
FunDecl(node).isPure = true
|
||||
FunDecl(name.node).isPure = true
|
||||
of lambdaExpr:
|
||||
LambdaExpr(node).isPure = true
|
||||
LambdaExpr(name.node).isPure = true
|
||||
else:
|
||||
self.error("'pure' pragma is not valid in this context")
|
||||
|
||||
|
||||
proc dispatchPragmas(self: Compiler, node: ASTnode, name: Name) =
|
||||
proc dispatchPragmas(self: Compiler, name: Name) =
|
||||
## Dispatches pragmas bound to objects
|
||||
if name.node.isNil():
|
||||
return
|
||||
var pragmas: seq[Pragma] = @[]
|
||||
case node.kind:
|
||||
case name.node.kind:
|
||||
of NodeKind.funDecl, NodeKind.typeDecl, NodeKind.varDecl:
|
||||
pragmas = Declaration(node).pragmas
|
||||
pragmas = Declaration(name.node).pragmas
|
||||
of lambdaExpr:
|
||||
pragmas = LambdaExpr(node).pragmas
|
||||
pragmas = LambdaExpr(name.node).pragmas
|
||||
else:
|
||||
discard # Unreachable
|
||||
for pragma in pragmas:
|
||||
if pragma.name.token.lexeme notin self.compilerProcs:
|
||||
self.error(&"unknown pragma '{pragma.name.token.lexeme}'")
|
||||
self.compilerProcs[pragma.name.token.lexeme](self, pragma, node, name)
|
||||
self.compilerProcs[pragma.name.token.lexeme](self, pragma, name)
|
||||
|
||||
|
||||
proc patchReturnAddress(self: Compiler, pos: int) =
|
||||
|
@ -1629,7 +1656,7 @@ proc identifier(self: Compiler, node: IdentExpr) =
|
|||
else:
|
||||
# Static name resolution, loads value at index in the stack. Very fast. Much wow.
|
||||
self.emitByte(LoadVar, node.token.line)
|
||||
# No need to check for -1 here: we already did a nil check above!ù
|
||||
# No need to check for -1 here: we already did a nil check above!
|
||||
self.emitBytes(self.getStackPos(s).toTriple(), node.token.line)
|
||||
|
||||
|
||||
|
@ -1764,6 +1791,7 @@ proc specialize(self: Compiler, name: Name, args: seq[Expression]): Name =
|
|||
var mapping: TableRef[string, Type] = newTable[string, Type]()
|
||||
var kind: Type
|
||||
result = deepCopy(name)
|
||||
result.valueType.isGeneric = false
|
||||
case name.kind:
|
||||
of NameKind.Function:
|
||||
# This first loop checks if a user tries to reassign a generic's
|
||||
|
@ -1793,6 +1821,7 @@ proc specialize(self: Compiler, name: Name, args: seq[Expression]): Name =
|
|||
))
|
||||
if result.valueType.returnType.kind == Generic:
|
||||
result.valueType.returnType = mapping[result.valueType.returnType.name]
|
||||
# self.funDecl(FunDecl(result.node), result)
|
||||
else:
|
||||
discard # TODO: Custom user-defined types
|
||||
|
||||
|
@ -1825,6 +1854,7 @@ proc callExpr(self: Compiler, node: CallExpr): Name {.discardable.} =
|
|||
# very last moment to compile it, once
|
||||
# that info is available to us
|
||||
result = self.specialize(result, argExpr)
|
||||
self.funDecl(FunDecl(result.node), result)
|
||||
# Now we call it
|
||||
self.generateCall(result, argExpr, node.token.line)
|
||||
of NodeKind.callExpr:
|
||||
|
@ -1990,7 +2020,7 @@ proc importStmt(self: Compiler, node: ImportStmt) =
|
|||
let filename = splitPath(node.moduleName.token.lexeme).tail
|
||||
try:
|
||||
self.compileModule(node.moduleName.token.lexeme)
|
||||
discard self.declareName(node)
|
||||
self.declareName(node)
|
||||
except IOError:
|
||||
self.error(&"""could not import '{filename}': {getCurrentExceptionMsg()}""")
|
||||
except OSError:
|
||||
|
@ -2148,6 +2178,8 @@ proc funDecl(self: Compiler, node: FunDecl, name: Name) =
|
|||
## Compiles function declarations
|
||||
if node.token.kind == Operator and node.name.token.lexeme in [".", ]:
|
||||
self.error(&"Due to current compiler limitations, the '{node.name.token.lexeme}' operator cannot be overridden", node.name)
|
||||
if name.valueType.isBuiltinFunction:
|
||||
return
|
||||
var node = node
|
||||
var jmp: int
|
||||
# We store the current function
|
||||
|
@ -2177,6 +2209,7 @@ proc funDecl(self: Compiler, node: FunDecl, name: Name) =
|
|||
else:
|
||||
self.chunk.cfi.add(0.toDouble())
|
||||
if BlockStmt(node.body).code.len() == 0:
|
||||
raise newException(IndexDefect, "")
|
||||
self.error("cannot declare function with empty body")
|
||||
# Since the deferred array is a linear
|
||||
# sequence of instructions and we want
|
||||
|
@ -2241,9 +2274,8 @@ proc declaration(self: Compiler, node: Declaration) =
|
|||
## the first time
|
||||
case node.kind:
|
||||
of NodeKind.varDecl, NodeKind.funDecl, NodeKind.typeDecl:
|
||||
self.dispatchPragmas(node, self.declareName(node))
|
||||
self.declareName(node)
|
||||
if node.kind == NodeKind.varDecl:
|
||||
self.names[^1].resolved = true
|
||||
# We compile this immediately because we
|
||||
# need to keep the stack in the right state
|
||||
# at runtime
|
||||
|
@ -2285,7 +2317,10 @@ proc compileModule(self: Compiler, moduleName: string) =
|
|||
## using the compiler's internal parser and lexer objects
|
||||
var path = ""
|
||||
for i, searchPath in moduleLookupPaths:
|
||||
path = joinPath(getCurrentDir(), joinPath(searchPath, moduleName))
|
||||
if searchPath == "":
|
||||
path = joinPath(getCurrentDir(), joinPath(splitPath(self.file).head, moduleName))
|
||||
else:
|
||||
path = joinPath(getCurrentDir(), joinPath(searchPath, moduleName))
|
||||
if fileExists(path):
|
||||
break
|
||||
elif i == searchPath.high():
|
||||
|
|
|
@ -730,7 +730,10 @@ proc importStmt(self: Parser, fromStmt: bool = false): Statement =
|
|||
lexer.fillSymbolTable()
|
||||
var path = ""
|
||||
for i, searchPath in moduleLookupPaths:
|
||||
path = joinPath(getCurrentDir(), joinPath(searchPath, moduleName))
|
||||
if searchPath == "":
|
||||
path = joinPath(getCurrentDir(), joinPath(splitPath(self.file).head, moduleName))
|
||||
else:
|
||||
path = joinPath(getCurrentDir(), joinPath(searchPath, moduleName))
|
||||
if fileExists(path):
|
||||
break
|
||||
elif i == searchPath.high():
|
||||
|
|
18
src/main.nim
18
src/main.nim
|
@ -67,7 +67,7 @@ proc repl =
|
|||
tokenizer.fillSymbolTable()
|
||||
editor.bindEvent(jeQuit):
|
||||
stdout.styledWriteLine(fgGreen, "Goodbye!")
|
||||
editor.prompt = ""
|
||||
editor.prompt = "=> "
|
||||
keep = false
|
||||
input = ""
|
||||
editor.bindKey("ctrl+a"):
|
||||
|
@ -76,10 +76,6 @@ proc repl =
|
|||
editor.content.`end`()
|
||||
while keep:
|
||||
try:
|
||||
# We incrementally add content to the input
|
||||
# so that you can, for example, define a function
|
||||
# then press enter and use it at the next iteration
|
||||
# of the read loop
|
||||
input = editor.read()
|
||||
if input.len() == 0:
|
||||
continue
|
||||
|
@ -153,7 +149,7 @@ proc repl =
|
|||
fgYellow, &"'{exc.file.extractFilename()}'", fgRed, ", line ", fgYellow, $exc.line, fgRed, " at ", fgYellow, &"'{exc.lexeme.escape()}'",
|
||||
fgRed, ": ", fgGreen , getCurrentExceptionMsg())
|
||||
styledEcho fgBlue, "Source line: " , fgDefault, line
|
||||
styledEcho fgCyan, " ".repeat(len("Source line: ") + line.find(exc.lexeme)) & "^".repeat(relPos.stop - relPos.start - line.find(exc.lexeme))
|
||||
styledEcho fgCyan, " ".repeat(len("Source line: ") + line.find(exc.lexeme)) & "^".repeat(abs(relPos.stop - relPos.start - line.find(exc.lexeme)))
|
||||
except ParseError:
|
||||
input = ""
|
||||
let exc = ParseError(getCurrentException())
|
||||
|
@ -169,7 +165,7 @@ proc repl =
|
|||
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: ") + line.find(lexeme)) & "^".repeat(relPos.stop - relPos.start - line.find(lexeme))
|
||||
styledEcho fgCyan, " ".repeat(len("Source line: ") + line.find(lexeme)) & "^".repeat(abs(relPos.stop - relPos.start - line.find(lexeme)))
|
||||
except CompileError:
|
||||
let exc = CompileError(getCurrentException())
|
||||
let lexeme = exc.node.token.lexeme
|
||||
|
@ -184,7 +180,7 @@ proc repl =
|
|||
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: ") + line.find(lexeme)) & "^".repeat(relPos.stop - relPos.start - line.find(lexeme))
|
||||
styledEcho fgCyan, " ".repeat(len("Source line: ") + line.find(lexeme)) & "^".repeat(abs(relPos.stop - relPos.start - line.find(lexeme)))
|
||||
except SerializationError:
|
||||
let exc = SerializationError(getCurrentException())
|
||||
stderr.styledWriteLine(fgRed, "A fatal error occurred while (de-)serializing", fgYellow, &"'{exc.file}'", fgGreen, ": ", getCurrentExceptionMsg())
|
||||
|
@ -280,7 +276,7 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false, dum
|
|||
fgYellow, &"'{exc.file.extractFilename()}'", fgRed, ", line ", fgYellow, $exc.line, fgRed, " at ", fgYellow, &"'{exc.lexeme.escape()}'",
|
||||
fgRed, ": ", fgGreen , getCurrentExceptionMsg())
|
||||
styledEcho fgBlue, "Source line: " , fgDefault, line
|
||||
styledEcho fgCyan, " ".repeat(len("Source line: ") + line.find(exc.lexeme)) & "^".repeat(relPos.stop - relPos.start - line.find(exc.lexeme))
|
||||
styledEcho fgCyan, " ".repeat(len("Source line: ") + line.find(exc.lexeme)) & "^".repeat(abs(relPos.stop - relPos.start - line.find(exc.lexeme)))
|
||||
except ParseError:
|
||||
let exc = ParseError(getCurrentException())
|
||||
let lexeme = exc.token.lexeme
|
||||
|
@ -295,7 +291,7 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false, dum
|
|||
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: ") + line.find(lexeme)) & "^".repeat(relPos.stop - relPos.start - line.find(lexeme))
|
||||
styledEcho fgCyan, " ".repeat(len("Source line: ") + line.find(lexeme)) & "^".repeat(abs(relPos.stop - relPos.start - line.find(lexeme)))
|
||||
except CompileError:
|
||||
let exc = CompileError(getCurrentException())
|
||||
let lexeme = exc.node.token.lexeme
|
||||
|
@ -310,7 +306,7 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false, dum
|
|||
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: ") + line.find(lexeme)) & "^".repeat(relPos.stop - relPos.start - line.find(lexeme))
|
||||
styledEcho fgCyan, " ".repeat(len("Source line: ") + line.find(lexeme)) & "^".repeat(abs(relPos.stop - relPos.start - line.find(lexeme)))
|
||||
except SerializationError:
|
||||
let exc = SerializationError(getCurrentException())
|
||||
stderr.styledWriteLine(fgRed, "A fatal error occurred while (de-)serializing", fgYellow, &"'{exc.file}'", fgGreen, ": ", getCurrentExceptionMsg())
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import std;
|
||||
|
||||
|
||||
fn makeAdder(x: int): fn (n: int): int {
|
||||
fn adder(n: int): int {
|
||||
return x + n;
|
||||
}
|
||||
return adder;
|
||||
}
|
||||
|
||||
|
||||
print(makeAdder(5)(2)); # 7
|
|
@ -0,0 +1,21 @@
|
|||
# Tests shadowing of arguments and local variables
|
||||
# across functions
|
||||
import std;
|
||||
|
||||
|
||||
fn first(x: int): int {
|
||||
var y = x;
|
||||
y = y + 1;
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
fn second(x: int): int {
|
||||
var y = first(x);
|
||||
y = y + 1;
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
|
||||
print(second(0)); # 2
|
|
@ -7,4 +7,4 @@ operator `+`(a: int): int {
|
|||
|
||||
|
||||
+1; # Works: defined for int64
|
||||
+1'i32; # Will not work
|
||||
# +1'i32; # Will not work
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# Tests generic functions
|
||||
import std;
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Tests var parameters
|
||||
# Tests var parameters. TODO: They don't actually exist yet, they're just checked statically
|
||||
|
||||
import std;
|
||||
|
||||
|
|
Loading…
Reference in New Issue