MCPcopy
hub / github.com/fluentpython/example-code-2e / expand

Function expand

18-with-match/lispy/original/lispy.py:220–270  ·  view source on GitHub ↗

Walk tree of x, making optimizations/fixes, and signaling SyntaxError.

(x, toplevel=False)

Source from the content-addressed store, hash-verified

218################ expand
219
220def expand(x, toplevel=False):
221 "Walk tree of x, making optimizations/fixes, and signaling SyntaxError."
222 require(x, x!=[]) # () => Error
223 if not isa(x, list): # constant => unchanged
224 return x
225 elif x[0] is _quote: # (quote exp)
226 require(x, len(x)==2)
227 return x
228 elif x[0] is _if:
229 if len(x)==3: x = x + [None] # (if t c) => (if t c None)
230 require(x, len(x)==4)
231 return list(map(expand, x))
232 elif x[0] is _set:
233 require(x, len(x)==3);
234 var = x[1] # (set! non-var exp) => Error
235 require(x, isa(var, Symbol), "can set! only a symbol")
236 return [_set, var, expand(x[2])]
237 elif x[0] is _define or x[0] is _definemacro:
238 require(x, len(x)>=3)
239 _def, v, body = x[0], x[1], x[2:]
240 if isa(v, list) and v: # (define (f args) body)
241 f, args = v[0], v[1:] # => (define f (lambda (args) body))
242 return expand([_def, f, [_lambda, args]+body])
243 else:
244 require(x, len(x)==3) # (define non-var/list exp) => Error
245 require(x, isa(v, Symbol), "can define only a symbol")
246 exp = expand(x[2])
247 if _def is _definemacro:
248 require(x, toplevel, "define-macro only allowed at top level")
249 proc = eval(exp)
250 require(x, callable(proc), "macro must be a procedure")
251 macro_table[v] = proc # (define-macro v proc)
252 return None # => None; add v:proc to macro_table
253 return [_define, v, exp]
254 elif x[0] is _begin:
255 if len(x)==1: return None # (begin) => None
256 else: return [expand(xi, toplevel) for xi in x]
257 elif x[0] is _lambda: # (lambda (x) e1 e2)
258 require(x, len(x)>=3) # => (lambda (x) (begin e1 e2))
259 vars, body = x[1], x[2:]
260 require(x, (isa(vars, list) and all(isa(v, Symbol) for v in vars))
261 or isa(vars, Symbol), "illegal lambda argument list")
262 exp = body[0] if len(body) == 1 else [_begin] + body
263 return [_lambda, vars, expand(exp)]
264 elif x[0] is _quasiquote: # `x => expand_quasiquote(x)
265 require(x, len(x)==2)
266 return expand_quasiquote(x[1])
267 elif isa(x[0], Symbol) and x[0] in macro_table:
268 return expand(macro_table[x[0]](*x[1:]), toplevel) # (m arg...)
269 else: # => macroexpand if m isa macro
270 return list(map(expand, x)) # (f arg...) => expand each
271
272def require(x, predicate, msg="wrong length"):
273 "Signal a syntax error if predicate is false."

Callers 2

parseFunction · 0.70
add_globalsFunction · 0.70

Calls 3

requireFunction · 0.85
expand_quasiquoteFunction · 0.85
evalFunction · 0.70

Tested by

no test coverage detected