Return addresses are now 64 bits long, return statements now compile to jumps, initial (broken) work on generics

This commit is contained in:
Mattia Giambirtone 2022-10-13 13:12:24 +02:00
parent 807b48bac9
commit d4d1034cef
7 changed files with 460 additions and 396 deletions

View File

@ -628,7 +628,7 @@ when debugVM: # So nim shuts up
stdout.styledWrite(fgGreen, "Call Stack: ", fgMagenta, "[")
for i, e in self.calls:
stdout.styledWrite(fgYellow, $e)
if i < self.calls.len():
if i < self.calls.high():
stdout.styledWrite(fgYellow, ", ")
styledEcho fgMagenta, "]"
if self.operands.len() !> 0:
@ -724,7 +724,7 @@ proc dispatch*(self: PeonVM) =
# Calls a peon function. The calling convention here
# is pretty simple: the first value in the frame is
# the new instruction pointer to jump to, then a
# 32-bit return address follows. After that, all
# 64-bit return address follows. After that, all
# arguments and locals follow. Note that, due to
# how the stack works, all arguments before the call
# are in the reverse order in which they are passed
@ -780,10 +780,6 @@ proc dispatch*(self: PeonVM) =
# in a hidden function, so this
# will also exit the VM if we're
# at the end of the program
while self.calls.len().uint64 !> self.frames[^1] + 2'u64:
# Discards the function's local variables,
# if there is any
discard self.popc()
let ret = self.popc() # Return address
discard self.popc() # Function address
if self.readByte() == 1:
@ -796,7 +792,12 @@ proc dispatch*(self: PeonVM) =
if self.frames.len() == 0:
# End of the program!
return
self.ip = ret.uint
# We change the instruction
# pointer just now because
# if we did it beforehand,
# our readByte() call would've
# read from the wrong offset
self.ip = ret
of SetResult:
# Sets the result of the
# current function. A Return
@ -1023,6 +1024,8 @@ proc dispatch*(self: PeonVM) =
# cannot be converted to a date. The number
# is in seconds
self.push(cast[uint64](getMonoTime().ticks().float() / 1_000_000_000))
of LogicalNot:
self.push(uint64(not self.pop().bool))
else:
discard

File diff suppressed because it is too large Load Diff

View File

@ -530,7 +530,7 @@ proc parseBackticks(self: Lexer) =
## parser complaining about syntax
## errors
while not self.match("`") and not self.done():
if self.peek().isAlphaNumeric() or self.symbols.existsSymbol(self.peek()) or self.peek() in ["&", "|"]:
if self.peek().isAlphaNumeric() or self.symbols.existsSymbol(self.peek()):
discard self.step()
continue
self.error(&"unexpected character: '{self.peek()}'")

View File

@ -147,7 +147,6 @@ type
StoreVar, # Stores the value of b at position a in the stack
LoadClosure, # Pushes the object position x in the closure array onto the stack
StoreClosure, # Stores the value of b at position a in the closure array
LiftArgument, # Closes over a function argument
PopClosure,
## Looping and jumping
Jump, # Absolute, unconditional jump into the bytecode
@ -175,7 +174,8 @@ type
NoOp, # Just a no-op
PopC, # Pop off the call stack onto the operand stack
PushC, # Pop off the operand stack onto the call stack
SysClock64 # Pushes the output of a monotonic clock on the stack
SysClock64, # Pushes the output of a monotonic clock on the stack
LogicalNot
# We group instructions by their operation/operand types for easier handling when debugging
@ -239,6 +239,7 @@ const simpleInstructions* = {Return, LoadNil,
PrintNan,
PrintInf,
PrintString,
LogicalNot
}
# Constant instructions are instructions that operate on the bytecode constant table
@ -251,7 +252,7 @@ const constantInstructions* = {LoadInt64, LoadUInt64,
# Stack triple instructions operate on the stack at arbitrary offsets and pop arguments off of it in the form
# of 24 bit integers
const stackTripleInstructions* = {StoreVar, LoadVar, LoadCLosure, LiftArgument, PopClosure}
const stackTripleInstructions* = {StoreVar, LoadVar, LoadCLosure, PopClosure}
# Stack double instructions operate on the stack at arbitrary offsets and pop arguments off of it in the form
# of 16 bit integers

View File

@ -59,5 +59,5 @@ proc fillSymbolTable*(tokenizer: Lexer) =
tokenizer.symbols.addKeyword("ref", TokenType.Ref)
tokenizer.symbols.addKeyword("ptr", TokenType.Ptr)
for sym in [">", "<", "=", "~", "/", "+", "-", "_", "*", "?", "@", ":", "==", "!=",
">=", "<=", "+=", "-=", "/=", "*=", "**=", "!", "%"]:
">=", "<=", "+=", "-=", "/=", "*=", "**=", "!", "%", "&", "|", "^"]:
tokenizer.symbols.addSymbol(sym, Symbol)

View File

@ -1,18 +1,11 @@
import std;
operator `+`(a, b: int): int {
#pragma[magic: "AddInt64", pure]
}
operator `+`(a, b: int32): int32 {
#pragma[magic: "AddInt64", pure]
}
fn sum[T: int | int32](a, b: T): T {
return a + b;
}
sum(1, 2);
sum(1'i32, 2'i32);
# print(sum(1, 2));
# print(sum(1'i32, 2'i32));
print(sum(1'i16, 2'i16)); # Will not work if uncommented!

View File

@ -535,19 +535,44 @@ operator `or`*(a, b: bool): bool {
}
operator `&`*(a, b: bool): bool {
#pragma[magic: "LogicalAnd", pure]
operator `not`*(a: bool): bool {
#pragma[magic: "LogicalNot", pure]
}
operator `|`*(a, b: bool): bool {
#pragma[magic: "LogicalOr", pure]
operator `&`*(a, b: int): bool {
#pragma[magic: "And", pure]
}
operator `|`*(a, b: int): int {
#pragma[magic: "Or", pure]
}
operator `~`*(a: int): int {
#pragma[magic: "Not", pure]
}
operator `>>`*(a, b: int): int {
#pragma[magic: "RShift", pure]
}
operator `<<`*(a, b: int): int {
#pragma[magic: "LShift", pure]
}
operator `^`*(a, b: int): int {
#pragma[magic: "Xor", pure]
}
# Assignment operators
operator `=`*[T: Any](a: var T, b: T) {
operator `=`*[T: all](a: var T, b: T) {
#pragma[magic: "GenericAssign"]
}