grasp-equery
Version:
grasp query using example code with wildcards
191 lines (190 loc) • 6.92 kB
JavaScript
// Generated by LiveScript 1.5.0
(function(){
var ref$, primitiveOnlyAttributes, eitherAttributes, syntaxFlat, all, tail, getNodeAtPath, toString$ = {}.toString, slice$ = [].slice;
ref$ = require('grasp-syntax-javascript'), primitiveOnlyAttributes = ref$.primitiveOnlyAttributes, eitherAttributes = ref$.eitherAttributes, syntaxFlat = ref$.syntaxFlat;
ref$ = require('prelude-ls'), all = ref$.all, tail = ref$.tail;
getNodeAtPath = require('./common').getNodeAtPath;
function matchNode(results, query, mainNode){
var spec, i$, ref$, len$, key, j$, ref1$, len1$, subNode;
if (eq(mainNode, query)) {
results.push(mainNode);
}
spec = syntaxFlat[mainNode.type];
if (spec == null) {
return;
}
for (i$ = 0, len$ = (ref$ = spec.nodes || []).length; i$ < len$; ++i$) {
key = ref$[i$];
if (mainNode[key]) {
matchNode(results, query, mainNode[key]);
}
}
for (i$ = 0, len$ = (ref$ = spec.nodeArrays || []).length; i$ < len$; ++i$) {
key = ref$[i$];
for (j$ = 0, len1$ = (ref1$ = mainNode[key]).length; j$ < len1$; ++j$) {
subNode = ref1$[j$];
if (subNode) {
matchNode(results, query, subNode);
}
}
}
function eq(targetNode, selectorNode){
var type, spec;
if (targetNode === selectorNode) {
return true;
} else if (selectorNode.type === 'Grasp') {
return matchSpecial(targetNode, selectorNode);
} else if (selectorNode.type === targetNode.type) {
type = selectorNode.type;
spec = syntaxFlat[type];
if (spec == null) {
return;
}
return all(function(it){
return eq(targetNode[it], selectorNode[it]);
}, spec.nodes || []) && all(function(it){
return matchArray(targetNode[it], selectorNode[it]);
}, spec.nodeArrays || []) && all(function(it){
return targetNode[it] === selectorNode[it];
}, spec.primitives || []);
} else {
return false;
}
}
function matchArray(input, pattern){
var that, ref$, patternFirst, patternRest, inputFirst, inputRest, arrayWildcardName, wildcardName;
if (toString$.call(pattern).slice(8, -1) === 'Object' && pattern.type === 'Grasp') {
return matchSpecial(input, pattern);
}
if (pattern.length === 0) {
return input.length === 0;
} else if (pattern.length === 1) {
if (that = isArrayWildcard(pattern[0])) {
if (that = that.name) {
mainNode._named == null && (mainNode._named = {});
(ref$ = mainNode._named)[that] == null && (ref$[that] = []);
(ref$ = mainNode._named)[that] = ref$[that].concat(input);
}
return true;
} else {
return input.length === 1 && eq(input[0], pattern[0]);
}
} else if (input.length === 0) {
return false;
} else {
patternFirst = pattern[0], patternRest = slice$.call(pattern, 1);
inputFirst = input[0], inputRest = slice$.call(input, 1);
if (that = isArrayWildcard(patternFirst)) {
if (that = that.name) {
arrayWildcardName = that;
mainNode._named == null && (mainNode._named = {});
(ref$ = mainNode._named)[arrayWildcardName] == null && (ref$[arrayWildcardName] = []);
}
if (that = eq(inputFirst, patternRest[0])) {
wildcardName = that;
if (matchArray(inputRest, tail(patternRest))) {
return true;
} else {
if (toString$.call(wildcardName).slice(8, -1) === 'String') {
delete mainNode._named[wildcardName];
}
return matchArray(inputRest, pattern);
}
} else {
if (arrayWildcardName) {
mainNode._named[arrayWildcardName].push(inputFirst);
}
return matchArray(inputRest, pattern);
}
} else {
return eq(inputFirst, patternFirst) && matchArray(inputRest, patternRest);
}
}
}
function matchSpecial(targetNode, selectorNode){
var named, name, that, identMatch, attrMatch;
switch (selectorNode.graspType) {
case 'wildcard':
return true;
case 'named-wildcard':
mainNode._named == null && (mainNode._named = {});
named = mainNode._named;
name = selectorNode.name;
if (that = named[name]) {
if (eq(targetNode, that)) {
return true;
} else {
return false;
}
} else {
named[name] = targetNode;
return name;
}
break;
case 'node-type':
return targetNode.type === selectorNode.value;
case 'matches':
return in$(targetNode.type, selectorNode.value);
case 'literal':
return targetNode.type === 'Literal' && toString$.call(targetNode.value).slice(8, -1) === selectorNode.value;
case 'compound':
identMatch = matchSpecial(targetNode, selectorNode.ident);
attrMatch = all(matchAttr(targetNode), selectorNode.attrs);
return identMatch && attrMatch;
}
}
function isArrayWildcard(node){
var cleanNode;
cleanNode = node.type === 'ExpressionStatement' ? node.expression : node;
return cleanNode.type === 'Grasp' && cleanNode.graspType === 'array-wildcard' && cleanNode;
}
function matchAttr(targetNode){
return function(attr){
var node, attrValue, lastPath, ref$;
node = getNodeAtPath(targetNode, attr.path);
if (node != null) {
attrValue = attr.value;
if (attrValue) {
lastPath = (ref$ = attr.path)[ref$.length - 1];
if (in$(lastPath, primitiveOnlyAttributes)) {
return matchPrimitive(attr.op, node, attrValue);
} else if (in$(lastPath, eitherAttributes)) {
return matchEither(attr.op, node, attrValue);
} else {
return matchComplex(attr.op, node, attrValue);
}
} else {
return true;
}
} else {
return false;
}
};
}
function matchPrimitive(op, node, attrValue){
if (op === '=') {
return node === attrValue.value;
} else {
return node !== attrValue.value;
}
}
function matchComplex(op, node, attrValue){
if (op === '=') {
return eq(node, attrValue);
} else {
return !eq(node, attrValue);
}
}
function matchEither(op, node, attrValue){
return matchPrimitive(op, node, attrValue) || matchComplex(op, node, attrValue);
}
}
module.exports = {
matchNode: matchNode
};
function in$(x, xs){
var i = -1, l = xs.length >>> 0;
while (++i < l) if (x === xs[i]) return true;
return false;
}
}).call(this);