def apply(self, expr, evaluation): 'Unset[expr_]' name = expr.get_head_name() if name in system_symbols('OwnValues', 'DownValues', 'SubValues', 'UpValues', 'NValues', 'Options', 'Messages'): if len(expr.leaves) != 1: evaluation.message_args(name, len(expr.leaves), 1) return Symbol('$Failed') symbol = expr.leaves[0].get_name() if not symbol: evaluation.message(name, 'fnsym', expr) return Symbol('$Failed') if name == 'System`Options': empty = {} else: empty = [] evaluation.definitions.set_values(symbol, name, empty) return Symbol('Null') name = expr.get_lookup_name() if not name: evaluation.message('Unset', 'usraw', expr) return Symbol('$Failed') if not evaluation.definitions.unset(name, expr): if not expr.is_atom(): evaluation.message('Unset', 'norep', expr, Symbol(name)) return Symbol('$Failed') return Symbol('Null')
def assign_elementary(self, lhs, rhs, evaluation, tags=None, upset=False): name = lhs.get_head_name() if name in system_symbols('OwnValues', 'DownValues', 'SubValues', 'UpValues', 'NValues', 'Options', 'DefaultValues', 'Attributes', 'Messages'): if len(lhs.leaves) != 1: evaluation.message_args(name, len(lhs.leaves), 1) return False tag = lhs.leaves[0].get_name() if not tag: evaluation.message(name, 'sym', lhs.leaves[0], 1) return False if tags is not None and tags != [tag]: evaluation.message(name, 'tag', Symbol(name), Symbol(tag)) return False if (name != 'System`Attributes' and 'System`Protected' # noqa in evaluation.definitions.get_attributes(tag)): evaluation.message(name, 'wrsym', Symbol(tag)) return False if name == 'System`Options': option_values = rhs.get_option_values(evaluation) if option_values is None: evaluation.message(name, 'options', rhs) return False evaluation.definitions.set_options(tag, option_values) elif name == 'System`Attributes': attributes = get_symbol_list( rhs, lambda item: evaluation.message(name, 'sym', item, 1)) if attributes is None: return False if 'System`Locked' in evaluation.definitions.get_attributes(tag): evaluation.message(name, 'locked', Symbol(tag)) return False evaluation.definitions.set_attributes(tag, attributes) else: rules = rhs.get_rules_list() if rules is None: evaluation.message(name, 'vrule', lhs, rhs) return False evaluation.definitions.set_values(tag, name, rules) return True form = '' nprec = None default = False message = False allow_custom_tag = False focus = lhs if name == 'System`N': if len(lhs.leaves) not in (1, 2): evaluation.message_args('N', len(lhs.leaves), 1, 2) return False if len(lhs.leaves) == 1: nprec = Symbol('MachinePrecision') else: nprec = lhs.leaves[1] focus = lhs.leaves[0] lhs = Expression('N', focus, nprec) elif name == 'System`MessageName': if len(lhs.leaves) != 2: evaluation.message_args('MessageName', len(lhs.leaves), 2) return False focus = lhs.leaves[0] message = True elif name == 'System`Default': if len(lhs.leaves) not in (1, 2, 3): evaluation.message_args('Default', len(lhs.leaves), 1, 2, 3) return False focus = lhs.leaves[0] default = True elif name == 'System`Format': if len(lhs.leaves) not in (1, 2): evaluation.message_args('Format', len(lhs.leaves), 1, 2) return False if len(lhs.leaves) == 2: form = lhs.leaves[1].get_name() if not form: evaluation.message('Format', 'fttp', lhs.leaves[1]) return False else: form = system_symbols( 'StandardForm', 'TraditionalForm', 'OutputForm', 'TeXForm', 'MathMLForm') lhs = focus = lhs.leaves[0] else: allow_custom_tag = True focus = focus.evaluate_leaves(evaluation) if tags is None and not upset: name = focus.get_lookup_name() if not name: evaluation.message(self.get_name(), 'setraw', focus) return False tags = [name] elif upset: if allow_custom_tag: tags = [] if focus.is_atom(): evaluation.message(self.get_name(), 'normal') return False for leaf in focus.leaves: name = leaf.get_lookup_name() tags.append(name) else: tags = [focus.get_lookup_name()] else: allowed_names = [focus.get_lookup_name()] if allow_custom_tag: for leaf in focus.get_leaves(): allowed_names.append(leaf.get_lookup_name()) for name in tags: if name not in allowed_names: evaluation.message(self.get_name(), 'tagnfd', Symbol(name)) return False ignore_protection = False rhs_int_value = rhs.get_int_value() lhs_name = lhs.get_name() if lhs_name == 'System`$RecursionLimit': # if (not rhs_int_value or rhs_int_value < 20) and not # rhs.get_name() == 'System`Infinity': if (not rhs_int_value or rhs_int_value < 20 or rhs_int_value > settings.MAX_RECURSION_DEPTH): # nopep8 evaluation.message('$RecursionLimit', 'limset', rhs) return False try: set_recursionlimit(rhs_int_value) except OverflowError: # TODO: Message return False ignore_protection = True elif lhs_name == 'System`$ModuleNumber': if not rhs_int_value or rhs_int_value <= 0: evaluation.message('$ModuleNumber', 'set', rhs) return False ignore_protection = True elif lhs_name in ('System`$Line', 'System`$HistoryLength'): if rhs_int_value is None or rhs_int_value < 0: evaluation.message(lhs_name, 'intnn', rhs) return False ignore_protection = True elif lhs_name == 'System`$RandomState': # TODO: allow setting of legal random states! # (but consider pickle's insecurity!) evaluation.message('$RandomState', 'rndst', rhs) return False elif lhs_name == 'System`$Context': new_context = rhs.get_string_value() if new_context is None or not valid_context_name( new_context, allow_initial_backquote=True): evaluation.message(lhs_name, 'cxset', rhs) return False # With $Context in Mathematica you can do some strange # things: e.g. with $Context set to Global`, something # like: # $Context = "`test`"; newsym # is accepted and creates Global`test`newsym. # Implement this behaviour by interpreting # $Context = "`test`" # as # $Context = $Context <> "test`" # if new_context.startswith('`'): new_context = (evaluation.definitions.get_current_context() + new_context.lstrip('`')) evaluation.definitions.set_current_context(new_context) ignore_protection = True return True elif lhs_name == 'System`$ContextPath': context_path = [s.get_string_value() for s in rhs.get_leaves()] if rhs.has_form('List', None) and all(valid_context_name(s) for s in context_path): evaluation.definitions.set_context_path(context_path) ignore_protection = True return True else: evaluation.message(lhs_name, 'cxlist', rhs) return False elif lhs_name == 'System`$MinPrecision': # $MinPrecision = Infinity is not allowed if rhs_int_value is not None and rhs_int_value >= 0: ignore_protection = True max_prec = evaluation.definitions.get_config_value('$MaxPrecision') if max_prec is not None and max_prec < rhs_int_value: evaluation.message('$MinPrecision', 'preccon', Symbol('$MinPrecision')) return True else: evaluation.message(lhs_name, 'precset', lhs, rhs) return False elif lhs_name == 'System`$MaxPrecision': if rhs.has_form('DirectedInfinity', 1) and rhs.leaves[0].get_int_value() == 1: ignore_protection = True elif rhs_int_value is not None and rhs_int_value > 0: ignore_protection = True min_prec = evaluation.definitions.get_config_value('$MinPrecision') if min_prec is not None and rhs_int_value < min_prec: evaluation.message('$MaxPrecision', 'preccon', Symbol('$MaxPrecision')) ignore_protection = True return True else: evaluation.message(lhs_name, 'precset', lhs, rhs) return False rhs_name = rhs.get_head_name() if rhs_name == 'System`Condition': if len(rhs.leaves) != 2: evaluation.message_args('Condition', len(rhs.leaves), 2) return False else: lhs = Expression('Condition', lhs, rhs.leaves[1]) rhs = rhs.leaves[0] rule = Rule(lhs, rhs) count = 0 defs = evaluation.definitions for tag in tags: if (not ignore_protection and 'System`Protected' # noqa in evaluation.definitions.get_attributes(tag)): if lhs.get_name() == tag: evaluation.message(self.get_name(), 'wrsym', Symbol(tag)) else: evaluation.message(self.get_name(), 'write', Symbol(tag), lhs) continue count += 1 if form: defs.add_format(tag, rule, form) elif nprec: defs.add_nvalue(tag, rule) elif default: defs.add_default(tag, rule) elif message: defs.add_message(tag, rule) else: if upset: defs.add_rule(tag, rule, position='up') else: defs.add_rule(tag, rule) if count == 0: return False return True
<dt>'ImageSize' -> 'Large' <dd>produces a large image. </dl> """ element_heads = frozenset( system_symbols( "Arrow", "BezierCurve", "Circle", "Cylinder", "Disk", "FilledCurve", "Inset", "Line", "Point", "Polygon", "Rectangle", "RegularPolygon", "Sphere", "Style", "Text", ) ) styles = system_symbols_dict( { "RGBColor": RGBColor, "XYZColor": XYZColor, "LABColor": LABColor,
def match_leaf(self, yield_func, leaf, rest_leaves, rest_expression, vars, expression, attributes, evaluation, leaf_index=1, leaf_count=None, first=False, fully=True, depth=1, wrap_oneid=True): if rest_expression is None: rest_expression = ([], []) evaluation.check_stopped() match_count = leaf.get_match_count(vars) leaf_candidates = leaf.get_match_candidates( rest_expression[1], # leaf.candidates, expression, attributes, evaluation, vars) if len(leaf_candidates) < match_count[0]: return # STRANGE: candidate in leaf_candidates causes BusError for # Real ^ Integer (e.g. 2.0^3) when not converted to a set! leaf_candidates = set(leaf_candidates) candidates = rest_expression[1] # "Artificially" only use more leaves than specified for some kind # of pattern. # TODO: This could be further optimized! try_flattened = ( ('System`Flat' in attributes) and (leaf.get_head_name() in ( system_symbols( 'Pattern', 'PatternTest', 'Condition', 'Optional', 'Blank', 'BlankSequence', 'BlankNullSequence', 'Alternatives', 'OptionsPattern', 'Repeated', 'RepeatedNull')))) if try_flattened: set_lengths = (match_count[0], None) else: set_lengths = match_count # try_flattened is used later to decide whether wrapping of leaves # into one operand may occur. # This can of course also be when flat and same head. try_flattened = try_flattened or (( 'System`Flat' in attributes) and leaf.get_head() == expression.head) less_first = len(rest_leaves) > 0 if 'System`Orderless' in attributes: sets = None if leaf.get_head_name() == 'System`Pattern': varname = leaf.leaves[0].get_name() existing = vars.get(varname, None) if existing is not None: head = existing.get_head() if (head.get_name() == 'System`Sequence' or ( 'System`Flat' in attributes and head == expression.get_head())): needed = existing.leaves else: needed = [existing] available = candidates[:] for needed_leaf in needed: if (needed_leaf in available and # nopep8 needed_leaf in leaf_candidates): available.remove(needed_leaf) else: return sets = [(needed, ([], available))] if sets is None: sets = subsets(candidates, included=leaf_candidates, less_first=less_first, *set_lengths) else: sets = subranges(candidates, flexible_start=first and not fully, included=leaf_candidates, less_first=less_first, *set_lengths) # print "Match %s in %s" % (leaf, expression) if rest_leaves: next_leaf = rest_leaves[0] next_rest_leaves = rest_leaves[1:] next_depth = depth + 1 next_index = leaf_index + 1 for items, items_rest in sets: # try: # print (u" " + u", ".join(unicode(item) # for item in items)).encode('utf-8') # except # Include wrappings like Plus[a, b] only if not all items taken # - in that case we would match the same expression over and over. include_flattened = (try_flattened and 0 < len(items) < len(expression.leaves)) # Don't try flattened when the expression would remain the same! def leaf_yield(next_vars, next_rest): # if next_rest is None: # next_rest = ([], []) # yield_func(next_vars, (rest_expression[0] + items_rest[0], # next_rest[1])) if next_rest is None: yield_func( next_vars, (rest_expression[0] + items_rest[0], [])) else: yield_func( next_vars, (rest_expression[0] + items_rest[0], next_rest[1])) def match_yield(new_vars, _): if rest_leaves: self.match_leaf( leaf_yield, next_leaf, next_rest_leaves, items_rest, new_vars, expression, attributes, evaluation, fully=fully, depth=next_depth, leaf_index=next_index, leaf_count=leaf_count, wrap_oneid=wrap_oneid) else: if not fully or (not items_rest[0] and not items_rest[1]): yield_func(new_vars, items_rest) def yield_wrapping(item): leaf.match(match_yield, item, vars, evaluation, fully=True, head=expression.head, leaf_index=leaf_index, leaf_count=leaf_count, wrap_oneid=wrap_oneid) self.get_wrappings( yield_wrapping, items, match_count[1], expression, attributes, include_flattened=include_flattened)
def match_leaf(self, yield_func, leaf, rest_leaves, rest_expression, vars, expression, attributes, evaluation, leaf_index=1, leaf_count=None, first=False, fully=True, depth=1, wrap_oneid=True): if rest_expression is None: rest_expression = ([], []) evaluation.check_stopped() match_count = leaf.get_match_count(vars) leaf_candidates = leaf.get_match_candidates( rest_expression[1], # leaf.candidates, expression, attributes, evaluation, vars) if len(leaf_candidates) < match_count[0]: return candidates = rest_expression[1] # "Artificially" only use more leaves than specified for some kind # of pattern. # TODO: This could be further optimized! try_flattened = (('System`Flat' in attributes) and (leaf.get_head_name() in (system_symbols( 'Pattern', 'PatternTest', 'Condition', 'Optional', 'Blank', 'BlankSequence', 'BlankNullSequence', 'Alternatives', 'OptionsPattern', 'Repeated', 'RepeatedNull')))) if try_flattened: set_lengths = (match_count[0], None) else: set_lengths = match_count # try_flattened is used later to decide whether wrapping of leaves # into one operand may occur. # This can of course also be when flat and same head. try_flattened = try_flattened or (('System`Flat' in attributes) and leaf.get_head() == expression.head) less_first = len(rest_leaves) > 0 if 'System`Orderless' in attributes: # we only want leaf_candidates to be a set if we're orderless. # otherwise, constructing a set() is very slow for large lists. # performance test case: # x = Range[100000]; Timing[Combinatorica`BinarySearch[x, 100]] leaf_candidates = set(leaf_candidates) # for fast lookup sets = None if leaf.get_head_name() == 'System`Pattern': varname = leaf.leaves[0].get_name() existing = vars.get(varname, None) if existing is not None: head = existing.get_head() if (head.get_name() == 'System`Sequence' or ('System`Flat' in attributes and head == expression.get_head())): needed = existing.leaves else: needed = [existing] available = candidates[:] for needed_leaf in needed: if (needed_leaf in available and # nopep8 needed_leaf in leaf_candidates): available.remove(needed_leaf) else: return sets = [(needed, ([], available))] if sets is None: sets = subsets(candidates, included=leaf_candidates, less_first=less_first, *set_lengths) else: sets = subranges(candidates, flexible_start=first and not fully, included=leaf_candidates, less_first=less_first, *set_lengths) if rest_leaves: next_leaf = rest_leaves[0] next_rest_leaves = rest_leaves[1:] next_depth = depth + 1 next_index = leaf_index + 1 for items, items_rest in sets: # Include wrappings like Plus[a, b] only if not all items taken # - in that case we would match the same expression over and over. include_flattened = (try_flattened and 0 < len(items) < len(expression.leaves)) # Don't try flattened when the expression would remain the same! def leaf_yield(next_vars, next_rest): # if next_rest is None: # next_rest = ([], []) # yield_func(next_vars, (rest_expression[0] + items_rest[0], # next_rest[1])) if next_rest is None: yield_func(next_vars, (rest_expression[0] + items_rest[0], [])) else: yield_func( next_vars, (rest_expression[0] + items_rest[0], next_rest[1])) def match_yield(new_vars, _): if rest_leaves: self.match_leaf(leaf_yield, next_leaf, next_rest_leaves, items_rest, new_vars, expression, attributes, evaluation, fully=fully, depth=next_depth, leaf_index=next_index, leaf_count=leaf_count, wrap_oneid=wrap_oneid) else: if not fully or (not items_rest[0] and not items_rest[1]): yield_func(new_vars, items_rest) def yield_wrapping(item): leaf.match(match_yield, item, vars, evaluation, fully=True, head=expression.head, leaf_index=leaf_index, leaf_count=leaf_count, wrap_oneid=wrap_oneid) self.get_wrappings(yield_wrapping, items, match_count[1], expression, attributes, include_flattened=include_flattened)