def get_functions(self, prefix="apply", is_pymodule=False): from mathics.core.parser import parse_builtin_rule unavailable_function = self._get_unavailable_function() for name in dir(self): if name.startswith(prefix): function = getattr(self, name) pattern = function.__doc__ if pattern is None: # Fixes PyPy bug continue else: m = re.match(r"([\w,]+)\:\s*(.*)", pattern) if m is not None: attrs = m.group(1).split(",") pattern = m.group(2) else: attrs = [] if is_pymodule: name = "PyMathics`" + self.get_name(short=True) else: name = self.get_name() pattern = pattern % {"name": name} definition_class = (PyMathicsDefinitions() if is_pymodule else SystemDefinitions()) pattern = parse_builtin_rule(pattern, definition_class) if unavailable_function: function = unavailable_function if attrs: yield (attrs, pattern), function else: yield (pattern, function)
def ensure_logical_algebraic_rules(): global logical_algebraic_rules global remove_not_rules if logical_algebraic_rules is None: logical_algebraic_rules = [] for pattern, replace in logical_algebraic_rules_spec.items(): pattern = parse_builtin_rule(pattern, SystemDefinitions()) logical_algebraic_rules.append( Rule(pattern, parse_builtin_rule(replace), system=True) ) remove_not_rules = [] for pattern, replace in remove_not_rules_spec.items(): pattern = parse_builtin_rule(pattern, SystemDefinitions()) remove_not_rules.append( Rule(pattern, parse_builtin_rule(replace), system=True) ) return
def contribute(self, definitions, is_pymodule=False): from mathics.core.parser import parse_builtin_rule if is_pymodule: name = "PyMathics`" + self.get_name(short=True) else: name = self.get_name() options = {} option_syntax = "Warn" for option, value in self.options.items(): if option == "$OptionSyntax": option_syntax = value continue option = ensure_context(option) options[option] = parse_builtin_rule(value) if option.startswith("System`"): # Create a definition for the option's symbol. # Otherwise it'll be created in Global` when it's # used, so it won't work. if option not in definitions.builtin: definitions.builtin[option] = Definition(name=name, attributes=set()) # Check if the given options are actually supported by the Builtin. # If not, we might issue an optx error and abort. Using '$OptionSyntax' # in your Builtin's 'options', you can specify the exact behaviour # using one of the following values: # - 'Strict': warn and fail with unsupported options # - 'Warn': warn about unsupported options, but continue # - 'Ignore': allow unsupported options, do not warn if option_syntax in ("Strict", "Warn", "System`Strict", "System`Warn"): def check_options(options_to_check, evaluation): name = self.get_name() for key, value in options_to_check.items(): short_key = strip_context(key) if not has_option(options, short_key, evaluation): evaluation.message( name, "optx", Expression("Rule", short_key, value), strip_context(name), ) if option_syntax in ("Strict", "System`Strict"): return False return True elif option_syntax in ("Ignore", "System`Ignore"): check_options = None else: raise ValueError("illegal option mode %s; check $OptionSyntax." % option_syntax) rules = [] definition_class = (PyMathicsDefinitions() if is_pymodule else SystemDefinitions()) for pattern, function in self.get_functions(is_pymodule=is_pymodule): rules.append( BuiltinRule(name, pattern, function, check_options, system=not is_pymodule)) for pattern, replace in self.rules.items(): if not isinstance(pattern, BaseExpression): pattern = pattern % {"name": name} pattern = parse_builtin_rule(pattern, definition_class) replace = replace % {"name": name} # FIXME: Should system=True be system=not is_pymodule ? rules.append( Rule(pattern, parse_builtin_rule(replace), system=True)) box_rules = [] if name != "System`MakeBoxes": new_rules = [] for rule in rules: if rule.pattern.get_head_name() == "System`MakeBoxes": box_rules.append(rule) else: new_rules.append(rule) rules = new_rules def extract_forms(name, pattern): # Handle a tuple of (forms, pattern) as well as a pattern # on the left-hand side of a format rule. 'forms' can be # an empty string (=> the rule applies to all forms), or a # form name (like 'System`TraditionalForm'), or a sequence # of form names. def contextify_form_name(f): # Handle adding 'System`' to a form name, unless it's # '' (meaning the rule applies to all forms). return "" if f == "" else ensure_context(f) if isinstance(pattern, tuple): forms, pattern = pattern if isinstance(forms, str): forms = [contextify_form_name(forms)] else: forms = [contextify_form_name(f) for f in forms] else: forms = [""] return forms, pattern formatvalues = {"": []} for pattern, function in self.get_functions("format_"): forms, pattern = extract_forms(name, pattern) for form in forms: if form not in formatvalues: formatvalues[form] = [] formatvalues[form].append( BuiltinRule(name, pattern, function, None, system=True)) for pattern, replace in self.formats.items(): forms, pattern = extract_forms(name, pattern) for form in forms: if form not in formatvalues: formatvalues[form] = [] if not isinstance(pattern, BaseExpression): pattern = pattern % {"name": name} pattern = parse_builtin_rule(pattern) replace = replace % {"name": name} formatvalues[form].append( Rule(pattern, parse_builtin_rule(replace), system=True)) for form, formatrules in formatvalues.items(): formatrules.sort() messages = [ Rule( Expression("MessageName", Symbol(name), String(msg)), String(value), system=True, ) for msg, value in self.messages.items() ] messages.append( Rule( Expression("MessageName", Symbol(name), String("optx")), String("`1` is not a supported option for `2`[]."), system=True, )) if name == "System`MakeBoxes": attributes = [] else: attributes = ["System`Protected"] attributes += list(ensure_context(a) for a in self.attributes) options = {} for option, value in self.options.items(): option = ensure_context(option) options[option] = parse_builtin_rule(value) if option.startswith("System`"): # Create a definition for the option's symbol. # Otherwise it'll be created in Global` when it's # used, so it won't work. if option not in definitions.builtin: definitions.builtin[option] = Definition(name=name, attributes=set()) defaults = [] for spec, value in self.defaults.items(): value = parse_builtin_rule(value) pattern = None if spec is None: pattern = Expression("Default", Symbol(name)) elif isinstance(spec, int): pattern = Expression("Default", Symbol(name), Integer(spec)) if pattern is not None: defaults.append(Rule(pattern, value, system=True)) definition = Definition( name=name, rules=rules, formatvalues=formatvalues, messages=messages, attributes=attributes, options=options, defaultvalues=defaults, ) if is_pymodule: definitions.pymathics[name] = definition else: definitions.builtin[name] = definition makeboxes_def = definitions.builtin["System`MakeBoxes"] for rule in box_rules: makeboxes_def.add_rule(rule)