Return addresses are now 64 bits long, return statements now compile to jumps, initial (broken) work on generics
This commit is contained in:
parent
807b48bac9
commit
d4d1034cef
|
@ -181,7 +181,7 @@ proc mark(self: ptr HeapObject): bool =
|
|||
return true
|
||||
|
||||
|
||||
proc markRoots(self: PeonGC): seq[ptr HeapObject] =
|
||||
proc markRoots(self: PeonGC): seq[ptr HeapObject] =
|
||||
## Marks root objects *not* to be
|
||||
## collected by the GC and returns
|
||||
## their addresses
|
||||
|
@ -433,7 +433,7 @@ proc peekc(self: PeonVM, distance: int = 0): uint64 {.used.} =
|
|||
return self.calls[self.calls.high() + distance]
|
||||
|
||||
|
||||
proc getc(self: PeonVM, idx: int): uint64 =
|
||||
proc getc(self: PeonVM, idx: int): uint64 =
|
||||
## Getter method that abstracts
|
||||
## indexing our call stack through
|
||||
## stack frames
|
||||
|
@ -474,7 +474,7 @@ proc popClosure(self: PeonVM, idx: int): uint64 =
|
|||
# Byte-level primitives to read and decode
|
||||
# bytecode
|
||||
|
||||
proc readByte(self: PeonVM): uint8 =
|
||||
proc readByte(self: PeonVM): uint8 =
|
||||
## Reads a single byte from the
|
||||
## bytecode and returns it as an
|
||||
## unsigned 8 bit integer
|
||||
|
@ -482,7 +482,7 @@ proc readByte(self: PeonVM): uint8 =
|
|||
return self.chunk.code[self.ip - 1]
|
||||
|
||||
|
||||
proc readShort(self: PeonVM): uint16 =
|
||||
proc readShort(self: PeonVM): uint16 =
|
||||
## Reads two bytes from the
|
||||
## bytecode and returns them
|
||||
## as an unsigned 16 bit
|
||||
|
@ -490,7 +490,7 @@ proc readShort(self: PeonVM): uint16 =
|
|||
return [self.readByte(), self.readByte()].fromDouble()
|
||||
|
||||
|
||||
proc readLong(self: PeonVM): uint32 =
|
||||
proc readLong(self: PeonVM): uint32 =
|
||||
## Reads three bytes from the
|
||||
## bytecode and returns them
|
||||
## as an unsigned 32 bit
|
||||
|
@ -500,7 +500,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 =
|
||||
## Reads three bytes from the
|
||||
## bytecode and returns them
|
||||
## as an unsigned 32 bit
|
||||
|
@ -511,7 +511,7 @@ proc readUInt(self: PeonVM): uint32 =
|
|||
# Functions to read primitives from the chunk's
|
||||
# constants table
|
||||
|
||||
proc constReadInt64(self: PeonVM, idx: int): int64 =
|
||||
proc constReadInt64(self: PeonVM, idx: int): int64 =
|
||||
## Reads a constant from the
|
||||
## chunk's constant table and
|
||||
## returns it as an int64
|
||||
|
@ -523,7 +523,7 @@ proc constReadInt64(self: PeonVM, idx: int): int64 =
|
|||
copyMem(result.addr, arr.addr, sizeof(arr))
|
||||
|
||||
|
||||
proc constReadUInt64(self: PeonVM, idx: int): uint64 =
|
||||
proc constReadUInt64(self: PeonVM, idx: int): uint64 =
|
||||
## Reads a constant from the
|
||||
## chunk's constant table and
|
||||
## returns it as an uint64
|
||||
|
@ -535,7 +535,7 @@ proc constReadUInt64(self: PeonVM, idx: int): uint64 =
|
|||
copyMem(result.addr, arr.addr, sizeof(arr))
|
||||
|
||||
|
||||
proc constReadUInt32(self: PeonVM, idx: int): uint32 =
|
||||
proc constReadUInt32(self: PeonVM, idx: int): uint32 =
|
||||
## Reads a constant from the
|
||||
## chunk's constant table and
|
||||
## returns it as an int32
|
||||
|
@ -544,7 +544,7 @@ proc constReadUInt32(self: PeonVM, idx: int): uint32 =
|
|||
copyMem(result.addr, arr.addr, sizeof(arr))
|
||||
|
||||
|
||||
proc constReadInt32(self: PeonVM, idx: int): int32 =
|
||||
proc constReadInt32(self: PeonVM, idx: int): int32 =
|
||||
## Reads a constant from the
|
||||
## chunk's constant table and
|
||||
## returns it as an uint32
|
||||
|
@ -553,7 +553,7 @@ proc constReadInt32(self: PeonVM, idx: int): int32 =
|
|||
copyMem(result.addr, arr.addr, sizeof(arr))
|
||||
|
||||
|
||||
proc constReadInt16(self: PeonVM, idx: int): int16 =
|
||||
proc constReadInt16(self: PeonVM, idx: int): int16 =
|
||||
## Reads a constant from the
|
||||
## chunk's constant table and
|
||||
## returns it as an int16
|
||||
|
@ -561,7 +561,7 @@ proc constReadInt16(self: PeonVM, idx: int): int16 =
|
|||
copyMem(result.addr, arr.addr, sizeof(arr))
|
||||
|
||||
|
||||
proc constReadUInt16(self: PeonVM, idx: int): uint16 =
|
||||
proc constReadUInt16(self: PeonVM, idx: int): uint16 =
|
||||
## Reads a constant from the
|
||||
## chunk's constant table and
|
||||
## returns it as an uint16
|
||||
|
@ -569,14 +569,14 @@ proc constReadUInt16(self: PeonVM, idx: int): uint16 =
|
|||
copyMem(result.addr, arr.addr, sizeof(arr))
|
||||
|
||||
|
||||
proc constReadInt8(self: PeonVM, idx: int): int8 =
|
||||
proc constReadInt8(self: PeonVM, idx: int): int8 =
|
||||
## Reads a constant from the
|
||||
## chunk's constant table and
|
||||
## returns it as an int8
|
||||
result = int8(self.chunk.consts[idx])
|
||||
|
||||
|
||||
proc constReadUInt8(self: PeonVM, idx: int): uint8 =
|
||||
proc constReadUInt8(self: PeonVM, idx: int): uint8 =
|
||||
## Reads a constant from the
|
||||
## chunk's constant table and
|
||||
## returns it as an uint8
|
||||
|
@ -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
|
@ -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()}'")
|
||||
|
|
|
@ -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
|
||||
|
@ -171,11 +170,12 @@ type
|
|||
## Coroutines
|
||||
Await, # Calls an asynchronous function
|
||||
## Misc
|
||||
Assert, # Raises an AssertionFailed exception if x is false
|
||||
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
|
||||
Assert, # Raises an AssertionFailed exception if x is false
|
||||
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
|
||||
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
|
||||
|
|
|
@ -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)
|
|
@ -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!
|
35
tests/std.pn
35
tests/std.pn
|
@ -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"]
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue