start = expr:expression { let node = { $name: null, $relation: null, $modify: [], $recursive: false, $allRecursive: false }; if (expr.$name === '*') { node.$allRecursive = true; } else { node[expr.$name] = expr; } return node; } / list:listExpression { let node = { $name: null, $relation: null, $modify: [], $recursive: false, $allRecursive: false }; list.forEach(expr => { node[expr.$name] = expr; }); return node; } expression = name:name args:args? alias:alias? list:subListExpression { let node = { $name: alias || name, $relation: name, $modify: args || [], $recursive: false, $allRecursive: false }; list.forEach(expr => { node[expr.$name] = expr; }); return node; } / name:name args:args? alias:alias? expr:subExpression? { let node = { $name: alias || name, $relation: name, $modify: args || [], $recursive: false, $allRecursive: false }; if (expr) { const match = /^\^(\d*)$/.exec(expr.$name); if (match) { if (match[1]) { node.$recursive = parseInt(match[1], 10); } else { node.$recursive = true; } } else if (expr.$name === '*') { node.$allRecursive = true; } else { node[expr.$name] = expr; } } return node; } alias = ws+ "as" ws+ alias:name { return alias; } name = name:char+ { return name.join(''); } char = [^\[\]\(\),\. \t\r\n] args = ws* "(" args:argListItem* ws* ")" { return args; } argListItem = ws* arg:name ws* ","? { return arg; } ws = [ \t\r\n] subListExpression = ws* "." list:listExpression { return list; } listExpression = ws* "[" items:listExpressionItem* ws* "]" ws* { return items; } listExpressionItem = ws* expr:expression ws* ","? { return expr; } subExpression = ws* "." ws* sub:expression ws* { return sub; }