Various fixes to module system

This commit is contained in:
Mattia Giambirtone 2022-10-21 16:10:00 +02:00
parent 1c54243d43
commit 9573769868
7 changed files with 69 additions and 33 deletions

View File

@ -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

View File

@ -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
"""

View File

@ -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,

View File

@ -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)

View File

@ -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"]

View File

@ -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!");

View File

@ -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!