mirror of
https://github.com/betagouv/mon-entreprise
synced 2025-02-09 02:55:01 +00:00
Deplacement de la détection de la règle "words" (ie une suite de mots) du lexer/tokenizer vers le parser. Le lexer se contente de donner les mots un à un, et une liste de "words" est détectée via une règle Nearley. Cela permet de corriger l'ambiguité entre unités et noms de variables qui est dépendante du contexte et ne peut donc pas être levée au niveau du lexer.
104 lines
No EOL
3.2 KiB
Text
104 lines
No EOL
3.2 KiB
Text
# This grammar is inspired by the "fancier grammar" tab of the nearley playground : https://omrelli.ug/nearley-playground
|
|
|
|
# Look for the PEMDAS system : Parentheses, Exponents (omitted here), Multiplication, and you should guess the rest :)
|
|
|
|
# This preprocessor was disabled because it doesn't work with Jest
|
|
# @preprocessor esmodule
|
|
|
|
@{%
|
|
const {string, filteredVariable, variable, temporalVariable, binaryOperation, unaryOperation, boolean, number, numberWithUnit, percentage } = require('./grammarFunctions')
|
|
|
|
const moo = require("moo");
|
|
|
|
const letter = '[a-zA-Z\u00C0-\u017F]';
|
|
const letterOrNumber = '[a-zA-Z\u00C0-\u017F0-9\']';
|
|
const word = `${letter}(?:[\-']?${letterOrNumber}+)*`;
|
|
const numberRegExp = '-?(?:[1-9][0-9]+|[0-9])(?:\.[0-9]+)?';
|
|
const percentageRegExp = numberRegExp + '\\%'
|
|
|
|
const lexer = moo.compile({
|
|
percentage: new RegExp(percentageRegExp),
|
|
number: new RegExp(numberRegExp),
|
|
'(': '(',
|
|
')': ')',
|
|
'[': '[',
|
|
']': ']',
|
|
comparison: ['>','<','>=','<=','=','!='],
|
|
additionSubstraction: /[\+-]/,
|
|
multiplicationDivision: ['*','/'],
|
|
word: new RegExp(word),
|
|
string: /'[ \t\.'a-zA-Z\-\u00C0-\u017F0-9 ]+'/,
|
|
'€': '€',
|
|
dot: ' . ',
|
|
letterOrNumber: new RegExp(letterOrNumber),
|
|
space: { match: /[\s]+/, lineBreaks: true }
|
|
});
|
|
|
|
const join = (args) => ({value: (args.map(x => x && x.value).join(""))})
|
|
const flattenJoin = ([a, b]) => Array.isArray(b) ? join([a, ...b]) : a
|
|
%}
|
|
|
|
@lexer lexer
|
|
|
|
main ->
|
|
AdditionSubstraction {% id %}
|
|
| Comparison {% id %}
|
|
| NonNumericTerminal {% id %}
|
|
| Negation {% id %}
|
|
|
|
NumericTerminal ->
|
|
Variable {% id %}
|
|
| TemporalVariable {% id %}
|
|
| FilteredVariable {% id %}
|
|
| number {% id %}
|
|
|
|
Negation ->
|
|
"-" %space Parentheses {% unaryOperation('calculation') %}
|
|
Parentheses ->
|
|
"(" AdditionSubstraction ")" {% ([,e]) => e %}
|
|
| "(" Negation ")" {% ([,e]) => e %}
|
|
| NumericTerminal {% id %}
|
|
|
|
Comparison -> Comparable %space %comparison %space Comparable {% binaryOperation('comparison')%}
|
|
|
|
Comparable -> ( AdditionSubstraction | NonNumericTerminal) {% ([[e]]) => e %}
|
|
|
|
NonNumericTerminal ->
|
|
boolean {% id %}
|
|
| string {% id %}
|
|
|
|
Words -> %word (%space (%word {% id %} | %letterOrNumber {% id %}) {% join %}):* {% flattenJoin %}
|
|
|
|
Variable -> Words (%dot Words {% ([,words]) => words %}):* {% variable %}
|
|
|
|
BaseUnit ->
|
|
%word {% id %}
|
|
| "€" {% id %}
|
|
|
|
Unit -> BaseUnit ("/" BaseUnit {% join %}):? {% join %}
|
|
|
|
Filter -> "[" Words "]" {% ([,filter]) => filter %}
|
|
FilteredVariable -> Variable %space Filter {% filteredVariable %}
|
|
|
|
TemporalTransform -> "[" ("mensuel" | "annuel" {% id %}) "]" {% ([,temporality]) => temporality %}
|
|
TemporalVariable -> Variable %space TemporalTransform {% temporalVariable %}
|
|
|
|
AdditionSubstraction ->
|
|
AdditionSubstraction %space %additionSubstraction %space MultiplicationDivision {% binaryOperation('calculation') %}
|
|
| MultiplicationDivision {% id %}
|
|
|
|
MultiplicationDivision ->
|
|
MultiplicationDivision %space %multiplicationDivision %space Parentheses {% binaryOperation('calculation') %}
|
|
| Parentheses {% id %}
|
|
|
|
|
|
boolean ->
|
|
"oui" {% boolean(true) %}
|
|
| "non" {% boolean(false) %}
|
|
|
|
number ->
|
|
%number {% number %}
|
|
| %number %space Unit {% numberWithUnit %}
|
|
| %percentage {% percentage %}
|
|
|
|
string -> %string {% string %} |