Réécriture de la grammaire
Elle renvoit un objet qui est une vision prefixe du contenu parsépull/529/head
parent
363d2795e8
commit
3b978d061a
|
@ -1,9 +1,3 @@
|
|||
@preprocessor esmodule
|
||||
|
||||
@{%
|
||||
import maSuperFonction from './maSuperFonction'
|
||||
import treatVariableTransforms from './treatVariable'
|
||||
%}
|
||||
|
||||
# To understand or edit this file, use the awesome nearley playground (but save your work, it can crash sometimes) : https://omrelli.ug/nearley-playground/
|
||||
|
||||
|
@ -21,13 +15,17 @@ NumericTerminal ->
|
|||
| number {% id %}
|
||||
|
||||
# Parentheses
|
||||
P -> "(" _ AS _ ")" {% function(d) {return {category:'parentheses', explanation: d[2]}} %}
|
||||
P -> "(" _ AS _ ")" {% ([,,e]) => e %}
|
||||
| NumericTerminal {% id %}
|
||||
|
||||
ComparisonOperator -> ">" | "<" | ">=" | "<=" | "=" | "!="
|
||||
|
||||
Comparison -> Comparable _ ComparisonOperator _ Comparable {% yo => maSuperFonction(yo) %}
|
||||
Comparison -> Comparable _ ComparisonOperator _ Comparable {% ([A, , operator, , B]) => ({
|
||||
[operator]:
|
||||
[A, B]
|
||||
}) %}
|
||||
|
||||
Comparable -> ( AS | NonNumericTerminal) {% d => d[0][0] %}
|
||||
Comparable -> ( AS | NonNumericTerminal) {% ([[e]]) => e %}
|
||||
|
||||
NonNumericTerminal ->
|
||||
Boolean {% id %}
|
||||
|
@ -35,28 +33,24 @@ NonNumericTerminal ->
|
|||
| NegatedVariable {% id %}
|
||||
|
||||
|
||||
ComparisonOperator -> ">" | "<" | ">=" | "<=" | "=" | "!="
|
||||
NegatedVariable -> "≠" _ Variable {% ([,,variable]) => ({'≠': variable }) %}
|
||||
|
||||
NegatedVariable -> "≠" _ Variable {% d => ({category: 'negatedVariable', variable: d[2] }) %}
|
||||
FilteredVariable -> Variable _ Filter {% ([variable,,filtre]) => ({filtre: {filtre, variable}}) %}
|
||||
|
||||
FilteredVariable -> Variable _ Filter {% d => ({category: 'variable', filter: d[2], variable: d[0] }) %}
|
||||
Filter -> "(" VariableFragment ")" {% ([,filtre]) =>filtre %}
|
||||
|
||||
Filter -> "(" VariableFragment ")" {% d =>d[1] %}
|
||||
TemporalVariable -> Variable _ TemporalTransform {% ([variable,,chemin]) => ({'conversion temporelle': {variable, chemin}}) %}
|
||||
|
||||
TemporalVariable -> Variable _ TemporalTransform {% d => ({...d[0], temporalTransform: d[2] }) %}
|
||||
TemporalTransform -> "[" Temporality "]" {% d =>d[1] %}
|
||||
|
||||
TemporalTransform -> "[" Temporalities "]" {% d =>d[1] %}
|
||||
|
||||
Temporalities -> "annuel" | "mensuel" {% id %}
|
||||
Temporality -> "annuel" | "mensuel" {% id %}
|
||||
#-----
|
||||
|
||||
|
||||
# Addition and subtraction
|
||||
AS -> AS _ ASOperator _ MD {% d => ({
|
||||
category: 'calcExpression',
|
||||
operator: d[2],
|
||||
explanation: [d[0], d[4]],
|
||||
type: 'numeric'
|
||||
AS -> AS _ ASOperator _ MD {% ([A, , operator, , B]) => ({
|
||||
[operator]:
|
||||
[A, B]
|
||||
}) %}
|
||||
|
||||
| MD {% id %}
|
||||
|
@ -69,11 +63,10 @@ MDOperator -> "*" {% id %}
|
|||
| "/" {% id %}
|
||||
|
||||
# Multiplication and division
|
||||
MD -> MD _ MDOperator _ P {% d => ({
|
||||
category: 'calcExpression',
|
||||
operator: d[2],
|
||||
explanation: [d[0], d[4]],
|
||||
type: 'numeric'
|
||||
MD -> MD _ MDOperator _ P {%
|
||||
([A, , operator, , B]) => ({
|
||||
[operator]:
|
||||
[A, B]
|
||||
}) %}
|
||||
|
||||
| P {% id %}
|
||||
|
@ -83,16 +76,18 @@ Term -> Variable {% id %}
|
|||
| number {% id %}
|
||||
| percentage {% id %}
|
||||
|
||||
Variable -> VariableFragment (_ Dot _ VariableFragment {% [,,,fragment] => fragment %}):*
|
||||
{% ([firstFragment, nextFragments]) => treatVariableTransforms({
|
||||
Variable -> VariableFragment (_ Dot _ VariableFragment {% ([,,,fragment]) => fragment %}):*
|
||||
{% ([firstFragment, nextFragments]) =>
|
||||
({variable: {
|
||||
category: 'variable',
|
||||
fragments: [firstFragment, ...nextFragments],
|
||||
}) %}
|
||||
}}) %}
|
||||
|
||||
String -> "'" [ .'a-zA-Z\-\u00C0-\u017F ]:+ "'" {% d => ({
|
||||
category: 'value',
|
||||
String -> "'" [ .'a-zA-Z\-\u00C0-\u017F ]:+ "'" {% d => ({constante: {
|
||||
|
||||
type: 'string',
|
||||
nodeValue: d[1].join('')
|
||||
}) %}
|
||||
}}) %}
|
||||
|
||||
VariableFragment -> VariableWord (_ VariableWord {% d=> ' ' + d[1] %}):* {% d => d[0] + d[1].join('') %}
|
||||
|
||||
|
@ -104,10 +99,11 @@ Dot -> [\.] {% d => null %}
|
|||
_ -> [\s] {% d => null %}
|
||||
|
||||
|
||||
number -> [0-9]:+ ([\.] [0-9]:+):? {% d => ({category: 'value', nodeValue: parseFloat(d[0].join("")+(d[1]?(d[1][0]+d[1][1].join("")):""))}) %}
|
||||
number -> [0-9]:+ ([\.] [0-9]:+):? {% d => ({constante:{ nodeValue: parseFloat(d[0].join("")+(d[1]?(d[1][0]+d[1][1].join("")):""))}}) %}
|
||||
|
||||
percentage -> [0-9]:+ ([\.] [0-9]:+):? [\%] {% d => percentage(d)%}
|
||||
percentage -> [0-9]:+ ([\.] [0-9]:+):? [\%] {% d => ({ 'percentage':{ nodeValue: parseFloat(d[0].join("")+(d[1]?(d[1][0]+d[1][1].join("")):""))/100}}) %}
|
||||
|
||||
Boolean -> "oui" {% d=> ({category: 'boolean', nodeValue: true}) %}
|
||||
| "non" {% d=> ({category: 'boolean', nodeValue: false}) %}
|
||||
|
||||
Boolean -> ("oui"
|
||||
| "non" ) {% ([val])=> ({constante:{type: 'boolean', nodeValue: {'oui': true, 'non': false}[val]}}) %}
|
||||
|
||||
|
|
|
@ -58,11 +58,9 @@ import {
|
|||
export let nearley = () => new Parser(Grammar.ParserRules, Grammar.ParserStart)
|
||||
|
||||
export let treatString = (rules, rule) => rawNode => {
|
||||
/* On a affaire à un string, donc à une expression infixe.
|
||||
Elle sera traité avec le parser obtenu grâce à NearleyJs et notre grammaire `grammar.ne`.
|
||||
On obtient un objet de type Variable (avec potentiellement un 'modifier', par exemple temporel), CalcExpression ou Comparison.
|
||||
Cet objet est alors rebalancé à 'treat'.
|
||||
*/
|
||||
/* Strings correspond to infix expressions.
|
||||
* Indeed, a subset of expressions like simple arithmetic operations `3 + (quantity * 2)` or like `salary [month]` are more explicit that their prefixed counterparts.
|
||||
* This function makes them prefixed operations. */
|
||||
|
||||
let [parseResult, ...additionnalResults] = nearley().feed(rawNode).results
|
||||
|
||||
|
@ -79,113 +77,7 @@ export let treatString = (rules, rule) => rawNode => {
|
|||
)
|
||||
}
|
||||
|
||||
if (parseResult.category == 'variable')
|
||||
return treatVariableTransforms(rules, rule)(parseResult)
|
||||
if (parseResult.category == 'negatedVariable')
|
||||
return treatNegatedVariable(
|
||||
treatVariable(rules, rule)(parseResult.variable)
|
||||
)
|
||||
|
||||
if (
|
||||
parseResult.category == 'calcExpression' ||
|
||||
parseResult.category == 'comparison'
|
||||
) {
|
||||
let evaluate = (cache, situation, parsedRules, node) => {
|
||||
let operatorFunction = {
|
||||
'*': multiply,
|
||||
'/': divide,
|
||||
'+': add,
|
||||
'-': subtract,
|
||||
'<': lt,
|
||||
'<=': lte,
|
||||
'>': gt,
|
||||
'>=': gte,
|
||||
'=': equals,
|
||||
'!=': (a, b) => !equals(a, b)
|
||||
}[node.operator],
|
||||
explanation = map(
|
||||
curry(evaluateNode)(cache, situation, parsedRules),
|
||||
node.explanation
|
||||
),
|
||||
value1 = explanation[0].nodeValue,
|
||||
value2 = explanation[1].nodeValue,
|
||||
nodeValue =
|
||||
value1 == null || value2 == null
|
||||
? null
|
||||
: operatorFunction(value1, value2),
|
||||
missingVariables = mergeMissing(
|
||||
explanation[0].missingVariables,
|
||||
explanation[1].missingVariables
|
||||
)
|
||||
|
||||
return rewriteNode(node, nodeValue, explanation, missingVariables)
|
||||
}
|
||||
|
||||
let explanation = parseResult.explanation.map(
|
||||
cond([
|
||||
[
|
||||
propEq('category', 'variable'),
|
||||
treatVariableTransforms(rules, rule)
|
||||
],
|
||||
[
|
||||
propEq('category', 'value'),
|
||||
node => ({
|
||||
nodeValue: node.nodeValue,
|
||||
// eslint-disable-next-line
|
||||
jsx: nodeValue => <span className="value">{nodeValue}</span>
|
||||
})
|
||||
],
|
||||
[
|
||||
propEq('category', 'percentage'),
|
||||
node => ({
|
||||
nodeValue: node.nodeValue,
|
||||
// eslint-disable-next-line
|
||||
jsx: nodeValue => (
|
||||
<span className="value">{nodeValue * 100}%</span>
|
||||
)
|
||||
//the best would be to display the original text before parsing, but nearley does'nt let us access it
|
||||
})
|
||||
]
|
||||
])
|
||||
),
|
||||
operator = parseResult.operator
|
||||
let operatorToUnicode = operator =>
|
||||
({
|
||||
'>=': '≥',
|
||||
'<=': '≤',
|
||||
'!=': '≠',
|
||||
'*': '∗',
|
||||
'/': '∕',
|
||||
'-': '−'
|
||||
}[operator] || operator)
|
||||
let jsx = (nodeValue, explanation) => (
|
||||
<Node
|
||||
classes={'inlineExpression ' + parseResult.category}
|
||||
value={nodeValue}
|
||||
child={
|
||||
<span className="nodeContent">
|
||||
<span className="fa fa" />
|
||||
{makeJsx(explanation[0])}
|
||||
<span className="operator">
|
||||
{operatorToUnicode(parseResult.operator)}
|
||||
</span>
|
||||
{makeJsx(explanation[1])}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
||||
return {
|
||||
evaluate,
|
||||
jsx,
|
||||
|
||||
operator,
|
||||
text: rawNode,
|
||||
category: parseResult.category,
|
||||
type: parseResult.category == 'calcExpression' ? 'numeric' : 'boolean',
|
||||
explanation
|
||||
}
|
||||
}
|
||||
return treatObject(rules, rule)(parseResult)
|
||||
}
|
||||
|
||||
export let treatNumber = rawNode => ({
|
||||
|
|
Loading…
Reference in New Issue