From be4159fc117c0ac79d26570162665b3d9953bb96 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 19 Apr 2017 11:17:00 +0200 Subject: [PATCH] stateful components now work --- experiments/example.nim | 2 +- src/components.nim | 93 ++++++++++++++++++++++++----------------- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/experiments/example.nim b/experiments/example.nim index 61235f8..3fe4000 100644 --- a/experiments/example.nim +++ b/experiments/example.nim @@ -6,7 +6,7 @@ var proc carousel*(key: VKey): VNode {.component.} = state: - var counter = 0 + var counter: int = 0 proc next(ev: Event; n: VNode) = counter = (counter + 1) mod images.len diff --git a/src/components.nim b/src/components.nim index f86cd14..b93742d 100644 --- a/src/components.nim +++ b/src/components.nim @@ -4,8 +4,9 @@ import macros, jdict, dom, vdom, tables, strutils type StateDict*[V] = ref object + defaultValue*: V -proc `[]`*[V](d: StateDict[V], k: VKey): V {.importcpp: "#[#]".} +proc get[V](d: StateDict[V], k: VKey): V {.importcpp: "#[#]".} proc put[V](d: StateDict[V], k: VKey, v: V) {.importcpp: "#[#] = #".} proc contains*[V](d: StateDict[V], k: VKey): bool {.importcpp: "#.hasOwnProperty(#)".} @@ -24,6 +25,10 @@ proc markDirty*(key: VKey) = proc unmarkDirty*(key: VKey) = dirty.del key proc isDirty*(key: VKey): bool = dirty.contains(key) +proc `[]`*[V](d: StateDict[V], k: VKey): V = + if d.contains(k): result = d.get(k) + else: result = d.defaultValue + proc `[]=`*[V](d: StateDict[V], k: VKey, v: V) = d.put(k, v) markDirty(k) @@ -56,50 +61,62 @@ proc addTags() {.compileTime.} = static: addTags() -proc stateDecl(n: NimNode; names: TableRef[string, bool]) = + +template toState(x): untyped = newIdentNode("state" & x) +proc accessState(sv: NimNode): NimNode {.compileTime.} = + newTree(nnkBracketExpr, sv, newIdentNode("key")) + +proc stateDecl(n: NimNode; names: TableRef[string, bool]; decl: NimNode) = case n.kind of nnkVarSection, nnkLetSection: for c in n: expectKind c, nnkIdentDefs + let typ = c[^2] + let val = c[^1] + let usedType = if typ.kind != nnkEmpty: typ else: newCall("type", val) + if usedType.kind == nnkEmpty: + error("cannot determine the variable's type", c) for i in 0 .. c.len-3: let v = $c[i] + let sv = toState v + decl.add quote do: + var `sv` = newStateDict[`usedType`]() + if val.kind != nnkEmpty: + decl.add newTree(nnkAsgn, newDotExpr(sv, newIdentNode"defaultValue"), + val) + else: + error("component state must have a primitive initializer") names[v] = true of nnkStmtList, nnkStmtListExpr: - for x in n: stateDecl(x, names) + for x in n: stateDecl(x, names, decl) of nnkDo: - stateDecl(n.body, names) - else: discard - -proc accessesState(n: NimNode; names: TableRef[string, bool]): bool = - case n.kind - of nnkSym, nnkIdent: - result = $n in names - of nnkBracketExpr, nnkDotExpr: - result = accessesState(n[0], names) + stateDecl(n.body, names, decl) + of nnkCommentStmt: discard else: - for i in 0..