def parse_binary_expr(node): g_flag_vals = list(map(parse_unary, node["val"])) g_ops = list(map(parse_bi_oper, node["op"])) g_vals = [] partial_idx = -1 for i in range(len(g_flag_vals)): g_vals.append(g_flag_vals[i][1]) if g_flag_vals[i][0] == "PARTIAL": syntax_cond_assert( partial_idx < 0, "partial binary expression can only have one unknown arg") partial_idx = i def ori_warpper(env): vals, ops = copy.copy(g_vals), copy.copy(g_ops) return compute_expr(env, vals, ops) def partial_warpper(env): def warpper(v): vals, ops = copy.copy(g_vals), copy.copy(g_ops) vals[partial_idx] = lambda env: g_vals[partial_idx](env)(v) return compute_expr(env, vals, ops) return warpper func = ori_warpper if partial_idx < 0 else partial_warpper return exception_warp(func, node["msg"])
def proc(*arg_val_list): syntax_cond_assert(len(arg_var_list) == len(arg_val_list), \ "unmatched arguments, need %d actually %d"%(len(arg_var_list), len(arg_val_list))) new_env = Env(arg_var_list, arg_val_list, outer=env) val = body_f(new_env) del new_env return val
def parse_case_expr(node, args_num=0): val = parse_block_or_expr(node["val"]) if node["type"] == "CASE_IF": cond_expr = parse_pipe_or_expr(node["cases"]) cond = lambda env, args: (cond_expr(env), []) elif node["type"] == "CASE_MULTI": syntax_cond_assert(args_num >= len(node["cases"]), "args less than case patterns") match_cases = list(map(parse_case_match_expr, node["cases"])) cond = lambda env, args: match_multi_cases(match_cases, args) else: # CASE_OTHERWISE cond = lambda env, args: (True, []) return (cond, val)
def parse_args(node): syntax_cond_assert(node["type"] in ("ARGS", "TUPLE", "PARN", "PARTIAL"), "error type") arg_vals = list(map(parse_pipe_or_expr, node["val"])) default_vals = [] if "default_vals" in node: default_vals = list(map(parse_pipe_or_expr, node["default_vals"])) partial_idx = [] for i, t in enumerate(arg_vals): if t is PARTIAL_FLAG_LAMBDA: partial_idx.append(i) def _args(env): r_default = {} if "default_args" in node: r_default_vals = [f(env) for f in default_vals] r_default = dict(zip(node["default_args"], r_default_vals)) r_arg_vals = [f(env) for f in arg_vals] return (r_arg_vals, r_default) return _args, tuple(partial_idx)
def python_import(_from, _import, _as): if _from: fromlist = _from.split(".") top_module = __import__(_from, fromlist=fromlist) _import_str, _import_val = "", [] for tkn in _import: if tkn.tp == "SEP": syntax_cond_assert(_import_str != "") _import_val.append(_import_str) _import_str = "" else: _import_str += tkn.val if _import_str: _import_val.append(_import_str) env = {} syntax_cond_assert(len(_as) == 0 or len(_as) == len(_import_val)) as_name = _as + [None] * len(_import_val) for t, g in zip(_import_val, as_name): sub_modules = t.split(".") nm = g if g else sub_modules[-1] if _from: env[nm] = top_module.__getattribute__(t) else: env[nm] = __import__(t, fromlist=sub_modules) return env
def parse_assign(node): if node["val"]["type"] in ("ASSIGN", "GASSIGN"): val = parse_assign(node["val"]) else: val = parse_pipe_or_expr(node["val"]) var_idx_val = None def _assign_var(env): right_val = val(env) if node["type"] == "GASSIGN": env = env.globals env[var] = right_val return right_val def _assign_expr_val(env): right_val = val(env) left_idx = var_idx_val(env) if node["type"] == "GASSIGN": env = env.globals left_val = var_val(env) left_val[left_idx] = right_val return right_val def _assign_unpack(env): right_val = val(env) if node["type"] == "GASSIGN": env = env.globals env.update(lst_combine(vars_tuple, right_val)) return right_val if node["var"]["type"] == "VAR": var = node["var"]["name"] return _assign_var elif node["var"]["type"] == "TUPLE": vars_tuple = [] for ele in node["var"]["val"]: if ele["type"] != "VAR": Error("multi assign only support variables, like a,b,c") vars_tuple.append(ele["name"]) return _assign_unpack else: var = node["var"] syntax_cond_assert(var["type"] == "UNARY" and len(var["suffix"]) > 0, "assign: left value is invalid") var_idx = var["suffix"][-1] var["suffix"] = var["suffix"][0:-1] syntax_cond_assert(var_idx["type"] == "LIST", "assign: left value is invalid") syntax_cond_assert( len(var_idx["val"]) == 1, "assign: left value is invalid") var_idx_val = parse_pipe_or_expr(var_idx["val"][0]) var_val = parse_pipe_or_expr(var) return _assign_expr_val
nums = len(lines) time_start = time.time() for line in lines: query = line.strip() if not query: continue ans = engine.apply(query) print(query, " =>\t", ans) a_time = time.time() - time_start print('totally cost', a_time, a_time / nums) if __name__ == "__main__": import sys ARGV = sys.argv[1:] lex_file, in_str, in_file, dict_dir = None, None, None, None for i in range(0, len(ARGV) - 1): if ARGV[i] == "-i": lex_file = ARGV[i + 1] elif ARGV[i] == "-f": in_file = ARGV[i + 1] elif ARGV[i] == "-s": in_str = ARGV[i + 1] elif ARGV[i] == "-d": dict_dir = ARGV[i + 1] syntax_cond_assert(lex_file is not None, "need input lex file") syntax_cond_assert(in_str or in_file, "need input str") run(lex_file, in_str, in_file, dict_dir)
def parse_parn(node): syntax_cond_assert(len(node["val"]) == 1, "error: empty parn") parn_node = parse_pipe_or_expr(node["val"][0]) return lambda env: parn_node(env)
def lst_combine(var, v): syntax_cond_assert( len(var) == len(v), "Value error: unpack %d values with %d variables" % (len(var), len(v))) return list(zip(var, v))
def _cd(env): cmd_val = cmd(env) syntax_cond_assert( type(cmd_val) in [str, int], "Value Error: cd accept a string or int") return cd(cmd_val)
def parse_import(node): import sys, os def python_import(_from, _import, _as): if _from: fromlist = _from.split(".") top_module = __import__(_from, fromlist=fromlist) _import_str, _import_val = "", [] for tkn in _import: if tkn.tp == "SEP": syntax_cond_assert(_import_str != "") _import_val.append(_import_str) _import_str = "" else: _import_str += tkn.val if _import_str: _import_val.append(_import_str) env = {} syntax_cond_assert(len(_as) == 0 or len(_as) == len(_import_val)) as_name = _as + [None] * len(_import_val) for t, g in zip(_import_val, as_name): sub_modules = t.split(".") nm = g if g else sub_modules[-1] if _from: env[nm] = top_module.__getattribute__(t) else: env[nm] = __import__(t, fromlist=sub_modules) return env def user_import_py(path, _as): from importlib.machinery import SourceFileLoader return SourceFileLoader(_as, path).load_module() def user_import_psh(path, module_name): from eval_ast import load_psh_file def _load(env): env.update({module_name: load_psh_file(path, env)}) return _load """ not neccssily def user_import_package(path, file_suffix): if file_suffix == ".py": return user_import_py(path + file_suffix, _as) elif file_suffix == ".psh": return user_import_psh(path) else: onlyfiles = [ f for f in os.listdir(path) ] env[_as] = user_import_package(path) """ _from, _import, _as = node["from"], node["import"], node["as"] module = {} if _from or _import[0].tp != "STRING": module = python_import(_from, _import, _as) return lambda env: env.update(module) else: syntax_cond_assert( len(_as) <= 1, "User Import Error: too many names after AS") path = _import[0].val.strip() syntax_cond_assert(os.path.isfile(path), "Error: path %s is not a file" % path) if len(_as) == 1: module_name = _as[0] else: module_name = os.path.split(path)[1].split(".")[0] if path.endswith(".py"): module_context = user_import_py(path, module_name) return lambda env: env.update({module_name: module_context}) elif path.endswith(".psh"): return user_import_psh(path, module_name) else: Error("expected py or psh file")
def _sh(env): cmd_val = cmd(env) syntax_cond_assert( type(cmd_val) == str, "Value Error: sh handles a string") return osCall(cmd_val)