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
|
return true
|
||||||
|
|
||||||
|
|
||||||
proc markRoots(self: PeonGC): seq[ptr HeapObject] =
|
proc markRoots(self: PeonGC): seq[ptr HeapObject] =
|
||||||
## Marks root objects *not* to be
|
## Marks root objects *not* to be
|
||||||
## collected by the GC and returns
|
## collected by the GC and returns
|
||||||
## their addresses
|
## their addresses
|
||||||
|
@ -433,7 +433,7 @@ proc peekc(self: PeonVM, distance: int = 0): uint64 {.used.} =
|
||||||
return self.calls[self.calls.high() + distance]
|
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
|
## Getter method that abstracts
|
||||||
## indexing our call stack through
|
## indexing our call stack through
|
||||||
## stack frames
|
## stack frames
|
||||||
|
@ -474,7 +474,7 @@ proc popClosure(self: PeonVM, idx: int): uint64 =
|
||||||
# Byte-level primitives to read and decode
|
# Byte-level primitives to read and decode
|
||||||
# bytecode
|
# bytecode
|
||||||
|
|
||||||
proc readByte(self: PeonVM): uint8 =
|
proc readByte(self: PeonVM): uint8 =
|
||||||
## Reads a single byte from the
|
## Reads a single byte from the
|
||||||
## bytecode and returns it as an
|
## bytecode and returns it as an
|
||||||
## unsigned 8 bit integer
|
## unsigned 8 bit integer
|
||||||
|
@ -482,7 +482,7 @@ proc readByte(self: PeonVM): uint8 =
|
||||||
return self.chunk.code[self.ip - 1]
|
return self.chunk.code[self.ip - 1]
|
||||||
|
|
||||||
|
|
||||||
proc readShort(self: PeonVM): uint16 =
|
proc readShort(self: PeonVM): uint16 =
|
||||||
## Reads two bytes from the
|
## Reads two bytes from the
|
||||||
## bytecode and returns them
|
## bytecode and returns them
|
||||||
## as an unsigned 16 bit
|
## as an unsigned 16 bit
|
||||||
|
@ -490,7 +490,7 @@ proc readShort(self: PeonVM): uint16 =
|
||||||
return [self.readByte(), self.readByte()].fromDouble()
|
return [self.readByte(), self.readByte()].fromDouble()
|
||||||
|
|
||||||
|
|
||||||
proc readLong(self: PeonVM): uint32 =
|
proc readLong(self: PeonVM): uint32 =
|
||||||
## Reads three bytes from the
|
## Reads three bytes from the
|
||||||
## bytecode and returns them
|
## bytecode and returns them
|
||||||
## as an unsigned 32 bit
|
## as an unsigned 32 bit
|
||||||
|
@ -500,7 +500,7 @@ proc readLong(self: PeonVM): uint32 =
|
||||||
return uint32([self.readByte(), self.readByte(), self.readByte()].fromTriple())
|
return uint32([self.readByte(), self.readByte(), self.readByte()].fromTriple())
|
||||||
|
|
||||||
|
|
||||||
proc readUInt(self: PeonVM): uint32 =
|
proc readUInt(self: PeonVM): uint32 =
|
||||||
## Reads three bytes from the
|
## Reads three bytes from the
|
||||||
## bytecode and returns them
|
## bytecode and returns them
|
||||||
## as an unsigned 32 bit
|
## as an unsigned 32 bit
|
||||||
|
@ -511,7 +511,7 @@ proc readUInt(self: PeonVM): uint32 =
|
||||||
# Functions to read primitives from the chunk's
|
# Functions to read primitives from the chunk's
|
||||||
# constants table
|
# constants table
|
||||||
|
|
||||||
proc constReadInt64(self: PeonVM, idx: int): int64 =
|
proc constReadInt64(self: PeonVM, idx: int): int64 =
|
||||||
## Reads a constant from the
|
## Reads a constant from the
|
||||||
## chunk's constant table and
|
## chunk's constant table and
|
||||||
## returns it as an int64
|
## returns it as an int64
|
||||||
|
@ -523,7 +523,7 @@ proc constReadInt64(self: PeonVM, idx: int): int64 =
|
||||||
copyMem(result.addr, arr.addr, sizeof(arr))
|
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
|
## Reads a constant from the
|
||||||
## chunk's constant table and
|
## chunk's constant table and
|
||||||
## returns it as an uint64
|
## returns it as an uint64
|
||||||
|
@ -535,7 +535,7 @@ proc constReadUInt64(self: PeonVM, idx: int): uint64 =
|
||||||
copyMem(result.addr, arr.addr, sizeof(arr))
|
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
|
## Reads a constant from the
|
||||||
## chunk's constant table and
|
## chunk's constant table and
|
||||||
## returns it as an int32
|
## returns it as an int32
|
||||||
|
@ -544,7 +544,7 @@ proc constReadUInt32(self: PeonVM, idx: int): uint32 =
|
||||||
copyMem(result.addr, arr.addr, sizeof(arr))
|
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
|
## Reads a constant from the
|
||||||
## chunk's constant table and
|
## chunk's constant table and
|
||||||
## returns it as an uint32
|
## returns it as an uint32
|
||||||
|
@ -553,7 +553,7 @@ proc constReadInt32(self: PeonVM, idx: int): int32 =
|
||||||
copyMem(result.addr, arr.addr, sizeof(arr))
|
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
|
## Reads a constant from the
|
||||||
## chunk's constant table and
|
## chunk's constant table and
|
||||||
## returns it as an int16
|
## returns it as an int16
|
||||||
|
@ -561,7 +561,7 @@ proc constReadInt16(self: PeonVM, idx: int): int16 =
|
||||||
copyMem(result.addr, arr.addr, sizeof(arr))
|
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
|
## Reads a constant from the
|
||||||
## chunk's constant table and
|
## chunk's constant table and
|
||||||
## returns it as an uint16
|
## returns it as an uint16
|
||||||
|
@ -569,14 +569,14 @@ proc constReadUInt16(self: PeonVM, idx: int): uint16 =
|
||||||
copyMem(result.addr, arr.addr, sizeof(arr))
|
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
|
## Reads a constant from the
|
||||||
## chunk's constant table and
|
## chunk's constant table and
|
||||||
## returns it as an int8
|
## returns it as an int8
|
||||||
result = int8(self.chunk.consts[idx])
|
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
|
## Reads a constant from the
|
||||||
## chunk's constant table and
|
## chunk's constant table and
|
||||||
## returns it as an uint8
|
## returns it as an uint8
|
||||||
|
@ -628,7 +628,7 @@ when debugVM: # So nim shuts up
|
||||||
stdout.styledWrite(fgGreen, "Call Stack: ", fgMagenta, "[")
|
stdout.styledWrite(fgGreen, "Call Stack: ", fgMagenta, "[")
|
||||||
for i, e in self.calls:
|
for i, e in self.calls:
|
||||||
stdout.styledWrite(fgYellow, $e)
|
stdout.styledWrite(fgYellow, $e)
|
||||||
if i < self.calls.len():
|
if i < self.calls.high():
|
||||||
stdout.styledWrite(fgYellow, ", ")
|
stdout.styledWrite(fgYellow, ", ")
|
||||||
styledEcho fgMagenta, "]"
|
styledEcho fgMagenta, "]"
|
||||||
if self.operands.len() !> 0:
|
if self.operands.len() !> 0:
|
||||||
|
@ -724,7 +724,7 @@ proc dispatch*(self: PeonVM) =
|
||||||
# Calls a peon function. The calling convention here
|
# Calls a peon function. The calling convention here
|
||||||
# is pretty simple: the first value in the frame is
|
# is pretty simple: the first value in the frame is
|
||||||
# the new instruction pointer to jump to, then a
|
# 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
|
# arguments and locals follow. Note that, due to
|
||||||
# how the stack works, all arguments before the call
|
# how the stack works, all arguments before the call
|
||||||
# are in the reverse order in which they are passed
|
# are in the reverse order in which they are passed
|
||||||
|
@ -780,10 +780,6 @@ proc dispatch*(self: PeonVM) =
|
||||||
# in a hidden function, so this
|
# in a hidden function, so this
|
||||||
# will also exit the VM if we're
|
# will also exit the VM if we're
|
||||||
# at the end of the program
|
# 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
|
let ret = self.popc() # Return address
|
||||||
discard self.popc() # Function address
|
discard self.popc() # Function address
|
||||||
if self.readByte() == 1:
|
if self.readByte() == 1:
|
||||||
|
@ -796,7 +792,12 @@ proc dispatch*(self: PeonVM) =
|
||||||
if self.frames.len() == 0:
|
if self.frames.len() == 0:
|
||||||
# End of the program!
|
# End of the program!
|
||||||
return
|
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:
|
of SetResult:
|
||||||
# Sets the result of the
|
# Sets the result of the
|
||||||
# current function. A Return
|
# current function. A Return
|
||||||
|
@ -1023,6 +1024,8 @@ proc dispatch*(self: PeonVM) =
|
||||||
# cannot be converted to a date. The number
|
# cannot be converted to a date. The number
|
||||||
# is in seconds
|
# is in seconds
|
||||||
self.push(cast[uint64](getMonoTime().ticks().float() / 1_000_000_000))
|
self.push(cast[uint64](getMonoTime().ticks().float() / 1_000_000_000))
|
||||||
|
of LogicalNot:
|
||||||
|
self.push(uint64(not self.pop().bool))
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -530,7 +530,7 @@ proc parseBackticks(self: Lexer) =
|
||||||
## parser complaining about syntax
|
## parser complaining about syntax
|
||||||
## errors
|
## errors
|
||||||
while not self.match("`") and not self.done():
|
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()
|
discard self.step()
|
||||||
continue
|
continue
|
||||||
self.error(&"unexpected character: '{self.peek()}'")
|
self.error(&"unexpected character: '{self.peek()}'")
|
||||||
|
|
|
@ -147,7 +147,6 @@ type
|
||||||
StoreVar, # Stores the value of b at position a in the stack
|
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
|
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
|
StoreClosure, # Stores the value of b at position a in the closure array
|
||||||
LiftArgument, # Closes over a function argument
|
|
||||||
PopClosure,
|
PopClosure,
|
||||||
## Looping and jumping
|
## Looping and jumping
|
||||||
Jump, # Absolute, unconditional jump into the bytecode
|
Jump, # Absolute, unconditional jump into the bytecode
|
||||||
|
@ -171,11 +170,12 @@ type
|
||||||
## Coroutines
|
## Coroutines
|
||||||
Await, # Calls an asynchronous function
|
Await, # Calls an asynchronous function
|
||||||
## Misc
|
## Misc
|
||||||
Assert, # Raises an AssertionFailed exception if x is false
|
Assert, # Raises an AssertionFailed exception if x is false
|
||||||
NoOp, # Just a no-op
|
NoOp, # Just a no-op
|
||||||
PopC, # Pop off the call stack onto the operand stack
|
PopC, # Pop off the call stack onto the operand stack
|
||||||
PushC, # Pop off the operand stack onto the call 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
|
# We group instructions by their operation/operand types for easier handling when debugging
|
||||||
|
@ -239,6 +239,7 @@ const simpleInstructions* = {Return, LoadNil,
|
||||||
PrintNan,
|
PrintNan,
|
||||||
PrintInf,
|
PrintInf,
|
||||||
PrintString,
|
PrintString,
|
||||||
|
LogicalNot
|
||||||
}
|
}
|
||||||
|
|
||||||
# Constant instructions are instructions that operate on the bytecode constant table
|
# 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
|
# Stack triple instructions operate on the stack at arbitrary offsets and pop arguments off of it in the form
|
||||||
# of 24 bit integers
|
# 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
|
# Stack double instructions operate on the stack at arbitrary offsets and pop arguments off of it in the form
|
||||||
# of 16 bit integers
|
# of 16 bit integers
|
||||||
|
|
|
@ -59,5 +59,5 @@ proc fillSymbolTable*(tokenizer: Lexer) =
|
||||||
tokenizer.symbols.addKeyword("ref", TokenType.Ref)
|
tokenizer.symbols.addKeyword("ref", TokenType.Ref)
|
||||||
tokenizer.symbols.addKeyword("ptr", TokenType.Ptr)
|
tokenizer.symbols.addKeyword("ptr", TokenType.Ptr)
|
||||||
for sym in [">", "<", "=", "~", "/", "+", "-", "_", "*", "?", "@", ":", "==", "!=",
|
for sym in [">", "<", "=", "~", "/", "+", "-", "_", "*", "?", "@", ":", "==", "!=",
|
||||||
">=", "<=", "+=", "-=", "/=", "*=", "**=", "!", "%"]:
|
">=", "<=", "+=", "-=", "/=", "*=", "**=", "!", "%", "&", "|", "^"]:
|
||||||
tokenizer.symbols.addSymbol(sym, Symbol)
|
tokenizer.symbols.addSymbol(sym, Symbol)
|
|
@ -1,18 +1,11 @@
|
||||||
import std;
|
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 {
|
fn sum[T: int | int32](a, b: T): T {
|
||||||
return a + b;
|
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 {
|
operator `not`*(a: bool): bool {
|
||||||
#pragma[magic: "LogicalAnd", pure]
|
#pragma[magic: "LogicalNot", pure]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator `|`*(a, b: bool): bool {
|
operator `&`*(a, b: int): bool {
|
||||||
#pragma[magic: "LogicalOr", pure]
|
#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
|
# Assignment operators
|
||||||
|
|
||||||
operator `=`*[T: Any](a: var T, b: T) {
|
operator `=`*[T: all](a: var T, b: T) {
|
||||||
#pragma[magic: "GenericAssign"]
|
#pragma[magic: "GenericAssign"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue