2017-03-14 10:42:44 +00:00
import React from 'react'
2017-06-27 17:53:37 +00:00
import { rules , findRuleByDottedName , disambiguateRuleReference , findRuleByName } from './rules'
2017-04-24 18:03:38 +00:00
import { evaluateVariable } from './variables'
2017-02-22 16:55:36 +00:00
import R from 'ramda'
2017-03-03 09:43:43 +00:00
import knownMecanisms from './known-mecanisms.yaml'
2017-03-07 17:25:25 +00:00
import { Parser } from 'nearley'
import Grammar from './grammar.ne'
2017-03-15 17:13:46 +00:00
import { Node , Leaf } from './traverse-common-jsx'
2017-07-30 21:50:36 +00:00
import {
mecanismOneOf , mecanismAllOf , mecanismNumericalSwitch , mecanismSum , mecanismProduct ,
mecanismPercentage , mecanismScale , mecanismMax , mecanismMin , mecanismError , mecanismComplement
} from "./mecanisms"
2017-07-13 19:55:59 +00:00
import { evaluateNode , rewriteNode , collectNodeMissing , makeJsx } from './evaluation'
2017-03-07 17:25:25 +00:00
2017-03-08 16:47:12 +00:00
let nearley = ( ) => new Parser ( Grammar . ParserRules , Grammar . ParserStart )
2017-01-09 17:17:51 +00:00
2017-03-06 16:35:30 +00:00
/ *
Dans ce fichier , les règles YAML sont parsées .
Elles expriment un langage orienté expression , les expressions étant
- préfixes quand elles sont des 'mécanismes' ( des mot - clefs représentant des calculs courants dans la loi )
- infixes pour les feuilles : des tests d 'égalité, d' inclusion , des comparaisons sur des variables ou tout simplement la variable elle - même , ou une opération effectuée sur la variable
* /
2017-02-22 16:55:36 +00:00
/ *
- > Notre règle est naturellement un AST ( car notation préfixe dans le YAML )
- > préliminaire : les expression infixes devront être parsées ,
par exemple ainsi : https : //github.com/Engelberg/instaparse#transforming-the-tree
- > Notre règle entière est un AST , qu ' il faut maintenant traiter :
- faire le calcul ( déterminer les valeurs de chaque noeud )
- trouver les branches complètes pour déterminer les autres branches courtcircuitées
- ex . rule . formule est courtcircuitée si rule . non applicable est vrai
2017-04-24 18:03:38 +00:00
- les feuilles de 'une de ces conditions' sont courtcircuitées si l 'une d' elle est vraie
2017-02-22 16:55:36 +00:00
- les feuilles de "toutes ces conditions" sont courtcircuitées si l 'une d' elle est fausse
- ...
( - bonus : utiliser ces informations pour l ' ordre de priorité des variables inconnues )
- si une branche est incomplète et qu 'elle est de type numérique, déterminer les bornes si c' est possible .
Ex . - pour une multiplication , si l 'assiette est connue mais que l ' applicabilité est inconnue ,
les bornes seront [ 0 , multiplication . value = assiette * taux ]
- si taux = effectif entreprise >= 20 ? 1 % : 2 % et que l ' applicabilité est connue ,
bornes = [ assiette * 1 % , assiette * 2 % ]
- transformer l ' arbre en JSX pour afficher le calcul * et son état en prenant en compte les variables renseignées et calculées * de façon sympathique dans un butineur Web tel que Mozilla Firefox .
- surement plein d ' autres applications ...
* /
2017-07-17 17:39:49 +00:00
let fillFilteredVariableNode = ( rules , rule ) => ( filter , parseResult ) => {
2017-07-16 21:58:06 +00:00
let evaluateFiltered = originalEval => ( situation , parsedRules , node ) => {
let newSituation = name => name == "sys.filter" ? filter : situation ( name )
return originalEval ( newSituation , parsedRules , node )
}
2017-07-17 17:39:49 +00:00
let node = fillVariableNode ( rules , rule ) ( parseResult )
2017-07-16 21:58:06 +00:00
return {
... node ,
evaluate : evaluateFiltered ( node . evaluate )
}
}
2017-07-31 15:32:59 +00:00
// TODO: dirty, dirty
// ne pas laisser trop longtemps cette "optimisation" qui tue l'aspect fonctionnel de l'algo
var dict ;
2017-08-22 09:38:11 +00:00
export let clearDict = ( ) => dict = { }
2017-08-22 08:53:38 +00:00
let fillVariableNode = ( rules , rule ) => ( parseResult ) => {
2017-07-09 14:39:31 +00:00
let evaluate = ( situation , parsedRules , node ) => {
let dottedName = node . dottedName ,
2017-08-22 08:53:38 +00:00
// On va vérifier dans le cache courant, dict, si la variable n'a pas été déjà évaluée
// En effet, l'évaluation dans le cas d'une variable qui a une formule, est coûteuse !
2017-09-23 10:54:09 +00:00
filter = situation ( "sys.filter" ) ,
cacheName = dottedName + ( filter ? "." + filter : "" ) ,
cached = dict [ cacheName ] ,
2017-08-22 08:53:38 +00:00
// make parsedRules a dict object, that also serves as a cache of evaluation ?
2017-07-31 15:32:59 +00:00
variable = cached ? cached : findRuleByDottedName ( parsedRules , dottedName ) ,
2017-09-08 10:06:53 +00:00
isMultipleChoice = R . path ( [ 'formule' , 'explanation' , 'une possibilité' ] ) ( variable ) ,
variableIsCalculable = variable . formule != null ,
2017-08-22 08:53:38 +00:00
2017-09-08 10:06:53 +00:00
parsedRule = variableIsCalculable && ( cached ? cached : evaluateNode ( situation , parsedRules , variable ) ) ,
2017-08-22 08:53:38 +00:00
// evaluateVariable renvoit la valeur déduite de la situation courante renseignée par l'utilisateur
2017-07-16 21:58:06 +00:00
situationValue = evaluateVariable ( situation , dottedName , variable ) ,
2017-07-17 12:01:48 +00:00
nodeValue = situationValue
2017-08-22 08:53:38 +00:00
!= null ? situationValue // cette variable a été directement renseignée
2017-07-09 14:39:31 +00:00
: ! variableIsCalculable
2017-08-22 08:53:38 +00:00
? null // pas moyen de calculer car il n'y a pas de formule, elle restera donc nulle
: parsedRule . nodeValue , // la valeur du calcul fait foi
2017-07-09 14:39:31 +00:00
explanation = parsedRule ,
missingVariables = variableIsCalculable ? [ ] : ( nodeValue == null ? [ dottedName ] : [ ] )
2017-09-08 10:06:53 +00:00
let collectMissing = node => variableIsCalculable ? collectNodeMissing ( parsedRule ) : node . missingVariables
2017-07-11 14:00:10 +00:00
2017-07-31 15:32:59 +00:00
let result = cached ? cached : {
2017-07-13 10:25:46 +00:00
... rewriteNode ( node , nodeValue , explanation , collectMissing ) ,
2017-07-09 14:39:31 +00:00
missingVariables ,
}
2017-09-23 10:54:09 +00:00
dict [ cacheName ] = result
2017-07-31 15:32:59 +00:00
return result
2017-07-09 14:39:31 +00:00
}
2017-07-17 17:39:49 +00:00
let { fragments } = parseResult ,
2017-03-08 16:49:22 +00:00
variablePartialName = fragments . join ( ' . ' ) ,
2017-07-09 14:39:31 +00:00
dottedName = disambiguateRuleReference ( rules , rule , variablePartialName )
2017-03-08 16:49:22 +00:00
2017-07-13 20:44:14 +00:00
let jsx = ( nodeValue , explanation ) =>
2017-07-13 19:55:59 +00:00
< Leaf
classes = "variable"
name = { fragments . join ( ' . ' ) }
value = { nodeValue }
/ >
2017-03-08 16:49:22 +00:00
return {
2017-07-09 14:39:31 +00:00
evaluate ,
2017-07-13 19:55:59 +00:00
jsx ,
2017-07-09 22:14:22 +00:00
name : variablePartialName ,
2017-03-08 16:49:22 +00:00
category : 'variable' ,
2017-07-13 19:55:59 +00:00
fragments ,
2017-05-09 15:14:13 +00:00
dottedName ,
2017-07-13 19:55:59 +00:00
type : 'boolean | numeric'
2017-03-08 16:49:22 +00:00
}
}
2017-05-09 13:39:42 +00:00
let buildNegatedVariable = variable => {
2017-07-13 10:12:19 +00:00
let evaluate = ( situation , parsedRules , node ) => {
2017-07-17 17:39:49 +00:00
let explanation = evaluateNode ( situation , parsedRules , node . explanation ) ,
2017-07-13 10:12:19 +00:00
nodeValue = explanation . nodeValue == null ? null : ! explanation . nodeValue
let collectMissing = node => collectNodeMissing ( node . explanation )
2017-07-13 10:25:46 +00:00
return rewriteNode ( node , nodeValue , explanation , collectMissing )
2017-07-13 10:12:19 +00:00
}
2017-07-13 20:45:54 +00:00
let jsx = ( nodeValue , explanation ) =>
2017-07-13 19:55:59 +00:00
< Node
2017-05-09 13:39:42 +00:00
classes = "inlineExpression negation"
2017-07-29 08:00:49 +00:00
value = { nodeValue }
2017-05-09 13:39:42 +00:00
child = {
< span className = "nodeContent" >
< span className = "operator" > ¬ < / s p a n >
2017-07-13 19:55:59 +00:00
{ makeJsx ( explanation ) }
2017-05-09 13:39:42 +00:00
< / s p a n >
}
/ >
2017-07-13 19:55:59 +00:00
return {
evaluate ,
jsx ,
category : 'mecanism' ,
name : 'négation' ,
type : 'boolean' ,
explanation : variable
2017-05-09 13:39:42 +00:00
}
}
2017-07-17 17:39:49 +00:00
let treat = ( rules , rule ) => rawNode => {
2017-06-27 21:09:03 +00:00
// inner functions
2017-07-31 14:30:05 +00:00
let
reTreat = treat ( rules , rule ) ,
2017-06-27 21:09:03 +00:00
treatString = rawNode => {
2017-07-31 14:30:05 +00:00
/ * O n a a f f a i r e à u n s t r i n g , d o n c à u n e e x p r e s s i o n i n f i x e .
Elle sera traité avec le parser obtenu grâce à NearleyJs et notre grammaire ` grammar.ne ` .
2017-06-27 21:09:03 +00:00
On obtient un objet de type Variable ( avec potentiellement un 'modifier' , par exemple temporel ( TODO ) ) , CalcExpression ou Comparison .
Cet objet est alors rebalancé à 'treat' .
* /
2017-03-08 16:47:12 +00:00
2017-06-27 21:09:03 +00:00
let [ parseResult , ... additionnalResults ] = nearley ( ) . feed ( rawNode ) . results
if ( additionnalResults && additionnalResults . length > 0 )
throw "Attention ! L'expression <" + rawNode + '> ne peut être traitée de façon univoque'
2017-06-29 10:03:01 +00:00
if ( ! R . contains ( parseResult . category ) ( [ 'variable' , 'calcExpression' , 'filteredVariable' , 'comparison' , 'negatedVariable' ] ) )
2017-06-27 21:09:03 +00:00
throw "Attention ! Erreur de traitement de l'expression : " + rawNode
if ( parseResult . category == 'variable' )
2017-07-17 17:39:49 +00:00
return fillVariableNode ( rules , rule ) ( parseResult )
2017-06-29 10:03:01 +00:00
if ( parseResult . category == 'filteredVariable' ) {
2017-07-17 17:39:49 +00:00
return fillFilteredVariableNode ( rules , rule ) ( parseResult . filter , parseResult . variable )
2017-06-29 10:03:01 +00:00
}
2017-06-27 21:09:03 +00:00
if ( parseResult . category == 'negatedVariable' )
return buildNegatedVariable (
2017-07-17 17:39:49 +00:00
fillVariableNode ( rules , rule ) ( parseResult . variable )
2017-06-27 21:09:03 +00:00
)
2017-07-28 09:30:23 +00:00
if ( parseResult . category == 'calcExpression' || parseResult . category == 'comparison' ) {
2017-07-09 16:48:00 +00:00
let evaluate = ( situation , parsedRules , node ) => {
let
operatorFunctionName = {
'*' : 'multiply' ,
'/' : 'divide' ,
'+' : 'add' ,
2017-07-28 09:30:23 +00:00
'-' : 'subtract' ,
'<' : 'lt' ,
'<=' : 'lte' ,
'>' : 'gt' ,
2017-09-07 14:52:14 +00:00
'>=' : 'gte' ,
2017-09-07 21:26:31 +00:00
'=' : 'equals' ,
'!=' : 'equals'
2017-07-09 16:48:00 +00:00
} [ node . operator ] ,
2017-07-11 14:00:10 +00:00
explanation = R . map ( R . curry ( evaluateNode ) ( situation , parsedRules ) , node . explanation ) ,
value1 = explanation [ 0 ] . nodeValue ,
value2 = explanation [ 1 ] . nodeValue ,
2017-09-08 08:09:19 +00:00
operatorFunction = node . operator == "!=" ? ( ( a , b ) => ! R . equals ( a , b ) ) : R [ operatorFunctionName ] ,
2017-07-09 16:48:00 +00:00
nodeValue = value1 == null || value2 == null ?
null
: operatorFunction ( value1 , value2 )
2017-07-11 14:00:10 +00:00
let collectMissing = node => R . chain ( collectNodeMissing , node . explanation )
2017-07-13 10:25:46 +00:00
return rewriteNode ( node , nodeValue , explanation , collectMissing )
2017-07-09 16:48:00 +00:00
}
2017-07-17 17:39:49 +00:00
let fillFiltered = parseResult => fillFilteredVariableNode ( rules , rule ) ( parseResult . filter , parseResult . variable )
let fillVariable = fillVariableNode ( rules , rule ) ,
2017-06-27 21:09:03 +00:00
filledExplanation = parseResult . explanation . map (
R . cond ( [
2017-06-29 10:03:01 +00:00
[ R . propEq ( 'category' , 'variable' ) , fillVariable ] ,
[ R . propEq ( 'category' , 'filteredVariable' ) , fillFiltered ] ,
2017-06-27 21:09:03 +00:00
[ R . propEq ( 'category' , 'value' ) , node =>
2017-07-09 16:48:00 +00:00
( {
2017-09-07 14:52:14 +00:00
evaluate : ( situation , parsedRules , me ) => ( { ... me , nodeValue : node . nodeValue } ) ,
2017-07-13 20:44:14 +00:00
jsx : nodeValue => < span className = "value" > { nodeValue } < / s p a n >
2017-07-09 16:48:00 +00:00
} )
2017-06-27 21:09:03 +00:00
]
] )
) ,
2017-07-09 16:48:00 +00:00
operator = parseResult . operator
2017-06-27 21:09:03 +00:00
2017-07-13 20:45:54 +00:00
let jsx = ( nodeValue , explanation ) =>
< Node
2017-07-28 09:30:23 +00:00
classes = { "inlineExpression " + parseResult . category }
2017-07-13 19:55:59 +00:00
value = { nodeValue }
2017-06-27 21:09:03 +00:00
child = {
< span className = "nodeContent" >
2017-07-13 19:55:59 +00:00
{ makeJsx ( explanation [ 0 ] ) }
2017-06-27 21:09:03 +00:00
< span className = "operator" > { parseResult . operator } < / s p a n >
2017-07-13 19:55:59 +00:00
{ makeJsx ( explanation [ 1 ] ) }
2017-06-27 21:09:03 +00:00
< / s p a n >
}
/ >
2017-07-13 19:55:59 +00:00
return {
evaluate ,
jsx ,
operator ,
text : rawNode ,
2017-07-28 09:30:23 +00:00
category : parseResult . category ,
type : parseResult . category == 'calcExpression' ? 'numeric' : 'boolean' ,
2017-07-13 19:55:59 +00:00
explanation : filledExplanation
2017-06-27 21:09:03 +00:00
}
}
} ,
treatNumber = rawNode => {
2017-03-09 15:42:52 +00:00
return {
2017-06-27 23:19:38 +00:00
text : "" + rawNode ,
2017-06-27 21:09:03 +00:00
category : 'number' ,
nodeValue : rawNode ,
2017-03-09 15:42:52 +00:00
type : 'numeric' ,
2017-06-27 21:09:03 +00:00
jsx :
< span className = "number" >
{ rawNode }
< / s p a n >
2017-03-09 15:42:52 +00:00
}
2017-06-27 21:09:03 +00:00
} ,
treatOther = rawNode => {
console . log ( ) // eslint-disable-line no-console
throw 'Cette donnée : ' + rawNode + ' doit être un Number, String ou Object'
} ,
2017-06-27 23:02:36 +00:00
treatObject = rawNode => {
let mecanisms = R . intersection ( R . keys ( rawNode ) , R . keys ( knownMecanisms ) )
if ( mecanisms . length != 1 ) {
console . log ( 'Erreur : On ne devrait reconnaître que un et un seul mécanisme dans cet objet' , rawNode )
throw 'OUPS !'
2017-06-27 21:09:03 +00:00
}
2017-04-24 18:03:38 +00:00
2017-06-27 23:02:36 +00:00
let k = R . head ( mecanisms ) ,
v = rawNode [ k ]
2017-06-28 07:06:52 +00:00
let dispatch = {
'une de ces conditions' : mecanismOneOf ,
'toutes ces conditions' : mecanismAllOf ,
2017-08-02 13:28:33 +00:00
'aiguillage numérique' : mecanismNumericalSwitch ,
2017-06-28 07:06:52 +00:00
'taux' : mecanismPercentage ,
'somme' : mecanismSum ,
'multiplication' : mecanismProduct ,
'barème' : mecanismScale ,
'le maximum de' : mecanismMax ,
2017-07-30 21:50:36 +00:00
'le minimum de' : mecanismMin ,
2017-06-29 12:26:24 +00:00
'complément' : mecanismComplement ,
2017-09-08 10:06:53 +00:00
'une possibilité' : R . always ( { 'une possibilité' : 'oui' , collectMissing : node => [ rule . dottedName ] } )
2017-06-28 07:06:52 +00:00
} ,
2017-07-31 14:30:05 +00:00
action = R . propOr ( mecanismError , k , dispatch )
2017-04-06 16:34:00 +00:00
2017-06-28 07:31:37 +00:00
return action ( reTreat , k , v )
2017-03-03 09:43:43 +00:00
}
2017-02-22 16:55:36 +00:00
2017-06-27 21:09:03 +00:00
let onNodeType = R . cond ( [
[ R . is ( String ) , treatString ] ,
[ R . is ( Number ) , treatNumber ] ,
2017-06-27 22:38:55 +00:00
[ R . is ( Object ) , treatObject ] ,
[ R . T , treatOther ]
2017-06-27 21:09:03 +00:00
] )
2017-07-09 16:48:00 +00:00
2017-07-11 15:39:50 +00:00
let defaultEvaluate = ( situationGate , parsedRules , node ) => node
2017-07-09 16:48:00 +00:00
let parsedNode = onNodeType ( rawNode )
return parsedNode . evaluate ? parsedNode :
{ ... parsedNode , evaluate : defaultEvaluate }
2017-02-22 16:55:36 +00:00
}
2017-05-07 17:45:44 +00:00
//TODO c'est moche :
export let computeRuleValue = ( formuleValue , condValue ) =>
condValue === undefined
? formuleValue
: formuleValue === 0
? 0
: condValue === null
? null
: condValue === true
? 0
: formuleValue
2017-07-17 17:39:49 +00:00
export let treatRuleRoot = ( rules , rule ) => {
2017-07-09 14:39:31 +00:00
let evaluate = ( situationGate , parsedRules , r ) => {
let
2017-07-11 14:00:10 +00:00
evaluated = R . evolve ( {
2017-07-31 14:30:05 +00:00
formule : R . curry ( evaluateNode ) ( situationGate , parsedRules ) ,
"non applicable si" : R . curry ( evaluateNode ) ( situationGate , parsedRules )
2017-07-11 14:00:10 +00:00
} , r ) ,
formuleValue = evaluated . formule && evaluated . formule . nodeValue ,
condition = R . prop ( 'non applicable si' , evaluated ) ,
condValue = condition && condition . nodeValue ,
2017-07-09 14:39:31 +00:00
nodeValue = computeRuleValue ( formuleValue , condValue )
2017-07-11 14:00:10 +00:00
return { ... evaluated , nodeValue }
}
let collectMissing = node => {
let cond = R . prop ( 'non applicable si' , node ) ,
condMissing = cond ? collectNodeMissing ( cond ) : [ ] ,
2017-07-28 08:22:22 +00:00
collectInFormule = ( cond && cond . nodeValue != undefined ) ? ! cond . nodeValue : true ,
2017-07-11 14:00:10 +00:00
formule = node . formule ,
2017-07-28 08:22:22 +00:00
formMissing = collectInFormule ? ( formule ? collectNodeMissing ( formule ) : [ ] ) : [ ]
2017-07-11 14:00:10 +00:00
return R . concat ( condMissing , formMissing )
2017-07-09 14:39:31 +00:00
}
2017-07-31 14:30:05 +00:00
let parsedRoot = R . evolve ( { // Voilà les attributs d'une règle qui sont aujourd'hui dynamiques, donc à traiter
2017-02-22 16:55:36 +00:00
2017-07-31 14:30:05 +00:00
// Les métadonnées d'une règle n'en font pas aujourd'hui partie
2017-02-22 16:55:36 +00:00
2017-07-31 14:30:05 +00:00
// condition d'applicabilité de la règle
2017-03-16 18:30:30 +00:00
'non applicable si' : value => {
2017-07-09 16:48:00 +00:00
let evaluate = ( situationGate , parsedRules , node ) => {
2017-07-13 10:25:46 +00:00
let collectMissing = node => collectNodeMissing ( node . explanation )
2017-07-11 14:00:10 +00:00
let explanation = evaluateNode ( situationGate , parsedRules , node . explanation ) ,
nodeValue = explanation . nodeValue
2017-07-13 10:25:46 +00:00
return rewriteNode ( node , nodeValue , explanation , collectMissing )
2017-07-09 16:48:00 +00:00
}
2017-07-17 17:39:49 +00:00
let child = treat ( rules , rule ) ( value )
2017-04-11 15:44:53 +00:00
2017-07-13 20:45:54 +00:00
let jsx = ( nodeValue , explanation ) =>
< Node
2017-07-13 19:55:59 +00:00
classes = "ruleProp mecanism cond"
name = "non applicable si"
value = { nodeValue }
child = {
2017-07-31 14:30:05 +00:00
explanation . category === 'variable' ? < div className = "node" > { makeJsx ( explanation ) } < / d i v >
2017-07-13 19:55:59 +00:00
: makeJsx ( explanation )
}
/ >
2017-03-16 18:30:30 +00:00
return {
2017-07-09 16:48:00 +00:00
evaluate ,
2017-07-13 19:55:59 +00:00
jsx ,
2017-03-16 18:30:30 +00:00
category : 'ruleProp' ,
rulePropType : 'cond' ,
name : 'non applicable si' ,
type : 'boolean' ,
2017-07-13 19:55:59 +00:00
explanation : child
2017-03-16 18:30:30 +00:00
}
2017-03-01 10:21:53 +00:00
}
2017-03-16 18:30:30 +00:00
,
'formule' : value => {
2017-07-09 16:48:00 +00:00
let evaluate = ( situationGate , parsedRules , node ) => {
2017-07-13 10:25:46 +00:00
let collectMissing = node => collectNodeMissing ( node . explanation )
2017-07-11 14:00:10 +00:00
let explanation = evaluateNode ( situationGate , parsedRules , node . explanation ) ,
nodeValue = explanation . nodeValue
2017-07-13 10:25:46 +00:00
return rewriteNode ( node , nodeValue , explanation , collectMissing )
2017-07-09 16:48:00 +00:00
}
2017-07-17 17:39:49 +00:00
let child = treat ( rules , rule ) ( value )
2017-07-11 14:00:10 +00:00
2017-07-13 20:45:54 +00:00
let jsx = ( nodeValue , explanation ) =>
< Node
2017-07-13 19:55:59 +00:00
classes = "ruleProp mecanism formula"
name = "formule"
value = { nodeValue }
child = { makeJsx ( explanation ) }
/ >
2017-03-16 18:30:30 +00:00
return {
2017-07-09 16:48:00 +00:00
evaluate ,
2017-07-13 19:55:59 +00:00
jsx ,
2017-03-16 18:30:30 +00:00
category : 'ruleProp' ,
rulePropType : 'formula' ,
name : 'formule' ,
type : 'numeric' ,
2017-07-13 19:55:59 +00:00
explanation : child
2017-03-16 18:30:30 +00:00
}
2017-03-01 10:21:53 +00:00
}
,
2017-02-22 16:55:36 +00:00
2017-07-09 14:39:31 +00:00
} ) ( rule )
2017-03-20 11:17:49 +00:00
2017-07-09 14:39:31 +00:00
return {
2017-07-31 14:30:05 +00:00
// Pas de propriété explanation et jsx ici car on est parti du (mauvais) principe que 'non applicable si' et 'formule' sont particuliers, alors qu'ils pourraient être rangé avec les autres mécanismes
2017-07-09 14:39:31 +00:00
... parsedRoot ,
2017-07-11 14:00:10 +00:00
evaluate ,
collectMissing
2017-03-16 18:30:30 +00:00
}
2017-07-09 14:39:31 +00:00
}
2017-02-22 16:55:36 +00:00
2017-03-27 13:02:50 +00:00
2017-07-09 14:39:31 +00:00
export let analyseSituation = ( rules , rootVariable ) => situationGate => {
2017-07-09 22:14:22 +00:00
let { root , parsedRules } = analyseTopDown ( rules , rootVariable ) ( situationGate )
return root
}
2017-07-31 14:30:05 +00:00
2017-07-09 22:14:22 +00:00
export let analyseTopDown = ( rules , rootVariable ) => situationGate => {
2017-08-22 09:38:11 +00:00
clearDict ( )
2017-07-31 14:30:05 +00:00
let
/ *
La fonction treatRuleRoot va descendre l 'arbre de la règle `rule` et produire un AST, un objet contenant d' autres objets contenant d ' autres objets ...
Aujourd ' hui , une règle peut avoir ( comme propriétés à parser ) ` non applicable si ` et ` formule ` ,
qui ont elles - mêmes des propriétés de type mécanisme ( ex . barème ) ou des expressions en ligne ( ex . maVariable + 3 ) .
Ces mécanismes où variables sont descendues à leur tour grâce à ` treat() ` .
Lors de ce traitement , des fonctions 'evaluate' , ` collectMissingVariables ` et ` jsx ` sont attachés aux objets de l ' AST
* /
treatOne = rule => treatRuleRoot ( rules , rule ) ,
//On fait ainsi pour chaque règle de la base.
2017-07-09 14:39:31 +00:00
parsedRules = R . map ( treatOne , rules ) ,
2017-07-09 22:14:22 +00:00
rootRule = findRuleByName ( parsedRules , rootVariable ) ,
2017-07-31 14:30:05 +00:00
/ *
Ce n 'est que dans cette nouvelle étape que l' arbre est vraiment évalué .
Auparavant , l 'évaluation était faite lors de la construction de l' AST .
* /
2017-07-09 22:14:22 +00:00
root = evaluateNode ( situationGate , parsedRules , rootRule )
2017-01-26 12:19:04 +00:00
2017-07-09 22:14:22 +00:00
return {
root ,
parsedRules
}
2017-07-09 14:39:31 +00:00
}