[moteur] Le parser Nearley renvoit maintenant un AST similaire au notre

Il reste à le reparser pour résoudre les variables en fonction de la situation, calculer les nodeValues, ajouter les missingVariables

Puis implémenter les modifieurs de temps

Puis ajouter le prorata à la multiplication

                             \
                              \
                               \\
                                \\
                                 >\/7
                             _.-(6'  \
                            (=___._/` \
                                 )  \ |
                                /   / |
                               /    > /
                              j    < _\
                          _.-' :      ``.
                          \ r=._\        `.
                         <`\\_  \         .`-.
                          \ r-7  `-. ._  ' .  `\
                           \`,      `-.`7  7)   )
                            \/         \|  \'  / `-._
                                       ||    .'
cjr                                     \\  (
10mar02                                  >\  >
                                     ,.-' >.'
                                    <.'_.''
                                      <'
pull/6/head
Mael Thomas 2017-03-07 18:25:25 +01:00
parent 578153a3b7
commit c1cfb20bf1
6 changed files with 46 additions and 162 deletions

View File

@ -17,6 +17,7 @@
"install": "^0.8.2",
"js-yaml": "^3.7.0",
"marked": "^0.3.6",
"nearley": "^2.7.14",
"npm": "^4.0.3",
"ramda": "^0.23.0",
"react": "^15.0.1",
@ -52,6 +53,7 @@
"html-loader": "^0.4.2",
"img-loader": "^1.2.2",
"json-loader": "^0.5.4",
"nearley-loader": "0.0.2",
"postcss-loader": "^1.2.2",
"redux-devtools": "^3.2.0",
"redux-devtools-dock-monitor": "^1.1.1",

View File

@ -5,13 +5,13 @@
collecteur: OPCA
références:
Code du travail - Article L6322-37 : https://www.legifrance.gouv.fr/affichCodeArticle.do?idArticle=LEGIARTI000022234996&cidTexte=LEGITEXT000006072050
non applicable si:
l'une de ces conditions:
- événements . CDD poursuivi en CDI
- motif . saisonnier
- motif . jeune vacances
- contrat aidé
#
# non applicable si:
# l'une de ces conditions:
# - événements . CDD poursuivi en CDI
# - motif . saisonnier
# - motif . jeune vacances
# - contrat aidé
# Données de test #
# non applicable si:

View File

@ -1,5 +1,6 @@
# CalcExpression
- salaire de base * 3
- Salariat . salaire de base * 3
- congés non pris / 25

View File

@ -1,83 +1,48 @@
main -> CalcExpression {% d => (['CalcExpression', ...d]) %}
| BooleanVariableExpression {% d => (['BooleanVariableExpression', ...d]) %}
| ModifiedVariable {% d => (['ModifiedVariable', ...d]) %}
| Comparison {% d => (['Comparison', ...d]) %}
@{% function buildNode(type, d){return ({nodeType: type, explanation: d})} %}
Comparison -> Comparable _ ComparisonOperator _ Comparable
main ->
CalcExpression {% id %}
| Variable {% id %}
| ModifiedVariable {% id %}
| Comparison {% id %}
Comparable -> (int | CalcExpression | Variable)
Comparison -> Comparable _ ComparisonOperator _ Comparable {% d => ({nodeType: 'Comparison', operator: d[2][0], explanation: [d[0], d[4]]}) %}
Comparable -> (int | CalcExpression | Variable) {% d => d[0][0] %}
ComparisonOperator -> ">" | "<" | ">=" | "<=" | "="
ModifiedVariable -> Variable _ Modifier {% d => ({nodeType: 'ModifiedVariable', modifier: d[2], variable: d[0] }) %}
ModifiedVariable -> Variable _ Modifier
Modifier -> "[" TemporalModifier "]" {% d =>d[1][0] %}
Modifier -> "[" TemporalModifier "]"
TemporalModifier -> "annuel" | "mensuel" | "jour ouvré" {% id %}
TemporalModifier -> "annuel" | "mensuel" | "jour ouvré"
CalcExpression -> Term _ ArithmeticOperator _ Term {% d => ({nodeType: 'CalcExpression', operator: d[2], explanation: [d[0], d[4]]}) %}
CalcExpression -> Term _ ArithmeticOperator _ Term
Term -> Variable {% id %}
| int {% id %}
Term -> Variable
| int
ArithmeticOperator -> "+" | "-" | "*" | "/"
BooleanVariableExpression -> ("!" _):? Variable {% d => (['BooleanVariableExpression', ...d]) %}
ArithmeticOperator -> "+" {% id %}
| "-" {% id %}
| "*" {% id %}
| "/" {% id %}
VariableWord -> [a-zA-Z\u00C0-\u017F]:+ {% d => (['VariableWord', ...d]) %}
Variable -> VariableFragment (_ Dot _ VariableFragment):* {% d => (['Variable', ...d]) %}
VariableFragment -> VariableWord (_ VariableWord):* {% d => (['VariableFragment', ...d]) %}
Dot -> [\.] {% d => (['Dot', ...d]) %}
_ -> [\s] {% function(d) {return null } %}
# BooleanVariableExpression -> ("!" _):? Variable {% d => (['BooleanVariableExpression', ...d]) %}
Variable -> VariableFragment (_ Dot _ VariableFragment {% d => d[3] %}):* {% d => ({nodeType: 'Variable', fragments: [d[0], ...d[1]] }) %}
# PEMDAS!
# We define each level of precedence as a nonterminal.
VariableFragment -> VariableWord (_ VariableWord {% d=> ' ' + d[1] %}):* {% d => d[0] + ' ' + d[1].join('') %}
# Parentheses
P -> "(" _ AS _ ")" {% function(d) {return {type:'P', d:d, v:d[2].v}} %}
| N {% id %}
# Exponents
E -> P _ "^" _ E {% function(d) {return {type:'E', d:d, v:Math.pow(d[0].v, d[4].v)}} %}
| P {% id %}
VariableWord -> [a-zA-Z\u00C0-\u017F]:+ {% d => d[0].join('') %}
# Multiplication and division
MD -> MD _ "*" _ E {% function(d) {return {type: 'M', d:d, v:d[0].v*d[4].v}} %}
| MD _ "/" _ E {% function(d) {return {type: 'D', d:d, v:d[0].v/d[4].v}} %}
| E {% id %}
Dot -> [\.] {% d => null %}
# Addition and subtraction
AS -> AS _ "+" _ MD {% function(d) {return {type:'A', d:d, v:d[0].v+d[4].v}} %}
| AS _ "-" _ MD {% function(d) {return {type:'S', d:d, v:d[0].v-d[4].v}} %}
| MD {% id %}
_ -> [\s] {% d => null %}
# A number or a function of a number
N -> float {% id %}
| "sin" _ P {% function(d) {return {type:'sin', d:d, v:Math.sin(d[2].v)}} %}
| "cos" _ P {% function(d) {return {type:'cos', d:d, v:Math.cos(d[2].v)}} %}
| "tan" _ P {% function(d) {return {type:'tan', d:d, v:Math.tan(d[2].v)}} %}
| "asin" _ P {% function(d) {return {type:'asin', d:d, v:Math.asin(d[2].v)}} %}
| "acos" _ P {% function(d) {return {type:'acos', d:d, v:Math.acos(d[2].v)}} %}
| "atan" _ P {% function(d) {return {type:'atan', d:d, v:Math.atan(d[2].v)}} %}
| "pi" {% function(d) {return {type:'pi', d:d, v:Math.PI}} %}
| "e" {% function(d) {return {type:'e', d:d, v:Math.E}} %}
| "sqrt" _ P {% function(d) {return {type:'sqrt', d:d, v:Math.sqrt(d[2].v)}} %}
| "ln" _ P {% function(d) {return {type:'ln', d:d, v:Math.log(d[2].v)}} %}
# I use `float` to basically mean a number with a decimal point in it
float ->
int "." int {% function(d) {return {v:parseFloat(d[0].v + d[1].v + d[2].v)}} %}
| int {% function(d) {return {v:parseInt(d[0].v)}} %}
int -> [0-9]:+ {% function(d) {return {v:d[0].join("")}} %}
int -> [0-9]:+ {% d => ({nodeType: 'value', value: d[0].join("")}) %}

View File

@ -2,6 +2,10 @@ import {rules, findRuleByName, parentName} from './rules'
import {recognizeExpression} from './expressions'
import R from 'ramda'
import knownMecanisms from './known-mecanisms.yaml'
import { Parser } from 'nearley'
import Grammar from './grammar.ne'
let nearley = new Parser(Grammar.ParserRules, Grammar.ParserStart)
/*
Dans ce fichier, les règles YAML sont parsées.
@ -234,6 +238,8 @@ let treat = (situationGate, rule) => rawNode => {
if (k === 'multiplication') {
let base = v['assiette'],
parsed = nearley.feed(base),
yaya = console.log('parsed', parsed),
[baseVariableName] = recognizeExpression(rule, base),
baseValue = situationGate(baseVariableName),
rateNode = treat(situationGate, rule)({taux: v['taux']}),
@ -255,7 +261,7 @@ let treat = (situationGate, rule) => rawNode => {
missingVariables: baseValue == null ? [baseVariableName] : []
},
rate: rateNode,
prorata:
// prorata:
//TODO limit: 'plafond'
//TODO multiplier: 'multiplicateur'
}
@ -328,99 +334,6 @@ let treatRuleRoot = (situationGate, rule) => R.evolve({ // -> Voilà les attribu
})(rule)
let deriveRuleOld = (situationGate, rule) => pipe( // eslint-disable-line no-unused-vars
toPairs,
reduce(({missingVariables, computedValue}, [key, value]) => {
if (key === 'concerne') {
let [variableName, evaluation] = recognizeExpression(rule, value)
// Si cette variable a été renseignée
if (knownVariable(situationGate, variableName)) {
// Si l'expression n'est pas vraie...
if (!evaluation(situationGate)) {
// On court-circuite toute la variable, et on n'a besoin d'aucune information !
return reduced({missingVariables: []})
} else {
// Sinon, on continue
return {missingVariables}
}
// sinon on demande la valeur de cette variable
} else return { missingVariables: [...missingVariables, variableName] }
}
if (key === 'non applicable si') {
let conditions = value['l\'une de ces conditions']
let [subVariableNames, reduced] = reduce(([variableNames], expression) => {
let [variableName, evaluation] = recognizeExpression(rule, expression)
if (knownVariable(situationGate, variableName)) {
if (evaluation(situationGate)) {
return reduced([[], true])
} else {
return [variableNames]
}
}
return [[...variableNames, variableName]]
}, [[], null])(conditions)
if (reduced) return reduced({missingVariables: []})
else return {missingVariables: [...missingVariables, ...subVariableNames]}
}
if (key === 'formule') {
if (value['multiplication']) {
let {assiette, taux} = value['multiplication']
// A propos de l'assiette
let [assietteVariableName] = recognizeExpression(rule, assiette),
assietteValue = situationGate(assietteVariableName),
unknownAssiette = assietteValue == undefined
// Arrivés là, cette formule devrait être calculable !
let {missingVariables: tauxMissingVariables = [], computedValue} = typeof taux !== 'string' ?
do {
let numericalLogic = taux['logique numérique']
if (!numericalLogic) throw 'On ne sait pas pour l\'instant traiter ce mécanisme de taux'
let treatNumericalLogic = numericalLogic => {
if (typeof numericalLogic == 'string') {
return new Object({computedValue: assietteValue * transformPercentage(numericalLogic)})
} else {
return pipe(
toPairs(),
reduce(({missingVariables}, [expression, subLogic]) => {
let [variableName, evaluation] = recognizeExpression(rule, expression)
if (knownVariable(situationGate, variableName)) {
if (evaluation(situationGate)) {
return reduced(treatNumericalLogic(subLogic))
} else {
return {missingVariables}
}
} else return {missingVariables: [...missingVariables, variableName]}
}, {missingVariables: []})
)(numericalLogic)
}}
treatNumericalLogic(numericalLogic)
} : ({computedValue: assietteValue * transformPercentage(taux)})
let formulaResult = {
missingVariables: [
...missingVariables,
...(unknownAssiette ? [assietteVariableName] : []),
...tauxMissingVariables
],
computedValue
}
return computedValue != null ? reduced(formulaResult) : formulaResult
}
}
return {missingVariables}
}, {missingVariables: []}
)
)
/* Analyse the set of selected rules, and add derived information to them :
- do they need variables that are not present in the user situation ?
- if not, do they have a computed value or are they non applicable ?

View File

@ -35,6 +35,9 @@ module.exports = {
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: 'url?limit=10000!img?progressive=true'
}, {
test: /\.ne$/,
loader: 'nearley'
}]
},
postcss: [