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"
for i in countup(0, 99999):
src &= "x = x + 1;\n"
src &= "print x;\n"
src &= "print (x);\n"
path.writeFile(src)
genAssignIncr100k()

View File

@ -11,4 +11,4 @@ while (i < 50000) {
res = res + fact(50);
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)
;
print fib(37);
print (fib(37));

View File

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

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
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,

View File

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

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,
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 =

View File

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

View File

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

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
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:

View File

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

View File

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

View File

@ -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.} =

View File

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

View File

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

View File

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

View File

@ -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];

View File

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

View File

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

View File

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

View File

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