Разбор логики c Выражение с Javascript - PullRequest
1 голос
/ 02 февраля 2020

Я создаю синтаксический анализатор выражений logi c. Мне очень нравится, как mongoDB структурирует свои выражения logi c. Тем не менее, я думаю, что это лучшая структура для хранения и анализа выражений logi c.

const logicPayload = [
  { varA: { $eq: "meow" } },
  { $and: [{ varB: { $lt: "varD" } }, { varB: { $gte: "varC" } }] },
  { $not: [{ varB: { $eq: "varA" } }] }
];

Учитывая полезную нагрузку выше, как я могу разработать функцию для анализа выражения. varA, varB varC и varD будут разрешены во время выполнения.

Ниже приведена функция разрешения пустышки.

const resovleValue = varID => {
  switch (varID) {
    case "varA":
      return "meow";
      break;
    case "varB":
      return 100;
    case "varC":
      return 100;
    case "varD":
      return 983;
  }
};

Я пытаюсь создать функцию logi c ниже

/**
 * This logic function must only return true or false
 */
const logicFunction = logicPayload => {};

Любое руководство высоко ценится. Спасибо.

1 Ответ

1 голос
/ 02 февраля 2020

Вот анализатор logi c, который использует рекурсию для работы с внутренними массивами logi c.

Он остановит обработку, как только найдет правило, которое возвращает false.

function checkRule(rule) {
  let key1 = Object.keys(rule)[0];
  let comp = Object.values(rule)[0];
  
  if(/^[$](and|or|not)$/.test(key1) && Array.isArray(comp)) {
    let aon = key1;
    let rules = comp;
    let results = [];
    
    for(r of rules){
      let valid = checkRule(r);
      results.push(valid);
      //console.log(`${aon} ${JSON.stringify(r)}: ${valid}`);
      if(aon === '$and' && !valid) return false;
      if(aon === '$or' && valid) return true;
      if(aon === '$not' && valid) return false;
    }
     //console.log (JSON.stringify(results));
     if(aon === '$and' && results.some((x)=>!x))
         return false;
     if(aon === '$or' && results.every((x)=>!x))
         return false;
     if(aon === '$not' && results.some((x)=>x))
         return false;
}
else {
  let operator = Object.keys(comp)[0];
  let key2 = comp[operator];
  let val1 = resolveValue(key1) || key1;
  let val2 = resolveValue(key2) || key2;
  //console.log(`\t${val1} ${operator} ${val2}`);
  
  switch(operator) {
    case '$eq': 
     if(!(val1 == val2)) return false;
     break;
    case '$ne': 
    case '$neq':
     if(!(val1 != val2)) return false;
     break;
    case '$lt': 
     if(!(val1 < val2)) return false;
     break;
    case '$le': 
    case '$lte': 
     if(!(val1 <= val2)) return false;
     break;
    case '$gt': 
     if(!(val1 > val2)) return false;
     break;
    case '$ge':
    case '$gte': 
     if(!(val1 >= val2)) return false;
     break;
    default: 
      return false;
   }
    
  }
  
  return true;
}

function logicFunction (logicPayload) {
   let results = [];
   
   for (rule of logicPayload) {
   	 let valid = checkRule(rule);
   	 //console.log(`${valid}: ${JSON.stringify(rule)}`);
   	 results.push(valid);
   	 if(!valid) return false;
   }
   return results.every((x)=>x);
};

const resolveValue = (varID) => {
  switch (varID) {
    case "varA": return "meow";
    case "varB": return 100;
    case "varC": return 100;
    case "varD": return 983;
  }
};


let logicPayload = [
  { varA: { $eq: "meow" } },
  { $and: [
      { varB: { $lt: "varD" } },
      { varB: { $gte: "varC" } }
   ] },
  { $not: [ { varB: { $eq: "varA" } } ] }
];

 let result = logicFunction(logicPayload);
 console.log(result);
  
...