Example #1
0
def _execute_ass(ast, vars):  # execute assignment if it was detected
    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())

    # start here
    if not vars:  # no assignment
        if not ast.is_ufunc:
            ast = _mapback(ast)

        _VARS['_'] = ast

        _vars_updated()

        return [ast]

    if len(vars) == 1:  # simple assignment
        if ast.op not in {'-ufunc', '-sym'}:
            ast = _mapback(ast, vars[0].var, {vars[0].var})

        vars = set_vars({vars[0]: ast})

    else:  # tuple assignment
        ast = ast.strip_paren

        if ast.op in {',', '[', '-set'}:
            asts = ast[1]

        else:
            asts = []
            itr = iter(sym.ast2spt(ast))

            for i in range(len(vars) + 1):
                try:
                    ast = sym.spt2ast(next(itr))
                except StopIteration:
                    break

                if vars[i].is_ufunc_named:
                    asts.append(AST.Ass.ufunc2lamb(vars[i], ast))

                    vars[i] = AST('@', vars[i].ufunc)

                else:
                    asts.append(ast)

        if len(vars) < len(asts):
            raise ValueError(
                f'too many values to unpack (expected {len (vars)})')
        elif len(vars) > len(asts):
            raise ValueError(
                f'not enough values to unpack (expected {len (vars)}, got {len (asts)})'
            )

        vasts = list(zip(vars, asts))
        exclude = set(va[0].var
                      for va in filter(lambda va: va[1].is_ufunc, vasts))
        asts = [
            a if a.op in {'-ufunc', '-sym'} else _mapback(a, v.var, exclude)
            for v, a in vasts
        ]
        vars = set_vars(dict(zip(vars, asts)))

    _vars_updated()

    return _present_vars(vars)
Example #2
0
        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
Example #3
0
def _admin_env(*args):
    vars_updated = False

    def _envop(env, apply):
        nonlocal vars_updated

        msgs = []

        for var, state in env.items():
            if apply:
                _ENV[var] = state

            if var == 'EI':
                msgs.append(
                    f'Uppercase E and I is {"on" if state else "off"}.')

                if apply:
                    AST.EI(state)

                    for var in (AST.E.var, AST.I.var):
                        if var in _VARS:
                            del _VARS[var]

            elif var == 'quick':
                msgs.append(f'Quick input mode is {"on" if state else "off"}.')

                if apply:
                    sym.set_quick(state)
                    _PARSER.set_quick(state)

                    vars_updated = True

            elif var == 'pyS':
                msgs.append(
                    f'Python S escaping is {"on" if state else "off"}.')

                if apply:
                    sym.set_pyS(state)

            elif var == 'simplify':
                msgs.append(
                    f'Post-evaluation simplify is {"on" if state else "off"}.')

                if apply:
                    sym.set_simplify(state)

            elif var == 'matsimp':
                msgs.append(
                    f'Matrix simplify is {"broken" if not spatch.SPATCHED else "on" if state else "off"}.'
                )

                if apply:
                    spatch.set_matmulsimp(state)

            elif var == 'ufuncmap':
                msgs.append(
                    f'Undefined function map to variable is {"on" if state else "off"}.'
                )

                if apply:
                    global _UFUNC_MAPBACK
                    _UFUNC_MAPBACK = state

            elif var == 'prodrat':
                msgs.append(
                    f'Leading product rational is {"on" if state else "off"}.')

                if apply:
                    sym.set_prodrat(state)

            elif var == 'doit':
                msgs.append(f'Expression doit is {"on" if state else "off"}.')

                if apply:
                    sym.set_doit(state)

            elif var == 'strict':
                msgs.append(
                    f'Strict LaTeX formatting is {"on" if state else "off"}.')

                if apply:
                    sym.set_strict(state)

            elif var in _ONE_FUNCS:
                msgs.append(f'Function {var} is {"on" if state else "off"}.')

                if apply:
                    vars_updated = True

        return msgs

    # start here
    if not args:
        return _envop(_ENV, False)

    env = OrderedDict()

    for arg in args:
        if arg.is_ass:
            var = arg.lhs.as_identifier

            if var:
                state = bool(sym.ast2spt(arg.rhs))

        else:
            var = arg.as_identifier

            if var:
                if var[:2] == 'no':
                    var, state = var[2:], False
                else:
                    state = True

        if var is None:
            raise TypeError(f'invalid argument {sym.ast2nat (arg)!r}')
        elif var not in _ENV_OPTS:
            raise NameError(f'invalid environment setting {var!r}')

        env[var] = state

    ret = _envop(env, True)

    if vars_updated:
        _vars_updated()

    return ret