natives
This commit is contained in:
parent
d5479a0be7
commit
9dc429c92d
|
@ -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()
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
|
@ -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
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
var argcap = funct(n)
|
|
||||||
:result = funct() print n
|
|
||||||
;
|
|
||||||
|
|
||||||
argcap(5)();
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
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 =
|
||||||
|
|
|
@ -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]) =
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
## 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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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.} =
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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());
|
|
@ -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];
|
||||||
|
|
|
@ -5,5 +5,5 @@ var returnlist = funct() {
|
||||||
};
|
};
|
||||||
|
|
||||||
//expect:3.0
|
//expect:3.0
|
||||||
print returnlist()[2];
|
print (returnlist()[2]);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
|
@ -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
|
Loading…
Reference in New Issue