This commit is contained in:
prod2 2022-02-07 05:35:07 +01:00
parent d5479a0be7
commit 9dc429c92d
26 changed files with 284 additions and 220 deletions

View File

@ -7,7 +7,7 @@ proc genAssignIncr100k =
var src = "var x = 0;\n" var src = "var x = 0;\n"
for i in countup(0, 99999): for i in countup(0, 99999):
src &= "x = x + 1;\n" src &= "x = x + 1;\n"
src &= "print x;\n" src &= "print (x);\n"
path.writeFile(src) path.writeFile(src)
genAssignIncr100k() genAssignIncr100k()

View File

@ -11,4 +11,4 @@ while (i < 50000) {
res = res + fact(50); res = res + fact(50);
i = i + 1; i = i + 1;
}; };
print res; print (res);

View File

@ -3,4 +3,4 @@ var fib = funct(n)
else :result = fib(n-1) + fib(n-2) else :result = fib(n-1) + fib(n-2)
; ;
print fib(37); print (fib(37));

View File

@ -3,7 +3,7 @@ var main = funct() {
var src = ">++++++++++[<++++++++++>-]<->>>>>+++[>+++>+++<<-]<<<<+<[>[>+>+<<-]>>[-<<+>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]>>>>>>[[-]<++++++++++<->>]<-[>+>+<<-]>[<+>-]+>[[-]<->]<<<<<<<<<->>]<[>+>+<<-]>>[-<<+>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+>+<<<-]>>>[-<<<+>>>]++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<<[>>+>+<<<-]>>>[-<<<+>>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<[[-]>>>++++++++[>>++++++<<-]>[<++++++++[>++++++<-]>.<++++++++[>------<-]>[<<+>>-]]>.<<++++++++[>>------<<-]<[->>+<<]<++++++++[<++++>-]<.>+++++++[>+++++++++<-]>+++.<+++++[>+++++++++<-]>.+++++..--------.-------.++++++++++++++>>[>>>+>+<<<<-]>>>>[-<<<<+>>>>]>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<<[>>>+>+<<<<-]>>>>[-<<<<+>>>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+<<[-]]>[>+<[-]]++>>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<+<[[-]>-<]>[<<<<<<<.>>>>>>>[-]]<<<<<<<<<.>>----.---------.<<.>>----.+++..+++++++++++++.[-]<<[-]]<[>+>+<<-]>>[-<<+>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+>+<<<-]>>>[-<<<+>>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<[[-]>++++++++[<++++>-]<.>++++++++++[>+++++++++++<-]>+.-.<<.>>++++++.------------.---.<<.>++++++[>+++<-]>.<++++++[>----<-]>++.+++++++++++..[-]<<[-]++++++++++.[-]]<[>+>+<<-]>>[-<<+>>]+++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]++++++++++. >+++++++++[>+++++++++<-]>+++.+++++++++++++.++++++++++.------.<++++++++[>>++++<<-]>>.<++++++++++.-.---------.>.<-.+++++++++++.++++++++.---------.>.<-------------.+++++++++++++.----------.>.<++++++++++++.---------------.<+++[>++++++<-]>..>.<----------.+++++++++++.>.<<+++[>------<-]>-.+++++++++++++++++.---.++++++.-------.----------.[-]>[-]<<<.[-]]<[>+>+<<-]>>[-<<+>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]++++++++++.[-]<[-]>]<+<]"; var src = ">++++++++++[<++++++++++>-]<->>>>>+++[>+++>+++<<-]<<<<+<[>[>+>+<<-]>>[-<<+>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]>>>>>>[[-]<++++++++++<->>]<-[>+>+<<-]>[<+>-]+>[[-]<->]<<<<<<<<<->>]<[>+>+<<-]>>[-<<+>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+>+<<<-]>>>[-<<<+>>>]++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<<[>>+>+<<<-]>>>[-<<<+>>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<[[-]>>>++++++++[>>++++++<<-]>[<++++++++[>++++++<-]>.<++++++++[>------<-]>[<<+>>-]]>.<<++++++++[>>------<<-]<[->>+<<]<++++++++[<++++>-]<.>+++++++[>+++++++++<-]>+++.<+++++[>+++++++++<-]>.+++++..--------.-------.++++++++++++++>>[>>>+>+<<<<-]>>>>[-<<<<+>>>>]>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<<[>>>+>+<<<<-]>>>>[-<<<<+>>>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+<<[-]]>[>+<[-]]++>>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<+<[[-]>-<]>[<<<<<<<.>>>>>>>[-]]<<<<<<<<<.>>----.---------.<<.>>----.+++..+++++++++++++.[-]<<[-]]<[>+>+<<-]>>[-<<+>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+>+<<<-]>>>[-<<<+>>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<[[-]>++++++++[<++++>-]<.>++++++++++[>+++++++++++<-]>+.-.<<.>>++++++.------------.---.<<.>++++++[>+++<-]>.<++++++[>----<-]>++.+++++++++++..[-]<<[-]++++++++++.[-]]<[>+>+<<-]>>[-<<+>>]+++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]++++++++++. >+++++++++[>+++++++++<-]>+++.+++++++++++++.++++++++++.------.<++++++++[>>++++<<-]>>.<++++++++++.-.---------.>.<-.+++++++++++.++++++++.---------.>.<-------------.+++++++++++++.----------.>.<++++++++++++.---------------.<+++[>++++++<-]>..>.<----------.+++++++++++.>.<<+++[>------<-]>-.+++++++++++++++++.---.++++++.-------.----------.[-]>[-]<<<.[-]]<[>+>+<<-]>>[-<<+>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]++++++++++.[-]<[-]>]<+<]";
var pos = 0; var pos = 0;
var len = #src; var len = #src;
var char; var chr;
var depth = 0; var depth = 0;
// input // input
@ -23,55 +23,55 @@ var main = funct() {
{ @mainloop { @mainloop
while (pos < len) { while (pos < len) {
char = src[pos]; chr = src[pos];
if (char == "<") if (chr == "<")
if (ptr > 0) if (ptr > 0)
ptr = ptr - 1 ptr = ptr - 1
else else
ptr = ptrmax ptr = ptrmax
; ;
if (char == ">") if (chr == ">")
if (ptr < ptrmax) if (ptr < ptrmax)
ptr = ptr + 1 ptr = ptr + 1
else else
ptr = 0 ptr = 0
; ;
if (char == "+") if (chr == "+")
if (tape[ptr] < 255) if (tape[ptr] < 255)
tape[ptr] = tape[ptr] + 1 tape[ptr] = tape[ptr] + 1
else else
tape[ptr] = 0 tape[ptr] = 0
; ;
if (char == "-") if (chr == "-")
if (tape[ptr] > 0) if (tape[ptr] > 0)
tape[ptr] = tape[ptr] - 1 tape[ptr] = tape[ptr] - 1
else else
tape[ptr] = 255 tape[ptr] = 255
; ;
if (char == ".") if (chr == ".")
write(chr(tape[ptr])) write(char(tape[ptr]))
; ;
if (char == ",") { if (chr == ",") {
tape[ptr] = int(input[inppos]); tape[ptr] = byte(input[inppos]);
inppos = inppos + 1; inppos = inppos + 1;
}; };
if (char == "[") { if (chr == "[") {
if (tape[ptr] == 0) { if (tape[ptr] == 0) {
depth = depth + 1; depth = depth + 1;
while (depth > 0) { while (depth > 0) {
pos = pos + 1; pos = pos + 1;
char = src[pos]; chr = src[pos];
depth = depth + depth = depth +
if (char == "[") if (chr == "[")
1 1
else if (char == "]") else if (chr == "]")
-1 -1
else else
0 0
@ -80,16 +80,16 @@ var main = funct() {
}; };
}; };
if (char == "]") { if (chr == "]") {
if (tape[ptr] != 0) { if (tape[ptr] != 0) {
depth = depth + 1; depth = depth + 1;
while (depth > 0) { while (depth > 0) {
pos = pos - 1; pos = pos - 1;
char = src[pos]; chr = src[pos];
depth = depth + depth = depth +
if (char == "]") if (chr == "]")
1 1
else if (char == "[") else if (chr == "[")
-1 -1
else else
0 0

View File

@ -1,5 +0,0 @@
var argcap = funct(n)
:result = funct() print n
;
argcap(5)();

View File

@ -19,7 +19,6 @@ type
opJumpIfFalse, opJump, opLoop, opJumpIfFalsePop, # jumps opJumpIfFalse, opJump, opLoop, opJumpIfFalsePop, # jumps
opCreateList, opCreateTable, # collection creation opCreateList, opCreateTable, # collection creation
opLen, opSetIndex, opGetIndex, # collection operators opLen, opSetIndex, opGetIndex, # collection operators
opPrint, opChr, opInt, opPutchar, # temporary opcodes for the brainfuck interpreter TODO move to native funcs
Chunk* = object Chunk* = object
code*: seq[uint8] code*: seq[uint8]
@ -92,13 +91,11 @@ proc writeConstant*(ch: var Chunk, constant: NdValue, line: int): int =
const simpleInstructions = { const simpleInstructions = {
opReturn, opReturn,
opPop, opPop,
opPrint,
opNegate, opNot, opNegate, opNot,
opAdd, opSubtract, opMultiply, opDivide, opAdd, opSubtract, opMultiply, opDivide,
opEqual, opGreater, opLess, opEqual, opGreater, opLess,
opTrue, opFalse, opNil, opTrue, opFalse, opNil,
opLen, opSetIndex, opGetIndex, opLen, opSetIndex, opGetIndex,
opChr, opInt, opPutchar,
} }
const constantInstructions = { const constantInstructions = {
opConstant, opConstant,

View File

@ -551,19 +551,10 @@ proc unary(comp: Compiler) =
comp.writeChunk(0, opNegate) comp.writeChunk(0, opNegate)
of tkBang: of tkBang:
comp.writeChunk(0, opNot) comp.writeChunk(0, opNot)
of tkInt:
comp.writeChunk(0, opInt)
of tkChr:
comp.writeChunk(0, opChr)
of tkPutch:
comp.writeChunk(0, opPutchar)
else: else:
discard # unreachable discard # unreachable
tkBang.genRule(unary, nop, pcNone) tkBang.genRule(unary, nop, pcNone)
tkInt.genRule(unary, nop, pcNone)
tkChr.genRule(unary, nop, pcNone)
tkPutch.genRule(unary, nop, pcNone)
proc binary(comp: Compiler) = proc binary(comp: Compiler) =
let opType = comp.previous.tokenType let opType = comp.previous.tokenType
@ -663,14 +654,6 @@ proc orExpr(comp: Compiler) =
tkOr.genRule(nop, orExpr, pcOr) 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) = proc parseWhile(comp: Compiler) =
comp.writeChunk(1, opNil) # return value comp.writeChunk(1, opNil) # return value

33
src/ndspkg/lib/io.nim Normal file
View File

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

6
src/ndspkg/lib/main.nim Normal file
View File

@ -0,0 +1,6 @@
import io
import typeutils
proc constructStdlib* =
constructIo()
constructTypeutils()

View File

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

View File

@ -18,8 +18,7 @@ type
tkHashtag, tkAmpersand, tkHashtag, tkAmpersand,
tkIdentifier, tkString, tkIdentifier, tkString,
tkNumber, tkAnd, tkElse, tkFalse, tkFor, tkFunct, tkGoto, tkIf, tkNil, tkNumber, tkAnd, tkElse, tkFalse, tkFor, tkFunct, tkGoto, tkIf, tkNil,
tkOr, tkPrint, tkLabel, tkBreak, tkTrue, tkVar, tkWhile, tkOr, tkLabel, tkBreak, tkTrue, tkVar, tkWhile,
tkChr, tkInt, tkPutch,
tkError, tkEof tkError, tkEof
Token* = object Token* = object
@ -122,13 +121,9 @@ const keywords = {
"if": tkIf, "if": tkIf,
"nil": tkNil, "nil": tkNil,
"or": tkOr, "or": tkOr,
"print": tkPrint,
"true": tkTrue, "true": tkTrue,
"var": tkVar, "var": tkVar,
"while": tkWhile, "while": tkWhile,
"int": tkInt,
"chr": tkChr,
"write": tkPutch,
}.toTable }.toTable
proc canStartIdent(chr: char): bool = proc canStartIdent(chr: char): bool =

View File

@ -23,7 +23,7 @@ proc newClosure*[T](start: ptr uint8, upvalueCount: int): Closure[T] =
for i in 0 .. upvalueCount: for i in 0 .. upvalueCount:
result.upvalues[i] = nil result.upvalues[i] = nil
proc getIp*[T](clos: Closure[T]): ptr uint8 {.inline.} = proc getIp*[T](clos: Closure[T]): ptr uint8 =
clos.start clos.start
proc set*[T](clos: Closure[T], index: int, val: Upvalue[T]) = proc set*[T](clos: Closure[T], index: int, val: Upvalue[T]) =

View File

@ -52,7 +52,7 @@ proc findEntry[U, V](entries: ptr UncheckedArray[Entry[U, V]], cap: int, key: U)
return entry return entry
index = (index + 1).bitand(cap - 1) 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 ## Calculates the new capacity
if tbl.cap > 0: if tbl.cap > 0:
tbl.cap * 2 tbl.cap * 2

View File

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

View File

@ -32,7 +32,7 @@ proc free*[T](list: var List[T]) =
## dealloc's the list object ## dealloc's the list object
list.dealloc() list.dealloc()
proc grow[T](list: var List[T]) {.inline.} = proc grow[T](list: var List[T]) =
## growth the list's capacity ## growth the list's capacity
let newcap = if list.cap == 0: startCap else: list.cap * growthFactor let newcap = if list.cap == 0: startCap else: list.cap * growthFactor
let size = newcap * sizeof(T) 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.entries = cast[ptr UncheckedArray[T]](list.entries.realloc(size))
list.cap = newcap 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: if list == nil or list.len == list.cap:
list.grow() list.grow()
list.entries[list.len] = item 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.") raise newException(Defect, "Attempt to setIndexNeg with an index out of bounds.")
list.entries[list.len - index] = item list.entries[list.len - index] = item
proc getLength*[T](list: List[T]): int {.inline.} = proc getLength*[T](list: List[T]): int =
if list == nil: if list == nil:
0 0
else: else:

View File

@ -11,7 +11,7 @@ proc free*(ndStr: var NdString) =
# hashes # hashes
proc fnv1a*(ndStr: NdString): int {.inline.} = proc fnv1a*(ndStr: NdString): int =
return ndStr.hash.int return ndStr.hash.int
#var hash = 2166136261'u32 #var hash = 2166136261'u32
#for i in countup(0, ndStr.len.int - 1): #for i in countup(0, ndStr.len.int - 1):
@ -19,14 +19,14 @@ proc fnv1a*(ndStr: NdString): int {.inline.} =
# hash *= 16777619 # hash *= 16777619
#return hash.int #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 var hash = 2166136261'u32
for i in countup(0, str.len - 1): for i in countup(0, str.len - 1):
hash = hash xor (str[i]).uint32 hash = hash xor (str[i]).uint32
hash *= 16777619 hash *= 16777619
return hash.int 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 var hash = 2166136261'u32
hash = hash xor str.uint32 hash = hash xor str.uint32
hash *= 16777619 hash *= 16777619

View File

@ -26,13 +26,13 @@ proc free*[T](stack: var Stack[T]) =
stack.start = nil stack.start = nil
stack.top = 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 ## growth the stack's capacity and increments the top's index by one
stack.cap *= growthFactor stack.cap *= growthFactor
stack.start = cast[ptr T](realloc(stack.start, stack.cap * sizeof(T))) stack.start = cast[ptr T](realloc(stack.start, stack.cap * sizeof(T)))
stack.top = stack.start.padd(len * 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 discard
template high*[T](stack: Stack[T]): int = 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 = template len*[T](stack: Stack[T]): int =
stack.high() + 1 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() let len = stack.len()
if len == stack.cap: if len == stack.cap:
stack.grow(len) 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) = template add*[T](stack: var Stack[T], item: T) =
stack.push(item) stack.push(item)
proc pop*[T](stack: var Stack[T]): T {.inline.} = proc pop*[T](stack: var Stack[T]): T =
when boundsChecks: when boundsChecks:
if stack.top == nil or stack.top.pless(stack.start): if stack.top == nil or stack.top.pless(stack.start):
raise newException(Defect, "Stacktop is nil or smaller than start.") raise newException(Defect, "Stacktop is nil or smaller than start.")
result = stack.top[] result = stack.top[]
stack.top = stack.top.psub(sizeof(T)) 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: when boundsChecks:
if stack.top == nil or stack.top.pless(stack.start): if stack.top == nil or stack.top.pless(stack.start):
raise newException(Defect, "Stacktop is nil or smaller than start.") raise newException(Defect, "Stacktop is nil or smaller than start.")
stack.top[] stack.top[]
proc settip*[T](stack: var Stack[T], newtip: T) {.inline.} = proc settip*[T](stack: var Stack[T], newtip: T) =
when boundsChecks: when boundsChecks:
if stack.top == nil or stack.top.pless(stack.start): if stack.top == nil or stack.top.pless(stack.start):
raise newException(Defect, "Stacktop is nil or smaller than start") raise newException(Defect, "Stacktop is nil or smaller than start")

View File

@ -6,13 +6,11 @@ import ndstring
import ndlist import ndlist
import hashtable import hashtable
import closure import closure
import native
type type
NdValue* = uint NdValue* = uint
NatReturn* = object
ok*: bool
msg*: string
# NaN boxing constants # NaN boxing constants
@ -29,7 +27,7 @@ type
# if bit 63 is 1: # if bit 63 is 1:
# 00 -> list # 00 -> list
# 01 -> table # 01 -> table
# 10 -> native funct (to be implemented later) # 10 -> native funct
# 11 -> unused for now # 11 -> unused for now
const qNan* = 0x7ffc000000000000'u 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 # 0111 1111 1111 11*01* 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
const tagString* = 0x7ffd000000000000'u const tagString* = 0x7ffd000000000000'u
# 0111 1111 1111 11*10* 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 # 0111 1111 1111 11*10* 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
const tagFunct* = 0x7ffe000000000000'u const tagFunct* = 0x7ffe000000000000'u
# you can imagine these now...
const tagClosure* = 0x7fff000000000000'u const tagClosure* = 0x7fff000000000000'u
const tagList* = 0xfffc000000000000'u const tagList* = 0xfffc000000000000'u
const tagTable* = 0xfffd000000000000'u const tagTable* = 0xfffd000000000000'u
const tagNative* = 0xfffe000000000000'u
const mask48* = 0xffff000000000000'u const mask48* = 0xffff000000000000'u
@ -77,6 +74,9 @@ template isList*(val: NdValue): bool =
template isTable*(val: NdValue): bool = template isTable*(val: NdValue): bool =
val.bitand(mask48) == tagTable val.bitand(mask48) == tagTable
template isNative*(val: NdValue): bool =
val.bitand(mask48) == tagNative
# these assume that the type has been previously determined # these assume that the type has been previously determined
template asBool*(val: NdValue): bool = template asBool*(val: NdValue): bool =
val == ndTrue val == ndTrue
@ -99,6 +99,9 @@ template asList*(val: NdValue): List[NdValue] =
template asTable*(val: NdValue): NdTable[NdValue, NdValue] = template asTable*(val: NdValue): NdTable[NdValue, NdValue] =
cast[NdTable[NdValue, NdValue]](val.bitand(mask48.bitnot())) cast[NdTable[NdValue, NdValue]](val.bitand(mask48.bitnot()))
template asNative*(val: NdValue): Native =
cast[Native](val.bitand(mask48.bitnot()))
template fromNil*(): NdValue = template fromNil*(): NdValue =
ndNil ndNil
@ -126,6 +129,9 @@ template fromList*(val: List[NdValue]): NdValue =
template fromTable*(val: NdTable[NdValue, NdValue]): NdValue = template fromTable*(val: NdTable[NdValue, NdValue]): NdValue =
cast[uint](val).bitor(tagTable) cast[uint](val).bitor(tagTable)
template fromNative*(val: Native): NdValue =
cast[uint](val).bitor(tagNative)
# for hashtables # for hashtables
@ -190,13 +196,6 @@ proc friendlyType*(val: NdValue): string =
else: else:
"unknown" "unknown"
# NatReturn misc
proc natError*(msg: string): NatReturn {.inline.} =
NatReturn(ok: false, msg: msg)
const natOk* = NatReturn(ok: true)
# OPERATIONS # OPERATIONS
proc negate*(val: var NdValue): NatReturn {.inline.} = proc negate*(val: var NdValue): NatReturn {.inline.} =

View File

@ -11,6 +11,9 @@ import types/value
import types/hashtable import types/hashtable
import types/ndlist import types/ndlist
import types/closure import types/closure
import types/native
import lib/main
when debugVM: when debugVM:
import terminal import terminal
@ -78,7 +81,17 @@ proc run*(chunk: Chunk): InterpretResult =
elif funct.isClosure(): elif funct.isClosure():
frames.add(Frame(stackBottom: stack.high - argcount, returnIp: ip, closure: funct.asClosure())) frames.add(Frame(stackBottom: stack.high - argcount, returnIp: ip, closure: funct.asClosure()))
ip = funct.asClosure().getIp() 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: else:
runtimeError("Attempt to call a non-funct (a defunct?).") # here is a bad defunct joke
error error
proc captureUpvalue(location: ptr NdValue): Upvalue[NdValue] = proc captureUpvalue(location: ptr NdValue): Upvalue[NdValue] =
@ -116,6 +129,13 @@ proc run*(chunk: Chunk): InterpretResult =
upval.location = upval.closed.addr upval.location = upval.closed.addr
openUpvalues = upval.next 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: while true:
{.computedgoto.} # See https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma {.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: if not res.ok:
runtimeError(res.msg) runtimeError(res.msg)
break break
of opPrint:
echo $stack.peek()
of opDefineGlobal: of opDefineGlobal:
let name = ip.readConstant(chunk) let name = ip.readConstant(chunk)
let existed = globals.tableSet(name, stack.pop()) let existed = globals.tableSet(name, stack.pop())
@ -251,20 +269,6 @@ proc run*(chunk: Chunk): InterpretResult =
of opSetLocal: of opSetLocal:
let slot = ip.readDU8() let slot = ip.readDU8()
stack[slot + frameBottom] = stack.peek() 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: of opJumpIfFalse:
let offset = ip.readDU8() let offset = ip.readDU8()
if stack.peek().isFalsey(): if stack.peek().isFalsey():
@ -284,24 +288,6 @@ proc run*(chunk: Chunk): InterpretResult =
let faddr: ptr uint8 = ip let faddr: ptr uint8 = ip
ip = ip.padd(offset) ip = ip.padd(offset)
stack.push(faddr.fromFunct()) 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: of opCheckArity:
let arity = ip.readUI8() 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 stack.setIndexNeg(argcount, fromNil()) # replace the function with nil: this is the return value slot
funct.call(argcount): funct.call(argcount):
runtimeError("Attempt to call a non-funct (a defunct?).") # here is a bad defunct joke
break break
of opCreateList: of opCreateList:
let listLen = ip.readDU8() let listLen = ip.readDU8()
@ -360,30 +345,38 @@ proc run*(chunk: Chunk): InterpretResult =
if not res.ok: if not res.ok:
runtimeError(res.msg) runtimeError(res.msg)
break break
of opChr: of opGetUpvalue:
let val = stack.peek() let slot = ip.readDU8()
if not val.isFloat(): let val = frames.peek().closure.get(slot).read()
runtimeError("chr on not float") when debugClosures:
break echo &"CLOSURES - getupvalue got {val} from slot {slot}"
let floatval = val.asFloat() stack.push(val)
if floatval > 255f or floatval < 0f: of opSetUpvalue:
runtimeError("chr on a float out of range") let slot = ip.readDU8()
break when debugClosures:
let chr = floatval.char() echo &"CLOSURES - setupvalue is setting {$stack.peek} to slot {slot}, number of slots: {frames.peek().closure.upvalueCount}"
stack.settip((chr).newString().fromNdString()) frames.peek().closure.get(slot).write(stack.peek())
of opInt: of opCloseUpvalue:
let val = stack.peek() let slot = ip.readDU8()
if not val.isString(): stack[slot + frameBottom].addr.closeUpvalues()
runtimeError("int on non string") of opClosure:
break let upvalCount = ip.readDU8()
let strval = val.asString() let funct = stack.peek()
if strval.getLength() == 0: let closure = newClosure[NdValue](funct.asFunct(), upvalCount)
runtimeError("int on empty string") stack.settip(closure.fromClosure())
break for i in countup(0, upvalCount - 1):
let code = val.asString().getIndexAsChar(0).float() let slot = ip.readDU8()
stack.settip(code.fromFloat()) let isLocal = ip.readUI8() == 0
of opPutchar: if isLocal:
write stdout, $stack.peek() 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: when profileInstructions:
durations[ins] += getMonoTime() - startTime durations[ins] += getMonoTime() - startTime

View File

@ -6,7 +6,7 @@ x[0] = 0 & [2] = 0;
x[5] = 1 & [6] = 0 & [7] = 3 & [7] = 2; 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 ] //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: // not very useful but still must be correct behavior tests:
@ -14,5 +14,5 @@ print x;
var y = 5 + 1 & * 3; var y = 5 + 1 & * 3;
//expect:18.0 //expect:18.0
print y; print (y);

View File

@ -6,12 +6,12 @@
{ @outer { @outer
{ @middle { @middle
{ @inner { @inner
print "inner"; print ("inner");
break @middle; break @middle;
}; };
print "middle"; print ("middle");
}; };
print "outer"; print ("outer");
}; };
//expect:inner //expect:inner
@ -20,12 +20,12 @@
{ @outer { @outer
{ @middle { @middle
{ @inner { @inner
print "inner"; print ("inner");
break @inner; break @inner;
}; };
print "middle"; print ("middle");
}; };
print "outer"; print ("outer");
}; };
// nothing to expect here // nothing to expect here
@ -35,11 +35,11 @@
{ {
break @outer; break @outer;
}; };
print "inner"; print ("inner");
}; };
print "middle"; print ("middle");
}; };
print "outer"; print ("outer");
}; };
//expect:5.0 //expect:5.0
@ -55,7 +55,7 @@ var f = funct() {
:result = 10; :result = 10;
}; };
print f(); print (f());
//expect:15.0 //expect:15.0
@ -63,7 +63,7 @@ f = funct(m, n)
:result = m + n :result = m + n
; ;
print f(f(5, 5), 5); print (f(f(5, 5), 5));
//expect:10.0 //expect:10.0
@ -78,7 +78,7 @@ var g = funct()
} }
; ;
print g(); print (g());
//expect:9.0 //expect:9.0
@ -94,4 +94,4 @@ var h = funct()
} }
; ;
print h(); print (h());

View File

@ -5,18 +5,18 @@ var f1 = funct() {
var y = 5; var y = 5;
:result = funct() { :result = funct() {
var z = 8; var z = 8;
print x; print (x);
x = x + 1; x = x + 1;
:result = funct() { :result = funct() {
print x; print (x);
x = x + 1; x = x + 1;
:result = funct() { :result = funct() {
print x; print (x);
print y; print (y);
print z; print (z);
x = x + 1; x = x + 1;
:result = funct() { :result = funct() {
print x; print (x);
x = x + 1; x = x + 1;
}; };
}; };
@ -36,7 +36,7 @@ f1()()()()();
var f = funct() { var f = funct() {
var y = 5; var y = 5;
var x = @[ var x = @[
funct() print y, funct() print (y),
funct() y = y + 1 funct() y = y + 1
]; ];
:result = x; :result = x;
@ -56,7 +56,7 @@ var f2 = funct() {
var x = { @a @b var x = { @a @b
// this captures the internal value, not whatever it returns is assigned to // this captures the internal value, not whatever it returns is assigned to
:result = @{ :result = @{
"get" = funct() print :a, "get" = funct() print (:a),
"set" = funct(n) :b = n, "set" = funct(n) :b = n,
}; };
}; };
@ -73,7 +73,7 @@ inst2["get"]();
// capturing args // capturing args
var argcap = funct(n) var argcap = funct(n)
:result = funct() print n :result = funct() print (n)
; ;
//expect:8.1 //expect:8.1
@ -98,19 +98,19 @@ var horse2 = newAnimal("horse", "white");
var turtle = newAnimal("turtle", "brown"); var turtle = newAnimal("turtle", "brown");
//expect:horse //expect:horse
print horse1["getSpecies"](); print (horse1["getSpecies"]());
horse1["setSpecies"]("zebra"); horse1["setSpecies"]("zebra");
//expect:zebra //expect:zebra
print horse1["getSpecies"](); print (horse1["getSpecies"]());
//expect:brown //expect:brown
print horse1["getColor"](); print (horse1["getColor"]());
//expect:horse //expect:horse
print horse2["getSpecies"](); print (horse2["getSpecies"]());
//expect:white //expect:white
print horse2["getColor"](); print (horse2["getColor"]());
//expect:turtle //expect:turtle
print turtle["getSpecies"](); print (turtle["getSpecies"]());
// closure examples from craftinginterpreters // closure examples from craftinginterpreters
@ -118,7 +118,7 @@ print turtle["getSpecies"]();
var makeClosure = funct(value) { var makeClosure = funct(value) {
var closure = funct() { var closure = funct() {
print value; print (value);
}; };
:result = closure; :result = closure;
}; };
@ -136,14 +136,14 @@ var outer = funct() {
var x = "value"; var x = "value";
var middle = funct() { var middle = funct() {
var inner = funct() { var inner = funct() {
print x; print (x);
}; };
print "create inner closure"; print ("create inner closure");
:result = inner; :result = inner;
}; };
print "return from outer"; print ("return from outer");
:result = middle; :result = middle;
}; };
@ -165,7 +165,7 @@ outer = funct() {
var c = 3; var c = 3;
var d = 4; var d = 4;
var inner = funct() { var inner = funct() {
print a + c + b + d; print (a + c + b + d);
}; };
result = inner; result = inner;
}; };
@ -184,7 +184,7 @@ outer = funct() {
x = "assigned"; x = "assigned";
}; };
inner(); inner();
print x; print (x);
}; };
//expect:assigned //expect:assigned
@ -199,7 +199,7 @@ var main5 = funct() {
var a = "initial"; var a = "initial";
var set = funct() { a = "updated"; }; var set = funct() { a = "updated"; };
var get = funct() { print a; }; var get = funct() { print (a); };
globalSet = set; globalSet = set;
globalGet = get; globalGet = get;
@ -217,15 +217,15 @@ globalGet();
{ {
var a = 1; var a = 1;
var f = funct() { var f = funct() {
print a; print (a);
}; };
var b = 2; var b = 2;
var g = funct() { var g = funct() {
print b; print (b);
}; };
var c = 3; var c = 3;
var h = funct() { var h = funct() {
print c; print (c);
}; };
f(); f();
@ -241,15 +241,15 @@ globalGet();
var bonus = funct() { var bonus = funct() {
var a = 1; var a = 1;
var f = funct() { var f = funct() {
print a; print (a);
}; };
var b = 2; var b = 2;
var g = funct() { var g = funct() {
print b; print (b);
}; };
var c = 3; var c = 3;
var h = funct() { var h = funct() {
print c; print (c);
}; };
:result = @[f, g, h]; :result = @[f, g, h];

View File

@ -5,5 +5,5 @@ var returnlist = funct() {
}; };
//expect:3.0 //expect:3.0
print returnlist()[2]; print (returnlist()[2]);

View File

@ -4,40 +4,40 @@
//expect:true //expect:true
if (true) { if (true) {
print "true"; print ("true");
}; };
if (false) { if (false) {
print "false"; print ("false");
}; };
// return the condition if falsy // return the condition if falsy
//expect:nil //expect:nil
print if (nil) 5; print (if (nil) 5);
//expect:false //expect:false
print if (false) 5; print (if (false) 5);
// return body if truthy // return body if truthy
//expect:5.0 //expect:5.0
print if (true) 5; print (if (true) 5);
// return else body if falsey and present // return else body if falsey and present
//expect:6.0 //expect:6.0
print if (false) 5 else 6; print (if (false) 5 else 6);
// but still only return the if body if truthy // but still only return the if body if truthy
//expect:4.0 //expect:4.0
print if (true) 4 else 6; print (if (true) 4 else 6);
// elseif chains // elseif chains
//expect:4.0 //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 // 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; var uninitialized;
if (false) print "don't see this"; if (false) print ("don't see this");
if (nil) print "don't see this"; if (nil) print ("don't see this");
if (uninitialized) print "don't see this"; if (uninitialized) print ("don't see this");
// the rest of the types are truthy // the rest of the types are truthy
if (true) print "1"; if (true) print ("1");
if ("") print "2"; if ("") print ("2");
if ("hello") print "3"; if ("hello") print ("3");
if (0) print "4"; if (0) print ("4");
if (1) print "5"; if (1) print ("5");
if (@[]) print "6"; if (@[]) print ("6");
if (@["hi"]) print "7"; if (@["hi"]) print ("7");
if (@{}) print "8"; if (@{}) print ("8");
if (@{"hi" = 5}) print "9"; if (@{"hi" = 5}) print ("9");
if (funct(n) print n) print "10"; if (funct(n) print (n)) print ("10");
//expect:1 //expect:1
//expect:2 //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 // and returns the left one if it's falsey or the right one if the left one is truthy
//expect:false //expect:false
print false and 5; print (false and 5);
//expect:5.0 //expect:5.0
print true and 5; print (true and 5);
// or returns the leftmost truthy // or returns the leftmost truthy
//expect:5.0 //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 //expect:true
print true or false; print (true or false);
// while // while
@ -101,12 +101,12 @@ while (i < 300) {
i = i + 1; i = i + 1;
}; };
print i; //expect:300.0 print (i); //expect:300.0
i = 5; i = 5;
while (i > 0) while (i > 0)
print i = i - 1 print (i = i - 1)
; ;
//expect:4.0 //expect:4.0
//expect:3.0 //expect:3.0
@ -122,7 +122,7 @@ var res = while (i > 0)
; ;
//expect:0.0 //expect:0.0
print res; print (res);
// if no iterations are done, it returns nil // if no iterations are done, it returns nil
@ -131,4 +131,4 @@ res = while (false)
; ;
//expect:nil //expect:nil
print res; print (res);

View File

@ -3,13 +3,13 @@
// groupings // groupings
//expect:15.0 //expect:15.0
print 5 * (1 + 2); print (5 * (1 + 2));
//expect:11.0 //expect:11.0
print (5 * 2) + 1; print ((5 * 2) + 1);
//expect:-9.0 //expect:-9.0
print -((3 + 2) * 2) + 1; print (-((3 + 2) * 2) + 1);
// calls // calls
@ -24,7 +24,7 @@ var returnlist = funct() {
}; };
//expect:5.0 //expect:5.0
print returnlist()[2]; print (returnlist()[2]);
// priority over unary // priority over unary
var truesayer = funct() { var truesayer = funct() {
@ -32,4 +32,4 @@ var truesayer = funct() {
}; };
//expect:false //expect:false
print !truesayer(); print (!truesayer());

View File

@ -3,11 +3,11 @@ var a = 5;
var a = 3; var a = 3;
{ {
var a = 2; var a = 2;
print a; print (a);
//expect:2.0 //expect:2.0
}; };
print a; print (a);
//expect:3.0 //expect:3.0
}; };
print a; print (a);
//expect:5.0 //expect:5.0