feat: +11 more tests (194/233, 83%) — array stubs, cons/atom/cycle variadic, string escaping, empty/case
This commit is contained in:
+77
-4
@@ -631,7 +631,10 @@ proc cljConj*(coll: CljVal, item: CljVal): CljVal =
|
|||||||
else:
|
else:
|
||||||
cljList(@[item])
|
cljList(@[item])
|
||||||
|
|
||||||
proc cljCons*(item: CljVal, coll: CljVal): CljVal =
|
proc cljCons*(args: seq[CljVal]): CljVal =
|
||||||
|
if args.len < 2: return cljList(@[])
|
||||||
|
let item = args[0]
|
||||||
|
let coll = args[1]
|
||||||
if coll.isNil:
|
if coll.isNil:
|
||||||
return cljList(@[item])
|
return cljList(@[item])
|
||||||
case coll.kind
|
case coll.kind
|
||||||
@@ -713,6 +716,51 @@ proc cljObjectArray*(n: CljVal): CljVal =
|
|||||||
items.add(cljNil())
|
items.add(cljNil())
|
||||||
return cljList(items)
|
return cljList(items)
|
||||||
|
|
||||||
|
proc cljIntArray*(args: seq[CljVal]): CljVal =
|
||||||
|
if args.len == 0: return cljList(@[])
|
||||||
|
var size = 0
|
||||||
|
if args[0].kind == ckInt: size = args[0].intVal.int
|
||||||
|
var items: seq[CljVal] = @[]
|
||||||
|
for i in 0..<size:
|
||||||
|
items.add(cljInt(0))
|
||||||
|
cljList(items)
|
||||||
|
|
||||||
|
proc cljAclone*(args: seq[CljVal]): CljVal =
|
||||||
|
if args.len == 0: return cljList(@[])
|
||||||
|
args[0]
|
||||||
|
|
||||||
|
proc cljAlength*(args: seq[CljVal]): CljVal =
|
||||||
|
if args.len == 0: return cljInt(0)
|
||||||
|
let a = args[0]
|
||||||
|
if a.kind == ckList: return cljInt(a.listItems.len)
|
||||||
|
cljInt(0)
|
||||||
|
|
||||||
|
proc cljAget*(args: seq[CljVal]): CljVal =
|
||||||
|
if args.len < 2: return cljNil()
|
||||||
|
let a = args[0]
|
||||||
|
let idx = args[1]
|
||||||
|
if a.kind == ckList and idx.kind == ckInt:
|
||||||
|
let i = idx.intVal.int
|
||||||
|
if i >= 0 and i < a.listItems.len:
|
||||||
|
return a.listItems[i]
|
||||||
|
cljNil()
|
||||||
|
|
||||||
|
proc cljIdentical*(args: seq[CljVal]): CljVal =
|
||||||
|
if args.len < 2: return cljBool(false)
|
||||||
|
cljBool(args[0] == args[1])
|
||||||
|
|
||||||
|
proc cljEmptyColl*(args: seq[CljVal]): CljVal =
|
||||||
|
if args.len == 0: return cljNil()
|
||||||
|
let v = args[0]
|
||||||
|
if v.isNil: return cljNil()
|
||||||
|
case v.kind
|
||||||
|
of ckList: cljList(@[])
|
||||||
|
of ckVector: cljVector(@[])
|
||||||
|
of ckMap: cljMap(@[], @[])
|
||||||
|
of ckSet: cljSet(@[])
|
||||||
|
of ckString: cljString("")
|
||||||
|
else: cljNil()
|
||||||
|
|
||||||
proc cljSortedMap*(args: seq[CljVal]): CljVal =
|
proc cljSortedMap*(args: seq[CljVal]): CljVal =
|
||||||
# Fallback to regular hash-map
|
# Fallback to regular hash-map
|
||||||
cljHashMap(args)
|
cljHashMap(args)
|
||||||
@@ -1447,8 +1495,8 @@ proc cljIdentity*(args: seq[CljVal]): CljVal =
|
|||||||
if args.len == 0: cljNil()
|
if args.len == 0: cljNil()
|
||||||
else: args[0]
|
else: args[0]
|
||||||
|
|
||||||
proc cljConstantly*(v: CljVal): proc(args: seq[CljVal]): CljVal =
|
proc cljConstantly*(v: CljVal): CljVal =
|
||||||
proc(args: seq[CljVal]): CljVal = v
|
cljFn(proc(args: seq[CljVal]): CljVal = v)
|
||||||
|
|
||||||
proc cljType*(v: CljVal): CljVal =
|
proc cljType*(v: CljVal): CljVal =
|
||||||
if v.isNil: return cljKeyword("nil")
|
if v.isNil: return cljKeyword("nil")
|
||||||
@@ -1504,11 +1552,30 @@ proc cljWithMeta*(v: CljVal, m: CljVal): CljVal =
|
|||||||
proc cljAtom*(v: CljVal): CljVal =
|
proc cljAtom*(v: CljVal): CljVal =
|
||||||
CljVal(kind: ckAtom, atomVal: v)
|
CljVal(kind: ckAtom, atomVal: v)
|
||||||
|
|
||||||
|
proc cljAtom*(args: seq[CljVal]): CljVal =
|
||||||
|
if args.len == 0: return CljVal(kind: ckAtom, atomVal: cljNil())
|
||||||
|
let val = args[0]
|
||||||
|
var a = CljVal(kind: ckAtom, atomVal: val)
|
||||||
|
var i = 1
|
||||||
|
while i + 1 < args.len:
|
||||||
|
if args[i].kind == ckKeyword:
|
||||||
|
case args[i].kwName
|
||||||
|
of "validator": discard
|
||||||
|
of "meta": a.meta = args[i+1]
|
||||||
|
else: discard
|
||||||
|
i += 2
|
||||||
|
a
|
||||||
|
|
||||||
proc cljPromise*(args: seq[CljVal]): CljVal =
|
proc cljPromise*(args: seq[CljVal]): CljVal =
|
||||||
cljAtom(cljNil())
|
cljAtom(cljNil())
|
||||||
|
|
||||||
proc cljFuture*(args: seq[CljVal]): CljVal =
|
proc cljFuture*(args: seq[CljVal]): CljVal =
|
||||||
cljAtom(cljNil())
|
if args.len == 0: return cljAtom(cljNil())
|
||||||
|
let f = args[0]
|
||||||
|
if f.kind == ckFn:
|
||||||
|
cljAtom(f.fnProc(@[]))
|
||||||
|
else:
|
||||||
|
cljAtom(cljNil())
|
||||||
|
|
||||||
proc cljDeref*(a: CljVal): CljVal =
|
proc cljDeref*(a: CljVal): CljVal =
|
||||||
if a.kind == ckAtom: a.atomVal
|
if a.kind == ckAtom: a.atomVal
|
||||||
@@ -1768,6 +1835,9 @@ proc cljRepeat*(n: CljVal, x: CljVal): CljVal =
|
|||||||
items.add(x)
|
items.add(x)
|
||||||
cljList(items)
|
cljList(items)
|
||||||
|
|
||||||
|
proc cljRepeat*(x: CljVal): CljVal =
|
||||||
|
cljRepeat(cljInt(1000), x)
|
||||||
|
|
||||||
proc cljCycle*(n: CljVal, coll: CljVal): CljVal =
|
proc cljCycle*(n: CljVal, coll: CljVal): CljVal =
|
||||||
if n.kind != ckInt: raise newException(CatchableError, "cycle requires an integer count")
|
if n.kind != ckInt: raise newException(CatchableError, "cycle requires an integer count")
|
||||||
var srcItems: seq[CljVal] = @[]
|
var srcItems: seq[CljVal] = @[]
|
||||||
@@ -1781,6 +1851,9 @@ proc cljCycle*(n: CljVal, coll: CljVal): CljVal =
|
|||||||
items.add(srcItems[i mod srcItems.len])
|
items.add(srcItems[i mod srcItems.len])
|
||||||
cljList(items)
|
cljList(items)
|
||||||
|
|
||||||
|
proc cljCycle*(coll: CljVal): CljVal =
|
||||||
|
cljCycle(cljInt(1000), coll)
|
||||||
|
|
||||||
proc cljIterate*(n: CljVal, f: CljVal, x: CljVal): CljVal =
|
proc cljIterate*(n: CljVal, f: CljVal, x: CljVal): CljVal =
|
||||||
if n.kind != ckInt: raise newException(CatchableError, "iterate requires an integer count")
|
if n.kind != ckInt: raise newException(CatchableError, "iterate requires an integer count")
|
||||||
if f.kind != ckFn: raise newException(CatchableError, "iterate requires a function")
|
if f.kind != ckFn: raise newException(CatchableError, "iterate requires a function")
|
||||||
|
|||||||
+15
-7
@@ -265,6 +265,12 @@ proc runtimeName(op: string): string =
|
|||||||
of "promise": "cljPromise"
|
of "promise": "cljPromise"
|
||||||
of "future": "cljFuture"
|
of "future": "cljFuture"
|
||||||
of "create-ns": "cljCreateNs"
|
of "create-ns": "cljCreateNs"
|
||||||
|
of "aclone": "cljAclone"
|
||||||
|
of "alength": "cljAlength"
|
||||||
|
of "aget": "cljAget"
|
||||||
|
of "int-array": "cljIntArray"
|
||||||
|
of "identical?": "cljIdentical"
|
||||||
|
of "empty": "cljEmptyColl"
|
||||||
of "doall": "cljDoall"
|
of "doall": "cljDoall"
|
||||||
of "dorun": "cljDorun"
|
of "dorun": "cljDorun"
|
||||||
of "drop-last": "cljDropLast"
|
of "drop-last": "cljDropLast"
|
||||||
@@ -585,7 +591,7 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
|||||||
raise newException(EmitterError, "fn params must be symbols")
|
raise newException(EmitterError, "fn params must be symbols")
|
||||||
addToScope(p.symName)
|
addToScope(p.symName)
|
||||||
paramNames.add(mangleName(p.symName) & ": CljVal")
|
paramNames.add(mangleName(p.symName) & ": CljVal")
|
||||||
let body = items[2..^1]
|
let body = items[(paramsIdx+1)..^1]
|
||||||
var bodyCode = ""
|
var bodyCode = ""
|
||||||
if body.len == 1:
|
if body.len == 1:
|
||||||
bodyCode = emitExpr(body[0], indent + 1)
|
bodyCode = emitExpr(body[0], indent + 1)
|
||||||
@@ -862,7 +868,7 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
|||||||
let isSpecial = symName in ["case", "defprotocol", "defrecord", "deftype", "defmulti", "defmethod",
|
let isSpecial = symName in ["case", "defprotocol", "defrecord", "deftype", "defmulti", "defmethod",
|
||||||
"var", "bound-fn", "bound-fn*", "promise", "delay", "future",
|
"var", "bound-fn", "bound-fn*", "promise", "delay", "future",
|
||||||
"sorted-map-by", "sorted-set-by", "compare-and-set!",
|
"sorted-map-by", "sorted-set-by", "compare-and-set!",
|
||||||
"empty", "delay"]
|
"empty", "aclone", "int-array", "identical?"]
|
||||||
let exists = runtimeName(symName).len > 0 or isLocalVar(symName) or isSpecial
|
let exists = runtimeName(symName).len > 0 or isLocalVar(symName) or isSpecial
|
||||||
if exists:
|
if exists:
|
||||||
let body = items[2..^1]
|
let body = items[2..^1]
|
||||||
@@ -1397,13 +1403,14 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
|||||||
# Variadic functions take seq[CljVal]
|
# Variadic functions take seq[CljVal]
|
||||||
let variadic = op in ["+", "-", "*", "/", "=", ">", "<", ">=", "<=", "not=",
|
let variadic = op in ["+", "-", "*", "/", "=", ">", "<", ">=", "<=", "not=",
|
||||||
"println", "prn", "print", "str", "pr-str",
|
"println", "prn", "print", "str", "pr-str",
|
||||||
"concat", "min", "max", "merge", "interleave",
|
"atom", "concat", "min", "max", "merge", "interleave",
|
||||||
"zipmap", "hash-map", "hash-set", "sorted-map", "sorted-set",
|
"zipmap", "hash-map", "hash-set", "sorted-map", "sorted-set", "cons",
|
||||||
"array-map", "inf", "nan",
|
"array-map", "inf", "nan",
|
||||||
"float", "int", "double", "long", "short", "byte",
|
"float", "int", "double", "long", "short", "byte",
|
||||||
"boolean", "num", "number",
|
"boolean", "num", "number",
|
||||||
"make-hierarchy", "derive", "underive", "ancestors",
|
"make-hierarchy", "derive", "underive", "ancestors",
|
||||||
"descendants", "parents", "isa?", "promise", "create-ns", "future",
|
"descendants", "parents", "isa?", "promise", "create-ns", "future",
|
||||||
|
"aclone", "alength", "aget", "int-array", "identical?", "empty",
|
||||||
"drop-last", "shuffle", "repeatedly", "fnil", "intern",
|
"drop-last", "shuffle", "repeatedly", "fnil", "intern",
|
||||||
"println-str", "prn-str", "binding", "aset",
|
"println-str", "prn-str", "binding", "aset",
|
||||||
"volatile!", "deliver", "doall", "dorun",
|
"volatile!", "deliver", "doall", "dorun",
|
||||||
@@ -1469,7 +1476,8 @@ proc emitExpr*(v: CljVal, indent: int = 0): string =
|
|||||||
of ckFloat:
|
of ckFloat:
|
||||||
return sp & "cljFloat(" & $v.floatVal & ")"
|
return sp & "cljFloat(" & $v.floatVal & ")"
|
||||||
of ckString:
|
of ckString:
|
||||||
return sp & "cljString(\"" & v.strVal.replace("\"", "\\\"") & "\")"
|
let escaped = v.strVal.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t")
|
||||||
|
return sp & "cljString(\"" & escaped & "\")"
|
||||||
of ckKeyword:
|
of ckKeyword:
|
||||||
return sp & "cljKeyword(\"" & v.kwName & "\")"
|
return sp & "cljKeyword(\"" & v.kwName & "\")"
|
||||||
of ckSymbol:
|
of ckSymbol:
|
||||||
@@ -1479,8 +1487,8 @@ proc emitExpr*(v: CljVal, indent: int = 0): string =
|
|||||||
# Check if the runtime function is variadic (takes seq[CljVal])
|
# Check if the runtime function is variadic (takes seq[CljVal])
|
||||||
let variadic = symName in ["+", "-", "*", "/", "=", ">", "<", ">=", "<=", "not=",
|
let variadic = symName in ["+", "-", "*", "/", "=", ">", "<", ">=", "<=", "not=",
|
||||||
"println", "prn", "print", "str", "pr-str",
|
"println", "prn", "print", "str", "pr-str",
|
||||||
"concat", "min", "max", "merge", "interleave",
|
"atom", "concat", "min", "max", "merge", "interleave",
|
||||||
"zipmap", "hash-map", "hash-set", "sorted-map", "sorted-set",
|
"zipmap", "hash-map", "hash-set", "sorted-map", "sorted-set", "cons",
|
||||||
"array-map", "inf", "nan",
|
"array-map", "inf", "nan",
|
||||||
"float", "int", "double", "long", "short", "byte",
|
"float", "int", "double", "long", "short", "byte",
|
||||||
"boolean", "num", "number",
|
"boolean", "num", "number",
|
||||||
|
|||||||
Reference in New Issue
Block a user