Navigation Menu

Skip to content
This repository has been archived by the owner on Jan 13, 2022. It is now read-only.

Commit

Permalink
Add support for ...
Browse files Browse the repository at this point in the history
Now for function calls and array initializers, you can use ... to match 0 or
more elements of the list.
  • Loading branch information
Ryan Patterson committed Jan 9, 2012
1 parent 4c6b655 commit 2cf1d47
Show file tree
Hide file tree
Showing 4 changed files with 8,501 additions and 5 deletions.
13 changes: 11 additions & 2 deletions README.mdown
Expand Up @@ -25,6 +25,15 @@ cases, the second parameter to setTimeout was a literal value of 0.
When the pattern references the same metavariable multiple times, jsgrep ensures When the pattern references the same metavariable multiple times, jsgrep ensures
that the value of the metavariable is the same throughout the match. that the value of the metavariable is the same throughout the match.


**Find the names of all invoked events**

$ ./jsgrep -p B "A.fire(B, ...)" tests/*.j
tests/connect.js: 'auth.logout'
tests/connect.js: 'auth.login'

The `...` operator matches 0 or more expressions in function calls and array
initializers.

**Find classes that have a 'path' property** **Find classes that have a 'path' property**


$ jsgrep -p C "JX.install(C, { properties: { path: X } })" tests/*.js $ jsgrep -p C "JX.install(C, { properties: { path: X } })" tests/*.js
Expand All @@ -37,8 +46,8 @@ the `-p` flag to print only a particular matched variable.


## TODO ## TODO


* Add support for ... to the parser * Consider support for --where/--eval and/or not-patterns
* Consider support for --where/--eval * Support for -l -L -n -h -H
* Support for most statements in patterns * Support for most statements in patterns


## Contributors ## Contributors
Expand Down
54 changes: 51 additions & 3 deletions jsgrep
Expand Up @@ -257,9 +257,7 @@ function astIsEqual(node, pattern, variables) {
case tokens.HOOK: case tokens.HOOK:
case tokens.INDEX: case tokens.INDEX:
// Special // Special
case tokens.ARRAY_INIT: // TODO: handle ... case tokens.OBJECT_INIT:
case tokens.LIST: // TODO: handle ...
case tokens.OBJECT_INIT: // TODO: handle ...
case tokens.PROPERTY_INIT: case tokens.PROPERTY_INIT:
//case tokens.SCRIPT: //case tokens.SCRIPT:
if (node.children.length == pattern.children.length) { if (node.children.length == pattern.children.length) {
Expand All @@ -272,6 +270,11 @@ function astIsEqual(node, pattern, variables) {
} }
break; break;


case tokens.ARRAY_INIT:
case tokens.LIST:
return astMatchEllipsis(node.children, pattern.children, variables);
break;

case tokens.LET: case tokens.LET:
case tokens.VAR: case tokens.VAR:
// All of var's children are IDENTIFIERs with name/initializer values // All of var's children are IDENTIFIERs with name/initializer values
Expand Down Expand Up @@ -413,6 +416,51 @@ function astIsEqual(node, pattern, variables) {
} }
} }


function astMatchEllipsis(nodes, patterns, variables) {
// XXX(rpatterson): this needs testing!
const tokens = Narcissus.definitions.tokenIds;
var permitVar = true, clonedVars = null;
function go(i, j) {
if (i == nodes.length && j == patterns.length) {
return true;
}

if (j == patterns.length) {
return false;
}

if (patterns[j].type == tokens.ELLIPSIS && j == patterns.length - 1) {
return true;
}

if(i == nodes.length) {
return false;
}

if (patterns[j].type == tokens.ELLIPSIS) {
permitVar = false;
clonedVars = _.clone(variables);
return go(i, j + 1) || go(i + 1, j);
}

return astIsEqual(nodes[i], patterns[j],
permitVar ? variables : clonedVars) &&
go(i + 1, j + 1);
}
var result = go(0, 0);
if (!permitVar && _.keys(clonedVars).length != _.keys(variables).length) {
// ..., A, ... is ambiguous, and if A was matched later in the pattern, we
// would have to backtrack to the ellipsis to try a different match. That's
// annoying.
//
// XXX(rpatterson): This incorrectly bails for (..., A)
console.error("jsgrep: Matching metavariables inside partially-matched " +
"lists is unsupported. Sorry!");
process.exit(1);
}
return result;
}

function forEachNode(node, callback) { function forEachNode(node, callback) {
const tokens = Narcissus.definitions.tokenIds; const tokens = Narcissus.definitions.tokenIds;


Expand Down

0 comments on commit 2cf1d47

Please sign in to comment.