Various fixes to module system
This commit is contained in:
parent
1c54243d43
commit
9573769868
|
@ -16,9 +16,8 @@
|
|||
import std/math
|
||||
import std/segfaults
|
||||
import std/strutils
|
||||
import std/sequtils
|
||||
import std/sets
|
||||
import std/times
|
||||
import std/monotimes
|
||||
|
||||
|
||||
import ../config
|
||||
|
@ -28,6 +27,7 @@ import ../util/multibyte
|
|||
|
||||
when debugVM or debugMem or debugGC:
|
||||
import std/strformat
|
||||
import std/sequtils
|
||||
import std/terminal
|
||||
|
||||
|
||||
|
@ -58,6 +58,7 @@ type
|
|||
envs: seq[uint64] # Stores variables that do not have stack semantics
|
||||
results: seq[uint64] # Stores function's results (return values)
|
||||
gc: PeonGC # Our memory manager
|
||||
breakpoints: seq[uint64] # Breakpoints where we call our debugger
|
||||
ObjectKind* = enum
|
||||
## A tag for heap-allocated
|
||||
## peon objects
|
||||
|
@ -500,7 +501,7 @@ proc readLong(self: PeonVM): uint32 =
|
|||
return uint32([self.readByte(), self.readByte(), self.readByte()].fromTriple())
|
||||
|
||||
|
||||
proc readUInt(self: PeonVM): uint32 =
|
||||
proc readUInt(self: PeonVM): uint32 {.used.} =
|
||||
## Reads three bytes from the
|
||||
## bytecode and returns them
|
||||
## as an unsigned 32 bit
|
||||
|
@ -681,7 +682,8 @@ proc dispatch*(self: PeonVM) =
|
|||
while true:
|
||||
{.computedgoto.} # https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
|
||||
when debugVM:
|
||||
self.debug()
|
||||
if self.ip in self.breakpoints or self.breakpoints.len() == 0:
|
||||
self.debug()
|
||||
instruction = OpCode(self.readByte())
|
||||
case instruction:
|
||||
# Constant loading instructions
|
||||
|
@ -1020,19 +1022,20 @@ proc dispatch*(self: PeonVM) =
|
|||
stdout.write(s.str[i])
|
||||
stdout.write("\n")
|
||||
of SysClock64:
|
||||
self.push(cast[uint64](cpuTime()))
|
||||
self.push(cast[uint64](getMonoTime().ticks.float() / 1_000_000_000))
|
||||
of LogicalNot:
|
||||
self.push(uint64(not self.pop().bool))
|
||||
else:
|
||||
discard
|
||||
|
||||
|
||||
proc run*(self: PeonVM, chunk: Chunk) =
|
||||
proc run*(self: PeonVM, chunk: Chunk, breakpoints: seq[uint64] = @[]) =
|
||||
## Executes a piece of Peon bytecode
|
||||
self.chunk = chunk
|
||||
self.frames = @[]
|
||||
self.calls = @[]
|
||||
self.operands = @[]
|
||||
self.breakpoints = breakpoints
|
||||
self.results = @[]
|
||||
self.ip = 0
|
||||
# Sorry, but there only is enough space
|
||||
|
|
|
@ -51,6 +51,8 @@ Basic usage
|
|||
|
||||
$ peon Opens an interactive session (REPL)
|
||||
$ peon file.pn Runs the given Peon source file
|
||||
$ peon file.pbc Runs the given Peon bytecode file
|
||||
|
||||
|
||||
Command-line options
|
||||
--------------------
|
||||
|
@ -58,7 +60,7 @@ Command-line options
|
|||
-h, --help Shows this help text and exits
|
||||
-v, --version Prints the peon version number and exits
|
||||
-s, --string Executes the passed string as if it was a file
|
||||
-i, --interactive Enables interactive mode, which opens a REPL session after execution of a file or source string
|
||||
-c, --nocache Disables dumping the result of bytecode compilation to files for caching
|
||||
-d, --cache-delay Configures the bytecode cache invalidation threshold, in minutes (defaults to 60)
|
||||
-i, --interactive Enables interactive mode: a REPL session is opened after execution
|
||||
-d, --nodump Disables dumping the result of bytecode compilation to files
|
||||
-b, --breakpoints Pauses execution of the peon virtual machine and runs the debugger at specific bytecode offsets
|
||||
"""
|
||||
|
|
|
@ -558,7 +558,9 @@ proc getStackPos(self: Compiler, name: Name): int =
|
|||
var found = false
|
||||
result = 2
|
||||
for variable in self.names:
|
||||
if variable.kind notin [NameKind.Var, NameKind.Argument]:
|
||||
if variable.kind in [NameKind.Module, NameKind.CustomType, NameKind.Enum, NameKind.Function]:
|
||||
continue
|
||||
elif variable.kind == NameKind.Argument and variable.depth > self.scopeDepth:
|
||||
continue
|
||||
elif not variable.belongsTo.isNil() and variable.belongsTo.valueType.isBuiltinFunction:
|
||||
continue
|
||||
|
@ -566,12 +568,11 @@ proc getStackPos(self: Compiler, name: Name): int =
|
|||
continue
|
||||
elif variable.owner != self.currentModule:
|
||||
continue
|
||||
if variable.depth > self.scopeDepth:
|
||||
continue
|
||||
if name.ident == variable.ident:
|
||||
found = true
|
||||
break
|
||||
inc(result)
|
||||
echo variable
|
||||
if not found:
|
||||
return -1
|
||||
|
||||
|
@ -1223,7 +1224,7 @@ proc declareName(self: Compiler, node: ASTNode, mutable: bool = false): Name =
|
|||
))
|
||||
if mutable:
|
||||
self.names[^1].valueType.mutable = true
|
||||
return self.names[^1]
|
||||
result = self.names[^1]
|
||||
of NodeKind.funDecl:
|
||||
var node = FunDecl(node)
|
||||
var generics: seq[Name] = @[]
|
||||
|
@ -1266,12 +1267,12 @@ proc declareName(self: Compiler, node: ASTNode, mutable: bool = false): Name =
|
|||
# wait, no LoadVar? Yes! That's because when calling functions,
|
||||
# arguments will already be on the stack, so there's no need to
|
||||
# load them here
|
||||
name = Name(depth: self.scopeDepth + 1,
|
||||
name = Name(depth: fn.depth + 1,
|
||||
isPrivate: true,
|
||||
owner: self.currentModule,
|
||||
isConst: false,
|
||||
ident: argument.name,
|
||||
valueType: nil,
|
||||
valueType: self.infer(argument.valueType),
|
||||
codePos: 0,
|
||||
isLet: false,
|
||||
line: argument.name.token.line,
|
||||
|
@ -1279,14 +1280,13 @@ proc declareName(self: Compiler, node: ASTNode, mutable: bool = false): Name =
|
|||
kind: NameKind.Argument
|
||||
)
|
||||
self.names.add(name)
|
||||
name.valueType = self.infer(argument.valueType)
|
||||
# If it's still nil, it's an error!
|
||||
# If it's nil, it's an error!
|
||||
if name.valueType.isNil():
|
||||
self.error(&"cannot determine the type of argument '{argument.name.token.lexeme}'", argument.name)
|
||||
fn.valueType.args.add((argument.name.token.lexeme, name.valueType))
|
||||
if generics.len() > 0:
|
||||
fn.valueType.isGeneric = true
|
||||
return fn
|
||||
result = fn
|
||||
of NodeKind.importStmt:
|
||||
var node = ImportStmt(node)
|
||||
var name = node.moduleName.token.lexeme.extractFilename().replace(".pn", "")
|
||||
|
@ -1301,12 +1301,14 @@ proc declareName(self: Compiler, node: ASTNode, mutable: bool = false): Name =
|
|||
kind: NameKind.Module,
|
||||
isPrivate: false
|
||||
))
|
||||
return self.names[^1]
|
||||
result = self.names[^1]
|
||||
else:
|
||||
discard # TODO: Types, enums
|
||||
for name in self.findByName(declaredName):
|
||||
if (name.kind == NameKind.Var and name.depth == self.scopeDepth) or name.kind in [NameKind.Module, NameKind.CustomType, NameKind.Enum]:
|
||||
self.error(&"attempt to redeclare '{name}', which was previously defined in '{name.owner}' at line {name.line}")
|
||||
if name == result:
|
||||
continue
|
||||
elif (name.kind == NameKind.Var and name.depth == self.scopeDepth) 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}")
|
||||
|
||||
|
||||
proc emitLoop(self: Compiler, begin: int, line: int) =
|
||||
|
@ -1746,7 +1748,7 @@ proc specialize(self: Compiler, name: Name, args: seq[Expression]): Name =
|
|||
for (argExpr, argName) in zip(args, result.valueType.args):
|
||||
if self.names.high() > 16777215:
|
||||
self.error("cannot declare more than 16777215 variables at a time")
|
||||
self.names.add(Name(depth: self.scopeDepth + 1,
|
||||
self.names.add(Name(depth: name.depth + 1,
|
||||
isPrivate: true,
|
||||
owner: self.currentModule,
|
||||
isConst: false,
|
||||
|
|
41
src/main.nim
41
src/main.nim
|
@ -191,7 +191,7 @@ proc repl =
|
|||
quit(0)
|
||||
|
||||
|
||||
proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
|
||||
proc runFile(f: string, interactive: bool = false, fromString: bool = false, dump: bool = true, breakpoints: seq[uint64] = @[]) =
|
||||
var
|
||||
tokens: seq[Token] = @[]
|
||||
tree: seq[Declaration] = @[]
|
||||
|
@ -242,10 +242,11 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
|
|||
if path.len() > 0:
|
||||
path &= "/"
|
||||
path &= splitFile(f).name & ".pbc"
|
||||
serializer.dumpFile(compiled, f, path)
|
||||
serialized = serializer.loadFile(path)
|
||||
if fromString:
|
||||
discard tryRemoveFile("<string>.pbc")
|
||||
if dump or not fromString:
|
||||
serializer.dumpFile(compiled, f, path)
|
||||
serialized = serializer.loadFile(path)
|
||||
else:
|
||||
serialized = serializer.loadBytes(serializer.dumpBytes(compiled, f))
|
||||
when debugSerializer:
|
||||
styledEcho fgCyan, "Serialization step: "
|
||||
styledEcho fgBlue, "\t- Peon version: ", fgYellow, &"{serialized.version.major}.{serialized.version.minor}.{serialized.version.patch}", fgBlue, " (commit ", fgYellow, serialized.commit[0..8], fgBlue, ") on branch ", fgYellow, serialized.branch
|
||||
|
@ -270,7 +271,7 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
|
|||
styledEcho fgGreen, "OK"
|
||||
else:
|
||||
styledEcho fgRed, "Corrupted"
|
||||
vm.run(serialized.chunk)
|
||||
vm.run(serialized.chunk, breakpoints)
|
||||
except LexingError:
|
||||
var exc = LexingError(getCurrentException())
|
||||
let relPos = exc.lexer.getRelPos(exc.line)
|
||||
|
@ -326,6 +327,8 @@ when isMainModule:
|
|||
var file: string = ""
|
||||
var fromString: bool = false
|
||||
var interactive: bool = false
|
||||
var dump: bool = true
|
||||
var breaks: seq[uint64] = @[]
|
||||
for kind, key, value in optParser.getopt():
|
||||
case kind:
|
||||
of cmdArgument:
|
||||
|
@ -343,6 +346,18 @@ when isMainModule:
|
|||
fromString = true
|
||||
of "interactive":
|
||||
interactive = true
|
||||
of "no-dump":
|
||||
dump = false
|
||||
of "breakpoints":
|
||||
when not debugVM:
|
||||
echo "error: cannot set breakpoints in release mode"
|
||||
quit()
|
||||
for point in value.strip(chars={' '}).split(","):
|
||||
try:
|
||||
breaks.add(parseBiggestUInt(point))
|
||||
except ValueError:
|
||||
echo &"error: invalid breakpoint value '{point}'"
|
||||
quit()
|
||||
else:
|
||||
echo &"error: unkown option '{key}'"
|
||||
quit()
|
||||
|
@ -359,6 +374,18 @@ when isMainModule:
|
|||
fromString = true
|
||||
of "i":
|
||||
interactive = true
|
||||
of "d":
|
||||
dump = false
|
||||
of "b":
|
||||
when not debugVM:
|
||||
echo "error: cannot set breakpoints in release mode"
|
||||
quit()
|
||||
for point in value.strip(chars={' '}).split(","):
|
||||
try:
|
||||
breaks.add(parseBiggestUInt(point))
|
||||
except ValueError:
|
||||
echo &"error: invalid breakpoint value '{point}'"
|
||||
quit()
|
||||
else:
|
||||
echo &"error: unkown option '{key}'"
|
||||
quit()
|
||||
|
@ -369,7 +396,7 @@ when isMainModule:
|
|||
if file == "":
|
||||
repl()
|
||||
else:
|
||||
runFile(file, interactive, fromString)
|
||||
runFile(file, interactive, fromString, dump, breaks)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
# Assignment operators
|
||||
# Various miscellaneous utilities
|
||||
|
||||
# Assignment operator
|
||||
|
||||
operator `=`*[T: all](a: var T, b: T) { # TODO: This is just a placeholder right now
|
||||
#pragma[magic: "GenericAssign"]
|
||||
|
|
|
@ -11,6 +11,6 @@ fn fib(n: int): int {
|
|||
|
||||
print("Computing the value of fib(37)");
|
||||
var x = clock();
|
||||
print(fib(37));
|
||||
print(fib(33));
|
||||
print(clock() - x);
|
||||
print("Done!");
|
||||
|
|
|
@ -6,6 +6,6 @@ fn sum[T: int | int32](a, b: T): T {
|
|||
}
|
||||
|
||||
|
||||
print(sum(1, 2));
|
||||
print(sum(1'i32, 2'i32));
|
||||
print(sum(1, 2)); # Prints 3
|
||||
print(sum(1'i32, 2'i32)); # Also prints 3!
|
||||
# print(sum(1'i16, 2'i16)); # Will not work if uncommented!
|
||||
|
|
Loading…
Reference in New Issue