def jsify_dict(node: ast.Dict) -> List[Compilable]: # keys, values output = [] for k, v in zip(node.keys, node.values): jk = jsify_node(k) jv = jsify_node(v) if len(jk) != 1: raise CompilationError( f'Dict key: Expected only one JSExpression (or Compilable) while got ' f'{len(jk)}: {jk!r}') if len(jv) != 1: raise CompilationError( f'Dict value: Expected only one JSExpression (or Compilable) while got ' f'{len(jv)}: {jv!r}') output.append( JSExpression([ JSExpression(['[', jk[0], ']', ':']), jv[0], ])) return [JSExpression([ '{', JSExpression(output), '}', ])]
def jsify_import(node: ast.Import) -> typing.List[Compilable]: requires = [] names = node.names for alias in names: alias: ast.alias requires.append( JSStatement('const ', [ JSExpression([alias.asname or alias.name]), ' = ', 'require(', JSExpression([f'"not_python/{alias.name}.js"']), ')' ])) return requires
def jsify_fstring(node: ast.JoinedStr) -> typing.List[Compilable]: values = [] for i in node.values: if isinstance(i, ast.FormattedValue): values.append(JSExpression(['${', *jsify_node(i), '}'])) else: if isinstance(i, ast.Constant): values.append(JSExpression([i.value])) else: values.extend(jsify_node(i)) return [JSExpression(['`', *values, '`'])]
def _jsify_sequential_container(node, prefix, suffix) -> List[Compilable]: elts = [] for i in node.elts: v = jsify_node(i) if len(v) != 1: raise CompilationError( f'Expected only one JSExpression (or Compilable) while got {len(v)}: {v!r}' ) elts.append(v[0]) elts.append(', ') return [JSExpression([prefix, JSExpression(elts), suffix])]
def jsify_formatted_value(node: ast.FormattedValue) -> typing.List[Compilable]: value = jsify_node(node.value) if node.format_spec: fspec = jsify_node(node.format_spec) return [ JSExpression(['unholy_js.py__format(', *value, ', ', *fspec, ')']) ] else: return value
def jsify_comparison(node: ast.Compare) -> List[Compilable]: # left, ops, comparators, left_most = node.left values = node.comparators out = [] left = left_most for num, val in enumerate(values): right = val oper = type(node.ops[num]) try: out.append(PY_TO_JS_OPERATORS[oper](left, right)) except KeyError as e: raise CompilationError(f'no known way to compile comparison operator {oper}') from e left = right new_out = [] for i in out: new_out.append(JSExpression(['&&'])) new_out.append(i) new_out.pop(0) # remove leading '&&' return [JSExpression(new_out)]
import ast from typing import List # noinspection PyUnresolvedReferences from typechecker import ensure_typecheck from unholy import jsify_node # noinspection PyUnresolvedReferences from unholy.classes import Compilable, CompilationError, JSExpression PY_TO_JS_OPERATORS = { ast.Mult: lambda l, r: JSExpression([ *jsify_node(l), '*', *jsify_node(r), ]), ast.Div: lambda l, r: JSExpression([ *jsify_node(l), '/', *jsify_node(r), ]), ast.Add: lambda l, r: JSExpression([ *jsify_node(l), '+', *jsify_node(r), ]), ast.Pow: lambda l, r: JSExpression([ *jsify_node(l), '**', *jsify_node(r), ]), ast.USub: lambda l, r: JSExpression([