Adding new built-in symbols to Mathics is very easy. Either place a new module in the builtin directory and add it to the list of modules in builtin/__init__.py or use an existing module. Create a new class derived from Builtin. If you want to add an operator, you should use one of the subclasses of Operator. Use SympyFunction for symbols that have a special meaning in SymPy.

To get an idea of how a built-in class can look like, consider the following implementation of If:


'If[$cond$, $pos$, $neg$]'
returns $pos$ if $cond$ evaluates to 'True', and $neg$ if it evaluates to 'False'.
'If[$cond$, $pos$, $neg$, $other$]'
returns $other$ if $cond$ evaluates to neither 'True' nor 'False'.
'If[$cond$, $pos$]'
returns 'Null' if $cond$ evaluates to 'False'.

>> If[1<2, a, b]
= a
If the second branch is not specified, 'Null' is taken:
>> If[1<2, a]
= a
>> If[False, a] //FullForm
= Null

You might use comments (inside '(*' and '*)') to make the branches of 'If' more readable:
>> If[a, (*then*) b, (*else*) c];
"""

attributes = ['HoldRest']

rules = {
'If[condition_, t_]': 'If[condition, t, Null]',
}

def apply_3(self, condition, t, f, evaluation):
'If[condition_, t_, f_]'

if condition == Symbol('True'):
return t.evaluate(evaluation)
elif condition == Symbol('False'):
return f.evaluate(evaluation)

def apply_4(self, condition, t, f, u, evaluation):
'If[condition_, t_, f_, u_]'

if condition == Symbol('True'):
return t.evaluate(evaluation)
elif condition == Symbol('False'):
return f.evaluate(evaluation)
else:
return u.evaluate(evaluation)
]]>

The class starts with a Python docstring that specifies the documentation and tests for the symbol. A list (or tuple) attributes can be used to assign attributes to the symbol. Protected is assigned by default. A dictionary rules can be used to add custom rules that should be applied.

Python functions starting with apply are converted to built-in rules. Their docstring is compiled to the corresponding Mathics pattern. Pattern variables used in the pattern are passed to the Python function by their same name, plus an additional evaluation object. This object is needed to evaluate further expressions, print messages in the Python code, etc. Unsurprisingly, the return value of the Python function is the expression which is replaced for the matched pattern. If the function does not return any value, the Mathics expression is left unchanged. Note that you have to return Symbol[“Null”] explicitely if you want that.