Skip to content

Commit

Permalink
first
Browse files Browse the repository at this point in the history
  • Loading branch information
zaach committed Apr 11, 2011
0 parents commit e4490a8
Show file tree
Hide file tree
Showing 14 changed files with 3,773 additions and 0 deletions.
Empty file added .gitignore
Empty file.
13 changes: 13 additions & 0 deletions Makefile
@@ -0,0 +1,13 @@
all: build test

build: move
jison lib/grammar.y lib/lexer.l
mv grammar.js dist/parser.js

move: lib
cp lib/*.js dist/


test: move dist
node test/reflect-parse.js

14 changes: 14 additions & 0 deletions README.md
@@ -0,0 +1,14 @@
![Reflect.js](reflectjs.png "Reflect.js")

Reflect.js is a pure JavaScript implementation of [Mozilla's Parser API](https://developer.mozilla.org/en/SpiderMonkey/Parser_API). It does not currently support Mozilla specific extentions such as `let`, generators, list comprehensions, patterns, E4X, etc. but may eventually support ones that are/become Harmony proposals. *I'll probably add patterns next because those are pretty sweet.*

Builders are also supported.

Parsing large files can be slow, for reasons [articulated](http://www.andychu.net/ecmascript/RegExp-Enhancements.html) by Andy Chu.

Install
=======

npm install reflect

MIT X Licensed.
1 change: 1 addition & 0 deletions dist/.gitignore
@@ -0,0 +1 @@
*.js
234 changes: 234 additions & 0 deletions examples/jsonml-ast.js
@@ -0,0 +1,234 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/

var Reflect = require('reflect').Reflect;

// A simple proof-of-concept that the builder API can be used to generate other
// formats, such as JsonMLAst:
//
// http://code.google.com/p/es-lab/wiki/JsonMLASTFormat
//
// It's incomplete (e.g., it doesn't convert source-location information and
// doesn't use all the direct-eval rules), but I think it proves the point.

var JsonMLAst = (function() {
function reject() {
throw new SyntaxError("node type not supported");
}

function isDirectEval(expr) {
// an approximation to the actual rules. you get the idea
return (expr[0] === "IdExpr" && expr[1].name === "eval");
}

function functionNode(type) {
return function(id, args, body, isGenerator, isExpression) {
if (isExpression)
body = ["ReturnStmt", {}, body];

if (!id)
id = ["Empty"];

// Patch up the argument node types: s/IdExpr/IdPatt/g
for (var i = 0; i < args.length; i++) {
args[i][0] = "IdPatt";
}

args.unshift("ParamDecl", {});

return [type, {}, id, args, body];
}
}

return {
program: function(stmts) {
stmts.unshift("Program", {});
return stmts;
},
identifier: function(name) {
return ["IdExpr", { name: name }];
},
literal: function(val) {
return ["LiteralExpr", { value: val }];
},
expressionStatement: function(expr) {return expr},
conditionalExpression: function(test, cons, alt) {
return ["ConditionalExpr", {}, test, cons, alt];
},
unaryExpression: function(op, expr) {
return ["UnaryExpr", {op: op}, expr];
},
binaryExpression: function(op, left, right) {
return ["BinaryExpr", {op: op}, left, right];
},
property: function(kind, key, val) {
return [kind === "init"
? "DataProp"
: kind === "get"
? "GetterProp"
: "SetterProp",
{name: key[1].name}, val];
},
functionDeclaration: functionNode("FunctionDecl"),
variableDeclaration: function(kind, elts) {
if (kind === "let" || kind === "const")
throw new SyntaxError("let and const not supported");
elts.unshift("VarDecl", {});
return elts;
},
variableDeclarator: function(id, init) {
id[0] = "IdPatt";
if (!init)
return id;
return ["InitPatt", {}, id, init];
},
sequenceExpression: function(exprs) {
var length = exprs.length;
var result = ["BinaryExpr", {op:","}, exprs[exprs.length - 2], exprs[exprs.length - 1]];
for (var i = exprs.length - 3; i >= 0; i--) {
result = ["BinaryExpr", {op:","}, exprs[i], result];
}
return result;
},
assignmentExpression: function(op, lhs, expr) {
return ["AssignExpr", {op: op}, lhs, expr];
},
logicalExpression: function(op, left, right) {
return [op === "&&" ? "LogicalAndExpr" : "LogicalOrExpr", {}, left, right];
},
updateExpression: function(expr, op, isPrefix) {
return ["CountExpr", {isPrefix:isPrefix, op:op}, expr];
},
newExpression: function(callee, args) {
args.unshift("NewExpr", {}, callee);
return args;
},
callExpression: function(callee, args) {
args.unshift(isDirectEval(callee) ? "EvalExpr" : "CallExpr", {}, callee);
return args;
},
memberExpression: function(isComputed, expr, member) {
return ["MemberExpr", {}, expr, isComputed ? member : ["LiteralExpr", {type: "string", value: member[1].name}]];
},
functionExpression: functionNode("FunctionExpr"),
arrayExpression: function(elts) {
for (var i = 0; i < elts.length; i++) {
if (!elts[i])
elts[i] = ["Empty"];
}
elts.unshift("ArrayExpr", {});
return elts;
},
objectExpression: function(props) {
props.unshift("ObjectExpr", {});
return props;
},
thisExpression: function() {
return ["ThisExpr", {}];
},

graphExpression: reject,
graphIndexExpression: reject,
comprehensionExpression: reject,
generatorExpression: reject,
yieldExpression: reject,
letExpression: reject,

emptyStatement: function() {return ["EmptyStmt", {}] },
blockStatement: function(stmts) {
stmts.unshift("BlockStmt", {});
return stmts;
},
labeledStatement: function(lab, stmt) {
return ["LabelledStmt", {label: lab}, stmt];
},
ifStatement: function(test, cons, alt) {
return ["IfStmt", {}, test, cons, alt || ["EmptyStmt", {}]];
},
switchStatement: function(test, clauses, isLexical) {
clauses.unshift("SwitchStmt", {}, test);
return clauses;
},
whileStatement: function(expr, stmt) {
return ["WhileStmt", {}, expr, stmt];
},
doWhileStatement: function(stmt, expr) {
return ["DoWhileStmt", {}, stmt, expr];
},
forStatement: function(init, test, update, body) {
return ["ForStmt", {}, init || ["Empty"], test || ["Empty"], update || ["Empty"], body];
},
forInStatement: function(lhs, rhs, body) {
return ["ForInStmt", {}, lhs, rhs, body];
},
breakStatement: function(lab) {
return lab ? ["BreakStmt", {}, lab] : ["BreakStmt", {}];
},
continueStatement: function(lab) {
return lab ? ["ContinueStmt", {}, lab] : ["ContinueStmt", {}];
},
withStatement: function(expr, stmt) {
return ["WithStmt", {}, expr, stmt];
},
returnStatement: function(expr) {
return expr ? ["ReturnStmt", {}, expr] : ["ReturnStmt", {}];
},
tryStatement: function(body, catches, fin) {
if (catches.length > 1)
throw new SyntaxError("multiple catch clauses not supported");
var node = ["TryStmt", body, catches[0] || ["Empty"]];
if (fin)
node.push(fin);
return node;
},
throwStatement: function(expr) {
return ["ThrowStmt", {}, expr];
},
debuggerStatement: function(){ return ["DebuggerStmt", {}] },
letStatement: reject,
switchCase: function(expr, stmts) {
if (expr)
stmts.unshift("SwitchCase", {}, expr);
else
stmts.unshift("DefaultCase", {});
return stmts;
},
catchClause: function(param, guard, body) {
if (guard)
throw new SyntaxError("catch guards not supported");
param[0] = "IdPatt";
return ["CatchClause", {}, param, body];
},
comprehensionBlock: reject,

arrayPattern: reject,
objectPattern: reject,
propertyPattern: reject,

xmlAnyName: reject,
xmlAttributeSelector: reject,
xmlEscape: reject,
xmlFilterExpression: reject,
xmlDefaultDeclaration: reject,
xmlQualifiedIdentifier: reject,
xmlFunctionQualifiedIdentifier: reject,
xmlElement: reject,
xmlText: reject,
xmlList: reject,
xmlStartTag: reject,
xmlEndTag: reject,
xmlPointTag: reject,
xmlName: reject,
xmlAttribute: reject,
xmlCdata: reject,
xmlComment: reject,
xmlProcessingInstruction: reject
};
})();

console.log(JSON.stringify(Reflect.parse("2 + (-x * y)", {loc: false, builder: JsonMLAst}),null," "));


0 comments on commit e4490a8

Please sign in to comment.