Defines an interpreter for a small declarative language used to define MotionBuilder relation constraints. In this language, a program consists of a series of relation constraint declarations, each of which contains a series of box and connection declarations, each on its own line.
Loading a relation constraint program takes place in three phases: parsing, compilation, and execution.
Parses, compiles, and executes a program from its provided source text.
|Returns:||a dictionary mapping constraint declaration names to their corresponding FBConstraintRelation objects.|
|Raises :||a RelationException if a program is invalid or unsupported.|
Parses, compiles, and executes a program from the provided open file.
|Note :||Returns and raises identically to loads.|
The implementation of loads() shows in very clear terms what happens when an fbrelation program is run:
def loads(string): syntax = ProgramSyntax.parse(string) declaration = syntax.compile() constraints = declaration.execute() return constraints
First, a new ProgramSyntax object is constructed from the input text. We can then use that object to compile a new ProgramDeclaration. We then execute the declaration in MotionBuilder, giving us a dictionary that contains the newly created relation constraints, indexed by name.
A collection of syntax classes model the abstract syntax of an fbrelation program. The syntax and structure of a program is defined recursively: a program is made up of relations, which are made up of node and connection declarations. The following table summarizes these composition relationships:
|element||composed of||syntax class|
|relation||1 name, n boxes, m connections||RelationSyntax|
|box||1 name, 1 attributelist||BoxSyntax|
|attributelist||n names, n values||AttributeListSyntax|
|node||1 box name, 0 or 1 node names||NodeSyntax|
Once the program and its constituent elements are compiled, the program’s semantics are represented by various declaration classes. The syntax objects employ an abstract factory pattern, with their compile methods creating a declaration object of the appropriate subclass based on the details specified in the program. The base classes for each of these elements are as follows:
Program, relation, and connection declarations do not themselves exhibit any polymorphism, as they serve mostly as containers. The different box and node declaration subclasses are documented in more detail in the corresponding modules.