Project API Docs

Semantic object overview

The MICD API allows editor content to be converted to and from a semantic object. This structure expresses the document as a heavily annotated JavaScript object that can be serialized via JSON. Leveraging our patented technology, semantic objects capture both the mathematical meaning and written structure of the content as expressed by the document author in a form that is accessible, familiar, and convenient for developers. Semantic objects are an ideal substrate for implementing advanced transformation, conversion, and computation tasks. Working with them is similar to working with a Walker or VisitorFunction, but with additional benefits:

  1. Higher level of abstraction
    They present a more semantically integrated view of the content. For example, contiguous digits are combined into a single number object, and exponents are combined with the objects to which they apply. Expressed in terms of compiler theory, a semantic object is closer to an abstract syntax tree than a parse tree.
  2. Decoupling from the content source
    A walker manipulates document content directly. It is a one-to-one representation: changes to the editor are immediately reflected in the corresponding walker, and vice-versa. A semantic object is separate from its source. So, for example, it can be transformed in multiple passes without disrupting the original editor.
  3. Object ownership
    The nodes in a walker present a read-only view of document content. A semantic object belongs to the caller requesting it, who is free to add, remove, and rewrite properties and modify the object structure in any way that is useful to completing a task.
  4. Serializability
    Because semantic objects are JSON-friendly, they are easily serialized and deserialized. This makes it trivial to hand them off to a server or worker thread to complete complex processing tasks in the background, using whatever language or environment is convenient.

Exporting to a semantic object

An editor's document content can be exported to a semantic object by calling Editor.toSemanticObject. The result is comparable to a graph of walker nodes, except for minor structural changes related to further abstraction, and semantic objects expressing child fields with arrays instead of the Field interface.

Importing from a semantic object

Semantic objects can be constructed by developers and imported into an editor by passing them to Editor.fromSemanticObject. This replaces the editor content with the semantic object, returning an array of any errors encountered while importing. While exported objects are strictly standardized, the API is extremely flexible with regard to imported objects.

Significant properties

Many properties of a semantic object are informational annotations that are not required to recreate the original content. These can be safely elided from objects generated for import. The following properties are significant and are generally required to import an object if they would be present in an exported semantic object of the desired type:

type

This is the primary way that objects are identified. Where other properties of an object conflict with the value of this property, this property is given precedence. For example, an object with type "plus" will be converted to a standard addition object regardless of the value of the symbol property.

fields

For objects that have fields, this property must be present if the object's children are to be included. The fields are listed in the same order as they would be completed in the editor. Missing fields will be left empty, while excess fields will be ignored. If an object has only one field, you may instead use the property name field and leave off the outer array. (If both properties are present, fields takes precedence.)

size

For objects with a variable rectangular shape, such as matrices, this field must be present to describe the dimensions used to interpret the fields property. The fields of such objects are listed in row-major order. This property is also used to describe the dimensions of certain objects, such as worksheet graphics.

symbol

This property is part of numbers, operators, variables, and identifiers. For numbers, it is the digit string that describes the number value (such as "3.14"). For variables and identifiers, it is the variable or identifier name (such as "y"). For operators, it is the mathematical symbol that represents the operation (such as "+"). It is not a significant property for most operators (see notes below).

symbolAbove

This is a rare property of some operators that have an additional symbol stacked above the primary symbol. An example is the chemistry operator "yields with heat". Where a Unicode code point exists that already combines the symbols in question, it should be used as the symbol and this property left undefined.

accent

For variables, this property indicates the type of accent applied to the variable, if any. It is optional if the variable has no accent.

dataType

For variables and identifiers, this property indicates the data type of the object, that is, the type of information that the symbol is standing in for. If not specified, the scalar type is used.

placement

For operators, this property can be used to give the operator symbol an operator placement other than the default. It is not significant if the operator is specified by type (see notes below).

text

For text annotations, this property's value is the text content of the node.

red, green blue, opacity

For styles that affect colour, these properties describe the desired colour.

scale

For style that affect size, this property describes the target size.

Additional notes

Primitive values

Primitive values in a field array will be coerced into semantic objects as follows:

  • boolean values to type "booleanTrue" or "booleanFalse";
  • numbers and big integers to type "number" with a symbol equivalent to the number's value;
  • strings can be converted into the following; they are tried in order and the first successful match is used:
    • a math object, if the string matches the name of a math object or a recognized synonym;
    • a number, if the string is a digit string;
    • a variable, if the string is a valid variable name;
    • an operator with default properties if it appears to be a simple operator symbol.

For example, the field ["x", "plus", 1, "=", "y"] would be imported as x + 1 = y.

Document roots

Exported objects always begin from a "documentRoot" object with a list of fields, where each field describes one line. When importing, if the imported object is an array, a document root will be synthesized as follows:

  • if the array has at least one child and that first child is also an array, the imported array is treated as an array of line fields (equivalent to passing just the fields value of a document root);
  • otherwise, the array is interpreted as a field describing a single line.

If a primitive value is imported, it will be coerced into a semantic object as described above and a document root will be synthesized that results in a document of a single line containing only the coerced object.

Numbers

When importing a number, the symbol property holds the value of the number, such as "3.14". The number will be inserted as if by using Walker.insert.number.

Operators

Simple operators (those with no child objects) can be described in one of two ways. If the operator is a standard math object, it can be imported using an object whose type is the API name of the object. Alternatively, the operator can be imported using a type of "operator" and a symbol property with the desired symbol. The placement property may optionally be specified to give the operator a non-standard placement. Thus, the following:

{ type: "plus" }

is equivalent to:

{
  type: "operator",
  symbol: "+",
  placement: "contextual"
}

Note: Using the operator type, it is possible to create new operators (operators with no equivalent MathObject or ChemistryObject). These can be used in an editor like any other operator, with some caveats: the editor may not have have the font support needed to properly render the specified symbol; exporting to other formats may not work as expected; and advanced features such as computation will not know how to apply the operator.

Variables

Variable names (as described by the symbol property) are restricted to a single code point from a list of allowed characters (generally, letters). When importing a variable that does not meet these requirements, it will be transformed into a valid identifier if possible.

Exponents and indices

When exporting a node followed by a power (superscript) and/or index (subscript) node, all nodes will be merged into a single placeholder node with three fields: the base node, the index, and the power. Missing scripts will have empty fields, but are definitively indicated by special properties. An object like the following could be used for 16²:

{
  type: "script",
  hasIndex: false,
  hasPower: true,
  fields: [
    [{ type: "number", symbol: "16" }],
    [],
    [{ type: "number", symbol: "2" }]
  ]
}

When importing, hasIndex and hasPower are optional. If they are not explicit properties of the object, they are assumed to be true; if only two fields are provided and neither property is defined, the second field it is taken to represent an exponent. The same is true if two fields are provided and only hasPower is true. This is an exception to the usual rule that missing fields are treated as empty.

An alternative to using a "script" object is to list the components inline in the field, as they would occur in the editor:

[
  { type: "number", symbol: "16" },
  { type: "toThePower", fields: [ [{ type: "number", symbol: "2" }] ] }
]

Elements and isotopes

When exporting, these are always exported by type using the full element name (for example, "carbon" or "carbonIsotope"). When importing, they can also be imported by symbol by using type "element" or "isotope". For example, these two objects are equivalent:

[
  { type: "helium" },
  { type: "element", symbol: "He" }
]

Text annotations

An object with no type but with a text property will be interpreted as a text annotation:

{ text: "Proof (by induction):" }

Back to contents

This API is still under development and is subject to change. Copyright © Math I Can Do Solutions Incorporated and/or its licensors.