Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import math, operator as op
- import re
- Symbol = str
- List = list
- Number = (int, float)
- class String(str): pass
- def tokenize(s):
- "Convert a string into a list of tokens, including strings in quotes."
- pattern = r'''\s*(?:(;.*) # comments
- |("(?:\\.|[^\\"])*") # strings
- |([()]|[^\s()"']+)) # parentheses or symbols
- '''
- tokens = []
- for part in re.findall(pattern, s, re.VERBOSE):
- if part[0]: continue # skip comments
- tokens.append(part[1] or part[2])
- return tokens
- def parse(tokens):
- if not tokens: raise SyntaxError('unexpected EOF')
- token = tokens.pop(0)
- if token == '(':
- L = []
- while tokens[0] != ')': L.append(parse(tokens))
- tokens.pop(0)
- return L
- elif token == ')':
- raise SyntaxError('unexpected )')
- else:
- return atom(token)
- def atom(token):
- if token.startswith('"') and token.endswith('"'):
- return String(token[1:-1]) # хранить как отдельный тип
- try: return int(token)
- except ValueError:
- try: return float(token)
- except ValueError:
- return Symbol(token)
- def standard_env():
- env = {}
- env.update(vars(math))
- env.update({
- '+':op.add, '-':op.sub, '*':op.mul, '/':op.truediv,
- '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
- 'abs': abs, 'append': lambda x, y: x + [y],
- 'begin': lambda *x: x[-1],
- 'car': lambda x: x[0], 'cdr': lambda x: x[1:],
- 'cons': lambda x, y: [x] + y,
- 'eq?': op.is_, 'equal?': op.eq,
- 'length': len, 'list': lambda *x: list(x),
- 'list?': lambda x: isinstance(x, list),
- 'map': lambda f, l: list(map(f, l)),
- 'max': max, 'min': min, 'not': op.not_,
- 'null?': lambda x: x == [],
- 'number?': lambda x: isinstance(x, Number),
- 'print': print,
- 'mod': op.mod,
- })
- return env
- global_env = standard_env()
- class Env(dict):
- def __init__(self, parms=(), args=(), outer=None):
- super().__init__(zip(parms, args))
- self.outer = outer
- def find(self, var):
- # return self if var in self else self.outer.find(var)
- if var in self:
- return self[var]
- elif isinstance(self.outer, Env):
- return self.outer.find(var)
- else:
- return self.outer[var]
- def eval(x, env=global_env):
- if isinstance(x, String):
- return str(x)
- elif isinstance(x, Symbol):
- try:
- # return env[x]
- if isinstance(env, Env):
- return env.find(x)
- return env[x]
- except KeyError:
- raise NameError(f"Неизвестный символ {x}")
- elif not isinstance(x, List): return x
- op, *args = x
- if op == 'quote': return args[0]
- elif op == 'if':
- (test, conseq, alt) = args
- return eval(conseq if eval(test, env) else alt, env)
- elif op == 'define':
- (symbol, exp) = args
- env[symbol] = eval(exp, env)
- elif op == 'lambda':
- (parms, body) = args
- return lambda *args: eval(body, Env(parms, args, env))
- else:
- proc = eval(op, env)
- vals = [eval(arg, env) for arg in args]
- return proc(*vals)
- def repl(code):
- return eval(parse(tokenize(code)))
- repl('(print "Hello, world!")')
- code = """
- (begin
- (define fizzbuzz
- (lambda (n)
- (if (= (mod n 15) 0) "FizzBuzz"
- (if (= (mod n 3) 0) "Fizz"
- (if (= (mod n 5) 0) "Buzz"
- n)))))
- (map fizzbuzz (list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)))
- """
- print(repl(code))
- code = """
- (begin
- (define fact
- (lambda (n)
- (if (= n 0) 1
- (* n (fact (- n 1))))))
- (fact 5))
- """
- print(repl(code))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement