# 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 %}