math_spec.expression_parser
The core AST every pass reads, and the pyparsing grammar that builds it.
Arithmetic nests anywhere; a comparison appears only at the top of a parsed expression.
ArithmeticNode = NumberNode | NameNode | NameListNode | VariableNode | ParameterNode | DimensionNode | LookupNode | EdgeNode | KeywordNode | UnaryOperatorNode | BinaryOperatorNode | FunctionCallNode | CasesNode
module-attribute
#
BinaryOperator = Literal['+', '-', '*', '/', '**']
module-attribute
#
BranchNode = UnaryOperatorNode | BinaryOperatorNode | ComparisonNode | FunctionCallNode | CasesNode
module-attribute
#
ComparisonOperator = Literal['<=', '>=', '==']
module-attribute
#
ExpressionNode = ArithmeticNode | ComparisonNode
module-attribute
#
KwargNode = DimensionNode | LookupNode | EdgeNode
module-attribute
#
LeafNode = NumberNode | VariableNode | ParameterNode | KwargNode | UnresolvedNode
module-attribute
#
NAME = '[a-zA-Z_][a-zA-Z0-9_]*'
module-attribute
#
REAL = '\\d+\\.\\d*([eE][+-]?\\d+)?|\\d+[eE][+-]?\\d+'
module-attribute
#
UnaryOperator = Literal['+', '-']
module-attribute
#
UnresolvedNode = NameNode | NameListNode | KeywordNode
module-attribute
#
BinaryOperatorNode(op, left, right)
dataclass
#
CaseArm(label, when, value)
dataclass
#
One region of a :class:CasesNode: where it applies, and the value there.
when is None on the last arm and only there — the block's
otherwise:, which is what makes the quantity total without anything
having to prove it. Every other arm's when is proved apart from every
other arm's.
CasesNode(name, arms)
dataclass
#
A value defined by region — a named expression's cases:, inlined where its name stood.
Exactly one arm applies at every coordinate, which :mod:math_spec.exclusivity
proves at load; the last arm is the block's otherwise: and carries no
when. The arms are in file order. The frame is not carried here: it is
on the declaration.
ComparisonNode(op, left, right)
dataclass
#
DimensionNode(name)
dataclass
#
A resolved reference to a declared dimension.
Only legal in operator kwarg values (sum(x, over=generator)), never as
a value in arithmetic — a dimension is a coordinate space, not data.
name
instance-attribute
#
EdgeNode()
dataclass
#
The resolved edge='wrap'; a number in the same position stays a :class:NumberNode.
FunctionCallNode(name, args=(), kwargs=dict())
dataclass
#
KeywordNode(value)
dataclass
#
A quoted closed keyword in a kwarg value — shift(..., edge='wrap').
Unresolved: which keywords the kwarg accepts is the operator's business.
value
instance-attribute
#
LookupNode(names, dimension, into)
dataclass
#
A resolved reference to one or more declared lookups, legal only in a kwarg value.
dimension is the one every lookup is over — what sum consumes and
at produces — and into the targets, one per name in the order
written; sum(x, by=[gen_bus, gen_tech]) is one grouping, not two.
NameListNode(names)
dataclass
#
NameNode(name)
dataclass
#
A bare name whose kind only the schema knows; resolution rewrites every one into a typed node.
name
instance-attribute
#
ParameterNode(name)
dataclass
#
A resolved reference to a declared parameter.
name
instance-attribute
#
VariableNode(name)
dataclass
#
A resolved reference to a declared decision variable.
name
instance-attribute
#
case_context(name, label)
#
The context an error inside one arm of a cased expression is reported under.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
The named expression the arm belongs to.
TYPE:
|
label
|
The case's name, or
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The context prefix an error message carries. |
Source code in src/math_spec/expression_parser.py
children(node)
#
The sub-expressions of node — the structural half of any walk.
Every pass that recurses the whole tree and acts only at certain leaves
goes through here, so a node added later reaches all of them. An
operator's kwargs are children too — a dimension or coordinate is an
ordinary node in a kwarg value, which is what lets a macro bind a formal.
A case arm's when is not: it is a mask over the frame, not a value in it.
Source code in src/math_spec/expression_parser.py
parse_expression(text)
cached
#
Parse a math expression string into an AST.
| RAISES | DESCRIPTION |
|---|---|
SchemaError
|
If text is not an expression of the language. A
predictable mistake — a strict or chained comparison, |
Source code in src/math_spec/expression_parser.py
parse_text(grammar, text, what, rewrite)
#
Parse the whole of text with grammar, or raise :class:SchemaError naming what failed to parse.
rewrite is asked for the predictable mistake at the failure position; its sentence, if any, precedes the grammar's own complaint.
Source code in src/math_spec/expression_parser.py
shown(names)
#
Names as a kwarg value is written: bare when one, bracketed when several.
with_children(node, recurse)
#
node rebuilt with recurse applied to each of its :func:children; a leaf comes back as is.
A case arm's when is a mask over the frame, not a value in it, and is
carried across unchanged.