OILS / mycpp / examples / scoped_resource.py View on Github | oilshell.org

198 lines, 79 significant
1#!/usr/bin/env python2
2"""
3scoped_resource.py
4"""
5from __future__ import print_function
6
7import os
8import sys
9
10from mycpp.mylib import log
11from typing import List, Optional, Any
12
13
14class MyError(Exception):
15
16 def __init__(self):
17 # type: () -> None
18 pass
19
20
21def Error(error):
22 # type: (bool) -> None
23 if error:
24 raise MyError()
25
26
27class ctx_NoArgs(object):
28 """Regression for most vexing parse."""
29
30 def __init__(self):
31 # type: () -> None
32 print('> NoArgs')
33
34 def __enter__(self):
35 # type: () -> None
36 """no-op, but it has to exist to be used as context manager."""
37 pass
38
39 def __exit__(self, type, value, traceback):
40 # type: (Any, Any, Any) -> None
41 print('< NoArgs')
42
43
44class ctx_DirStack(object):
45
46 def __init__(self, state, entry):
47 # type: (DirStack, str) -> None
48 self.state = state
49 state.Push(entry)
50
51 def __enter__(self):
52 # type: () -> None
53 """no-op, but it has to exist to be used as context manager."""
54 pass
55
56 def __exit__(self, type, value, traceback):
57 # type: (Any, Any, Any) -> None
58 self.state.Pop()
59
60
61class DirStack(object):
62 """For pushd/popd/dirs."""
63
64 def __init__(self):
65 # type: () -> None
66 self.stack = [] # type: List[str]
67 self.Reset() # Invariant: it always has at least ONE entry.
68
69 def Reset(self):
70 # type: () -> None
71 del self.stack[:]
72 self.stack.append('CWD')
73
74 def Push(self, entry):
75 # type: (str) -> None
76 self.stack.append(entry)
77
78 def Pop(self):
79 # type: () -> Optional[str]
80 if len(self.stack) <= 1:
81 return None
82 self.stack.pop() # remove last
83 return self.stack[-1] # return second to last
84
85 def Iter(self):
86 # type: () -> List[str]
87 """Iterate in reverse order."""
88 # mycpp REWRITE:
89 #return reversed(self.stack)
90 ret = [] # type: List[str]
91 ret.extend(self.stack)
92 ret.reverse()
93 return ret
94
95 def __repr__(self):
96 # type: () -> str
97 return repr(self.stack)
98
99
100# C++ translation
101#
102# class _ErrExit__Context; // forward declaration
103# class _ErrExit {
104# };
105#
106# class _ErrExit__Context {
107# _ErrExit__Context(_ErrExit* state) : state_(state) {
108# state->Push();
109# }
110# ~_ErrExit__Context() {
111# state->Pop();
112# }
113# };
114
115
116def DoWork(d, do_raise):
117 # type: (DirStack, bool) -> None
118
119 # problem
120 # with self.mem.ctx_Call(...)
121 # PushCall/PopCall
122 # with self.mem.ctx_Temp(...)
123 # PushTemp/PopCall
124 # with self.mem.ctx_Source(...)
125 # PushSource/PopSource
126 #
127 # Scope_Call
128 # Scope_Temp
129
130 # PROBLEM: WE LOST TYPE CHECKING!
131 #with e.Context('zz') as _:
132 with ctx_DirStack(d, 'foo') as _:
133 log(' in context stack %d', len(d.stack))
134 if do_raise:
135 Error(do_raise)
136
137
138def run_tests():
139 # type: () -> None
140
141 # Use cases:
142 #
143 # Many in cmd_exec.py
144 #
145 # fd_state.Push(...) and Pop
146 # BeginAlias, EndAlias
147 # PushSource, PopSource (opens files)
148 # source
149 # eval -- no file opened, but need to change the current file
150 # PushTemp, PopTemp for env bindings
151 # PushErrExit, PopErrExit
152 # loop_level in cmd_exec
153
154 d = DirStack()
155
156 for do_raise in [False, True]:
157 log('')
158 log('-> dir stack %d', len(d.stack))
159 try:
160 DoWork(d, do_raise)
161 except MyError:
162 log('exited with exception')
163 log('<- dir stack %d', len(d.stack))
164
165 # C++ translation
166 #
167 # _Errexit e;
168 # e.errexit = true;
169 #
170 # log("-> errexit %d", e.errexit)
171 # {
172 # _ErrExit__Context(e);
173 # log(" errexit %d", e.errexit)
174 # }
175 # log("<- errexit %d", e.errexit)
176
177 with ctx_NoArgs():
178 print('hi')
179
180
181def run_benchmarks():
182 # type: () -> None
183 d = DirStack()
184 for i in xrange(1000000):
185 try:
186 with ctx_DirStack(d, 'foo') as _:
187 if i % 10000 == 0:
188 raise MyError()
189 except MyError:
190 log('exception')
191
192
193if __name__ == '__main__':
194 if os.getenv('BENCHMARK'):
195 log('Benchmarking...')
196 run_benchmarks()
197 else:
198 run_tests()