def simplify(expr, env): if isinstance(expr, sym): try: return env[expr] except KeyError: raise NameError("symbol %s is not defined"%(expr,)) elif isinstance(expr, hack): return simplify(expr[0], expr[1]) elif isinstance(expr, linked_list): f = expr[0] if isinstance(f, jcli_parser.syntax): f=f.value if f == sym('define'): if len(expr) != 3: raise SyntaxError("bad syntax in define") env[expr[1].value] = eval_ast(expr[2], env) elif f == sym('lambda'): if len(expr) != 3: raise SyntaxError("bad syntax in lambda") arg_names = expr[1].value body = expr[2] def function(*args): c = closure(env) if len(arg_names) != len(args): raise TypeError( 'function expected %s arguments, got %s' %(len(arg_names), len(args))) for arg_name, arg in zip(arg_names, args): c[arg_name.value] = arg out = hack((body.value, c)) return out return function elif f == sym('if'): if len(expr) != 4: raise SyntaxError("bad syntax in if") if eval_ast(expr[1], env): return hack((expr[2].value, env)) else: return hack((expr[3].value, env)) elif f == sym('quote'): if len(expr) != 2: raise SyntaxError("bad syntax in quote") return quote(jcli_parser.syntax_to_list(expr[1])) elif f == sym('begin'): out = None for sub_expr in cdr(expr): out = eval_ast(sub_expr, env) return out else: return apply( eval_ast(expr[0], env), map(lambda x: eval_ast(x, env), cdr(expr))) else: return expr
def eval(string, bindings=None, builtins=None): if builtins is None: builtins = jcli_globals if bindings is None: bindings = closure(builtins) else: bindings = {sym(k): bindings[k] for k in bindings.keys()} bindings.update(builtins) asts = jcli_parser.parse(string) return list(map(lambda ast: eval_ast(ast, bindings), asts))
def match_quote(tokens): if len(tokens) < 2: return None if tokens[0].name != "QUOTE": return None match = match_expr(tokens[1:]) if match is not None: t = tokens[0] quote = syntax(sym("quote"), t.line_no, t.char_no) expr = linked_list([quote, match[0]]) return syntax(expr, t.line_no, t.char_no), match[1] + 1
def match_literal(tokens): if len(tokens) == 0: return None token = tokens[0] name = token.name string = token.string value = None if name == "INTEGER": value = int(string) if name == "FLOAT": value = float(string) if name == "BOOL": value = bool(string) if name == "STRING": value = str(string) if name == "ID": value = sym(string) if value is not None: return syntax(value, token.line_no, token.char_no), 1
from jcli_datatypes import linked_list, sym, quote, closure, car, cdr, cons, null import jcli_tokenizer import jcli_parser import operator jcli_globals = { sym('eval'): lambda x: ( eval_ast(x.value, closure(jcli_globals)) if isinstance(x, quote) else x), sym('+'): operator.add, sym('-'): operator.sub, sym('*'): operator.mul, # sym('/'): operator.div, sym('='): operator.eq, sym('or'): lambda x,y: x or y, sym('and'): lambda x,y: x and y, sym('not'): lambda x: not x, sym('cons'): lambda x,y: cons(x, y.value), sym('car'): lambda x: car(x.value), sym('cdr'): lambda x: cdr(x.value),} def eval(string, bindings=None, builtins=None): if builtins is None: builtins = jcli_globals if bindings is None: bindings = closure(builtins) else: bindings = {sym(k): bindings[k] for k in bindings.keys()} bindings.update(builtins)