Advertisement
Guest User

Untitled

a guest
Nov 20th, 2019
2,046
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 26.60 KB | None | 0 0
  1. """A Scheme interpreter and its read-eval-print loop."""
  2. from __future__ import print_function # Python 2 compatibility
  3.  
  4. from scheme_builtins import *
  5. from scheme_reader import *
  6. from ucb import main, trace
  7.  
  8. ##############
  9. # Eval/Apply #
  10. ##############
  11.  
  12.  
  13. def scheme_eval(expr, env, _=None): # Optional third argument is ignored
  14. """Evaluate Scheme expression EXPR in environment ENV.
  15.  
  16. >>> expr = read_line('(+ 2 2)')
  17. >>> expr
  18. Pair('+', Pair(2, Pair(2, nil)))
  19. >>> scheme_eval(expr, create_global_frame())
  20. 4
  21. """
  22. # Evaluate atoms
  23. if scheme_symbolp(expr):
  24. return env.lookup(expr)
  25. elif self_evaluating(expr):
  26. return expr
  27.  
  28. #if isinstance(expr, MacroProcedure):
  29. # return macro_apply(expr, expr.first, env)
  30.  
  31. # All non-atomic expressions are lists (combinations)
  32. if not scheme_listp(expr):
  33. raise SchemeError('malformed list: {0}'.format(repl_str(expr)))
  34. first, rest = expr.first, expr.rest
  35. if scheme_symbolp(first) and first in SPECIAL_FORMS:
  36. return SPECIAL_FORMS[first](rest, env)
  37. else:
  38. # BEGIN PROBLEM 4
  39. expr_eval = expr.map(lambda subexpr: scheme_eval(subexpr, env))
  40. return scheme_apply(expr_eval.first, expr_eval.rest, env)
  41. # END PROBLEM 4
  42.  
  43. def self_evaluating(expr):
  44. """Return whether EXPR evaluates to itself."""
  45. return (scheme_atomp(expr) and not scheme_symbolp(expr)) or expr is None
  46.  
  47. def scheme_apply(procedure, args, env):
  48. """Apply Scheme PROCEDURE to argument values ARGS (a Scheme list) in
  49. environment ENV."""
  50. check_procedure(procedure)
  51. if isinstance(procedure, BuiltinProcedure):
  52. return procedure.apply(args, env)
  53. else:
  54. new_env = procedure.make_call_frame(args, env)
  55. return eval_all(procedure.body, new_env)
  56.  
  57. def eval_all(expressions, env):
  58. """Evaluate each expression in the Scheme list EXPRESSIONS in
  59. environment ENV and return the value of the last."""
  60. # BEGIN PROBLEM 7
  61. if expressions is nil:
  62. return None
  63. return_expr = expressions.map(lambda eval_expr: scheme_eval(eval_expr, env))
  64. while return_expr.rest is not nil:
  65. return_expr = return_expr.rest
  66. return return_expr.first
  67. # END PROBLEM 7
  68.  
  69. ################
  70. # Environments #
  71. ################
  72.  
  73. class Frame(object):
  74. """An environment frame binds Scheme symbols to Scheme values."""
  75.  
  76. def __init__(self, parent):
  77. """An empty frame with parent frame PARENT (which may be None)."""
  78. self.bindings = {}
  79. self.parent = parent
  80.  
  81. def __repr__(self):
  82. if self.parent is None:
  83. return '<Global Frame>'
  84. s = sorted(['{0}: {1}'.format(k, v) for k, v in self.bindings.items()])
  85. return '<{{{0}}} -> {1}>'.format(', '.join(s), repr(self.parent))
  86.  
  87. def define(self, symbol, value):
  88. """Define Scheme SYMBOL to have VALUE."""
  89. # BEGIN PROBLEM 2
  90. self.bindings[symbol] = value
  91. # END PROBLEM 2
  92.  
  93. def lookup(self, symbol):
  94. """Return the value bound to SYMBOL. Errors if SYMBOL is not found."""
  95. # BEGIN PROBLEM 2
  96. value = self.bindings.get(symbol)
  97. if value is not None: #need to specify None because value itself can be 0 or False
  98. return value
  99. elif self.parent:
  100. return Frame.lookup(self.parent, symbol)
  101. "*** YOUR CODE HERE ***"
  102. # END PROBLEM 2
  103. raise SchemeError('unknown identifier: {0}'.format(symbol))
  104.  
  105.  
  106. def make_child_frame(self, formals, vals):
  107. """Return a new local frame whose parent is SELF, in which the symbols
  108. in a Scheme list of formal parameters FORMALS are bound to the Scheme
  109. values in the Scheme list VALS. Raise an error if too many or too few
  110. vals are given.
  111.  
  112. >>> env = create_global_frame()
  113. >>> formals, expressions = read_line('(a b c)'), read_line('(1 2 3)')
  114. >>> env.make_child_frame(formals, expressions)
  115. <{a: 1, b: 2, c: 3} -> <Global Frame>>
  116. """
  117. # BEGIN PROBLEM 10
  118. child_frame = Frame(self)
  119. env_vars, env_vals = formals, vals
  120. while env_vars is not nil and env_vals is not nil:
  121. child_frame.define(env_vars.first, env_vals.first)
  122. env_vars, env_vals = env_vars.rest, env_vals.rest
  123. if env_vars is not nil or env_vals is not nil:
  124. raise SchemeError('Values do not correspond to variables.')
  125. return child_frame
  126. # END PROBLEM 10
  127.  
  128. ##############
  129. # Procedures #
  130. ##############
  131.  
  132. class Procedure(object):
  133. """The supertype of all Scheme procedures."""
  134.  
  135. def scheme_procedurep(x):
  136. return isinstance(x, Procedure)
  137.  
  138. class BuiltinProcedure(Procedure):
  139. """A Scheme procedure defined as a Python function."""
  140.  
  141. def __init__(self, fn, use_env=False, name='builtin'):
  142. self.name = name
  143. self.fn = fn
  144. self.use_env = use_env
  145.  
  146. def __str__(self):
  147. return '#[{0}]'.format(self.name)
  148.  
  149. def apply(self, args, env):
  150. """Apply SELF to ARGS in ENV, where ARGS is a Scheme list.
  151.  
  152. >>> env = create_global_frame()
  153. >>> plus = env.bindings['+']
  154. >>> twos = Pair(2, Pair(2, nil))
  155. >>> plus.apply(twos, env)
  156. 4
  157. """
  158. if not scheme_listp(args):
  159. raise SchemeError('arguments are not in a list: {0}'.format(args))
  160. # Convert a Scheme list to a Python list
  161. python_args = []
  162. while args is not nil:
  163. python_args.append(args.first)
  164. args = args.rest
  165. # BEGIN PROBLEM 3
  166. if self.use_env:
  167. python_args.append(env)
  168. try:
  169. return self.fn(*python_args)
  170. except TypeError:
  171. raise SchemeError('Wrong number of arguments for', self.fn)
  172. # END PROBLEM 3
  173.  
  174. class LambdaProcedure(Procedure):
  175. """A procedure defined by a lambda expression or a define form."""
  176.  
  177. def __init__(self, formals, body, env):
  178. """A procedure with formal parameter list FORMALS (a Scheme list),
  179. whose body is the Scheme list BODY, and whose parent environment
  180. starts with Frame ENV."""
  181. self.formals = formals
  182. self.body = body
  183. self.env = env
  184.  
  185. def make_call_frame(self, args, env):
  186. """Make a frame that binds my formal parameters to ARGS, a Scheme list
  187. of values, for a lexically-scoped call evaluated in environment ENV."""
  188. # BEGIN PROBLEM 11
  189. return self.env.make_child_frame(self.formals, args)
  190. # END PROBLEM 11
  191.  
  192. def __str__(self):
  193. return str(Pair('lambda', Pair(self.formals, self.body)))
  194.  
  195. def __repr__(self):
  196. return 'LambdaProcedure({0}, {1}, {2})'.format(
  197. repr(self.formals), repr(self.body), repr(self.env))
  198.  
  199. class MacroProcedure(LambdaProcedure):
  200. """A macro: a special form that operates on its unevaluated operands to
  201. create an expression that is evaluated in place of a call."""
  202.  
  203. def apply_macro(self, operands, env):
  204. """Apply this macro to the operand expressions."""
  205. return complete_apply(self, operands, env)
  206.  
  207. def add_builtins(frame, funcs_and_names):
  208. """Enter bindings in FUNCS_AND_NAMES into FRAME, an environment frame,
  209. as built-in procedures. Each item in FUNCS_AND_NAMES has the form
  210. (NAME, PYTHON-FUNCTION, INTERNAL-NAME)."""
  211. for name, fn, proc_name in funcs_and_names:
  212. frame.define(name, BuiltinProcedure(fn, name=proc_name))
  213.  
  214. #################
  215. # Special Forms #
  216. #################
  217.  
  218. # Each of the following do_xxx_form functions takes the cdr of a special form as
  219. # its first argument---a Scheme list representing a special form without the
  220. # initial identifying symbol (if, lambda, quote, ...). Its second argument is
  221. # the environment in which the form is to be evaluated.
  222.  
  223. def do_define_form(expressions, env):
  224. """Evaluate a define form."""
  225. check_form(expressions, 2)
  226. target = expressions.first
  227. if scheme_symbolp(target):
  228. check_form(expressions, 2, 2)
  229. # BEGIN PROBLEM 5
  230. val_bind = scheme_eval(expressions.rest.first, env)
  231. env.define(target, val_bind)
  232. return target
  233. # END PROBLEM 5
  234. elif isinstance(target, Pair) and scheme_symbolp(target.first):
  235. # BEGIN PROBLEM 9
  236. #restructure expressions into a lambda expression
  237. return do_define_form(Pair(target.first, Pair(Pair('lambda', Pair(target.rest, expressions.rest)), nil)), env)
  238. # END PROBLEM 9
  239. else:
  240. bad_target = target.first if isinstance(target, Pair) else target
  241. raise SchemeError('non-symbol: {0}'.format(bad_target))
  242.  
  243. def do_quote_form(expressions, env):
  244. """Evaluate a quote form."""
  245. check_form(expressions, 1, 1)
  246. # BEGIN PROBLEM 6
  247. return expressions.first #expressions is a list containing only one expression, resulted in ((quote hello)) instead of (quote hello)
  248. # END PROBLEM 6
  249.  
  250. def do_begin_form(expressions, env):
  251. """Evaluate a begin form."""
  252. check_form(expressions, 1)
  253. return eval_all(expressions, env)
  254.  
  255. def do_lambda_form(expressions, env):
  256. """Evaluate a lambda form."""
  257. check_form(expressions, 2)
  258. formals = expressions.first
  259. check_formals(formals)
  260. # BEGIN PROBLEM 8
  261. return LambdaProcedure(expressions.first, expressions.rest, env)
  262. # END PROBLEM 8
  263.  
  264. def do_if_form(expressions, env):
  265. """Evaluate an if form."""
  266. check_form(expressions, 2, 3)
  267. if scheme_truep(scheme_eval(expressions.first, env, True)):
  268. return scheme_eval(expressions.rest.first, env, True)
  269. elif len(expressions) == 3:
  270. return scheme_eval(expressions.rest.rest.first, env, True)
  271.  
  272. def do_and_form(expressions, env):
  273. """Evaluate a (short-circuited) and form."""
  274. # BEGIN PROBLEM 12
  275. return_val, eval_expr = True, expressions
  276. while eval_expr is not nil:
  277. return_val, eval_expr = scheme_eval(eval_expr.first, env), eval_expr.rest
  278. if scheme_falsep(return_val):
  279. return return_val
  280. return return_val
  281. # END PROBLEM 12
  282.  
  283. def do_or_form(expressions, env):
  284. """Evaluate a (short-circuited) or form."""
  285. # BEGIN PROBLEM 12
  286. return_val, eval_expr = False, expressions
  287. while eval_expr is not nil:
  288. return_val, eval_expr = scheme_eval(eval_expr.first, env), eval_expr.rest
  289. if scheme_truep(return_val):
  290. return return_val
  291. return return_val
  292. # END PROBLEM 12
  293.  
  294. def do_cond_form(expressions, env):
  295. """Evaluate a cond form."""
  296. while expressions is not nil:
  297. clause = expressions.first
  298. check_form(clause, 1)
  299. if clause.first == 'else':
  300. test = True
  301. if expressions.rest != nil:
  302. raise SchemeError('else must be last')
  303. else:
  304. test = scheme_eval(clause.first, env)
  305. if scheme_truep(test):
  306. # BEGIN PROBLEM 13
  307. if clause.rest is nil:
  308. return test
  309. else:
  310. return eval_all(clause.rest, env)
  311. # END PROBLEM 13
  312. expressions = expressions.rest
  313.  
  314. def do_let_form(expressions, env):
  315. """Evaluate a let form."""
  316. check_form(expressions, 2)
  317. let_env = make_let_frame(expressions.first, env)
  318. return eval_all(expressions.rest, let_env)
  319.  
  320. def make_let_frame(bindings, env):
  321. """Create a child frame of ENV that contains the definitions given in
  322. BINDINGS. The Scheme list BINDINGS must have the form of a proper bindings
  323. list in a let expression: each item must be a list containing a symbol
  324. and a Scheme expression."""
  325. if not scheme_listp(bindings):
  326. raise SchemeError('bad bindings list in let form')
  327. # BEGIN PROBLEM 14
  328. formals, vals, bind_eval = nil, nil, bindings
  329. while bind_eval is not nil: #every element of bind_eval is a "symbol/value binding pair" that should be a linked list of length two
  330. if bind_eval.first.rest.rest is not nil: #length of linked list is longer than two
  331. raise SchemeError('Invalid input.')
  332. formals, vals, bind_eval = Pair(bind_eval.first.first, formals), Pair(scheme_eval(bind_eval.first.rest.first, env), vals), bind_eval.rest
  333. check_formals(formals)
  334. return env.make_child_frame(formals, vals)
  335. # END PROBLEM 14
  336.  
  337. def do_define_macro(expressions, env):
  338. """Evaluate a define-macro form."""
  339. # BEGIN Problem 20
  340. check_form(expressions, 2)
  341. target = expressions.first
  342. #if scheme_symbolp(target):
  343. # return target
  344. if isinstance(target, Pair) and scheme_symbolp(target.first):
  345. env.define(target.first, MacroProcedure(target.rest, expressions.rest, env))
  346. return target.first #name
  347. else:
  348. bad_target = target.first if isinstance(target, Pair) else target
  349. raise SchemeError('non-symbol: {0}'.format(bad_target))
  350. # END Problem 20
  351.  
  352. check_form(expressions, 2)
  353. target = expressions.first
  354. if scheme_symbolp(target):
  355. check_form(expressions, 2, 2)
  356. # BEGIN PROBLEM 5
  357. val_bind = scheme_eval(expressions.rest.first, env)
  358. env.define(target, val_bind)
  359. return target
  360. # END PROBLEM 5
  361. elif isinstance(target, Pair) and scheme_symbolp(target.first):
  362. # BEGIN PROBLEM 9
  363. #restructure expressions into a lambda expression
  364. return do_define_form(Pair(target.first, Pair(Pair('lambda', Pair(target.rest, expressions.rest)), nil)), env)
  365. # END PROBLEM 9
  366. else:
  367. bad_target = target.first if isinstance(target, Pair) else target
  368. raise SchemeError('non-symbol: {0}'.format(bad_target))
  369.  
  370. def do_quasiquote_form(expressions, env):
  371. """Evaluate a quasiquote form with parameters EXPRESSIONS in
  372. environment ENV."""
  373. def quasiquote_item(val, env, level):
  374. """Evaluate Scheme expression VAL that is nested at depth LEVEL in
  375. a quasiquote form in environment ENV."""
  376. if not scheme_pairp(val):
  377. return val
  378. if val.first == 'unquote':
  379. level -= 1
  380. if level == 0:
  381. expressions = val.rest
  382. check_form(expressions, 1, 1)
  383. return scheme_eval(expressions.first, env)
  384. elif val.first == 'quasiquote':
  385. level += 1
  386.  
  387. return val.map(lambda elem: quasiquote_item(elem, env, level))
  388.  
  389. check_form(expressions, 1, 1)
  390. return quasiquote_item(expressions.first, env, 1)
  391.  
  392. def do_unquote(expressions, env):
  393. raise SchemeError('unquote outside of quasiquote')
  394.  
  395.  
  396. SPECIAL_FORMS = {
  397. 'and': do_and_form,
  398. 'begin': do_begin_form,
  399. 'cond': do_cond_form,
  400. 'define': do_define_form,
  401. 'if': do_if_form,
  402. 'lambda': do_lambda_form,
  403. 'let': do_let_form,
  404. 'or': do_or_form,
  405. 'quote': do_quote_form,
  406. 'define-macro': do_define_macro,
  407. 'quasiquote': do_quasiquote_form,
  408. 'unquote': do_unquote,
  409. }
  410.  
  411. # Utility methods for checking the structure of Scheme programs
  412.  
  413. def check_form(expr, min, max=float('inf')):
  414. """Check EXPR is a proper list whose length is at least MIN and no more
  415. than MAX (default: no maximum). Raises a SchemeError if this is not the
  416. case.
  417.  
  418. >>> check_form(read_line('(a b)'), 2)
  419. """
  420. if not scheme_listp(expr):
  421. raise SchemeError('badly formed expression: ' + repl_str(expr))
  422. length = len(expr)
  423. if length < min:
  424. raise SchemeError('too few operands in form')
  425. elif length > max:
  426. raise SchemeError('too many operands in form')
  427.  
  428. def check_formals(formals):
  429. """Check that FORMALS is a valid parameter list, a Scheme list of symbols
  430. in which each symbol is distinct. Raise a SchemeError if the list of
  431. formals is not a list of symbols or if any symbol is repeated.
  432.  
  433. >>> check_formals(read_line('(a b c)'))
  434. """
  435. symbols = set()
  436. def check_and_add(symbol, is_last):
  437. if not scheme_symbolp(symbol):
  438. raise SchemeError('non-symbol: {0}'.format(symbol))
  439. if symbol in symbols:
  440. raise SchemeError('duplicate symbol: {0}'.format(symbol))
  441. symbols.add(symbol)
  442.  
  443. while isinstance(formals, Pair):
  444. check_and_add(formals.first, formals.rest is nil)
  445. formals = formals.rest
  446.  
  447.  
  448. def check_procedure(procedure):
  449. """Check that PROCEDURE is a valid Scheme procedure."""
  450. if not scheme_procedurep(procedure):
  451. raise SchemeError('{0} is not callable: {1}'.format(
  452. type(procedure).__name__.lower(), repl_str(procedure)))
  453.  
  454. #################
  455. # Dynamic Scope #
  456. #################
  457.  
  458. class MuProcedure(Procedure):
  459. """A procedure defined by a mu expression, which has dynamic scope.
  460. _________________
  461. < Scheme is cool! >
  462. -----------------
  463. \ ^__^
  464. \ (oo)\_______
  465. (__)\ )\/\
  466. ||----w |
  467. || ||
  468. """
  469.  
  470. def __init__(self, formals, body):
  471. """A procedure with formal parameter list FORMALS (a Scheme list) and
  472. Scheme list BODY as its definition."""
  473. self.formals = formals
  474. self.body = body
  475.  
  476. # BEGIN PROBLEM 15
  477. def make_call_frame(self, args, env):
  478. return env.make_child_frame(self.formals, args)
  479. # END PROBLEM 15
  480.  
  481. def __str__(self):
  482. return str(Pair('mu', Pair(self.formals, self.body)))
  483.  
  484. def __repr__(self):
  485. return 'MuProcedure({0}, {1})'.format(
  486. repr(self.formals), repr(self.body))
  487.  
  488. def do_mu_form(expressions, env):
  489. """Evaluate a mu form."""
  490. check_form(expressions, 2)
  491. formals = expressions.first
  492. check_formals(formals)
  493. # BEGIN PROBLEM 15
  494. return MuProcedure(expressions.first, expressions.rest)
  495. # END PROBLEM 15
  496.  
  497. SPECIAL_FORMS['mu'] = do_mu_form
  498.  
  499. ###########
  500. # Streams #
  501. ###########
  502.  
  503. class Promise(object):
  504. """A promise."""
  505. def __init__(self, expression, env):
  506. self.expression = expression
  507. self.env = env
  508.  
  509. def evaluate(self):
  510. if self.expression is not None:
  511. value = scheme_eval(self.expression, self.env)
  512. if not (value is nil or isinstance(value, Pair)):
  513. raise SchemeError("result of forcing a promise should be a pair or nil, but was %s" % value)
  514. self.value = value
  515. self.expression = None
  516. return self.value
  517.  
  518. def __str__(self):
  519. return '#[promise ({0}forced)]'.format(
  520. 'not ' if self.expression is not None else '')
  521.  
  522. def do_delay_form(expressions, env):
  523. """Evaluates a delay form."""
  524. check_form(expressions, 1, 1)
  525. return Promise(expressions.first, env)
  526.  
  527. def do_cons_stream_form(expressions, env):
  528. """Evaluate a cons-stream form."""
  529. check_form(expressions, 2, 2)
  530. return Pair(scheme_eval(expressions.first, env),
  531. do_delay_form(expressions.rest, env))
  532.  
  533. SPECIAL_FORMS['cons-stream'] = do_cons_stream_form
  534. SPECIAL_FORMS['delay'] = do_delay_form
  535.  
  536. ##################
  537. # Tail Recursion #
  538. ##################
  539.  
  540. class Thunk(object):
  541. """An expression EXPR to be evaluated in environment ENV."""
  542. def __init__(self, expr, env):
  543. self.expr = expr
  544. self.env = env
  545.  
  546. def complete_apply(procedure, args, env):
  547. """Apply procedure to args in env; ensure the result is not a Thunk."""
  548. val = scheme_apply(procedure, args, env)
  549. if isinstance(val, Thunk):
  550. return scheme_eval(val.expr, val.env)
  551. else:
  552. return val
  553.  
  554. def optimize_tail_calls(original_scheme_eval):
  555. """Return a properly tail recursive version of an eval function."""
  556. def optimized_eval(expr, env, tail=False):
  557. """Evaluate Scheme expression EXPR in environment ENV. If TAIL,
  558. return a Thunk containing an expression for further evaluation.
  559. """
  560. if tail and not scheme_symbolp(expr) and not self_evaluating(expr):
  561. return Thunk(expr, env)
  562.  
  563. result = Thunk(expr, env)
  564. # BEGIN
  565. print("DEBUG:", result.expr)
  566. while isinstance(result, Thunk):
  567. result = original_scheme_eval(expr, env)
  568. #args = expr.rest.map(lambda arg: optimized_eval(arg, env, True))
  569. #result = complete_apply(expr.first, args, env)
  570. print('DEBUG: LOL')
  571. return result
  572. # END
  573. return optimized_eval
  574.  
  575.  
  576.  
  577.  
  578.  
  579.  
  580. ################################################################
  581. # Uncomment the following line to apply tail call optimization #
  582. ################################################################
  583. scheme_eval = optimize_tail_calls(scheme_eval)
  584.  
  585.  
  586.  
  587.  
  588.  
  589.  
  590. ####################
  591. # Extra Procedures #
  592. ####################
  593.  
  594. def scheme_map(fn, s, env):
  595. check_type(fn, scheme_procedurep, 0, 'map')
  596. check_type(s, scheme_listp, 1, 'map')
  597. return s.map(lambda x: complete_apply(fn, Pair(x, nil), env))
  598.  
  599. def scheme_filter(fn, s, env):
  600. check_type(fn, scheme_procedurep, 0, 'filter')
  601. check_type(s, scheme_listp, 1, 'filter')
  602. head, current = nil, nil
  603. while s is not nil:
  604. item, s = s.first, s.rest
  605. if complete_apply(fn, Pair(item, nil), env):
  606. if head is nil:
  607. head = Pair(item, nil)
  608. current = head
  609. else:
  610. current.rest = Pair(item, nil)
  611. current = current.rest
  612. return head
  613.  
  614. def scheme_reduce(fn, s, env):
  615. check_type(fn, scheme_procedurep, 0, 'reduce')
  616. check_type(s, lambda x: x is not nil, 1, 'reduce')
  617. check_type(s, scheme_listp, 1, 'reduce')
  618. value, s = s.first, s.rest
  619. while s is not nil:
  620. value = complete_apply(fn, scheme_list(value, s.first), env)
  621. s = s.rest
  622. return value
  623.  
  624. ################
  625. # Input/Output #
  626. ################
  627.  
  628. def read_eval_print_loop(next_line, env, interactive=False, quiet=False,
  629. startup=False, load_files=(), report_errors=False):
  630. """Read and evaluate input until an end of file or keyboard interrupt."""
  631. if startup:
  632. for filename in load_files:
  633. scheme_load(filename, True, env)
  634. while True:
  635. try:
  636. src = next_line()
  637. while src.more_on_line:
  638. expression = scheme_read(src)
  639. result = scheme_eval(expression, env)
  640. if not quiet and result is not None:
  641. print(repl_str(result))
  642. except (SchemeError, SyntaxError, ValueError, RuntimeError) as err:
  643. if report_errors:
  644. if isinstance(err, SyntaxError):
  645. err = SchemeError(err)
  646. raise err
  647. if (isinstance(err, RuntimeError) and
  648. 'maximum recursion depth exceeded' not in getattr(err, 'args')[0]):
  649. raise
  650. elif isinstance(err, RuntimeError):
  651. print('Error: maximum recursion depth exceeded')
  652. else:
  653. print('Error:', err)
  654. except KeyboardInterrupt: # <Control>-C
  655. if not startup:
  656. raise
  657. print()
  658. print('KeyboardInterrupt')
  659. if not interactive:
  660. return
  661. except EOFError: # <Control>-D, etc.
  662. print()
  663. return
  664.  
  665. def scheme_load(*args):
  666. """Load a Scheme source file. ARGS should be of the form (SYM, ENV) or
  667. (SYM, QUIET, ENV). The file named SYM is loaded into environment ENV,
  668. with verbosity determined by QUIET (default true)."""
  669. if not (2 <= len(args) <= 3):
  670. expressions = args[:-1]
  671. raise SchemeError('"load" given incorrect number of arguments: '
  672. '{0}'.format(len(expressions)))
  673. sym = args[0]
  674. quiet = args[1] if len(args) > 2 else True
  675. env = args[-1]
  676. if (scheme_stringp(sym)):
  677. sym = eval(sym)
  678. check_type(sym, scheme_symbolp, 0, 'load')
  679. with scheme_open(sym) as infile:
  680. lines = infile.readlines()
  681. args = (lines, None) if quiet else (lines,)
  682. def next_line():
  683. return buffer_lines(*args)
  684.  
  685. read_eval_print_loop(next_line, env, quiet=quiet, report_errors=True)
  686.  
  687. def scheme_load_all(directory, env):
  688. """
  689. Loads all .scm files in the given directory, alphabetically. Used only
  690. in tests/ code.
  691. """
  692. assert scheme_stringp(directory)
  693. directory = eval(directory)
  694. import os
  695. for x in sorted(os.listdir(".")):
  696. if not x.endswith(".scm"):
  697. continue
  698. scheme_load(x, env)
  699.  
  700. def scheme_open(filename):
  701. """If either FILENAME or FILENAME.scm is the name of a valid file,
  702. return a Python file opened to it. Otherwise, raise an error."""
  703. try:
  704. return open(filename)
  705. except IOError as exc:
  706. if filename.endswith('.scm'):
  707. raise SchemeError(str(exc))
  708. try:
  709. return open(filename + '.scm')
  710. except IOError as exc:
  711. raise SchemeError(str(exc))
  712.  
  713. def create_global_frame():
  714. """Initialize and return a single-frame environment with built-in names."""
  715. env = Frame(None)
  716. env.define('eval',
  717. BuiltinProcedure(scheme_eval, True, 'eval'))
  718. env.define('apply',
  719. BuiltinProcedure(complete_apply, True, 'apply'))
  720. env.define('load',
  721. BuiltinProcedure(scheme_load, True, 'load'))
  722. env.define('load-all',
  723. BuiltinProcedure(scheme_load_all, True, 'load-all'))
  724. env.define('procedure?',
  725. BuiltinProcedure(scheme_procedurep, False, 'procedure?'))
  726. env.define('map',
  727. BuiltinProcedure(scheme_map, True, 'map'))
  728. env.define('filter',
  729. BuiltinProcedure(scheme_filter, True, 'filter'))
  730. env.define('reduce',
  731. BuiltinProcedure(scheme_reduce, True, 'reduce'))
  732. env.define('undefined', None)
  733. add_builtins(env, BUILTINS)
  734. return env
  735.  
  736. @main
  737. def run(*argv):
  738. import argparse
  739. parser = argparse.ArgumentParser(description='CS 61A Scheme Interpreter')
  740. parser.add_argument('-load', '-i', action='store_true',
  741. help='run file interactively')
  742. parser.add_argument('file', nargs='?',
  743. type=argparse.FileType('r'), default=None,
  744. help='Scheme file to run')
  745. args = parser.parse_args()
  746.  
  747.  
  748. next_line = buffer_input
  749. interactive = True
  750. load_files = []
  751.  
  752. if args.file is not None:
  753. if args.load:
  754. load_files.append(getattr(args.file, 'name'))
  755. else:
  756. lines = args.file.readlines()
  757. def next_line():
  758. return buffer_lines(lines)
  759. interactive = False
  760.  
  761. read_eval_print_loop(next_line, create_global_frame(), startup=True,
  762. interactive=interactive, load_files=load_files)
  763. tscheme_exitonclick()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement