Case 01 C++ · WebAssembly · Compilers
Parsec: one formula language shared across platforms
Business formulas must produce the same result wherever they are calculated. I worked on Parsec, a C++ library that interprets equations in compiler-style stages, and independently developed parsec-web, its WebAssembly version.
Context
Business systems often store rules as formulas and equations. At Oxeanbits, those formulas had to be evaluated in different contexts, from the backend to web and mobile applications.
Parsec is the equation-evaluation library built for that. Its C++ core was built from muparserx, an open source library, and received contributions from other people at Oxeanbits. I do not present it as exclusively my own work.
Problem
When each platform implements its own interpretation of a formula, small differences creep in: operator precedence, type handling, error messages. The same calculation can produce different results on the server and in the app, and the difference only surfaces for the people using the system.
Invalid formulas also need to be rejected clearly before execution, instead of failing halfway through a calculation.
My responsibility
I worked on developing Parsec, whose interpretation follows typical compiler stages: tokenization, syntax analysis and semantic analysis before evaluation.
I independently developed parsec-web, the WebAssembly version that brings this interpretation to the browser. That is a specific contribution of mine; it does not mean I single-handedly built every product or integration around the library.
Decision
The architectural intention was to define a shared language for formulas and equations, interpreted by a common core and consumed across backend, web, mobile and offline scenarios, instead of letting each platform reinterpret the rules.
That describes the project's goal, not proof that every target shipped. There are public repositories for use in Ruby, the parsec gem, and on the web, parsec-web.
Alternatives and trade-offs
Present-day analysis written for this site. It is not a record of the alternatives evaluated at the time.
- Reimplementing the interpreter in each language removes the integration layer, but multiplies the work and the chances of platforms drifting apart.
- A shared core keeps correctness in one place. In exchange, it needs a bridge for each platform, such as WebAssembly in the browser, and tests that confirm the same behavior across environments.
Implementation
Evaluating a formula goes through stages, each with a clear responsibility.
Tokenization
The expression is split into meaningful units: numbers, variables, operators, functions and parentheses.
Syntax analysis
Tokens are arranged into a structure that respects precedence and grouping, such as an expression tree.
Semantic analysis
The structure is validated before execution: operations must make sense for the types involved, and errors are reported clearly.
WebAssembly
In parsec-web, the C++ core is compiled to WebAssembly with Emscripten and exposed through a JavaScript library. Instead of sending each formula to the backend, the browser evaluates it locally with the same logic, which also makes offline use possible.
Visualization
Stage 1 of 5: Expression
Valid formula
01 · Expression
quantity * price * (1 - discount)02 · Tokens
quantityvariable*operatorpricevariable*operator(parenthesis1number-operatordiscountvariable)parenthesis
03 · Structure
04 · Validation
- Variables defined: quantity, price, discount
- The * operator receives two numbers
- The - operator receives two numbers
05 · Result
108
3 × 40 × (1 − 0.1) = 108
Example values: quantity = 3 · price = 40 · discount = 0.1
Formula with an error
01 · Expression
quantity * price * (1 - "10%")02 · Tokens
quantityvariable*operatorpricevariable*operator(parenthesis1number-operator"10%"text)parenthesis
03 · Structure
04 · Validation
- Variables defined: quantity, price
- The * operator receives two numbers
- The - operator receives a number and a text value
05 · Result
The "-" operator received a number and a text value. The formula is rejected before any calculation.
Example values: quantity = 3 · price = 40
Text description
Valid formula
- Expression:
quantity * price * (1 - discount). The formula text, as someone would write it in a business rule. - Tokens: quantity (variable), * (operator), price (variable), * (operator), ( (parenthesis), 1 (number), - (operator), discount (variable), ) (parenthesis). Tokenization separates numbers, variables, operators and parentheses.
- Structure: Multiplication of (quantity × price) by (1 − discount). The parentheses make the subtraction happen before the final multiplication. Syntax analysis arranges the tokens into a tree that respects precedence and parentheses.
- Validation: Variables defined: quantity, price, discount (ok); The * operator receives two numbers (ok); The - operator receives two numbers (ok). All checks passed.
- Result: 3 × 40 × (1 − 0.1) = 108
Formula with an error
- Expression:
quantity * price * (1 - "10%"). The formula text, as someone would write it in a business rule. - Tokens: quantity (variable), * (operator), price (variable), * (operator), ( (parenthesis), 1 (number), - (operator), "10%" (text), ) (parenthesis). Tokenization separates numbers, variables, operators and parentheses.
- Structure: Multiplication of (quantity × price) by (1 − "10%"). The structure is syntactically valid: the problem only shows up in semantic analysis. Syntax analysis arranges the tokens into a tree that respects precedence and parentheses.
- Validation: Variables defined: quantity, price (ok); The * operator receives two numbers (ok); The - operator receives a number and a text value (fails).
- Result: The "-" operator received a number and a text value. The formula is rejected before any calculation. Not evaluated. The error is reported before execution.
Outcome
parsec-web brings formula evaluation to the browser, in line with the idea of a single language across platforms. The repository is public.
The case shows the kind of problem I enjoy: when consistency across environments depends on decisions about language, parsing and integration, not just on writing more code.