Expand description
AST-style rewriters consumed by super::MilkEvaluator::preprocess_expression.
Each rewrite_* / wrap_* function takes an expression string and
returns a normalised form evalexpr can parse. The passes are
idempotent and are run in the order documented in
super::preprocess.
ConstantsΒ§
- KNOWN_
ARITY π - Fixed arity for MD2 EEL2 builtins whose argument count is known up
front. Used by
rewrite_arity_mismatched_semisto decide when a mixed,+;argument list can be unambiguously normalised.
FunctionsΒ§
- arg_
already_ πwrapped - Return
truewhens(already a comma-piece) consists of a single(...)group at depth 0. Detects the idempotent case wherewrap_semi_chain_argshas already run. - call_
name_ πbefore_ paren - Return the identifier bytes immediately preceding
paren_pos(skipping inter-token whitespace).Noneif the byte before(after whitespace isnβt an identifier β i.e.(is a grouping paren. - call_
name_ πskips_ semi_ rewrite - Return
truewhen the identifier precedingparen_posnames a builtin that uses;-chain semantics inside its args (loop,exec2,exec3,while). - count_
top_ πlevel_ byte - Count top-level
targetoccurrences ins(at paren depth 0). - find_
amp_ πpipe_ operands - Locate the first
&or|insthat is a single (non-&&/ non-||, non-&=/ non-|=) operator, plus the byte offsets of its left and right operand spans. ReturnsNoneif no eligible operator remains or either operand boundary canβt be resolved. - find_
double_ πop_ pos - Locate the next
<op_char><op_char>(i.e.&&or||) ins. - find_
left_ πoperand_ start - find_
logical_ πleft_ operand_ start - Walk left from
op_posto find the start of the logical operatorβs left operand. Spans comparison/arithmetic ops at depth 0 (sorg4 > 1.2 && change2givesrg4 > 1.2as the left operand). Stops at the nearest depth-0(,,,;,&&,||, or assignment=. - find_
logical_ πright_ operand_ end - Walk right from
op_end(the byte just past the 2-char operator) to find the end of the right operand. Mirror offind_logical_left_operand_start. - find_
right_ πoperand_ end - find_
unary_ πbang_ operand - Locate the next unary
!plus its operand end ins, starting at byte offsetfrom. - is_
unary_ πbang_ context - True if the byte at
posis!in unary position. - known_
arity_ πfor - Return the fixed arity of
nameif known. - replace_
top_ πlevel_ semis_ with_ commas - Single-pass
;β,substitution at paren depth 0 ofs. - rewrite_
amp_ πpipe_ to_ band_ bor - Rewrite
a & btoband(a, b)anda | btobor(a, b), leaving&&,||,&=,|=untouched. MD2 expression syntax treats single&/|as numeric short-circuit AND/OR (returning 0.0/1.0), not as bitwise ops, so we map them onto our registeredband/borbuiltins which already preserve those semantics. Operates iteratively: each pass rewrites one operator from the left, then the next scan picks up any nested&/|that the previous editβs right operand contained. - rewrite_
arity_ πmismatched_ semis - Arity-aware companion of
rewrite_semis_in_call_args. Walks every function-call paren group and, for builtins with a known fixed arity, converts top-level;separators inside the arg list to,when doing so unambiguously yields the expected arg count. - rewrite_
chain_ πassignments - Rewrite
a = b = β¦ = <expr>into<last> = <expr>; <prev> = <last>; β¦so evalexpr β which makes=returnEmptyβ doesnβt choke on the outer assignments. Detected via a strict left-to-right scan: each step requires a bare identifier followed by=and another bare identifier followed by=, no operators between them. Real-world presets in the corpus:dx=dx=(y*dx)*cos(time)*β¦(the LHS is repeated β a common author typo, but evalexpr still has to accept). - rewrite_
chained_ πat_ this_ level - Apply the chained-comparison rewrite to a single comma-piece.
- rewrite_
chained_ πcomparisons - Rewrite Python-style chained comparisons (
A > B <= C <= 1) into the explicit AND-chain ((A > B) && (B <= C) && (C <= 1)) that evalexprβs left-associative comparison precedence can type-check. - rewrite_
logical_ πop - Inner rewriter for one operator family.
op_charisb'&'(for&&) orb'|'(for||);func_nameis the destination builtin ("band"/"bor"). - rewrite_
logical_ πto_ bandbor - Rewrite
a && btoband(a, b)anda || btobor(a, b), preserving the corpus shapeFloat && Float(which evalexpr 13 strict-types asBoolean op Booleanand rejects when the operands come back as Float). Two-pass with operator-precedence respect: (1)&&is rewritten first (higher precedence in C/EEL2/evalexpr βa || b && cparses asa || (b && c)), then (2)||is rewritten. - rewrite_
semis_ πin_ call_ args - Walk
sand, for every function-call paren group, rewrite top-level;in the args to,when the args contain no top-level,already. Calls namedloop/exec2/exec3/whileare skipped because their interceptors rely on;-chain syntax inside the arg body. - rewrite_
unary_ πbang_ to_ bnot - Rewrite unary
!xtobnot(x). evalexpr 13 type-checks the!operator asBoolean β Boolean; MD2 EEL2 treats it as numeric NOT (returns 1.0 ifx == 0.0, else 0.0) β same semantics asbnot. - top_
level_ πcomparison_ ops - Return a list of
(start, end)byte offsets for every top-level comparison operator ins(<,>,<=,>=,==,!=). - wrap_
bare_ πcmp_ assignment - Wrap
<ident> = <rhs>when<rhs>contains a top-level comparison operator. evalexprβs=type-checks the RHS against the LHSβs stored type; auto-init seeds every variable asFloat(0.0), so assigning a bareBooleanfromrand(100) >= 30blows up at runtime. - wrap_
bare_ πcmp_ assignment_ one - Single-statement helper for
wrap_bare_cmp_assignment. ReturnsSome(rewritten)if a<ident> = <rhs>shape with top-level cmp in<rhs>was found,Noneotherwise (caller passes through). - wrap_
boolean_ πassignment_ rhs - Rewrite Boolean-producing parenthesised comparisons to a Float-returning
milkif(<cmp>, 1, 0)call. evalexpr is strictly typed: a(a > b)producesBoolean, which then dies on*///+against a Float neighbour. - wrap_
chain_ πargs_ in_ parens - Wrap each comma-separated arg of a function call whose body still
contains a top-level
;in(...), so evalexpr parses the arg as a single value-producing statement chain. - wrap_
paren_ πbalanced_ cmp - Paren-balanced sibling of
wrap_boolean_assignment_rhs. The regex pass only matches(cmp)whose interior contains no(or,; the walker variant tracks paren depth and catches(lev1-gmegabuf(1)>0)and(y<=(0.4+0.1*cos(mang))). Recurses inner-first so a chain(a > (b > c))gets each level wrapped. Skips(that follow an identifier (function-call form). - wrap_
semi_ πchain_ args - Split
argson each top-level,and wrap any arg whose interior contains a top-level;in(...). Helper forwrap_chain_args_in_parens.