parse_expression
Stable function · Expressions
Tier: stable · Kind: function · Topic: Expressions
| Julia | TypeScript | Python | Rust | Go |
|---|---|---|---|---|
parse_expression | parseExpression | parse_expression | parse_expression | ParseExpression |
Julia
parse_expression(src::AbstractString)
parse_expression(src::AbstractString) -> ASTExpr
Parse a single expression string in the INFIX TEXT form into an AST expression —
the inverse of to_ascii
. Throws ExpressionParseError
on
malformed input or an operator with no text surface yet.
The JSON (wire → typed IR) decoder is a different entry point,
expression_from_json
.
Examples
parse_expression("k1 * NO2 * O2 - k2 * O3")
parse_expression("D(O3)/Dt")
parse_expression("sum[i] (u[i, k]) where {i in cells, k in edges_of_cell(i)}")
Example (expressions)
# Parse from text, or build the tree directly.
expr = parse_expression("k * x + y")
built = OpExpr("+", [OpExpr("*", [VarExpr("k"), VarExpr("x")]), VarExpr("y")])
@assert to_ascii(expr) == to_ascii(built) == "k * x + y"
@assert free_variables(expr) == Set(["k", "x", "y"])
# `substitute` takes a Dict{String,ASTExpr}: give the value type explicitly.
replaced = substitute(expr, Dict{String,ASTExpr}("y" => parse_expression("2 * x")))
@assert to_ascii(replaced) == "k * x + 2 * x"
@assert free_variables(replaced) == Set(["k", "x"])
# Constant subexpressions fold away.
@assert to_ascii(simplify(parse_expression("x * (1 + 1)"))) == "x * 2"
# An equation parses the same way, with D(x, t) for a time derivative.
eq = parse_equation("D(x, t) = -k * x")
@assert eq isa Equation
@assert to_unicode(eq) == "∂x/∂t = −k·x"
TypeScript
function parseExpression(src: string): Expr
Parse a single expression string into an AST expression — the inverse of
toAscii
. Throws ExpressionParseError
on malformed input or an
operator with no text surface yet.
Example (expressions)
// Expressions are plain JSON trees; build one directly ...
const built: Expr = { op: '*', args: ['k', { op: '-', args: ['T_wall', 'T_air'] }] }
// ... or parse the text form, which is the inverse of `toAscii`.
const parsed = parseExpression('k * (T_wall - T_air)')
assert.deepEqual(parsed, built)
assert.deepEqual([...freeVariables(parsed)].sort(), ['T_air', 'T_wall', 'k'])
assert.equal(contains(parsed, 'T_wall'), true)
// Substitution is single-pass and returns a new tree.
const bound = substitute(parsed, { T_wall: 300, k: 0.05 })
assert.equal(toAscii(bound), '0.05 * (300 - T_air)')
assert.deepEqual([...freeVariables(bound)], ['T_air'])
assert.equal(toAscii(simplify(substitute(parsed, { T_wall: 300, T_air: 300 }))), '0')
const eq = parseEquation('D(T_air) = k * (T_wall - T_air)')
assert.deepEqual(eq.rhs, built)
assert.throws(() => parseExpression('k * (T_wall'), ExpressionParseError)
Python
parse_expression(src: str) -> Expr
Parse a single expression string into an AST expression — the inverse of
to_ascii
.
Operator nodes come back in their JSON dict form (see the module
docstring); numbers and bare references come back as int / float /
str.
Raises
ExpressionParseError— on malformed input, or on an operator that has no text surface yet (table_lookup/broadcast/enum/intersect_polygon).
Example (expressions)
# An expression is a number, a variable name, or an operator node.
exchange = ExprNode(op="*", args=["k", ExprNode(op="-", args=["T_wall", "T_air"])])
assert earthsci_ast.free_variables(exchange) == {"k", "T_wall", "T_air"}
# Text parses to the same tree that to_ascii prints.
parsed = earthsci_ast.parse_expression("k * (T_wall - T_air)")
assert earthsci_ast.to_ascii(parsed) == earthsci_ast.to_ascii(exchange)
# Substitution replaces names with numbers or with other expressions.
fixed = earthsci_ast.substitute(exchange, {"k": 0.05, "T_wall": ExprNode(op="+", args=["T0", 10])})
assert earthsci_ast.to_ascii(fixed) == "0.05 * (T0 + 10 - T_air)"
assert earthsci_ast.free_variables(fixed) == {"T0", "T_air"}
Rust
pub fn parse_expression(src: &str) -> Result<Expr, ExpressionParseError>
Parse a single expression string into an AST expression — the inverse of
crate::display::to_ascii
.
Errors
Returns an ExpressionParseError
on malformed input, or on an operator
that has no text surface yet (table_lookup in its CALL spelling — the
bracket form visc[T=temp] parses — broadcast, and enum).
Examples
use earthsci_ast::parse_expression;
use earthsci_ast::to_ascii;
let e = parse_expression("k1 * NO2 * O2 - k2 * O3")?;
assert_eq!(to_ascii(&e), "k1 * NO2 * O2 - k2 * O3");
Example (expressions)
// Parse the text form (the same syntax `to_ascii` prints) ...
let rate = parse_expression("k * A - x")?;
assert_eq!(to_ascii(&rate), "k * A - x");
// ... or a whole equation.
let eq = parse_equation("D(x)/Dt = k * A - x")?;
assert_eq!(to_ascii(&eq.lhs), "D(x)/Dt");
let mut names: Vec<String> = free_variables(&rate).into_iter().collect();
names.sort();
assert_eq!(names, ["A", "k", "x"]);
// Replace `k` with `2 * j`.
let subs = HashMap::from([("k".to_string(), parse_expression("2 * j")?)]);
let replaced = substitute(&rate, &subs);
assert_eq!(to_ascii(&replaced), "2 * j * A - x");
// Expressions are also plain Rust values.
let one = Expr::Variable("x".to_string());
assert_eq!(to_ascii(&one), "x");
Go
func ParseExpression(src string) (Expression, error)
ParseExpression parses a single expression string into an AST expression — the inverse of ToASCII. It returns an error wrapping *ExpressionParseError on malformed input or on an operator with no text surface yet.
Example (expressions)
parsed, err := esm.ParseExpression("k * (T_wall - T_air)")
if err != nil {
log.Fatal(err)
}
fmt.Println(sortedKeys(esm.FreeVariables(parsed)))
// The same tree, built directly: an operator node is an ExprNode, a
// variable is a string and a number is a float64.
built := esm.ExprNode{Op: "*", Args: []any{
"k",
esm.ExprNode{Op: "-", Args: []any{"T_wall", "T_air"}},
}}
fmt.Println(esm.ToASCII(built) == esm.ToASCII(parsed))
substituted, err := esm.Substitute(parsed, map[string]esm.Expression{
"T_wall": 290.0,
"k": esm.ExprNode{Op: "/", Args: []any{1.0, "tau"}},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(esm.ToASCII(substituted))
fmt.Println(sortedKeys(esm.FreeVariables(substituted)))
value, err := esm.Evaluate(substituted, map[string]float64{"tau": 20, "T_air": 280})
if err != nil {
log.Fatal(err)
}
fmt.Println(value)