natives
This commit is contained in:
parent
d5479a0be7
commit
9dc429c92d
|
@ -7,7 +7,7 @@ proc genAssignIncr100k =
|
|||
var src = "var x = 0;\n"
|
||||
for i in countup(0, 99999):
|
||||
src &= "x = x + 1;\n"
|
||||
src &= "print x;\n"
|
||||
src &= "print (x);\n"
|
||||
path.writeFile(src)
|
||||
|
||||
genAssignIncr100k()
|
|
@ -11,4 +11,4 @@ while (i < 50000) {
|
|||
res = res + fact(50);
|
||||
i = i + 1;
|
||||
};
|
||||
print res;
|
||||
print (res);
|
||||
|
|
|
@ -3,4 +3,4 @@ var fib = funct(n)
|
|||
else :result = fib(n-1) + fib(n-2)
|
||||
;
|
||||
|
||||
print fib(37);
|
||||
print (fib(37));
|
|
@ -3,7 +3,7 @@ var main = funct() {
|
|||
var src = ">++++++++++[<++++++++++>-]<->>>>>+++[>+++>+++<<-]<<<<+<[>[>+>+<<-]>>[-<<+>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]>>>>>>[[-]<++++++++++<->>]<-[>+>+<<-]>[<+>-]+>[[-]<->]<<<<<<<<<->>]<[>+>+<<-]>>[-<<+>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+>+<<<-]>>>[-<<<+>>>]++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<<[>>+>+<<<-]>>>[-<<<+>>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<[[-]>>>++++++++[>>++++++<<-]>[<++++++++[>++++++<-]>.<++++++++[>------<-]>[<<+>>-]]>.<<++++++++[>>------<<-]<[->>+<<]<++++++++[<++++>-]<.>+++++++[>+++++++++<-]>+++.<+++++[>+++++++++<-]>.+++++..--------.-------.++++++++++++++>>[>>>+>+<<<<-]>>>>[-<<<<+>>>>]>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<<[>>>+>+<<<<-]>>>>[-<<<<+>>>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+<<[-]]>[>+<[-]]++>>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<+<[[-]>-<]>[<<<<<<<.>>>>>>>[-]]<<<<<<<<<.>>----.---------.<<.>>----.+++..+++++++++++++.[-]<<[-]]<[>+>+<<-]>>[-<<+>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+>+<<<-]>>>[-<<<+>>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<[[-]>++++++++[<++++>-]<.>++++++++++[>+++++++++++<-]>+.-.<<.>>++++++.------------.---.<<.>++++++[>+++<-]>.<++++++[>----<-]>++.+++++++++++..[-]<<[-]++++++++++.[-]]<[>+>+<<-]>>[-<<+>>]+++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]++++++++++. >+++++++++[>+++++++++<-]>+++.+++++++++++++.++++++++++.------.<++++++++[>>++++<<-]>>.<++++++++++.-.---------.>.<-.+++++++++++.++++++++.---------.>.<-------------.+++++++++++++.----------.>.<++++++++++++.---------------.<+++[>++++++<-]>..>.<----------.+++++++++++.>.<<+++[>------<-]>-.+++++++++++++++++.---.++++++.-------.----------.[-]>[-]<<<.[-]]<[>+>+<<-]>>[-<<+>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]++++++++++.[-]<[-]>]<+<]";
|
||||
var pos = 0;
|
||||
var len = #src;
|
||||
var char;
|
||||
var chr;
|
||||
var depth = 0;
|
||||
|
||||
// input
|
||||
|
@ -23,55 +23,55 @@ var main = funct() {
|
|||
|
||||
{ @mainloop
|
||||
while (pos < len) {
|
||||
char = src[pos];
|
||||
chr = src[pos];
|
||||
|
||||
if (char == "<")
|
||||
if (chr == "<")
|
||||
if (ptr > 0)
|
||||
ptr = ptr - 1
|
||||
else
|
||||
ptr = ptrmax
|
||||
;
|
||||
|
||||
if (char == ">")
|
||||
if (chr == ">")
|
||||
if (ptr < ptrmax)
|
||||
ptr = ptr + 1
|
||||
else
|
||||
ptr = 0
|
||||
;
|
||||
|
||||
if (char == "+")
|
||||
if (chr == "+")
|
||||
if (tape[ptr] < 255)
|
||||
tape[ptr] = tape[ptr] + 1
|
||||
else
|
||||
tape[ptr] = 0
|
||||
;
|
||||
|
||||
if (char == "-")
|
||||
if (chr == "-")
|
||||
if (tape[ptr] > 0)
|
||||
tape[ptr] = tape[ptr] - 1
|
||||
else
|
||||
tape[ptr] = 255
|
||||
;
|
||||
|
||||
if (char == ".")
|
||||
write(chr(tape[ptr]))
|
||||
if (chr == ".")
|
||||
write(char(tape[ptr]))
|
||||
;
|
||||
|
||||
if (char == ",") {
|
||||
tape[ptr] = int(input[inppos]);
|
||||
if (chr == ",") {
|
||||
tape[ptr] = byte(input[inppos]);
|
||||
inppos = inppos + 1;
|
||||
};
|
||||
|
||||
if (char == "[") {
|
||||
if (chr == "[") {
|
||||
if (tape[ptr] == 0) {
|
||||
depth = depth + 1;
|
||||
while (depth > 0) {
|
||||
pos = pos + 1;
|
||||
char = src[pos];
|
||||
chr = src[pos];
|
||||
depth = depth +
|
||||
if (char == "[")
|
||||
if (chr == "[")
|
||||
1
|
||||
else if (char == "]")
|
||||
else if (chr == "]")
|
||||
-1
|
||||
else
|
||||
0
|
||||
|
@ -80,16 +80,16 @@ var main = funct() {
|
|||
};
|
||||
};
|
||||
|
||||
if (char == "]") {
|
||||
if (chr == "]") {
|
||||
if (tape[ptr] != 0) {
|
||||
depth = depth + 1;
|
||||
while (depth > 0) {
|
||||
pos = pos - 1;
|
||||
char = src[pos];
|
||||
chr = src[pos];
|
||||
depth = depth +
|
||||
if (char == "]")
|
||||
if (chr == "]")
|
||||
1
|
||||
else if (char == "[")
|
||||
else if (chr == "[")
|
||||
-1
|
||||
else
|
||||
0
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
var argcap = funct(n)
|
||||
:result = funct() print n
|
||||
;
|
||||
|
||||
argcap(5)();
|
|
@ -19,7 +19,6 @@ type
|
|||
opJumpIfFalse, opJump, opLoop, opJumpIfFalsePop, # jumps
|
||||
opCreateList, opCreateTable, # collection creation
|
||||
opLen, opSetIndex, opGetIndex, # collection operators
|
||||
opPrint, opChr, opInt, opPutchar, # temporary opcodes for the brainfuck interpreter TODO move to native funcs
|
||||
|
||||
Chunk* = object
|
||||
code*: seq[uint8]
|
||||
|
@ -92,13 +91,11 @@ proc writeConstant*(ch: var Chunk, constant: NdValue, line: int): int =
|
|||
const simpleInstructions = {
|
||||
opReturn,
|
||||
opPop,
|
||||
opPrint,
|
||||
opNegate, opNot,
|
||||
opAdd, opSubtract, opMultiply, opDivide,
|
||||
opEqual, opGreater, opLess,
|
||||
opTrue, opFalse, opNil,
|
||||
opLen, opSetIndex, opGetIndex,
|
||||
opChr, opInt, opPutchar,
|
||||
}
|
||||
const constantInstructions = {
|
||||
opConstant,
|
||||
|
|
|
@ -551,19 +551,10 @@ proc unary(comp: Compiler) =
|
|||
comp.writeChunk(0, opNegate)
|
||||
of tkBang:
|
||||
comp.writeChunk(0, opNot)
|
||||
of tkInt:
|
||||
comp.writeChunk(0, opInt)
|
||||
of tkChr:
|
||||
comp.writeChunk(0, opChr)
|
||||
of tkPutch:
|
||||
comp.writeChunk(0, opPutchar)
|
||||
else:
|
||||
discard # unreachable
|
||||
|
||||
tkBang.genRule(unary, nop, pcNone)
|
||||
tkInt.genRule(unary, nop, pcNone)
|
||||
tkChr.genRule(unary, nop, pcNone)
|
||||
tkPutch.genRule(unary, nop, pcNone)
|
||||
|
||||
proc binary(comp: Compiler) =
|
||||
let opType = comp.previous.tokenType
|
||||
|
@ -663,14 +654,6 @@ proc orExpr(comp: Compiler) =
|
|||
|
||||
tkOr.genRule(nop, orExpr, pcOr)
|
||||
|
||||
proc debugExpr(comp: Compiler) =
|
||||
comp.expression()
|
||||
when debugCompiler:
|
||||
debugEcho &"debug expression, current stackindex: {comp.stackIndex}"
|
||||
comp.writeChunk(0, opPrint)
|
||||
|
||||
tkPrint.genRule(debugExpr, nop, pcNone)
|
||||
|
||||
proc parseWhile(comp: Compiler) =
|
||||
|
||||
comp.writeChunk(1, opNil) # return value
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import ../types/value
|
||||
import ../types/native
|
||||
import ../types/ndstring
|
||||
import bitops
|
||||
|
||||
proc natRead(args: seq[NdValue], retval: var NdValue): NatReturn =
|
||||
retval = stdin.readLine().fromNimString()
|
||||
return natOk
|
||||
|
||||
proc natPrint(args: seq[NdValue], retval: var NdValue): NatReturn =
|
||||
if args.len() == 0:
|
||||
retval = fromNil()
|
||||
return natOk
|
||||
for i, arg in args.pairs:
|
||||
write stdout, $arg
|
||||
if i < args.high():
|
||||
write stdout, " "
|
||||
write stdout, "\n"
|
||||
retval = args[0];
|
||||
return natOk
|
||||
|
||||
proc natWrite(args: seq[NdValue], retval: var NdValue): NatReturn =
|
||||
if args.len() != 1:
|
||||
return natError("Write expects exactly 1 argument, got " & $args.len() & ".")
|
||||
let arg = args[0]
|
||||
write stdout, $arg
|
||||
retval = arg;
|
||||
return natOk
|
||||
|
||||
proc constructIo* =
|
||||
defNative("read", natRead)
|
||||
defNative("print", natPrint)
|
||||
defNative("write", natWrite)
|
|
@ -0,0 +1,6 @@
|
|||
import io
|
||||
import typeutils
|
||||
|
||||
proc constructStdlib* =
|
||||
constructIo()
|
||||
constructTypeutils()
|
|
@ -0,0 +1,36 @@
|
|||
import ../types/value
|
||||
import ../types/native
|
||||
import ../types/ndstring
|
||||
import bitops
|
||||
|
||||
proc natChar(args: seq[NdValue], retval: var NdValue): NatReturn =
|
||||
if args.len() != 1:
|
||||
return natError("Char expects 1 argument.")
|
||||
let arg = args[0]
|
||||
if not arg.isFloat():
|
||||
return natError("Char expects a number.")
|
||||
let floatval = arg.asFloat()
|
||||
if floatval > 255f or floatval < 0f:
|
||||
return natError("Char got a number out of range.")
|
||||
let chr = floatval.char()
|
||||
retval = (chr).newString().fromNdString()
|
||||
return natOk
|
||||
|
||||
proc natByte(args: seq[NdValue], retval: var NdValue): NatReturn =
|
||||
if args.len() != 1:
|
||||
return natError("Byte expects 1 argument.")
|
||||
let arg = args[0]
|
||||
if not arg.isString():
|
||||
return natError("Byte expects a string.")
|
||||
if arg.asString().getLength() != 1:
|
||||
return natError("Byte expects a single character string.")
|
||||
|
||||
let byt = arg.asString().getIndexAsChar(0).float()
|
||||
retval = byt.fromFloat()
|
||||
return natOk
|
||||
|
||||
|
||||
proc constructTypeutils* =
|
||||
defNative("char", natChar)
|
||||
defNative("byte", natByte)
|
||||
|
|
@ -18,8 +18,7 @@ type
|
|||
tkHashtag, tkAmpersand,
|
||||
tkIdentifier, tkString,
|
||||
tkNumber, tkAnd, tkElse, tkFalse, tkFor, tkFunct, tkGoto, tkIf, tkNil,
|
||||
tkOr, tkPrint, tkLabel, tkBreak, tkTrue, tkVar, tkWhile,
|
||||
tkChr, tkInt, tkPutch,
|
||||
tkOr, tkLabel, tkBreak, tkTrue, tkVar, tkWhile,
|
||||
tkError, tkEof
|
||||
|
||||
Token* = object
|
||||
|
@ -122,13 +121,9 @@ const keywords = {
|
|||
"if": tkIf,
|
||||
"nil": tkNil,
|
||||
"or": tkOr,
|
||||
"print": tkPrint,
|
||||
"true": tkTrue,
|
||||
"var": tkVar,
|
||||
"while": tkWhile,
|
||||
"int": tkInt,
|
||||
"chr": tkChr,
|
||||
"write": tkPutch,
|
||||
}.toTable
|
||||
|
||||
proc canStartIdent(chr: char): bool =
|
||||
|
|
|
@ -23,7 +23,7 @@ proc newClosure*[T](start: ptr uint8, upvalueCount: int): Closure[T] =
|
|||
for i in 0 .. upvalueCount:
|
||||
result.upvalues[i] = nil
|
||||
|
||||
proc getIp*[T](clos: Closure[T]): ptr uint8 {.inline.} =
|
||||
proc getIp*[T](clos: Closure[T]): ptr uint8 =
|
||||
clos.start
|
||||
|
||||
proc set*[T](clos: Closure[T], index: int, val: Upvalue[T]) =
|
||||
|
|
|
@ -52,7 +52,7 @@ proc findEntry[U, V](entries: ptr UncheckedArray[Entry[U, V]], cap: int, key: U)
|
|||
return entry
|
||||
index = (index + 1).bitand(cap - 1)
|
||||
|
||||
proc grow[U, V](tbl: var Table[U, V]): int {.inline.} =
|
||||
proc grow[U, V](tbl: var Table[U, V]): int =
|
||||
## Calculates the new capacity
|
||||
if tbl.cap > 0:
|
||||
tbl.cap * 2
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
type
|
||||
NatReturn* = object
|
||||
ok*: bool
|
||||
msg*: string
|
||||
|
||||
Native* = uint32
|
||||
|
||||
natProc = proc (args: seq[uint], retval: var uint): NatReturn
|
||||
|
||||
# NatReturn misc
|
||||
|
||||
proc natError*(msg: string): NatReturn =
|
||||
NatReturn(ok: false, msg: msg)
|
||||
|
||||
const natOk* = NatReturn(ok: true)
|
||||
|
||||
# natives
|
||||
|
||||
var natives*: seq[natProc]
|
||||
var nativeNames*: seq[string]
|
||||
|
||||
proc defNative*(name: string, action: natProc) =
|
||||
natives.add(action)
|
||||
nativeNames.add(name)
|
||||
|
||||
proc callNative*(native: Native, args: seq[uint], retval: var uint): NatReturn =
|
||||
natives[native.int](args, retval)
|
|
@ -32,7 +32,7 @@ proc free*[T](list: var List[T]) =
|
|||
## dealloc's the list object
|
||||
list.dealloc()
|
||||
|
||||
proc grow[T](list: var List[T]) {.inline.} =
|
||||
proc grow[T](list: var List[T]) =
|
||||
## growth the list's capacity
|
||||
let newcap = if list.cap == 0: startCap else: list.cap * growthFactor
|
||||
let size = newcap * sizeof(T)
|
||||
|
@ -43,7 +43,7 @@ proc grow[T](list: var List[T]) {.inline.} =
|
|||
list.entries = cast[ptr UncheckedArray[T]](list.entries.realloc(size))
|
||||
list.cap = newcap
|
||||
|
||||
proc add*[T](list: var List[T], item: T) {.inline.} =
|
||||
proc add*[T](list: var List[T], item: T) =
|
||||
if list == nil or list.len == list.cap:
|
||||
list.grow()
|
||||
list.entries[list.len] = item
|
||||
|
@ -75,7 +75,7 @@ proc setIndexNeg*[T](list: List[T], index: int, item: T) =
|
|||
raise newException(Defect, "Attempt to setIndexNeg with an index out of bounds.")
|
||||
list.entries[list.len - index] = item
|
||||
|
||||
proc getLength*[T](list: List[T]): int {.inline.} =
|
||||
proc getLength*[T](list: List[T]): int =
|
||||
if list == nil:
|
||||
0
|
||||
else:
|
||||
|
|
|
@ -11,7 +11,7 @@ proc free*(ndStr: var NdString) =
|
|||
|
||||
# hashes
|
||||
|
||||
proc fnv1a*(ndStr: NdString): int {.inline.} =
|
||||
proc fnv1a*(ndStr: NdString): int =
|
||||
return ndStr.hash.int
|
||||
#var hash = 2166136261'u32
|
||||
#for i in countup(0, ndStr.len.int - 1):
|
||||
|
@ -19,14 +19,14 @@ proc fnv1a*(ndStr: NdString): int {.inline.} =
|
|||
# hash *= 16777619
|
||||
#return hash.int
|
||||
|
||||
proc fnv1a*(str: string): int {.inline.} = # SHOULD RETURN THE SAME HASH AS AN NDSTRING WITH THE SAME CONTENTS
|
||||
proc fnv1a*(str: string): int = # SHOULD RETURN THE SAME HASH AS AN NDSTRING WITH THE SAME CONTENTS
|
||||
var hash = 2166136261'u32
|
||||
for i in countup(0, str.len - 1):
|
||||
hash = hash xor (str[i]).uint32
|
||||
hash *= 16777619
|
||||
return hash.int
|
||||
|
||||
proc fnv1a*(str: char): int {.inline.} = # SHOULD RETURN THE SAME AS A 1 LENGTH STRING
|
||||
proc fnv1a*(str: char): int = # SHOULD RETURN THE SAME AS A 1 LENGTH STRING
|
||||
var hash = 2166136261'u32
|
||||
hash = hash xor str.uint32
|
||||
hash *= 16777619
|
||||
|
|
|
@ -26,13 +26,13 @@ proc free*[T](stack: var Stack[T]) =
|
|||
stack.start = nil
|
||||
stack.top = nil
|
||||
|
||||
proc grow[T](stack: var Stack[T], len: int) {.inline.} =
|
||||
proc grow[T](stack: var Stack[T], len: int) =
|
||||
## growth the stack's capacity and increments the top's index by one
|
||||
stack.cap *= growthFactor
|
||||
stack.start = cast[ptr T](realloc(stack.start, stack.cap * sizeof(T)))
|
||||
stack.top = stack.start.padd(len * sizeof(T))
|
||||
|
||||
proc shrink[T](stack: var Stack[T]) {.inline.} =
|
||||
proc shrink[T](stack: var Stack[T]) =
|
||||
discard
|
||||
|
||||
template high*[T](stack: Stack[T]): int =
|
||||
|
@ -41,7 +41,7 @@ template high*[T](stack: Stack[T]): int =
|
|||
template len*[T](stack: Stack[T]): int =
|
||||
stack.high() + 1
|
||||
|
||||
proc push*[T](stack: var Stack[T], item: T) {.inline.} =
|
||||
proc push*[T](stack: var Stack[T], item: T) =
|
||||
let len = stack.len()
|
||||
if len == stack.cap:
|
||||
stack.grow(len)
|
||||
|
@ -52,20 +52,20 @@ proc push*[T](stack: var Stack[T], item: T) {.inline.} =
|
|||
template add*[T](stack: var Stack[T], item: T) =
|
||||
stack.push(item)
|
||||
|
||||
proc pop*[T](stack: var Stack[T]): T {.inline.} =
|
||||
proc pop*[T](stack: var Stack[T]): T =
|
||||
when boundsChecks:
|
||||
if stack.top == nil or stack.top.pless(stack.start):
|
||||
raise newException(Defect, "Stacktop is nil or smaller than start.")
|
||||
result = stack.top[]
|
||||
stack.top = stack.top.psub(sizeof(T))
|
||||
|
||||
proc peek*[T](stack: Stack[T]): var T {.inline.} =
|
||||
proc peek*[T](stack: Stack[T]): var T =
|
||||
when boundsChecks:
|
||||
if stack.top == nil or stack.top.pless(stack.start):
|
||||
raise newException(Defect, "Stacktop is nil or smaller than start.")
|
||||
stack.top[]
|
||||
|
||||
proc settip*[T](stack: var Stack[T], newtip: T) {.inline.} =
|
||||
proc settip*[T](stack: var Stack[T], newtip: T) =
|
||||
when boundsChecks:
|
||||
if stack.top == nil or stack.top.pless(stack.start):
|
||||
raise newException(Defect, "Stacktop is nil or smaller than start")
|
||||
|
|
|
@ -6,13 +6,11 @@ import ndstring
|
|||
import ndlist
|
||||
import hashtable
|
||||
import closure
|
||||
import native
|
||||
|
||||
type
|
||||
NdValue* = uint
|
||||
|
||||
NatReturn* = object
|
||||
ok*: bool
|
||||
msg*: string
|
||||
|
||||
# NaN boxing constants
|
||||
|
||||
|
@ -29,7 +27,7 @@ type
|
|||
# if bit 63 is 1:
|
||||
# 00 -> list
|
||||
# 01 -> table
|
||||
# 10 -> native funct (to be implemented later)
|
||||
# 10 -> native funct
|
||||
# 11 -> unused for now
|
||||
|
||||
const qNan* = 0x7ffc000000000000'u
|
||||
|
@ -40,14 +38,13 @@ const ndFalse* = 0x7ffc000000000003'u
|
|||
|
||||
# 0111 1111 1111 11*01* 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
const tagString* = 0x7ffd000000000000'u
|
||||
|
||||
# 0111 1111 1111 11*10* 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
const tagFunct* = 0x7ffe000000000000'u
|
||||
|
||||
# you can imagine these now...
|
||||
const tagClosure* = 0x7fff000000000000'u
|
||||
|
||||
const tagList* = 0xfffc000000000000'u
|
||||
const tagTable* = 0xfffd000000000000'u
|
||||
const tagNative* = 0xfffe000000000000'u
|
||||
|
||||
const mask48* = 0xffff000000000000'u
|
||||
|
||||
|
@ -77,6 +74,9 @@ template isList*(val: NdValue): bool =
|
|||
template isTable*(val: NdValue): bool =
|
||||
val.bitand(mask48) == tagTable
|
||||
|
||||
template isNative*(val: NdValue): bool =
|
||||
val.bitand(mask48) == tagNative
|
||||
|
||||
# these assume that the type has been previously determined
|
||||
template asBool*(val: NdValue): bool =
|
||||
val == ndTrue
|
||||
|
@ -99,6 +99,9 @@ template asList*(val: NdValue): List[NdValue] =
|
|||
template asTable*(val: NdValue): NdTable[NdValue, NdValue] =
|
||||
cast[NdTable[NdValue, NdValue]](val.bitand(mask48.bitnot()))
|
||||
|
||||
template asNative*(val: NdValue): Native =
|
||||
cast[Native](val.bitand(mask48.bitnot()))
|
||||
|
||||
template fromNil*(): NdValue =
|
||||
ndNil
|
||||
|
||||
|
@ -126,6 +129,9 @@ template fromList*(val: List[NdValue]): NdValue =
|
|||
template fromTable*(val: NdTable[NdValue, NdValue]): NdValue =
|
||||
cast[uint](val).bitor(tagTable)
|
||||
|
||||
template fromNative*(val: Native): NdValue =
|
||||
cast[uint](val).bitor(tagNative)
|
||||
|
||||
|
||||
# for hashtables
|
||||
|
||||
|
@ -190,13 +196,6 @@ proc friendlyType*(val: NdValue): string =
|
|||
else:
|
||||
"unknown"
|
||||
|
||||
# NatReturn misc
|
||||
|
||||
proc natError*(msg: string): NatReturn {.inline.} =
|
||||
NatReturn(ok: false, msg: msg)
|
||||
|
||||
const natOk* = NatReturn(ok: true)
|
||||
|
||||
# OPERATIONS
|
||||
|
||||
proc negate*(val: var NdValue): NatReturn {.inline.} =
|
||||
|
|
|
@ -11,6 +11,9 @@ import types/value
|
|||
import types/hashtable
|
||||
import types/ndlist
|
||||
import types/closure
|
||||
import types/native
|
||||
|
||||
import lib/main
|
||||
|
||||
when debugVM:
|
||||
import terminal
|
||||
|
@ -78,7 +81,17 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
elif funct.isClosure():
|
||||
frames.add(Frame(stackBottom: stack.high - argcount, returnIp: ip, closure: funct.asClosure()))
|
||||
ip = funct.asClosure().getIp()
|
||||
elif funct.isNative():
|
||||
var args: seq[NdValue] = newSeq[NdValue](argcount)
|
||||
if argcount > 0:
|
||||
copyMem(args[0].unsafeAddr, stack.getIndexNeg(argcount - 1).addr, argcount * sizeof(NdValue))
|
||||
stack.deleteTopN(argcount)
|
||||
let res = callNative(funct.asNative(), args, stack.peek())
|
||||
if not res.ok:
|
||||
runtimeError(res.msg)
|
||||
error
|
||||
else:
|
||||
runtimeError("Attempt to call a non-funct (a defunct?).") # here is a bad defunct joke
|
||||
error
|
||||
|
||||
proc captureUpvalue(location: ptr NdValue): Upvalue[NdValue] =
|
||||
|
@ -116,6 +129,13 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
upval.location = upval.closed.addr
|
||||
openUpvalues = upval.next
|
||||
|
||||
# initialize globals
|
||||
constructStdlib()
|
||||
for i in 0 .. natives.high():
|
||||
let native = i.uint32.fromNative()
|
||||
let name = nativeNames[i].fromNimString()
|
||||
discard globals.tableSet(name, native)
|
||||
|
||||
while true:
|
||||
{.computedgoto.} # See https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
|
||||
|
||||
|
@ -222,8 +242,6 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
if not res.ok:
|
||||
runtimeError(res.msg)
|
||||
break
|
||||
of opPrint:
|
||||
echo $stack.peek()
|
||||
of opDefineGlobal:
|
||||
let name = ip.readConstant(chunk)
|
||||
let existed = globals.tableSet(name, stack.pop())
|
||||
|
@ -251,20 +269,6 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
of opSetLocal:
|
||||
let slot = ip.readDU8()
|
||||
stack[slot + frameBottom] = stack.peek()
|
||||
of opGetUpvalue:
|
||||
let slot = ip.readDU8()
|
||||
let val = frames.peek().closure.get(slot).read()
|
||||
when debugClosures:
|
||||
echo &"CLOSURES - getupvalue got {val} from slot {slot}"
|
||||
stack.push(val)
|
||||
of opSetUpvalue:
|
||||
let slot = ip.readDU8()
|
||||
when debugClosures:
|
||||
echo &"CLOSURES - setupvalue is setting {$stack.peek} to slot {slot}, number of slots: {frames.peek().closure.upvalueCount}"
|
||||
frames.peek().closure.get(slot).write(stack.peek())
|
||||
of opCloseUpvalue:
|
||||
let slot = ip.readDU8()
|
||||
stack[slot + frameBottom].addr.closeUpvalues()
|
||||
of opJumpIfFalse:
|
||||
let offset = ip.readDU8()
|
||||
if stack.peek().isFalsey():
|
||||
|
@ -284,24 +288,6 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
let faddr: ptr uint8 = ip
|
||||
ip = ip.padd(offset)
|
||||
stack.push(faddr.fromFunct())
|
||||
of opClosure:
|
||||
let upvalCount = ip.readDU8()
|
||||
let funct = stack.peek()
|
||||
let closure = newClosure[NdValue](funct.asFunct(), upvalCount)
|
||||
stack.settip(closure.fromClosure())
|
||||
for i in countup(0, upvalCount - 1):
|
||||
let slot = ip.readDU8()
|
||||
let isLocal = ip.readUI8() == 0
|
||||
if isLocal:
|
||||
let loc = stack[slot + frameBottom].addr
|
||||
when debugClosures:
|
||||
echo &"CLOSURES - opClosure: local upvalue {loc[]} from local slot {slot} to slot {i}"
|
||||
closure.set(i, loc.captureUpvalue())
|
||||
else:
|
||||
let val = frames.peek().closure.get(slot)
|
||||
when debugClosures:
|
||||
echo &"CLOSURES - opClosure: non local upvalue {val.location[]} from slot {slot} to slot {i}"
|
||||
closure.set(i, val)
|
||||
|
||||
of opCheckArity:
|
||||
let arity = ip.readUI8()
|
||||
|
@ -320,7 +306,6 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
|
||||
stack.setIndexNeg(argcount, fromNil()) # replace the function with nil: this is the return value slot
|
||||
funct.call(argcount):
|
||||
runtimeError("Attempt to call a non-funct (a defunct?).") # here is a bad defunct joke
|
||||
break
|
||||
of opCreateList:
|
||||
let listLen = ip.readDU8()
|
||||
|
@ -360,30 +345,38 @@ proc run*(chunk: Chunk): InterpretResult =
|
|||
if not res.ok:
|
||||
runtimeError(res.msg)
|
||||
break
|
||||
of opChr:
|
||||
let val = stack.peek()
|
||||
if not val.isFloat():
|
||||
runtimeError("chr on not float")
|
||||
break
|
||||
let floatval = val.asFloat()
|
||||
if floatval > 255f or floatval < 0f:
|
||||
runtimeError("chr on a float out of range")
|
||||
break
|
||||
let chr = floatval.char()
|
||||
stack.settip((chr).newString().fromNdString())
|
||||
of opInt:
|
||||
let val = stack.peek()
|
||||
if not val.isString():
|
||||
runtimeError("int on non string")
|
||||
break
|
||||
let strval = val.asString()
|
||||
if strval.getLength() == 0:
|
||||
runtimeError("int on empty string")
|
||||
break
|
||||
let code = val.asString().getIndexAsChar(0).float()
|
||||
stack.settip(code.fromFloat())
|
||||
of opPutchar:
|
||||
write stdout, $stack.peek()
|
||||
of opGetUpvalue:
|
||||
let slot = ip.readDU8()
|
||||
let val = frames.peek().closure.get(slot).read()
|
||||
when debugClosures:
|
||||
echo &"CLOSURES - getupvalue got {val} from slot {slot}"
|
||||
stack.push(val)
|
||||
of opSetUpvalue:
|
||||
let slot = ip.readDU8()
|
||||
when debugClosures:
|
||||
echo &"CLOSURES - setupvalue is setting {$stack.peek} to slot {slot}, number of slots: {frames.peek().closure.upvalueCount}"
|
||||
frames.peek().closure.get(slot).write(stack.peek())
|
||||
of opCloseUpvalue:
|
||||
let slot = ip.readDU8()
|
||||
stack[slot + frameBottom].addr.closeUpvalues()
|
||||
of opClosure:
|
||||
let upvalCount = ip.readDU8()
|
||||
let funct = stack.peek()
|
||||
let closure = newClosure[NdValue](funct.asFunct(), upvalCount)
|
||||
stack.settip(closure.fromClosure())
|
||||
for i in countup(0, upvalCount - 1):
|
||||
let slot = ip.readDU8()
|
||||
let isLocal = ip.readUI8() == 0
|
||||
if isLocal:
|
||||
let loc = stack[slot + frameBottom].addr
|
||||
when debugClosures:
|
||||
echo &"CLOSURES - opClosure: local upvalue {loc[]} from local slot {slot} to slot {i}"
|
||||
closure.set(i, loc.captureUpvalue())
|
||||
else:
|
||||
let val = frames.peek().closure.get(slot)
|
||||
when debugClosures:
|
||||
echo &"CLOSURES - opClosure: non local upvalue {val.location[]} from slot {slot} to slot {i}"
|
||||
closure.set(i, val)
|
||||
|
||||
when profileInstructions:
|
||||
durations[ins] += getMonoTime() - startTime
|
||||
|
|
|
@ -6,7 +6,7 @@ x[0] = 0 & [2] = 0;
|
|||
x[5] = 1 & [6] = 0 & [7] = 3 & [7] = 2;
|
||||
|
||||
//expect:@[ 0.0, 2.0, 0.0, 4.0, 5.0, 1.0, 0.0, 2.0 ]
|
||||
print x;
|
||||
print (x);
|
||||
|
||||
// not very useful but still must be correct behavior tests:
|
||||
|
||||
|
@ -14,5 +14,5 @@ print x;
|
|||
|
||||
var y = 5 + 1 & * 3;
|
||||
//expect:18.0
|
||||
print y;
|
||||
print (y);
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
{ @outer
|
||||
{ @middle
|
||||
{ @inner
|
||||
print "inner";
|
||||
print ("inner");
|
||||
break @middle;
|
||||
};
|
||||
print "middle";
|
||||
print ("middle");
|
||||
};
|
||||
print "outer";
|
||||
print ("outer");
|
||||
};
|
||||
|
||||
//expect:inner
|
||||
|
@ -20,12 +20,12 @@
|
|||
{ @outer
|
||||
{ @middle
|
||||
{ @inner
|
||||
print "inner";
|
||||
print ("inner");
|
||||
break @inner;
|
||||
};
|
||||
print "middle";
|
||||
print ("middle");
|
||||
};
|
||||
print "outer";
|
||||
print ("outer");
|
||||
};
|
||||
|
||||
// nothing to expect here
|
||||
|
@ -35,11 +35,11 @@
|
|||
{
|
||||
break @outer;
|
||||
};
|
||||
print "inner";
|
||||
print ("inner");
|
||||
};
|
||||
print "middle";
|
||||
print ("middle");
|
||||
};
|
||||
print "outer";
|
||||
print ("outer");
|
||||
};
|
||||
|
||||
//expect:5.0
|
||||
|
@ -55,7 +55,7 @@ var f = funct() {
|
|||
:result = 10;
|
||||
};
|
||||
|
||||
print f();
|
||||
print (f());
|
||||
|
||||
//expect:15.0
|
||||
|
||||
|
@ -63,7 +63,7 @@ f = funct(m, n)
|
|||
:result = m + n
|
||||
;
|
||||
|
||||
print f(f(5, 5), 5);
|
||||
print (f(f(5, 5), 5));
|
||||
|
||||
|
||||
//expect:10.0
|
||||
|
@ -78,7 +78,7 @@ var g = funct()
|
|||
}
|
||||
;
|
||||
|
||||
print g();
|
||||
print (g());
|
||||
|
||||
//expect:9.0
|
||||
|
||||
|
@ -94,4 +94,4 @@ var h = funct()
|
|||
}
|
||||
;
|
||||
|
||||
print h();
|
||||
print (h());
|
|
@ -5,18 +5,18 @@ var f1 = funct() {
|
|||
var y = 5;
|
||||
:result = funct() {
|
||||
var z = 8;
|
||||
print x;
|
||||
print (x);
|
||||
x = x + 1;
|
||||
:result = funct() {
|
||||
print x;
|
||||
print (x);
|
||||
x = x + 1;
|
||||
:result = funct() {
|
||||
print x;
|
||||
print y;
|
||||
print z;
|
||||
print (x);
|
||||
print (y);
|
||||
print (z);
|
||||
x = x + 1;
|
||||
:result = funct() {
|
||||
print x;
|
||||
print (x);
|
||||
x = x + 1;
|
||||
};
|
||||
};
|
||||
|
@ -36,7 +36,7 @@ f1()()()()();
|
|||
var f = funct() {
|
||||
var y = 5;
|
||||
var x = @[
|
||||
funct() print y,
|
||||
funct() print (y),
|
||||
funct() y = y + 1
|
||||
];
|
||||
:result = x;
|
||||
|
@ -56,7 +56,7 @@ var f2 = funct() {
|
|||
var x = { @a @b
|
||||
// this captures the internal value, not whatever it returns is assigned to
|
||||
:result = @{
|
||||
"get" = funct() print :a,
|
||||
"get" = funct() print (:a),
|
||||
"set" = funct(n) :b = n,
|
||||
};
|
||||
};
|
||||
|
@ -73,7 +73,7 @@ inst2["get"]();
|
|||
// capturing args
|
||||
|
||||
var argcap = funct(n)
|
||||
:result = funct() print n
|
||||
:result = funct() print (n)
|
||||
;
|
||||
|
||||
//expect:8.1
|
||||
|
@ -98,19 +98,19 @@ var horse2 = newAnimal("horse", "white");
|
|||
var turtle = newAnimal("turtle", "brown");
|
||||
|
||||
//expect:horse
|
||||
print horse1["getSpecies"]();
|
||||
print (horse1["getSpecies"]());
|
||||
horse1["setSpecies"]("zebra");
|
||||
//expect:zebra
|
||||
print horse1["getSpecies"]();
|
||||
print (horse1["getSpecies"]());
|
||||
|
||||
//expect:brown
|
||||
print horse1["getColor"]();
|
||||
print (horse1["getColor"]());
|
||||
//expect:horse
|
||||
print horse2["getSpecies"]();
|
||||
print (horse2["getSpecies"]());
|
||||
//expect:white
|
||||
print horse2["getColor"]();
|
||||
print (horse2["getColor"]());
|
||||
//expect:turtle
|
||||
print turtle["getSpecies"]();
|
||||
print (turtle["getSpecies"]());
|
||||
|
||||
// closure examples from craftinginterpreters
|
||||
|
||||
|
@ -118,7 +118,7 @@ print turtle["getSpecies"]();
|
|||
|
||||
var makeClosure = funct(value) {
|
||||
var closure = funct() {
|
||||
print value;
|
||||
print (value);
|
||||
};
|
||||
:result = closure;
|
||||
};
|
||||
|
@ -136,14 +136,14 @@ var outer = funct() {
|
|||
var x = "value";
|
||||
var middle = funct() {
|
||||
var inner = funct() {
|
||||
print x;
|
||||
print (x);
|
||||
};
|
||||
|
||||
print "create inner closure";
|
||||
print ("create inner closure");
|
||||
:result = inner;
|
||||
};
|
||||
|
||||
print "return from outer";
|
||||
print ("return from outer");
|
||||
:result = middle;
|
||||
};
|
||||
|
||||
|
@ -165,7 +165,7 @@ outer = funct() {
|
|||
var c = 3;
|
||||
var d = 4;
|
||||
var inner = funct() {
|
||||
print a + c + b + d;
|
||||
print (a + c + b + d);
|
||||
};
|
||||
result = inner;
|
||||
};
|
||||
|
@ -184,7 +184,7 @@ outer = funct() {
|
|||
x = "assigned";
|
||||
};
|
||||
inner();
|
||||
print x;
|
||||
print (x);
|
||||
};
|
||||
|
||||
//expect:assigned
|
||||
|
@ -199,7 +199,7 @@ var main5 = funct() {
|
|||
var a = "initial";
|
||||
|
||||
var set = funct() { a = "updated"; };
|
||||
var get = funct() { print a; };
|
||||
var get = funct() { print (a); };
|
||||
|
||||
globalSet = set;
|
||||
globalGet = get;
|
||||
|
@ -217,15 +217,15 @@ globalGet();
|
|||
{
|
||||
var a = 1;
|
||||
var f = funct() {
|
||||
print a;
|
||||
print (a);
|
||||
};
|
||||
var b = 2;
|
||||
var g = funct() {
|
||||
print b;
|
||||
print (b);
|
||||
};
|
||||
var c = 3;
|
||||
var h = funct() {
|
||||
print c;
|
||||
print (c);
|
||||
};
|
||||
|
||||
f();
|
||||
|
@ -241,15 +241,15 @@ globalGet();
|
|||
var bonus = funct() {
|
||||
var a = 1;
|
||||
var f = funct() {
|
||||
print a;
|
||||
print (a);
|
||||
};
|
||||
var b = 2;
|
||||
var g = funct() {
|
||||
print b;
|
||||
print (b);
|
||||
};
|
||||
var c = 3;
|
||||
var h = funct() {
|
||||
print c;
|
||||
print (c);
|
||||
};
|
||||
|
||||
:result = @[f, g, h];
|
||||
|
|
|
@ -5,5 +5,5 @@ var returnlist = funct() {
|
|||
};
|
||||
|
||||
//expect:3.0
|
||||
print returnlist()[2];
|
||||
print (returnlist()[2]);
|
||||
|
||||
|
|
|
@ -4,40 +4,40 @@
|
|||
|
||||
//expect:true
|
||||
if (true) {
|
||||
print "true";
|
||||
print ("true");
|
||||
};
|
||||
|
||||
if (false) {
|
||||
print "false";
|
||||
print ("false");
|
||||
};
|
||||
|
||||
// return the condition if falsy
|
||||
|
||||
//expect:nil
|
||||
print if (nil) 5;
|
||||
print (if (nil) 5);
|
||||
|
||||
//expect:false
|
||||
print if (false) 5;
|
||||
print (if (false) 5);
|
||||
|
||||
// return body if truthy
|
||||
|
||||
//expect:5.0
|
||||
print if (true) 5;
|
||||
print (if (true) 5);
|
||||
|
||||
// return else body if falsey and present
|
||||
|
||||
//expect:6.0
|
||||
print if (false) 5 else 6;
|
||||
print (if (false) 5 else 6);
|
||||
|
||||
// but still only return the if body if truthy
|
||||
|
||||
//expect:4.0
|
||||
print if (true) 4 else 6;
|
||||
print (if (true) 4 else 6);
|
||||
|
||||
// elseif chains
|
||||
|
||||
//expect:4.0
|
||||
print if (false) 1 else if (false) 2 else if (false) 3 else if (true) 4 else if (false) 5 else 8;
|
||||
print (if (false) 1 else if (false) 2 else if (false) 3 else if (true) 4 else if (false) 5 else 8);
|
||||
|
||||
// falsiness, truthiness
|
||||
|
||||
|
@ -45,22 +45,22 @@ print if (false) 1 else if (false) 2 else if (false) 3 else if (true) 4 else if
|
|||
|
||||
var uninitialized;
|
||||
|
||||
if (false) print "don't see this";
|
||||
if (nil) print "don't see this";
|
||||
if (uninitialized) print "don't see this";
|
||||
if (false) print ("don't see this");
|
||||
if (nil) print ("don't see this");
|
||||
if (uninitialized) print ("don't see this");
|
||||
|
||||
// the rest of the types are truthy
|
||||
|
||||
if (true) print "1";
|
||||
if ("") print "2";
|
||||
if ("hello") print "3";
|
||||
if (0) print "4";
|
||||
if (1) print "5";
|
||||
if (@[]) print "6";
|
||||
if (@["hi"]) print "7";
|
||||
if (@{}) print "8";
|
||||
if (@{"hi" = 5}) print "9";
|
||||
if (funct(n) print n) print "10";
|
||||
if (true) print ("1");
|
||||
if ("") print ("2");
|
||||
if ("hello") print ("3");
|
||||
if (0) print ("4");
|
||||
if (1) print ("5");
|
||||
if (@[]) print ("6");
|
||||
if (@["hi"]) print ("7");
|
||||
if (@{}) print ("8");
|
||||
if (@{"hi" = 5}) print ("9");
|
||||
if (funct(n) print (n)) print ("10");
|
||||
|
||||
//expect:1
|
||||
//expect:2
|
||||
|
@ -78,18 +78,18 @@ if (funct(n) print n) print "10";
|
|||
// and returns the left one if it's falsey or the right one if the left one is truthy
|
||||
|
||||
//expect:false
|
||||
print false and 5;
|
||||
print (false and 5);
|
||||
|
||||
//expect:5.0
|
||||
print true and 5;
|
||||
print (true and 5);
|
||||
|
||||
// or returns the leftmost truthy
|
||||
|
||||
//expect:5.0
|
||||
print false or false or false or false or 5 or false or 7;
|
||||
print (false or false or false or false or 5 or false or 7);
|
||||
|
||||
//expect:true
|
||||
print true or false;
|
||||
print (true or false);
|
||||
|
||||
// while
|
||||
|
||||
|
@ -101,12 +101,12 @@ while (i < 300) {
|
|||
i = i + 1;
|
||||
};
|
||||
|
||||
print i; //expect:300.0
|
||||
print (i); //expect:300.0
|
||||
|
||||
|
||||
i = 5;
|
||||
while (i > 0)
|
||||
print i = i - 1
|
||||
print (i = i - 1)
|
||||
;
|
||||
//expect:4.0
|
||||
//expect:3.0
|
||||
|
@ -122,7 +122,7 @@ var res = while (i > 0)
|
|||
;
|
||||
|
||||
//expect:0.0
|
||||
print res;
|
||||
print (res);
|
||||
|
||||
// if no iterations are done, it returns nil
|
||||
|
||||
|
@ -131,4 +131,4 @@ res = while (false)
|
|||
;
|
||||
|
||||
//expect:nil
|
||||
print res;
|
||||
print (res);
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
// groupings
|
||||
|
||||
//expect:15.0
|
||||
print 5 * (1 + 2);
|
||||
print (5 * (1 + 2));
|
||||
|
||||
//expect:11.0
|
||||
print (5 * 2) + 1;
|
||||
print ((5 * 2) + 1);
|
||||
|
||||
//expect:-9.0
|
||||
print -((3 + 2) * 2) + 1;
|
||||
print (-((3 + 2) * 2) + 1);
|
||||
|
||||
// calls
|
||||
|
||||
|
@ -24,7 +24,7 @@ var returnlist = funct() {
|
|||
};
|
||||
|
||||
//expect:5.0
|
||||
print returnlist()[2];
|
||||
print (returnlist()[2]);
|
||||
|
||||
// priority over unary
|
||||
var truesayer = funct() {
|
||||
|
@ -32,4 +32,4 @@ var truesayer = funct() {
|
|||
};
|
||||
|
||||
//expect:false
|
||||
print !truesayer();
|
||||
print (!truesayer());
|
|
@ -3,11 +3,11 @@ var a = 5;
|
|||
var a = 3;
|
||||
{
|
||||
var a = 2;
|
||||
print a;
|
||||
print (a);
|
||||
//expect:2.0
|
||||
};
|
||||
print a;
|
||||
print (a);
|
||||
//expect:3.0
|
||||
};
|
||||
print a;
|
||||
print (a);
|
||||
//expect:5.0
|
Loading…
Reference in New Issue