create an nds testing tool
This commit is contained in:
parent
ef0775b252
commit
9fdbb1dda6
|
@ -1,6 +1,6 @@
|
||||||
var fib = funct(n)
|
var fib = funct(n)
|
||||||
if (n < 2) :result = 1.5
|
if (n < 2) :result = 1
|
||||||
else :result = fib(n-1) + fib(n-2)
|
else :result = fib(n-1) + fib(n-2)
|
||||||
;
|
;
|
||||||
|
|
||||||
print fib(37.2);
|
print fib(37);
|
|
@ -1,11 +1,6 @@
|
||||||
{
|
var main = funct() {
|
||||||
// source
|
// source
|
||||||
var src = ">++++++++++>+>+[
|
var src = ">++++++++++[<++++++++++>-]<->>>>>+++[>+++>+++<<-]<<<<+<[>[>+>+<<-]>>[-<<+>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]>>>>>>[[-]<++++++++++<->>]<-[>+>+<<-]>[<+>-]+>[[-]<->]<<<<<<<<<->>]<[>+>+<<-]>>[-<<+>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+>+<<<-]>>>[-<<<+>>>]++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<<[>>+>+<<<-]>>>[-<<<+>>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<[[-]>>>++++++++[>>++++++<<-]>[<++++++++[>++++++<-]>.<++++++++[>------<-]>[<<+>>-]]>.<<++++++++[>>------<<-]<[->>+<<]<++++++++[<++++>-]<.>+++++++[>+++++++++<-]>+++.<+++++[>+++++++++<-]>.+++++..--------.-------.++++++++++++++>>[>>>+>+<<<<-]>>>>[-<<<<+>>>>]>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<<[>>>+>+<<<<-]>>>>[-<<<<+>>>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+<<[-]]>[>+<[-]]++>>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<+<[[-]>-<]>[<<<<<<<.>>>>>>>[-]]<<<<<<<<<.>>----.---------.<<.>>----.+++..+++++++++++++.[-]<<[-]]<[>+>+<<-]>>[-<<+>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+>+<<<-]>>>[-<<<+>>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<[[-]>++++++++[<++++>-]<.>++++++++++[>+++++++++++<-]>+.-.<<.>>++++++.------------.---.<<.>++++++[>+++<-]>.<++++++[>----<-]>++.+++++++++++..[-]<<[-]++++++++++.[-]]<[>+>+<<-]>>[-<<+>>]+++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]++++++++++. >+++++++++[>+++++++++<-]>+++.+++++++++++++.++++++++++.------.<++++++++[>>++++<<-]>>.<++++++++++.-.---------.>.<-.+++++++++++.++++++++.---------.>.<-------------.+++++++++++++.----------.>.<++++++++++++.---------------.<+++[>++++++<-]>..>.<----------.+++++++++++.>.<<+++[>------<-]>-.+++++++++++++++++.---.++++++.-------.----------.[-]>[-]<<<.[-]]<[>+>+<<-]>>[-<<+>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]++++++++++.[-]<[-]>]<+<]";
|
||||||
[+++++[>++++++++<-]>.<++++++[>--------<-]+<<<]>.>>[
|
|
||||||
[-]<[>+<-]>>[<<+>+>-]<[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
|
|
||||||
[>+<-[>+<-[>+<-[>[-]>+>+<<<-[>+<-]]]]]]]]]]]+>>>
|
|
||||||
]<<<
|
|
||||||
]";
|
|
||||||
var pos = 0;
|
var pos = 0;
|
||||||
var len = #src;
|
var len = #src;
|
||||||
var char;
|
var char;
|
||||||
|
@ -20,8 +15,6 @@
|
||||||
var ptr = 0;
|
var ptr = 0;
|
||||||
var ptrmax = 30000 - 1;
|
var ptrmax = 30000 - 1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
while (i < ptrmax) {
|
while (i < ptrmax) {
|
||||||
tape[i] = 0;
|
tape[i] = 0;
|
||||||
|
@ -61,7 +54,7 @@
|
||||||
;
|
;
|
||||||
|
|
||||||
if (char == ".")
|
if (char == ".")
|
||||||
print(chr(tape[ptr]))
|
write(chr(tape[ptr]))
|
||||||
;
|
;
|
||||||
|
|
||||||
if (char == ",") {
|
if (char == ",") {
|
||||||
|
@ -109,4 +102,6 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
main();
|
|
@ -7,7 +7,6 @@ type
|
||||||
OpCode* = enum
|
OpCode* = enum
|
||||||
opReturn, opCall, opCheckArity, opFunctionDef, # functions
|
opReturn, opCall, opCheckArity, opFunctionDef, # functions
|
||||||
opPop, opPopSA, opPopA # pop
|
opPop, opPopSA, opPopA # pop
|
||||||
opPrint, # print TODO move to native func
|
|
||||||
opNegate, opNot # unary
|
opNegate, opNot # unary
|
||||||
opAdd, opSubtract, opMultiply, opDivide, # math
|
opAdd, opSubtract, opMultiply, opDivide, # math
|
||||||
opEqual, opGreater, opLess, # comparison
|
opEqual, opGreater, opLess, # comparison
|
||||||
|
@ -18,7 +17,7 @@ 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
|
||||||
opChr, opInt, # temporary opcodes for the brainfuck interpreter TODO move to native funcs
|
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]
|
||||||
|
@ -83,7 +82,7 @@ const simpleInstructions = {
|
||||||
opEqual, opGreater, opLess,
|
opEqual, opGreater, opLess,
|
||||||
opTrue, opFalse, opNil,
|
opTrue, opFalse, opNil,
|
||||||
opLen, opSetIndex, opGetIndex,
|
opLen, opSetIndex, opGetIndex,
|
||||||
opChr, opInt,
|
opChr, opInt, opPutchar,
|
||||||
}
|
}
|
||||||
const constantInstructions = {
|
const constantInstructions = {
|
||||||
opConstant,
|
opConstant,
|
||||||
|
|
|
@ -473,12 +473,15 @@ proc unary(comp: Compiler) =
|
||||||
comp.writeChunk(0, opInt)
|
comp.writeChunk(0, opInt)
|
||||||
of tkChr:
|
of tkChr:
|
||||||
comp.writeChunk(0, opChr)
|
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)
|
tkInt.genRule(unary, nop, pcNone)
|
||||||
tkChr.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
|
||||||
|
|
|
@ -19,7 +19,7 @@ type
|
||||||
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, tkPrint, tkLabel, tkBreak, tkTrue, tkVar, tkWhile,
|
||||||
tkChr, tkInt,
|
tkChr, tkInt, tkPutch,
|
||||||
tkError, tkEof
|
tkError, tkEof
|
||||||
|
|
||||||
Token* = object
|
Token* = object
|
||||||
|
@ -128,6 +128,7 @@ const keywords = {
|
||||||
"while": tkWhile,
|
"while": tkWhile,
|
||||||
"int": tkInt,
|
"int": tkInt,
|
||||||
"chr": tkChr,
|
"chr": tkChr,
|
||||||
|
"write": tkPutch,
|
||||||
}.toTable
|
}.toTable
|
||||||
|
|
||||||
proc canStartIdent(chr: char): bool =
|
proc canStartIdent(chr: char): bool =
|
||||||
|
|
|
@ -123,7 +123,7 @@ proc tableFindString*[U, V](tbl: Table[U, V], chars: ptr char, len: int, hash: i
|
||||||
if entry.entryStatus == esNil:
|
if entry.entryStatus == esNil:
|
||||||
return nil
|
return nil
|
||||||
elif entry.key.len.int == len and entry.key.hash.int == hash and
|
elif entry.key.len.int == len and entry.key.hash.int == hash and
|
||||||
equalMem(chars, entry.key.chars[0].unsafeAddr, len):
|
(len == 0 or equalMem(chars, entry.key.chars[0].unsafeAddr, len)):
|
||||||
return entry.key
|
return entry.key
|
||||||
index = (index + 1).bitand(tbl.cap - 1)
|
index = (index + 1).bitand(tbl.cap - 1)
|
||||||
|
|
||||||
|
|
|
@ -11,20 +11,26 @@ proc free*(ndStr: var NdString) =
|
||||||
|
|
||||||
# hashes
|
# hashes
|
||||||
|
|
||||||
proc fnv1a*(ndStr: NdString): int =
|
proc fnv1a*(ndStr: NdString): int {.inline.} =
|
||||||
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):
|
||||||
hash = hash xor (ndStr.chars[i]).uint32
|
hash = hash xor (ndStr.chars[i]).uint32
|
||||||
hash *= 16777619
|
hash *= 16777619
|
||||||
return hash.int
|
return hash.int
|
||||||
|
|
||||||
proc fnv1a*(str: string): int =
|
proc fnv1a*(str: string): int {.inline.} = # 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
|
||||||
|
var hash = 2166136261'u32
|
||||||
|
hash = hash xor str.uint32
|
||||||
|
hash *= 16777619
|
||||||
|
return hash.int
|
||||||
|
|
||||||
|
|
||||||
# equals
|
# equals
|
||||||
|
|
||||||
|
@ -37,25 +43,48 @@ proc newString*(str: string): NdString =
|
||||||
let strlen = str.len()
|
let strlen = str.len()
|
||||||
let hash = str.fnv1a()
|
let hash = str.fnv1a()
|
||||||
|
|
||||||
let interned = ndStrings.tableFindString(str[0].unsafeAddr, strlen, hash)
|
if strlen > 0:
|
||||||
if interned != nil:
|
let interned = ndStrings.tableFindString(str[0].unsafeAddr, strlen, hash)
|
||||||
return interned
|
if interned != nil:
|
||||||
|
return interned
|
||||||
|
else:
|
||||||
|
let interned = ndStrings.tableFindString(nil, 0, hash)
|
||||||
|
if interned != nil:
|
||||||
|
return interned
|
||||||
|
|
||||||
let len = 8 + strlen
|
let len = 8 + strlen
|
||||||
result = cast[NdString](alloc(len))
|
result = cast[NdString](alloc(len))
|
||||||
result.len = strlen.uint32
|
result.len = strlen.uint32
|
||||||
result.hash = hash.uint32
|
result.hash = hash.uint32
|
||||||
copyMem(result.chars[0].unsafeAddr, str[0].unsafeAddr, strlen)
|
if strlen > 0:
|
||||||
|
copyMem(result.chars[0].unsafeAddr, str[0].unsafeAddr, strlen)
|
||||||
|
|
||||||
discard ndStrings.tableSet(result, nil)
|
discard ndStrings.tableSet(result, nil)
|
||||||
|
|
||||||
|
proc newString*(str: char): NdString =
|
||||||
|
let hash = str.fnv1a()
|
||||||
|
|
||||||
|
let interned = ndStrings.tableFindString(str.unsafeAddr, 1, hash)
|
||||||
|
if interned != nil:
|
||||||
|
return interned
|
||||||
|
|
||||||
|
let len = 8 + 1
|
||||||
|
result = cast[NdString](alloc(len))
|
||||||
|
result.len = 1.uint32
|
||||||
|
result.hash = hash.uint32
|
||||||
|
result.chars[0] = str
|
||||||
|
|
||||||
|
discard ndStrings.tableSet(result, nil)
|
||||||
|
|
||||||
|
|
||||||
proc resetInternedStrings* =
|
proc resetInternedStrings* =
|
||||||
ndStrings.free()
|
ndStrings.free()
|
||||||
ndStrings = newTable[NdString, NdString]()
|
ndStrings = newTable[NdString, NdString]()
|
||||||
|
|
||||||
proc `$`*(ndStr: NdString): string =
|
proc `$`*(ndStr: NdString): string =
|
||||||
result = newString(ndStr.len.int)
|
result = newString(ndStr.len.int)
|
||||||
copyMem(result[0].unsafeAddr, ndStr.chars[0].unsafeAddr, ndStr.len.int)
|
if ndStr.len.int > 0:
|
||||||
|
copyMem(result[0].unsafeAddr, ndStr.chars[0].unsafeAddr, ndStr.len.int)
|
||||||
|
|
||||||
proc `&`*(left, right: NdString): NdString =
|
proc `&`*(left, right: NdString): NdString =
|
||||||
# TODO optimize this later when strings will be benchmarked
|
# TODO optimize this later when strings will be benchmarked
|
||||||
|
@ -65,5 +94,7 @@ proc getLength*(ndStr: NdString): int =
|
||||||
ndStr.len.int
|
ndStr.len.int
|
||||||
|
|
||||||
proc getIndex*(ndStr: NdString, index: int): NdString =
|
proc getIndex*(ndStr: NdString, index: int): NdString =
|
||||||
# TODO optimize this later
|
newString(ndStr.chars[index])
|
||||||
newString($($ndStr)[index])
|
|
||||||
|
proc getIndexAsChar*(ndStr: NdString, index: int): char =
|
||||||
|
ndStr.chars[index]
|
|
@ -65,6 +65,12 @@ proc peek*[T](stack: Stack[T]): var T {.inline.} =
|
||||||
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.} =
|
||||||
|
when boundsChecks:
|
||||||
|
if stack.top == nil or stack.top.pless(stack.start):
|
||||||
|
raise newException(Defect, "Stacktop is nil or smaller than start")
|
||||||
|
stack.top[]= newtip
|
||||||
|
|
||||||
proc deleteTopN*[T](stack: var Stack[T], n: Natural) =
|
proc deleteTopN*[T](stack: var Stack[T], n: Natural) =
|
||||||
stack.top = stack.top.psub(sizeof(T) * n)
|
stack.top = stack.top.psub(sizeof(T) * n)
|
||||||
when boundsChecks:
|
when boundsChecks:
|
||||||
|
|
|
@ -157,7 +157,7 @@ proc run*(chunk: Chunk): InterpretResult =
|
||||||
runtimeError(res.msg)
|
runtimeError(res.msg)
|
||||||
break
|
break
|
||||||
of opPrint:
|
of opPrint:
|
||||||
write stdout, $stack.peek()
|
echo $stack.peek()
|
||||||
of opDefineGlobal:
|
of opDefineGlobal:
|
||||||
let name = readConstant().asString()
|
let name = readConstant().asString()
|
||||||
let existed = globals.tableSet(name.fromNdString(), stack.pop())
|
let existed = globals.tableSet(name.fromNdString(), stack.pop())
|
||||||
|
@ -253,7 +253,7 @@ proc run*(chunk: Chunk): InterpretResult =
|
||||||
break
|
break
|
||||||
of opGetIndex:
|
of opGetIndex:
|
||||||
let index = stack.pop()
|
let index = stack.pop()
|
||||||
let res = stack.peek().getIndex(index)
|
let res = stack.peek().getIndex(index) # getIndex modifies the top value of the stack
|
||||||
if not res.ok:
|
if not res.ok:
|
||||||
runtimeError(res.msg)
|
runtimeError(res.msg)
|
||||||
break
|
break
|
||||||
|
@ -265,19 +265,31 @@ proc run*(chunk: Chunk): InterpretResult =
|
||||||
runtimeError(res.msg)
|
runtimeError(res.msg)
|
||||||
break
|
break
|
||||||
of opChr:
|
of opChr:
|
||||||
let val = stack.pop()
|
let val = stack.peek()
|
||||||
if not val.isFloat() or val.asFloat() > 255f or val.asFloat() < 0f:
|
if not val.isFloat():
|
||||||
runtimeError("chr on not float or float out of range")
|
runtimeError("chr on not float")
|
||||||
break
|
break
|
||||||
let chr = val.asFloat().int().char()
|
let floatval = val.asFloat()
|
||||||
stack.push(($chr).fromNimString())
|
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:
|
of opInt:
|
||||||
let val = stack.pop()
|
let val = stack.peek()
|
||||||
if not val.isString():
|
if not val.isString():
|
||||||
runtimeError("int on non string")
|
runtimeError("int on non string")
|
||||||
break
|
break
|
||||||
let code = ($val.asString())[0].int().float()
|
let strval = val.asString()
|
||||||
stack.push(code.fromFloat())
|
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()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
when profileInstructions:
|
when profileInstructions:
|
||||||
durations[ins] += getMonoTime() - startTime
|
durations[ins] += getMonoTime() - startTime
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
// intended use cases of ampersand:
|
||||||
|
|
||||||
|
var x = @[1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// not very useful but still must be correct behavior tests:
|
||||||
|
|
||||||
|
// change of precedence where interjected
|
||||||
|
|
||||||
|
var y = 5 + 1 & * 3;
|
||||||
|
//expect:18.0
|
||||||
|
print y;
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
|
||||||
print "expect: inner douter";
|
// tests for nested scopes, labels, breaking labels and setting the result of block expressions
|
||||||
|
|
||||||
|
//expect:inner
|
||||||
|
//expect:outer
|
||||||
{ @outer
|
{ @outer
|
||||||
{ @middle
|
{ @middle
|
||||||
{ @inner
|
{ @inner
|
||||||
|
@ -11,7 +14,9 @@ print "expect: inner douter";
|
||||||
print "outer";
|
print "outer";
|
||||||
};
|
};
|
||||||
|
|
||||||
print "expect: inner middle outer";
|
//expect:inner
|
||||||
|
//expect:middle
|
||||||
|
//expect:outer
|
||||||
{ @outer
|
{ @outer
|
||||||
{ @middle
|
{ @middle
|
||||||
{ @inner
|
{ @inner
|
||||||
|
@ -23,7 +28,7 @@ print "expect: inner middle outer";
|
||||||
print "outer";
|
print "outer";
|
||||||
};
|
};
|
||||||
|
|
||||||
print "expect: nothing";
|
// nothing to expect here
|
||||||
{ @outer
|
{ @outer
|
||||||
{ @middle
|
{ @middle
|
||||||
{ @inner
|
{ @inner
|
||||||
|
@ -37,7 +42,7 @@ print "expect: nothing";
|
||||||
print "outer";
|
print "outer";
|
||||||
};
|
};
|
||||||
|
|
||||||
print "expect 5";
|
//expect:5.0
|
||||||
|
|
||||||
var f = funct() {
|
var f = funct() {
|
||||||
var y = 1;
|
var y = 1;
|
||||||
|
@ -52,7 +57,7 @@ var f = funct() {
|
||||||
|
|
||||||
print f();
|
print f();
|
||||||
|
|
||||||
print "expect 15";
|
//expect:15.0
|
||||||
|
|
||||||
f = funct(m, n)
|
f = funct(m, n)
|
||||||
:result = m + n
|
:result = m + n
|
||||||
|
@ -61,7 +66,7 @@ f = funct(m, n)
|
||||||
print f(f(5, 5), 5);
|
print f(f(5, 5), 5);
|
||||||
|
|
||||||
|
|
||||||
print "expect: 10";
|
//expect:10.0
|
||||||
|
|
||||||
var g = funct()
|
var g = funct()
|
||||||
:result = {@a
|
:result = {@a
|
||||||
|
@ -75,7 +80,7 @@ var g = funct()
|
||||||
|
|
||||||
print g();
|
print g();
|
||||||
|
|
||||||
print "expect: 9";
|
//expect:9.0
|
||||||
|
|
||||||
var h = funct()
|
var h = funct()
|
||||||
:result = {@a
|
:result = {@a
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
// tests for basic control flow constructs
|
||||||
|
|
||||||
|
// if, else
|
||||||
|
|
||||||
|
//expect:true
|
||||||
|
if (true) {
|
||||||
|
print "true";
|
||||||
|
};
|
||||||
|
|
||||||
|
if (false) {
|
||||||
|
print "false";
|
||||||
|
};
|
||||||
|
|
||||||
|
// return the condition if falsy
|
||||||
|
|
||||||
|
//expect:nil
|
||||||
|
print if (nil) 5;
|
||||||
|
|
||||||
|
//expect:false
|
||||||
|
print if (false) 5;
|
||||||
|
|
||||||
|
// return body if truthy
|
||||||
|
|
||||||
|
//expect:5.0
|
||||||
|
print if (true) 5;
|
||||||
|
|
||||||
|
// return else body if falsey and present
|
||||||
|
|
||||||
|
//expect:6.0
|
||||||
|
print if (false) 5 else 6;
|
||||||
|
|
||||||
|
// but still only return the if body if truthy
|
||||||
|
|
||||||
|
//expect:4.0
|
||||||
|
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;
|
||||||
|
|
||||||
|
// falsiness, truthiness
|
||||||
|
|
||||||
|
// false and nil are falsey
|
||||||
|
|
||||||
|
var uninitialized;
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
//expect:1
|
||||||
|
//expect:2
|
||||||
|
//expect:3
|
||||||
|
//expect:4
|
||||||
|
//expect:5
|
||||||
|
//expect:6
|
||||||
|
//expect:7
|
||||||
|
//expect:8
|
||||||
|
//expect:9
|
||||||
|
//expect:10
|
||||||
|
|
||||||
|
// and, or
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
//expect:5.0
|
||||||
|
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;
|
||||||
|
|
||||||
|
//expect:true
|
||||||
|
print true or false;
|
||||||
|
|
||||||
|
// while
|
||||||
|
|
||||||
|
// basic looping examples
|
||||||
|
|
||||||
|
var i = 1;
|
||||||
|
|
||||||
|
while (i < 300) {
|
||||||
|
i = i + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
print i; //expect:300.0
|
||||||
|
|
||||||
|
|
||||||
|
i = 5;
|
||||||
|
while (i > 0)
|
||||||
|
print i = i - 1
|
||||||
|
;
|
||||||
|
//expect:4.0
|
||||||
|
//expect:3.0
|
||||||
|
//expect:2.0
|
||||||
|
//expect:1.0
|
||||||
|
//expect:0.0
|
||||||
|
|
||||||
|
// while returns the result of the last iteration
|
||||||
|
|
||||||
|
i = 5;
|
||||||
|
var res = while (i > 0)
|
||||||
|
i = i - 1
|
||||||
|
;
|
||||||
|
|
||||||
|
//expect:0.0
|
||||||
|
print res;
|
||||||
|
|
||||||
|
// if no iterations are done, it returns nil
|
||||||
|
|
||||||
|
res = while (false)
|
||||||
|
i = 6
|
||||||
|
;
|
||||||
|
|
||||||
|
//expect:nil
|
||||||
|
print res;
|
|
@ -1,7 +1,49 @@
|
||||||
import hashtable
|
import hashtable
|
||||||
|
import ndlist
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import strutils
|
||||||
|
import osproc
|
||||||
|
|
||||||
testHashtables()
|
testHashtables()
|
||||||
|
|
||||||
import ndlist
|
testNdlist()
|
||||||
|
|
||||||
|
var ndsPath = "bin/nds"
|
||||||
|
var testsPath = "tests"
|
||||||
|
|
||||||
|
proc assembleTestOutput(path: string): string =
|
||||||
|
for line in path.lines:
|
||||||
|
if line.contains(re"//expect:"):
|
||||||
|
result &= line[line.find(re"//expect:") + "//expect:".len()..^1] & "\n"
|
||||||
|
|
||||||
|
proc runTest(path: string) =
|
||||||
|
let (output, exitcode) = execCmdEx(ndsPath & " " & path)
|
||||||
|
let expoutput = assembleTestOutput(path)
|
||||||
|
let success = output == expoutput
|
||||||
|
if not success:
|
||||||
|
echo "Nds test failed: " & path
|
||||||
|
echo "expected output:"
|
||||||
|
echo expoutput
|
||||||
|
echo "got output:"
|
||||||
|
echo output
|
||||||
|
else:
|
||||||
|
echo "Test success: " & path
|
||||||
|
|
||||||
|
if not dirExists(testsPath):
|
||||||
|
testsPath = "."
|
||||||
|
|
||||||
|
if not fileExists(ndsPath):
|
||||||
|
if fileExists(".." / ndsPath):
|
||||||
|
ndsPath = ".." / ndsPath
|
||||||
|
else:
|
||||||
|
echo "Couldn't find nds binary in bin/nds or ../bin/nds, run nimble build first."
|
||||||
|
quit 1
|
||||||
|
|
||||||
|
for test in walkDir(testsPath):
|
||||||
|
if test.path.splitFile.ext == ".nds":
|
||||||
|
runTest(test.path)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
testNdlist()
|
|
|
@ -1,8 +0,0 @@
|
||||||
|
|
||||||
var i = 1;
|
|
||||||
|
|
||||||
while (i < 300) {
|
|
||||||
i = i + 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
print i;
|
|
|
@ -1,4 +0,0 @@
|
||||||
var i = 5;
|
|
||||||
while (i > 0)
|
|
||||||
print i = i - 1
|
|
||||||
;
|
|
Loading…
Reference in New Issue