2019-02-20 10:57:35 +00:00
// This should be the new way to implement mecanisms
// In a specific file
// TODO import them automatically
// TODO convert the legacy functions to new files
2019-04-03 15:40:51 +00:00
import barème from 'Engine/mecanisms/barème.js'
import { Parser } from 'nearley'
import {
add ,
curry ,
divide ,
equals ,
gt ,
gte ,
keys ,
2019-05-15 08:52:20 +00:00
without ,
2019-04-03 15:40:51 +00:00
lt ,
lte ,
map ,
multiply ,
propOr ,
subtract
} from 'ramda'
import React from 'react'
import { evaluateNode , makeJsx , mergeMissing , rewriteNode } from './evaluation'
import Grammar from './grammar.ne'
import {
mecanismAllOf ,
mecanismComplement ,
mecanismContinuousScale ,
mecanismError ,
mecanismInversion ,
mecanismLinearScale ,
mecanismMax ,
mecanismMin ,
mecanismNumericalSwitch ,
mecanismOneOf ,
mecanismProduct ,
mecanismReduction ,
mecanismSum ,
mecanismSynchronisation ,
2019-05-14 11:52:23 +00:00
mecanismVariations ,
mecanismOnePossibility
2019-04-03 15:40:51 +00:00
} from './mecanisms'
import { Node } from './mecanismViews/common'
import { treat } from './traverse'
import {
treatNegatedVariable ,
treatVariable ,
treatVariableTransforms
} from './treatVariable'
2019-02-20 10:57:35 +00:00
2019-03-04 17:55:51 +00:00
export let nearley = ( ) => new Parser ( Grammar . ParserRules , Grammar . ParserStart )
2018-06-29 09:13:05 +00:00
export let treatString = ( rules , rule ) => rawNode => {
2019-05-14 17:40:47 +00:00
/ * S t r i n g s c o r r e s p o n d t o i n f i x e x p r e s s i o n s .
* 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 . * /
2018-06-29 09:13:05 +00:00
2019-06-04 14:37:20 +00:00
let [ parseResult ] = nearley ( ) . feed ( rawNode ) . results
2018-06-29 09:13:05 +00:00
2019-05-14 17:40:47 +00:00
return treatObject ( rules , rule ) ( parseResult )
2018-06-29 09:13:05 +00:00
}
2018-07-27 16:50:11 +00:00
export let treatNumber = rawNode => ( {
text : '' + rawNode ,
category : 'number' ,
nodeValue : rawNode ,
type : 'numeric' ,
jsx : < span className = "number" > { rawNode } < / s p a n >
} )
2018-06-29 09:13:05 +00:00
export let treatOther = rawNode => {
throw new Error (
'Cette donnée : ' + rawNode + ' doit être un Number, String ou Object'
)
}
2019-05-02 14:24:22 +00:00
2018-09-30 18:38:57 +00:00
export let treatObject = ( rules , rule , treatOptions ) => rawNode => {
2019-05-15 08:52:20 +00:00
/ * T O D O i n s t e a d o f d e s c r i b i n g m e c a n i s m s i n k n o w n M e c a n i s m s . y a m l , e x t e r n a l i z e t h e m e c a n i s m s t h e m s e l v e s i n a n i n d i v i d u a l f i l e a n d d e s c r i b e i t
2018-06-29 09:13:05 +00:00
let mecanisms = intersection ( keys ( rawNode ) , keys ( knownMecanisms ) )
if ( mecanisms . length != 1 ) {
2019-05-15 08:52:20 +00:00
}
* /
let attributes = keys ( rawNode ) ,
descriptiveAttributes = [ 'description' , 'note' , 'référence' ] ,
relevantAttributes = without ( descriptiveAttributes , attributes )
if ( relevantAttributes . length !== 1 )
throw new Error ( ` OUPS : On ne devrait reconnaître que un et un seul mécanisme dans cet objet (au-delà des attributs descriptifs tels que "description", "commentaire", etc.)
2018-07-09 12:13:38 +00:00
Objet YAML : $ { JSON . stringify ( rawNode ) }
Cette liste doit avoir un et un seul élément .
2019-05-15 08:52:20 +00:00
Si vous venez tout juste d 'ajouter un nouveau mécanisme, vérifier qu' il est bien intégré dans le dispatch de treat . js
2018-07-09 12:13:38 +00:00
` )
2019-05-15 08:52:20 +00:00
let k = relevantAttributes [ 0 ] ,
2018-06-29 09:13:05 +00:00
v = rawNode [ k ]
2019-05-15 08:52:20 +00:00
let knownOperations = {
'*' : [ multiply , '∗ ' ] ,
'/' : [ divide , '∕ ' ] ,
'+' : [ add ] ,
'-' : [ subtract , '− ' ] ,
'<' : [ lt ] ,
'<=' : [ lte , '≤' ] ,
'>' : [ gt ] ,
'>=' : [ gte , '≥' ] ,
'=' : [ equals ] ,
'!=' : [ ( a , b ) => ! equals ( a , b ) , '≠' ]
} ,
operationDispatch = map (
2019-06-04 14:37:20 +00:00
( [ f , symbol ] ) => mecanismOperation ( f , symbol || k ) ,
2019-05-15 08:52:20 +00:00
knownOperations
)
2018-06-29 09:13:05 +00:00
let dispatch = {
'une de ces conditions' : mecanismOneOf ,
'toutes ces conditions' : mecanismAllOf ,
'aiguillage numérique' : mecanismNumericalSwitch ,
somme : mecanismSum ,
multiplication : mecanismProduct ,
2019-02-20 10:57:35 +00:00
barème ,
2018-07-09 12:13:38 +00:00
'barème linéaire' : mecanismLinearScale ,
2018-12-05 17:19:11 +00:00
'barème continu' : mecanismContinuousScale ,
2018-06-29 09:13:05 +00:00
'le maximum de' : mecanismMax ,
'le minimum de' : mecanismMin ,
complément : mecanismComplement ,
2019-05-15 14:31:33 +00:00
'une possibilité' : mecanismOnePossibility ( rule . dottedName ) ,
2019-01-30 17:53:57 +00:00
'inversion numérique' : mecanismInversion ( rule . dottedName ) ,
2018-08-07 16:20:08 +00:00
allègement : mecanismReduction ,
2018-09-06 14:45:50 +00:00
variations : mecanismVariations ,
2019-05-15 08:52:20 +00:00
synchronisation : mecanismSynchronisation ,
... operationDispatch ,
'≠' : ( ) =>
treatNegatedVariable ( treatVariable ( rules , rule ) ( v . explanation ) ) ,
filter : ( ) =>
treatVariableTransforms ( rules , rule ) ( {
2019-05-15 14:31:33 +00:00
filter : v . filter ,
2019-05-15 08:52:20 +00:00
variable : v . explanation
} ) ,
variable : ( ) => treatVariableTransforms ( rules , rule ) ( { variable : v } ) ,
temporalTransform : ( ) =>
treatVariableTransforms ( rules , rule ) ( {
variable : v . explanation ,
temporalTransform : v . temporalTransform
} ) ,
constant : ( ) => ( {
type : v . type ,
nodeValue : v . nodeValue ,
// eslint-disable-next-line
jsx : ( ) => < span className = { v . type } > { v . rawNode } < / s p a n >
} )
2018-06-29 09:13:05 +00:00
} ,
action = propOr ( mecanismError , k , dispatch )
2018-09-30 18:38:57 +00:00
return action ( treat ( rules , rule , treatOptions ) , k , v )
2018-06-29 09:13:05 +00:00
}
2019-05-15 08:52:20 +00:00
2019-06-04 14:37:20 +00:00
let mecanismOperation = ( operatorFunction , symbol ) => ( recurse , k , v ) => {
2019-05-15 08:52:20 +00:00
let evaluate = ( cache , situation , parsedRules , node ) => {
let 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 = v . explanation . map ( recurse )
let jsx = ( nodeValue , explanation ) => (
< Node
2019-06-04 14:37:20 +00:00
classes = { 'inlineExpression ' + k }
2019-05-15 08:52:20 +00:00
value = { nodeValue }
child = {
< span className = "nodeContent" >
< span className = "fa fa" / >
{ makeJsx ( explanation [ 0 ] ) }
2019-06-04 14:37:20 +00:00
< span className = "operator" > { symbol } < / s p a n >
2019-05-15 08:52:20 +00:00
{ makeJsx ( explanation [ 1 ] ) }
< / s p a n >
}
/ >
)
return {
evaluate ,
jsx ,
2019-06-04 14:37:20 +00:00
operator : symbol ,
2019-05-15 08:52:20 +00:00
// is this useful ? text: rawNode,
explanation
}
}