def func_rest(arg): if isinstance(arg, parser.NilSymbol): return parser.LispList([]) if (isinstance(arg, parser.LispList) or isinstance(arg, parser.LispVector)): return parser.LispList(arg.values[1:]) raise ArgumentError("should be list or vector")
def quasiquote(ast): #print ("quasiquote with", printer.pr_str(ast, True)) if not is_pair(ast): #print("step i: ast is not pair", ast) return parser.LispList([parser.StrSymbol('quote'), ast]) if (isinstance(ast.values[0], parser.StrSymbol) and ast.values[0].val == 'unquote'): #print("step ii : found 'unquote'") return ast.values[1] if is_pair(ast.values[0]): zz = ast.values[0].values[0] #print ("zz", zz) #print ("t(zz)", type(zz)) if isinstance(zz, parser.StrSymbol) and zz.val == 'splice-unquote': #print("step iii : found 'splice-unquote'") return parser.LispList([ parser.StrSymbol('concat'), ast.values[0].values[1], quasiquote(parser.LispList(ast.values[1:])) ]) #print("step iv : else") return parser.LispList([ parser.StrSymbol('cons'), quasiquote(ast.values[0]), quasiquote(parser.LispList(ast.values[1:])) ])
def func_seq(arg): if (isinstance(arg, parser.NilSymbol)): return parser.NilSymbol() if (isinstance(arg, parser.LispList) or isinstance(arg, parser.LispVector)): if len(arg.values) == 0: return parser.NilSymbol() return parser.LispList(arg.values) if isinstance(arg, parser.LispString): if len(arg.str) == 0: return parser.NilSymbol() return parser.LispList([parser.LispString(x) for x in list(arg.str)])
def eval_ast(ast, env): if isinstance(ast, parser.StrSymbol): v = ast.val return env.get(v) elif isinstance(ast, parser.LispList): return parser.LispList([EVAL(x, env) for x in ast.values]) else: return ast
def func_conj(*args): first = args[0] first_values = list(first.values) #print(type(first)) #print(type(first.values)) rest = list(args[1:]) #print(type(rest)) if isinstance(first, parser.LispList): rest.reverse() return parser.LispList(rest + first_values) if isinstance(first, parser.LispVector): return parser.LispVector(first_values + rest) return parser.NilSymbol()
def func_map(fn, argList): """takes a function and a list (or vector) and evaluates the function against every element of the list (or vector) one at a time and returns the results as a list.""" retvals = [] for arg in argList.values: if isinstance(fn, parser.FuncClosure): r = fn.call([arg]) else: r = fn(arg) retvals.append(r) return parser.LispList(retvals)
def eval_ast(ast, env): if isinstance(ast, parser.StrSymbol): v = ast.val return env.get(v) elif isinstance(ast, parser.LispList): return parser.LispList([EVAL(x, env) for x in ast.values]) elif isinstance(ast, parser.LispVector): return parser.LispVector([EVAL(x, env) for x in ast.values]) elif isinstance(ast, parser.LispHashMap): keyvals = [] for k in ast.keys(): keyvals.append(EVAL(k, env)) keyvals.append(EVAL(ast.lookup(k), env)) return parser.LispHashMap(keyvals) else: return ast
def read_form(readerInst): """this function will peek at the first token in the Reader object and switch on the first character of that token. If the character is a left paren then read_list is called with the Reader object. Otherwise, read_atom is called with the Reader Ojbect. The return value from read_form is a MAL data type. You can likely just return a plain list of MAL types. """ tok = readerInst.peek() if tok is '(': return parser.LispList(read_list(readerInst, ')')) elif tok is '[': return parser.LispVector(read_list(readerInst, ']')) elif tok is '{': return parser.LispHashMap(read_list(readerInst, '}')) elif tok is '@': atSign = readerInst.next() nextForm = read_form(readerInst) return parser.LispList([parser.StrSymbol('deref'), nextForm]) elif tok is "'": readerInst.next() nextForm = read_form(readerInst) return parser.LispList([parser.StrSymbol('quote'), nextForm]) elif tok is "`": readerInst.next() nextForm = read_form(readerInst) return parser.LispList([parser.StrSymbol('quasiquote'), nextForm]) elif tok is "~": readerInst.next() nextForm = read_form(readerInst) return parser.LispList([parser.StrSymbol('unquote'), nextForm]) elif tok == "~@": readerInst.next() nextForm = read_form(readerInst) return parser.LispList([parser.StrSymbol('splice-unquote'), nextForm]) elif tok == "^": readerInst.next() nf = read_form(readerInst) nnf = read_form(readerInst) return parser.LispList([parser.StrSymbol('with-meta'), nnf, nf]) else: return read_atom(readerInst)
def mainloop(): while True: s = input("user> ") try: print (rep(s)) except ValueError as e: print(e) except IndexError as e: print(e) except parser.MalException as me: print(me) print(printer.pr_str(me.mal_obj, True)) if __name__ == "__main__": if len(sys.argv) == 1: mainloop() else: #print ("processing command line:", sys.argv) fn = sys.argv[1] #print ("processing file:", fn) #print ("extra args:", sys.argv[2:]) argStrings = [parser.LispString(x) for x in sys.argv[2:]] listObj = parser.LispList(argStrings) repl_env.set('*ARGV*', listObj) rep('(load-file "{0}")'.format(fn)) #print("Done")
def func_list(*args): return parser.LispList(args)
def func_vals(arg): vals = [] for k in arg.keys(): vals.append(arg.lookup(k)) return parser.LispList(vals)
def func_keys(arg): return parser.LispList(list(arg.keys()))
def func_concat(*args): outvals = [] for a in args: outvals += a.values return parser.LispList(outvals)
def EVAL(ast, env): while True: #print ("evaluating", ast) if not isinstance(ast, parser.LispList): return eval_ast(ast, env) if len(ast.values) == 0: return ast op = ast.values[0] #print ("op", op) if isinstance(op, parser.StrSymbol) and op.val == 'def!': """call the set method of the current environment (second parameter of EVAL called env) using the unevaluated first parameter (second list element) as the symbol key and the evaluated second parameter as the value.""" val = EVAL(ast.values[2], env) env.set(ast.values[1].val, val) return val elif isinstance(op, parser.StrSymbol) and op.val == 'let*': newenv = environment.Environment(env) for i in range(0, len(ast.values[1]), 2): name = ast.values[1][i].val val = EVAL(ast.values[1][i + 1], newenv) newenv.set(name, val) env = newenv ast = ast.values[2] continue elif isinstance(op, parser.StrSymbol) and op.val == 'do': ret = None for t in ast.values[1:-1]: #print ("evaluating",t) ret = EVAL(t, env) #print ("got ret") #print ("env:", env) ast = ast.values[-1] continue elif isinstance(op, parser.StrSymbol) and op.val == 'if': #print ("evaluating if") test = EVAL(ast.values[1], env) #print ("test:", test) if not (isinstance(test, parser.NilSymbol) or isinstance(test, parser.FalseSymbol)): # true eval #print ("test was true, evaluating", ast.values[2]) ast = ast.values[2] continue elif len(ast.values) > 3: #print ("test was false, evaluating else", ast.values[3]) #else ast = ast.values[3] continue else: #print ("test was false, returning Nil") return parser.NilSymbol() elif isinstance(op, parser.StrSymbol) and op.val == 'fn*': newenv = environment.Environment(env, [], []) params = [x.val for x in ast.values[1].values] body = ast.values[2] #print ("making func", params, body) funcClosure = parser.FuncClosure(newenv, params, body) return funcClosure else: ast_list = eval_ast(ast, env) if isinstance(ast_list.values[0], parser.FuncClosure): func = ast_list.values[0] newenv = environment.Environment(func.env, [], []) for i in range(len(func.params)): p = func.params[i] if p == '&': nextP = func.params[i + 1] val = parser.LispList(ast_list.values[i + 1:]) newenv.set(nextP, val) break val = ast_list.values[1 + i] newenv.set(p, val) ast = func.body env = newenv continue #print ("about to call", ast_list.values[0]) return ast_list.values[0](*ast_list.values[1:])