Path: blob/main/python/pylang/src/output/operators.py
1398 views
# vim:fileencoding=utf-81# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>2from __python__ import hash_literals3from ast_types import (AST_Array, AST_Assign, AST_BaseCall, AST_Binary,4AST_Conditional, AST_ItemAccess, AST_Number, AST_Object,5AST_Return, AST_Seq, AST_Set, AST_SimpleStatement,6AST_Statement, AST_String, AST_Sub, AST_Symbol,7AST_SymbolRef, AST_Unary, is_node_type)8from output.loops import unpack_tuple91011def print_getattr(self, output, skip_expression): # AST_Dot12if not skip_expression:13expr = self.expression14expr.print(output)15if is_node_type(expr, AST_Number) and expr.value >= 0:16if not RegExp("[xa-f.]", "i").test(output.last()):17output.print(".")18output.print(".")19# the name after dot would be mapped about here.20output.print_name(self.property)212223def print_getitem(self, output): # AST_Sub24expr = self.expression25prop = self.property26if (is_node_type(prop, AST_Number) or is_node_type(prop, AST_String)) or (27is_node_type(prop, AST_SymbolRef) and prop.name28and prop.name.startsWith('ρσ_')):29expr.print(output)30output.print('['), prop.print(output), output.print(']')31return32is_negative_number = is_node_type(33prop, AST_Unary) and prop.operator is "-" and is_node_type(34prop.expression, AST_Number)35is_repeatable = is_node_type(expr, AST_SymbolRef)36if is_repeatable:37expr.print(output)38else:39output.spaced('(ρσ_expr_temp', '=', expr), output.print(')')40expr = {'print': lambda: output.print('ρσ_expr_temp')}4142if is_negative_number:43output.print('['), expr.print(output), output.print(44'.length'), prop.print(output), output.print(']')45return46is_repeatable = is_node_type(prop, AST_SymbolRef)47# We have to check the type of the property because if it is a Symbol, it48# will raise a TypeError with the < operator.49if is_repeatable:50output.spaced('[(typeof', prop, '===', '"number"', '&&', prop)51output.spaced('', '<', '0)', '?',52expr), output.spaced('.length', '+', prop, ':', prop)53output.print("]")54else:55output.print('[ρσ_bound_index('), prop.print(56output), output.comma(), expr.print(output), output.print(')]')575859def print_rich_getitem(self, output): # AST_ItemAccess60func = 'ρσ_' + ('setitem' if self.assignment else 'getitem')61output.print(func + '(')62self.expression.print(output), output.comma(), self.property.print(output)63if self.assignment:64output.comma(), self.assignment.print(output)65output.print(')')666768def print_splice_assignment(self, output): # AST_Splice69# splice assignment via pythonic array[start:end]70output.print('ρσ_splice(')71self.expression.print(output), output.comma(), self.assignment.print(72output), output.comma()73self.property.print(output) if self.property else output.print('0')74if self.property2:75output.comma()76self.property2.print(output)77output.print(')')787980def print_delete(self, output):81if is_node_type(self, AST_Symbol):82output.assign(self), output.print('undefined')83elif is_node_type(self, AST_Sub) or is_node_type(self, AST_ItemAccess):84output.print('ρσ_delitem('), self.expression.print(85output), output.comma(), self.property.print(output), output.print(86')')87else:88output.spaced('delete', self)899091# def print_unary_prefix(self, output):92# op = self.operator93# if op is 'delete':94# return print_delete(self.expression, output)95# if op is '-':96# output.print("ρσ_operator_neg(")97# else:98# output.print(op)99# if RegExp("^[a-z]", "i").test(op):100# output.space()101# if self.parenthesized:102# output.with_parens(lambda: self.expression.print(output))103# else:104# self.expression.print(output)105# if op is '-':106# output.print(")")107108def print_unary_prefix(self, output):109op = self.operator110if op is 'delete':111return print_delete(self.expression, output)112output.print(op)113if RegExp("^[a-z]", "i").test(op):114output.space()115if self.parenthesized:116output.with_parens(lambda: self.expression.print(output))117else:118self.expression.print(output)119120def write_instanceof(left, right, output):121def do_many(vals):122output.print('ρσ_instanceof.apply(null,'), output.space()123output.print('['), left.print(output), output.comma()124for i in range(len(vals)):125vals[i].print(output)126if i is not vals.length - 1:127output.comma()128output.print('])')129130if is_node_type(right, AST_Seq):131do_many(right.to_array())132elif is_node_type(right, AST_Array):133do_many(right.elements)134else:135output.print('ρσ_instanceof(')136left.print(output), output.comma(), right.print(output), output.print(137')')138139140def write_smart_equality(self, output):141def is_ok(x):142return not (143is_node_type(x, AST_Array) or is_node_type(x, AST_Set)144or is_node_type(x, AST_Object) or is_node_type(x, AST_Statement)145or is_node_type(x, AST_Binary) or is_node_type(x, AST_Conditional)146or is_node_type(x, AST_BaseCall) or is_node_type(x, AST_SymbolRef))147148if is_ok(self.left) and is_ok(self.right):149if self.operator is '==':150output.print('(')151output.spaced(self.left, '===', self.right, '||', 'typeof',152self.left, '===', '"object"', '&&', 'ρσ_equals(')153self.left.print(output), output.print(','), output.space(154), self.right.print(output), output.print('))')155else:156output.print('(')157output.spaced(self.left, '!==', self.right, '&&', '(typeof',158self.left, '!==', '"object"', '||', 'ρσ_not_equals(')159self.left.print(output), output.print(','), output.space(160), self.right.print(output), output.print(')))')161else:162output.print('ρσ_' +163('equals(' if self.operator is '==' else 'not_equals('))164self.left.print(output), output.print(165','), output.space(), self.right.print(output), output.print(')')166167168comparators = {169"<": True,170">": True,171"<=": True,172">=": True,173}174175function_ops = {176"in": "ρσ_in",177'nin': '!ρσ_in',178}179180181def print_binary_op(self, output):182if function_ops[self.operator]:183output.print(function_ops[self.operator])184185def f_comma():186self.left.print(output)187output.comma()188self.right.print(output)189190output.with_parens(f_comma)191elif comparators[self.operator] and is_node_type(192self.left, AST_Binary) and comparators[self.left.operator]:193# A chained comparison such as a < b < c194if is_node_type(self.left.right, AST_Symbol):195# left side compares against a regular variable,196# no caching needed197self.left.print(output)198leftvar = self.left.right.name199else:200# some logic is being performed, let's cache it201self.left.left.print(output)202output.space()203output.print(self.left.operator)204output.space()205206def f_cond_temp():207nonlocal leftvar208output.assign("ρσ_cond_temp")209self.left.right.print(output)210leftvar = "ρσ_cond_temp"211212output.with_parens(f_cond_temp)213214output.space()215output.print("&&")216output.space()217output.print(leftvar)218output.space()219output.print(self.operator)220output.space()221self.right.print(output)222elif self.operator is '**':223left = self.left224if is_node_type(self.left, AST_Unary) and not self.left.parenthesized:225left = self.left.expression226output.print(self.left.operator)227output.print("ρσ_operator_pow(")228left.print(output)229output.comma()230self.right.print(output)231output.print(')')232elif self.operator is '==' or self.operator is '!=':233write_smart_equality(self, output)234elif self.operator is 'instanceof':235write_instanceof(self.left, self.right, output)236elif self.operator is '*' and is_node_type(self.left, AST_String):237self.left.print(output), output.print('.repeat('), self.right.print(238output), output.print(')')239elif self.operator is '===' or self.operator is '!==':240nan_check = None241if is_node_type(self.right, AST_Symbol) and self.right.name is 'NaN':242nan_check = self.left243if is_node_type(self.left, AST_Symbol) and self.left.name is 'NaN':244nan_check = self.right245if nan_check is not None:246# We use the fact that NaN is the only object that is not equal to247# itself248output.spaced(nan_check,249'!==' if self.operator is '===' else '===',250nan_check)251else:252output.spaced(self.left, self.operator, self.right)253elif self.operator is '+':254output.print('ρσ_operator_add('), self.left.print(255output), output.comma(), self.right.print(output), output.print(256')')257elif self.operator is '-':258output.print('ρσ_operator_sub('), self.left.print(259output), output.comma(), self.right.print(output), output.print(260')')261elif self.operator is '*':262output.print('ρσ_operator_mul('), self.left.print(263output), output.comma(), self.right.print(output), output.print(264')')265elif self.operator is '/':266output.print('ρσ_operator_truediv('), self.left.print(267output), output.comma(), self.right.print(output), output.print(268')')269elif self.operator is '//':270output.print('ρσ_operator_floordiv('), self.left.print(271output), output.comma(), self.right.print(output), output.print(272')')273else:274output.spaced(self.left, self.operator, self.right)275276277after_map = {'.': 'd', '(': 'c', '[': 'd', 'g': 'g', 'null': 'n'}278279280def print_existential(self, output):281key = after_map[self.after] if self.after is None or jstype(282self.after) is 'string' else 'e'283if is_node_type(self.expression, AST_SymbolRef):284if key is 'n':285output.spaced('(typeof', self.expression, '!==', '"undefined"',286'&&', self.expression, '!==', 'null)')287return288if key is 'c':289output.spaced('(typeof', self.expression, '===', '"function"', '?',290self.expression, ':',291'(function(){return undefined;}))')292return293after = self.after294if key is 'd':295after = 'Object.create(null)'296elif key is 'g':297after = '{__getitem__:function(){return undefined;}}'298output.spaced('(typeof', self.expression, '!==', '"undefined"', '&&',299self.expression, '!==', 'null', '?', self.expression,300':', after)301output.print(')')302return303output.print('ρσ_exists.' + key + '(')304self.expression.print(output)305if key is 'e':306output.comma(), self.after.print(output)307output.print(')')308309310def print_assignment(self, output):311flattened = False312left = self.left313if is_node_type(left, AST_Seq):314left = AST_Array({'elements': [left.car, left.cdr]})315if is_node_type(left, AST_Array):316flat = left.flatten()317flattened = flat.length > left.elements.length318output.print("ρσ_unpack")319else:320left.print(output)321output.space()322output.print(self.operator)323output.space()324if flattened:325output.print('ρσ_flatten')326output.with_parens(lambda: self.right.print(output))327else:328self.right.print(output)329if is_node_type(left, AST_Array):330output.end_statement()331if not is_node_type(self.right, AST_Seq) and not is_node_type(332self.right, AST_Array):333output.assign('ρσ_unpack')334output.print('ρσ_unpack_asarray(' +335flat.length), output.comma(), output.print(336'ρσ_unpack)')337output.end_statement()338unpack_tuple(flat, output, True)339340341def print_assign(self, output):342if self.operator is '//=':343output.assign(self.left)344output.print('Math.floor')345346def f_slash():347self.left.print(output)348output.space()349output.print('/')350output.space()351self.right.print(output)352353output.with_parens(f_slash)354return355if self.operator is '+=':356output.assign(self.left)357output.print('ρσ_operator_iadd('), self.left.print(358output), output.comma(), self.right.print(output), output.print(359')')360return361if self.operator is '-=':362output.assign(self.left)363output.print('ρσ_operator_isub('), self.left.print(364output), output.comma(), self.right.print(output), output.print(365')')366return367if self.operator is '*=':368output.assign(self.left)369output.print('ρσ_operator_imul('), self.left.print(370output), output.comma(), self.right.print(output), output.print(371')')372return373if self.operator is '/=':374output.assign(self.left)375output.print('ρσ_operator_idiv('), self.left.print(376output), output.comma(), self.right.print(output), output.print(377')')378return379if self.operator is '=' and self.is_chained():380left_hand_sides, rhs = self.traverse_chain()381is_compound_assign = False382for lhs in left_hand_sides:383if is_node_type(lhs, AST_Seq) or is_node_type(lhs, AST_Array):384is_compound_assign = True385break386if is_compound_assign:387temp_rhs = AST_SymbolRef({'name': 'ρσ_chain_assign_temp'})388print_assignment(389AST_Assign({390'left': temp_rhs,391'operator': '=',392'right': rhs393}), output)394for lhs in left_hand_sides:395output.end_statement(), output.indent()396print_assignment(397AST_Assign({398'left': lhs,399'right': temp_rhs,400'operator': self.operator401}), output)402else:403for lhs in left_hand_sides:404output.spaced(lhs, '=', '')405rhs.print(output)406else:407print_assignment(self, output)408409410def print_conditional(self, output, condition, consequent, alternative):411condition, consequent, alternative = self.condition, self.consequent, self.alternative412output.with_parens(lambda: condition.print(output))413output.space()414output.print("?")415output.space()416consequent.print(output)417output.space()418output.colon()419alternative.print(output)420421422def print_seq(output):423self = this424p = output.parent()425426def print_seq0():427self.car.print(output)428if self.cdr:429output.comma()430if output.should_break():431output.newline()432output.indent()433self.cdr.print(output)434435# this will effectively convert tuples to arrays436if (is_node_type(p, AST_Binary) or is_node_type(p, AST_Return)437or is_node_type(p, AST_Array) or is_node_type(p, AST_BaseCall)438or is_node_type(p, AST_SimpleStatement)):439output.with_square(print_seq0)440else:441print_seq0()442443444