Created
October 21, 2016 00:17
-
-
Save mjendrusch/60cc4648d87448727b290faf0a6ef06c to your computer and use it in GitHub Desktop.
Current state of type-checked JsObject using a compile-time heap.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tables | |
# A template to generate all needed types and procs to emulate | |
# variable compile-time fields for objects. | |
template initHeap*(ptrName, ptrType: untyped): untyped = | |
type | |
ptrName* = distinct int | |
`ptrType Heap`* = Table[ptrName, ptrType] | |
proc `==`*(a, b: ptrName): bool = | |
int(a) == int(b) | |
var | |
counter* {. gensym, compileTime .}: int = 0 | |
heap* {. gensym, compileTime .}: `ptrType Heap` = | |
initTable[ptrName, ptrType]() | |
template `[]`*(pt: ptrName): ptrType = | |
heap[pt] | |
template `[]=`*(pt: ptrName; val: ptrType) = | |
static: | |
heap[pt] = val | |
template `new ptrName`*(): ptrName = | |
static: | |
inc counter | |
ptrName(counter) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ctJsObject | |
# Demo of static (flow-) typing together with structural types | |
# (using concepts and when), for JsObjects. | |
# A structural type | |
type someStructure = concept c | |
c is JsObject | |
c.a is int | |
c.b is string | |
# Quick and dirty import of console | |
var console {. importc, nodecl .}: JsObject[newPtrTab] | |
var x = newJsObject() | |
var y = newJsObject() | |
x.a = "22" | |
x.d = "test" | |
y.a = 42 | |
y.b = "foo" | |
console.log(x, y) | |
# A branching `proc` to demonstrate flow typing | |
# plus structural types. | |
proc doSomething(x: JsObject) = | |
when x is someStructure: | |
x.a = "surprise" | |
x.b = 42 | |
else: | |
x.a = 42 | |
x.c = 99 | |
block: | |
var x = clone(x) | |
x.a = "foo" | |
# x is not someStructure | |
doSomething(x) | |
# y is someStructure | |
doSomething(y) | |
# both take the right branches | |
var b: int = y.b | |
# Though all this looks very dynamic, it is still fully | |
# statically checked, and the compiler will return an error, | |
# if the types do not fit. | |
var a: int = x.c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import macros | |
import strutils | |
import typetraits | |
import tables | |
import strutils | |
import sequtils | |
import compileTimeHeap | |
{.experimental.} | |
initHeap(ptrTab, Table[string, cstring]) | |
type | |
JsObject*[pt: static[ptrTab]] = object | |
template newTab*(): ptrTab = | |
const res = newPtrTab() | |
res[] = initTable[string, cstring]() | |
res | |
macro stringifyIdent*(x: untyped): string = | |
if x.kind == nnkHiddenDeref: | |
return $(x[0]) | |
$x | |
macro stringToIdent*(x: static[cstring]): untyped = | |
result = newIdentNode(!($x)) | |
template identOrName*(x: auto): static[string] = | |
"`" & stringifyIdent(x) & "`" | |
proc setImpl*[T; pt: static[ptrTab]](obj: JsObject[pt]; field: static[string]; val: T) = #{. importcpp: "#[#] = #" .} | |
{. emit: "`obj`[\"" & field & "\"]" & " = `val`;" .} | |
proc getImpl*[pt: static[ptrTab]](obj: JsObject[pt]; name: static[string]): JsObject[ptrTab(-1)] = #{. importcpp: "(#[#])" .} | |
{. emit: "`result` = `obj`[\"" & name & "\"];".} | |
proc callImpl*[pt: static[ptrTab]](obj: JsObject[pt]; nam: static[string]; | |
args: static[string]; qt: static[ptrTab]): JsObject[qt] {. discardable .} = | |
{. emit: "`result` = `obj`[\"" & nam & "\"](" & args & ");" .} | |
template `.=`*[T; pt: static[ptrTab]](obj: JsObject[pt]; nam: string; val: T) = | |
static: | |
pt[][stringifyIdent(nam)] = T.name | |
setImpl(obj, nam, val) | |
template `.`*[pt: static[ptrTab]](obj: JsObject[pt]; nam: untyped): auto = | |
when compiles(stringToIdent(pt[][stringifyIdent(nam)])): | |
cast[stringToIdent(pt[][stringifyIdent(nam)])](getImpl(obj, stringifyIdent(nam))) | |
else: | |
cast[JsObject[newTab()]](getImpl(obj, stringifyIdent(nam))) | |
template `.()`*[pt: static[ptrTab]](obj: JsObject[pt]; nam: static[string]; args: varargs[string, identOrName]): auto = | |
callImpl(obj, nam, join(args, ","), newTab()) | |
template newJsObject*(): auto = | |
const res = newTab() | |
proc ret(): JsObject[res] {. gensym .} = | |
{. emit: "`result` = {};" .} | |
ret() | |
template clone*[procPt: static[ptrTab]](obj: JsObject[procPt]): auto = | |
var res = newJsObject() | |
static: | |
if not compiles(res.pt[]): | |
res.pt[] = initTable[string, cstring]() | |
for k, v in procPt[].pairs: | |
res.pt[][k] = v | |
res |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment