2626 importCache* : TableRef [string , ImportCacheEntry ]
2727 cleanup* : seq [proc ()]
2828
29+ ClosureState * = object
30+ g* : GlobalState
31+ dicts* : seq [Dict ]
32+
2933 State * = ref object
3034 g* : GlobalState
35+ parent* : State
3136 dictMin: int
3237 dicts: seq [Dict ]
3338 stack: seq [Value ]
@@ -50,6 +55,12 @@ func copy*(dict: Dict): Dict =
5055 for (k, v) in dict.pairs:
5156 result [k] = v
5257
58+ func pairSeq * (dict: Dict ): seq [(string , Value )] =
59+ result = newSeqOfCap [(string , Value )](dict.len)
60+
61+ for p in dict.pairs:
62+ result .add (p)
63+
5364
5465func newGlobalState * (exe, file: string , args: seq [string ]): GlobalState =
5566 new result
@@ -59,8 +70,17 @@ func newGlobalState*(exe, file: string, args: seq[string]): GlobalState =
5970 result .importCache = newTable [string , ImportCacheEntry ](0 )
6071
6172
62- func newState * (dictMin: int , dicts: varargs [Dict ]): State =
73+ func stateFromClosure * (clos: ptr ClosureState ): State =
74+ if clos == nil :
75+ return nil
76+
6377 new result
78+ result .g = clos[].g
79+ result .dicts = clos[].dicts
80+
81+ func newState * (dictMin: int , dicts: varargs [Dict ], parent: State = nil ): State =
82+ new result
83+ result .parent = parent
6484 result .dictMin = dictMin
6585 result .dicts = newSeqOfCap [Dict ](varargsLen (dicts))
6686 result .deferred = newSeqOfCap [seq [Value ]](varargsLen (dicts))
@@ -78,6 +98,8 @@ proc doCleanup*(self: State) =
7898 for f in self.g.cleanup:
7999 f ()
80100
101+ self.g.cleanup = @ []
102+
81103func dicts * (self: State ): seq [Dict ] =
82104 self.dicts
83105
@@ -88,6 +110,18 @@ func dbegin*(self: State, dict: Dict) =
88110 self.dicts.add (dict)
89111 self.deferred.add (@ [])
90112
113+ proc closure * (self: State ): ptr ClosureState =
114+ let clos = allocZ (ClosureState )
115+ clos[].g = self.g
116+ clos [].dicts = newSeqOfCap [Dict ](self.dicts.len)
117+
118+ for d in self.dicts:
119+ clos[].dicts.add (d)
120+
121+ self.g.cleanup.add (proc () = dealloc (clos))
122+
123+ clos
124+
91125func dbegin * (self: State , size: int ) =
92126 self.dbegin (newDict (size))
93127
@@ -110,11 +144,14 @@ func has*(self: State, name: string): bool =
110144proc set * (self: State , name: string , val: Value ) =
111145 self.dicts[^ 1 ][name] = val
112146
113- proc get * (self: State , name: string ): Value =
147+ proc get * (self: State , name: string , closure: State = nil ): Value =
114148 for d in self.dicts.rev:
115149 if d.hasKey (name):
116150 return d[name]
117151
152+ if closure != nil :
153+ return closure.get (name)
154+
118155 raise newPgError (fmt" Undefined symbol '{ name} ' " )
119156
120157proc unset * (self: State , name: string ): bool =
@@ -160,6 +197,9 @@ proc push*(self: State, val: Value) =
160197
161198func pop * (self: State ): Value =
162199 if self.stack.len == 0 :
200+ if self.parent != nil :
201+ return self.parent.pop ()
202+
163203 raise newPgError (" stack underflow" )
164204
165205 self.stack.pop ()
@@ -174,14 +214,38 @@ func peek*(self: State, ind: BackwardsIndex): Value =
174214 self.peek (self.stack.len - int (ind))
175215
176216proc check * (self: State , args: ProcArgs ) =
177- if self.stack.len < args.len:
178- raise newPgError (fmt" Expected { args.len} items on the stack but found { self.stack.len} items instead " )
217+ if args.len == 0 :
218+ return
219+
220+ var
221+ srcState = self
222+ ind = args.len - 1
223+ stackLen = 0
224+ stack = newSeq [Value ](args.len)
225+
226+ while true :
227+ if srcState.stack.len > 0 :
228+ for i in countdown (srcState.stack.len - 1 , 0 , 1 ):
229+ if ind < 0 :
230+ break
231+
232+ stack[ind] = srcState.stack[i]
233+ dec ind
234+ inc stackLen
235+
236+ if ind < 0 or srcState.parent == nil :
237+ break
238+
239+ srcState = srcState.parent
240+
241+ if stackLen < args.len:
242+ raise newPgError (fmt" Expected { args.len} items on the stack but found { stackLen} items instead " )
179243
180- var i = self. stack.len - 1
244+ var i = stack.len - 1
181245
182246 for pst in args:
183- if self. stack[i] isnot pst.typ:
184- raise newPgError (fmt" Expected type { pst.typ} for argument { pst.name} at stack position { i + 1 } , but found type { self. stack[i].typ} instead " )
247+ if stack[i] isnot pst.typ:
248+ raise newPgError (fmt" Expected type { pst.typ} for argument { pst.name} at stack position { i + 1 } , but found type { stack[i].typ} instead " )
185249
186250 dec i
187251
0 commit comments