def set_vars (vars): nvars = {} for v, a in vars.items (): v = v.var if a.is_ufunc: if v in sparser.RESERVED_FUNCS: raise NameError (f'cannot assign undefined function to concrete function name {v!r}') if a.is_ufunc_anonymous: a = AST (a.op, v, *a [2:]) elif a.is_sym_anonymous: if a.is_sym_unqualified: raise CircularReferenceError ('cannot asign unqualified anonymous symbol') a = AST (a.op, v, *a [2:]) nvars [v] = a try: # check for circular references AST.apply_vars (AST (',', tuple (('@', v) for v in nvars)), {**_VARS, **nvars}) except RecursionError: raise CircularReferenceError ("I'm sorry, Dave. I'm afraid I can't do that.") from None _VARS.update (nvars) return list (nvars.items ())
def _vars_updated(): global _VARS_FLAT vars = { v: a if a.is_lamb else AST.apply_vars(a, _VARS, mode=False) for v, a in _VARS.items() } # flattened vars so sym and sparser don't need to do apply_vars() one = (f for f in filter(lambda f: _ENV.get(f), _ONE_FUNCS) ) # hidden functions for stuff like Gamma lamb = (va[0] for va in filter(lambda va: va[1].is_lamb, vars.items()) ) # user lambda functions assfunc = (va[0] for va in filter( lambda va: va[1].is_var and va[1].var in AST.Func.PYBASE, vars.items()) ) # user variables assigned to concrete functions funcs = {*one, *lamb, *assfunc} sym.set_sym_user_vars(vars) sym.set_sym_user_funcs(funcs) sparser.set_sp_user_vars(vars) sparser.set_sp_user_funcs(funcs) _UFUNC_MAP.clear() _SYM_MAP.clear() _SYM_VARS.clear() _VARS_FLAT = vars for v, a in vars.items(): # build ufunc and sym mapback dict if v != '_': if a.is_ufunc: _UFUNC_MAP.setdefault(a, set()).add(v) elif a.is_sym: _SYM_MAP.setdefault(a, set()).add(v) _SYM_VARS.add(v)
def _prepare_ass(ast): # check and prepare for simple or tuple assignment if not ast.ass_valid: vars = None elif ast.ass_valid.error: raise RealityRedefinitionError(ast.ass_valid.error) else: vars, ast = ast.ass_valid.lhs, ast.ass_valid.rhs vars = list(vars.comma) if vars.is_comma else [vars] return AST.apply_vars(ast, _VARS_FLAT), vars
def evalexpr(ast): sym.ast2spt.set_precision(ast) if ast.is_func and ast.func in AST.Func.PLOT: # plotting? args, kw = AST.args2kwargs(AST.apply_vars(ast.args, _VARS), sym.ast2spt) ret = getattr(splot, ast.func)(*args, **kw) return { 'msg': [ 'Plotting not available because matplotlib is not installed.' ] } if ret is None else { 'img': ret } elif ast.op in { '@', '-func' } and ast[1] in AST.Func.ADMIN: # special admin function? asts = globals()[f'_admin_{ast [1]}']( *(ast.args if ast.is_func else ())) if isinstance(asts, str): return {'msg': [asts]} elif isinstance(asts, list) and isinstance(asts[0], str): return {'msg': asts} else: # not admin function, normal evaluation ast, vars = _prepare_ass(ast) if _SYMPAD_DEBUG: print('ast: ', ast, file=sys.stderr) try: spt, xlat = sym.ast2spt(ast, retxlat=True) # , _VARS) if _SYMPAD_DEBUG and xlat: print('xlat: ', xlat, file=sys.stderr) sptast = sym.spt2ast(spt) except: if _SYMPAD_DEBUG: print(file=sys.stderr) raise if _SYMPAD_DEBUG: try: print('spt: ', repr(spt), file=sys.stderr) except: pass print('spt type: ', type(spt), file=sys.stderr) try: print('spt args: ', repr(spt.args), file=sys.stderr) except: pass print('spt latex: ', sp.latex(spt), file=sys.stderr) print('spt ast: ', sptast, file=sys.stderr) print('spt tex: ', sym.ast2tex(sptast), file=sys.stderr) print('spt nat: ', sym.ast2nat(sptast), file=sys.stderr) print('spt py: ', sym.ast2py(sptast), file=sys.stderr) print(file=sys.stderr) asts = _execute_ass(sptast, vars) response = {} if asts and asts[0] != AST.None_: response.update({ 'math': [{ 'tex': sym.ast2tex(ast), 'nat': sym.ast2nat(ast), 'py': sym.ast2py(ast), } for ast in asts] }) return response