зеркало из https://github.com/mozilla/pjs.git
bug 533874, r=cdleary: expose the parser as a JS API
This commit is contained in:
Родитель
417af815e0
Коммит
4c29abba51
|
@ -157,6 +157,7 @@ CPPSRCS = \
|
|||
jsprf.cpp \
|
||||
jspropertycache.cpp \
|
||||
jspropertytree.cpp \
|
||||
jsreflect.cpp \
|
||||
jsregexp.cpp \
|
||||
jsscan.cpp \
|
||||
jsscope.cpp \
|
||||
|
@ -220,6 +221,7 @@ INSTALLED_HEADERS = \
|
|||
jsproto.tbl \
|
||||
jsprvtd.h \
|
||||
jspubtd.h \
|
||||
jsreflect.h \
|
||||
jsregexp.h \
|
||||
jsscan.h \
|
||||
jsscope.h \
|
||||
|
@ -548,7 +550,7 @@ endif
|
|||
ifeq ($(OS_ARCH),IRIX)
|
||||
ifndef GNU_CC
|
||||
_COMPILE_CFLAGS = $(patsubst -O%,-O1,$(COMPILE_CFLAGS))
|
||||
jsapi.o jsxdrapi.o jsarena.o jsarray.o jsatom.o jsemit.o jsfun.o jsinterp.o jsregexp.o jsparse.o jsopcode.o jsscript.o: %.o: %.cpp Makefile.in
|
||||
jsapi.o jsxdrapi.o jsarena.o jsarray.o jsatom.o jsemit.o jsfun.o jsinterp.o jsreflect.o jsregexp.o jsparse.o jsopcode.o jsscript.o: %.o: %.cpp Makefile.in
|
||||
$(REPORT_BUILD)
|
||||
@$(MAKE_DEPS_AUTO_CXX)
|
||||
$(CXX) -o $@ -c $(_COMPILE_CFLAGS) $<
|
||||
|
|
|
@ -330,3 +330,5 @@ MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 247, 0, JSEXN_ERR, "call to Function() blo
|
|||
MSG_DEF(JSMSG_BAD_GET_SET_FIELD, 248, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function")
|
||||
MSG_DEF(JSMSG_BAD_PROXY_FIX, 249, 0, JSEXN_TYPEERR, "proxy was fixed while executing the handler")
|
||||
MSG_DEF(JSMSG_INVALID_EVAL_SCOPE_ARG, 250, 0, JSEXN_EVALERR, "invalid eval scope argument")
|
||||
MSG_DEF(JSMSG_BAD_PARSE_NODE, 251, 2, JSEXN_INTERNALERR, "unimplemented parse node (type {0}, at {1})")
|
||||
MSG_DEF(JSMSG_BAD_INTERNAL_ARG, 252, 0, JSEXN_INTERNALERR, "unexpected argument")
|
||||
|
|
|
@ -1498,6 +1498,10 @@ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
|
|||
CHECK_REQUEST(cx);
|
||||
rt = cx->runtime;
|
||||
|
||||
#ifdef DEBUG_dherman
|
||||
fprintf(stderr, "JS_EnumerateStandardClasses!\n");
|
||||
#endif
|
||||
|
||||
/* Check whether we need to bind 'undefined' and define it if so. */
|
||||
atom = rt->atomState.typeAtoms[JSTYPE_VOID];
|
||||
if (!AlreadyHasOwnProperty(cx, obj, atom) &&
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* These must be listed in exactly this order so the AST_xxx fields match up
|
||||
* with their integer definition in jsreflect.cpp.
|
||||
*/
|
||||
|
||||
/* AST_ERROR = -1 */
|
||||
|
||||
ASTDEF(AST_PROGRAM, 0, "Program")
|
||||
|
||||
ASTDEF(AST_IDENTIFIER, 1, "Identifier")
|
||||
ASTDEF(AST_UNOP, 2, "UnaryOperator")
|
||||
ASTDEF(AST_BINOP, 3, "BinaryOperator")
|
||||
ASTDEF(AST_LOGOP, 4, "LogicalOperator")
|
||||
ASTDEF(AST_AOP, 5, "AssignmentOperator")
|
||||
ASTDEF(AST_UPDOP, 6, "UpdateOperator")
|
||||
ASTDEF(AST_LITERAL, 7, "Literal")
|
||||
|
||||
ASTDEF(AST_FUNC_DECL, 8, "FunctionDeclaration")
|
||||
ASTDEF(AST_VAR_DECL, 9, "VariableDeclaration")
|
||||
|
||||
ASTDEF(AST_LIST_EXPR, 10, "SequenceExpression")
|
||||
ASTDEF(AST_COND_EXPR, 11, "ConditionalExpression")
|
||||
ASTDEF(AST_UNARY_EXPR, 12, "UnaryExpression")
|
||||
ASTDEF(AST_BINARY_EXPR, 13, "BinaryExpression")
|
||||
ASTDEF(AST_ASSIGN_EXPR, 14, "AssignmentExpression")
|
||||
ASTDEF(AST_LOGICAL_EXPR, 15, "LogicalExpression")
|
||||
ASTDEF(AST_UPDATE_EXPR, 16, "UpdateExpression")
|
||||
ASTDEF(AST_NEW_EXPR, 17, "NewExpression")
|
||||
ASTDEF(AST_CALL_EXPR, 18, "CallExpression")
|
||||
ASTDEF(AST_MEMBER_EXPR, 19, "MemberExpression")
|
||||
ASTDEF(AST_FUNC_EXPR, 20, "FunctionExpression")
|
||||
ASTDEF(AST_ARRAY_EXPR, 21, "ArrayExpression")
|
||||
ASTDEF(AST_OBJECT_EXPR, 22, "ObjectExpression")
|
||||
ASTDEF(AST_THIS_EXPR, 23, "ThisExpression")
|
||||
ASTDEF(AST_GRAPH_EXPR, 24, "GraphExpression")
|
||||
ASTDEF(AST_GRAPH_IDX_EXPR, 25, "GraphIndexExpression")
|
||||
ASTDEF(AST_COMP_EXPR, 26, "ComprehensionExpression")
|
||||
ASTDEF(AST_GENERATOR_EXPR, 27, "GeneratorExpression")
|
||||
ASTDEF(AST_YIELD_EXPR, 28, "YieldExpression")
|
||||
|
||||
ASTDEF(AST_EMPTY_STMT, 29, "EmptyStatement")
|
||||
ASTDEF(AST_BLOCK_STMT, 30, "BlockStatement")
|
||||
ASTDEF(AST_EXPR_STMT, 31, "ExpressionStatement")
|
||||
ASTDEF(AST_LAB_STMT, 32, "LabeledStatement")
|
||||
ASTDEF(AST_IF_STMT, 33, "IfStatement")
|
||||
ASTDEF(AST_SWITCH_STMT, 34, "SwitchStatement")
|
||||
ASTDEF(AST_WHILE_STMT, 35, "WhileStatement")
|
||||
ASTDEF(AST_DO_STMT, 36, "DoWhileStatement")
|
||||
ASTDEF(AST_FOR_STMT, 37, "ForStatement")
|
||||
ASTDEF(AST_FOR_IN_STMT, 38, "ForInStatement")
|
||||
ASTDEF(AST_BREAK_STMT, 39, "BreakStatement")
|
||||
ASTDEF(AST_CONTINUE_STMT, 40, "ContinueStatement")
|
||||
ASTDEF(AST_WITH_STMT, 41, "WithStatement")
|
||||
ASTDEF(AST_RETURN_STMT, 42, "ReturnStatement")
|
||||
ASTDEF(AST_TRY_STMT, 43, "TryStatement")
|
||||
ASTDEF(AST_THROW_STMT, 44, "ThrowStatement")
|
||||
ASTDEF(AST_DEBUGGER_STMT, 45, "DebuggerStatement")
|
||||
|
||||
ASTDEF(AST_CASE, 46, "SwitchCase")
|
||||
ASTDEF(AST_CATCH, 47, "CatchClause")
|
||||
ASTDEF(AST_COMP_BLOCK, 48, "ComprehensionBlock")
|
||||
|
||||
ASTDEF(AST_ARRAY_PATT, 49, "ArrayPattern")
|
||||
ASTDEF(AST_OBJECT_PATT, 50, "ObjectPattern")
|
||||
|
||||
ASTDEF(AST_XMLANYNAME, 51, "XMLAnyName")
|
||||
ASTDEF(AST_XMLATTR_SEL, 52, "XMLAttributeSelector")
|
||||
ASTDEF(AST_XMLESCAPE, 53, "XMLEscape")
|
||||
ASTDEF(AST_XMLFILTER, 54, "XMLFilterExpression")
|
||||
ASTDEF(AST_XMLDEFAULT, 55, "XMLDefaultDeclaration")
|
||||
ASTDEF(AST_XMLQUAL, 56, "XMLQualifiedIdentifier")
|
||||
ASTDEF(AST_XMLELEM, 57, "XMLElement")
|
||||
ASTDEF(AST_XMLTEXT, 58, "XMLText")
|
||||
ASTDEF(AST_XMLLIST, 59, "XMLList")
|
||||
ASTDEF(AST_XMLSTART, 60, "XMLStartTag")
|
||||
ASTDEF(AST_XMLEND, 61, "XMLEndTag")
|
||||
ASTDEF(AST_XMLPOINT, 62, "XMLPointTag")
|
||||
ASTDEF(AST_XMLNAME, 63, "XMLName")
|
||||
ASTDEF(AST_XMLATTR, 64, "XMLAttribute")
|
||||
ASTDEF(AST_XMLCDATA, 65, "XMLCdata")
|
||||
ASTDEF(AST_XMLCOMMENT, 66, "XMLComment")
|
||||
ASTDEF(AST_XMLPI, 67, "XMLProcessingInstruction")
|
||||
|
||||
/* AST_LIMIT = last + 1 */
|
|
@ -532,6 +532,35 @@ public:
|
|||
pn_pos.begin.index + str->length() + 2 == pn_pos.end.index);
|
||||
}
|
||||
|
||||
#ifdef JS_HAS_GENERATOR_EXPRS
|
||||
/*
|
||||
* True if this node is a desugared generator expression.
|
||||
*/
|
||||
bool isGeneratorExpr() const {
|
||||
if (PN_TYPE(this) == js::TOK_LP) {
|
||||
JSParseNode *callee = this->pn_head;
|
||||
if (PN_TYPE(callee) == js::TOK_FUNCTION) {
|
||||
JSParseNode *body = (PN_TYPE(callee->pn_body) == js::TOK_UPVARS)
|
||||
? callee->pn_body->pn_tree
|
||||
: callee->pn_body;
|
||||
if (PN_TYPE(body) == js::TOK_LEXICALSCOPE)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
JSParseNode *generatorExpr() const {
|
||||
JS_ASSERT(isGeneratorExpr());
|
||||
JSParseNode *callee = this->pn_head;
|
||||
JSParseNode *body = PN_TYPE(callee->pn_body) == js::TOK_UPVARS
|
||||
? callee->pn_body->pn_tree
|
||||
: callee->pn_body;
|
||||
JS_ASSERT(PN_TYPE(body) == js::TOK_LEXICALSCOPE);
|
||||
return body->pn_expr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compute a pointer to the last element in a singly-linked list. NB: list
|
||||
* must be non-empty for correct PN_LAST usage -- this is asserted!
|
||||
|
@ -959,6 +988,11 @@ struct Parser : private js::AutoGCRooter
|
|||
|
||||
void setPrincipals(JSPrincipals *prin);
|
||||
|
||||
const char *getFilename()
|
||||
{
|
||||
return tokenStream.getFilename();
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a top-level JS script.
|
||||
*/
|
||||
|
|
|
@ -103,6 +103,8 @@ JS_PROTO(Float32Array, 34, js_InitTypedArrayClasses)
|
|||
JS_PROTO(Float64Array, 35, js_InitTypedArrayClasses)
|
||||
JS_PROTO(Uint8ClampedArray, 36, js_InitTypedArrayClasses)
|
||||
JS_PROTO(Proxy, 37, js_InitProxyClass)
|
||||
JS_PROTO(Reflect, 38, js_InitReflectClasses)
|
||||
JS_PROTO(ASTNode, 39, js_InitReflectClasses)
|
||||
|
||||
#undef XML_INIT
|
||||
#undef NAMESPACE_INIT
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,142 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* June 12, 2009.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Corporation.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Herman <dherman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* JS reflection package.
|
||||
*/
|
||||
#ifndef jsreflect_h___
|
||||
#define jsreflect_h___
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "jspubtd.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
typedef enum ASTType {
|
||||
AST_ERROR = -1,
|
||||
#define ASTDEF(ast, val, str) ast = val,
|
||||
#include "jsast.tbl"
|
||||
#undef ASTDEF
|
||||
AST_LIMIT
|
||||
} ASTType;
|
||||
|
||||
typedef enum {
|
||||
AOP_ERR = -1,
|
||||
|
||||
/* assign */
|
||||
AOP_ASSIGN = 0,
|
||||
/* operator-assign */
|
||||
AOP_PLUS, AOP_MINUS, AOP_STAR, AOP_DIV, AOP_MOD,
|
||||
/* shift-assign */
|
||||
AOP_LSH, AOP_RSH, AOP_URSH,
|
||||
/* binary */
|
||||
AOP_BITOR, AOP_BITXOR, AOP_BITAND,
|
||||
|
||||
AOP_LIMIT
|
||||
} AssignmentOperator;
|
||||
|
||||
typedef enum {
|
||||
BINOP_ERR = -1,
|
||||
|
||||
/* eq */
|
||||
BINOP_EQ = 0, BINOP_NE, BINOP_STRICTEQ, BINOP_STRICTNE,
|
||||
/* rel */
|
||||
BINOP_LT, BINOP_LE, BINOP_GT, BINOP_GE,
|
||||
/* shift */
|
||||
BINOP_LSH, BINOP_RSH, BINOP_URSH,
|
||||
/* arithmetic */
|
||||
BINOP_PLUS, BINOP_MINUS, BINOP_STAR, BINOP_DIV, BINOP_MOD,
|
||||
/* binary */
|
||||
BINOP_BITOR, BINOP_BITXOR, BINOP_BITAND,
|
||||
/* misc */
|
||||
BINOP_IN, BINOP_INSTANCEOF,
|
||||
/* xml */
|
||||
BINOP_DBLDOT,
|
||||
|
||||
BINOP_LIMIT
|
||||
} BinaryOperator;
|
||||
|
||||
typedef enum {
|
||||
UNOP_ERR = -1,
|
||||
|
||||
UNOP_DELETE = 0,
|
||||
UNOP_NEG,
|
||||
UNOP_POS,
|
||||
UNOP_NOT,
|
||||
UNOP_BITNOT,
|
||||
UNOP_TYPEOF,
|
||||
UNOP_VOID,
|
||||
|
||||
UNOP_LIMIT
|
||||
} UnaryOperator;
|
||||
|
||||
typedef enum {
|
||||
VARDECL_ERR = -1,
|
||||
VARDECL_VAR = 0,
|
||||
VARDECL_CONST,
|
||||
VARDECL_LET,
|
||||
VARDECL_LIMIT
|
||||
} VarDeclKind;
|
||||
|
||||
typedef enum {
|
||||
PROP_ERR = -1,
|
||||
PROP_INIT = 0,
|
||||
PROP_GETTER,
|
||||
PROP_SETTER,
|
||||
PROP_LIMIT
|
||||
} PropKind;
|
||||
|
||||
extern char const *aopNames[];
|
||||
extern char const *binopNames[];
|
||||
extern char const *unopNames[];
|
||||
extern char const *nodeTypeNames[];
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
extern JSClass js_ReflectClass;
|
||||
extern JSClass js_ASTNodeClass;
|
||||
|
||||
extern JSObject *
|
||||
js_InitReflectClasses(JSContext *cx, JSObject *obj);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsreflect_h___ */
|
|
@ -72,6 +72,7 @@
|
|||
#include "jsscope.h"
|
||||
#include "jsscript.h"
|
||||
#include "jstracer.h"
|
||||
#include "jsreflect.h"
|
||||
#include "jsxml.h"
|
||||
|
||||
#include "prmjtime.h"
|
||||
|
@ -2657,6 +2658,24 @@ split_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
ResolveClass(JSContext *cx, JSObject *obj, jsval id, JSBool *resolved)
|
||||
{
|
||||
if (!JS_ResolveStandardClass(cx, obj, id, resolved))
|
||||
return JS_FALSE;
|
||||
|
||||
if (! *resolved) {
|
||||
JSAtom *atom = OFFSET_TO_ATOM(cx->runtime, CLASS_ATOM_OFFSET(Reflect));
|
||||
if (ATOM_KEY(atom) == id) {
|
||||
if (!js_InitReflectClasses(cx, obj))
|
||||
return JS_FALSE;
|
||||
*resolved = JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
split_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp)
|
||||
{
|
||||
|
@ -2691,7 +2710,7 @@ split_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **ob
|
|||
if (!(flags & JSRESOLVE_ASSIGNING)) {
|
||||
JSBool resolved;
|
||||
|
||||
if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
|
||||
if (!ResolveClass(cx, obj, id, &resolved))
|
||||
return JS_FALSE;
|
||||
|
||||
if (resolved) {
|
||||
|
@ -2905,7 +2924,7 @@ sandbox_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
|||
|
||||
JS_ValueToBoolean(cx, v, &b);
|
||||
if (b && (flags & JSRESOLVE_ASSIGNING) == 0) {
|
||||
if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
|
||||
if (!ResolveClass(cx, obj, id, &resolved))
|
||||
return JS_FALSE;
|
||||
if (resolved) {
|
||||
*objp = obj;
|
||||
|
@ -4614,7 +4633,7 @@ global_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
|||
#ifdef LAZY_STANDARD_CLASSES
|
||||
JSBool resolved;
|
||||
|
||||
if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
|
||||
if (!ResolveClass(cx, obj, id, &resolved))
|
||||
return JS_FALSE;
|
||||
if (resolved) {
|
||||
*objp = obj;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
function Elements(arrayLike) {
|
||||
this.i = 0;
|
||||
this.stop = arrayLike.length;
|
||||
this.source = arrayLike;
|
||||
}
|
||||
Elements.prototype = {
|
||||
// FIXME: use Proxy.iterator when it's available
|
||||
__iterator__: function() this,
|
||||
next: function() {
|
||||
if (this.i >= this.stop)
|
||||
throw StopIteration;
|
||||
return this.source[this.i++];
|
||||
}
|
||||
};
|
||||
function elements(arrayLike) {
|
||||
return new Elements(arrayLike);
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var Match =
|
||||
|
||||
(function() {
|
||||
|
||||
function Pattern(template) {
|
||||
// act like a constructor even as a function
|
||||
if (!(this instanceof Pattern))
|
||||
return new Pattern(template);
|
||||
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
Pattern.prototype = {
|
||||
match: function(act) {
|
||||
return match(act, this.template);
|
||||
},
|
||||
|
||||
matches: function(act) {
|
||||
try {
|
||||
return this.match(act);
|
||||
}
|
||||
catch (e if e instanceof MatchError) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
assert: function(act, message) {
|
||||
try {
|
||||
return this.match(act);
|
||||
}
|
||||
catch (e if e instanceof MatchError) {
|
||||
throw new Error((message || "failed match") + ": " + e.message);
|
||||
}
|
||||
},
|
||||
|
||||
toString: function() "[object Pattern]"
|
||||
};
|
||||
|
||||
Pattern.ANY = new Pattern;
|
||||
Pattern.ANY.template = Pattern.ANY;
|
||||
|
||||
var quote = uneval;
|
||||
|
||||
function MatchError(msg) {
|
||||
this.message = msg;
|
||||
}
|
||||
|
||||
MatchError.prototype = {
|
||||
toString: function() {
|
||||
return "match error: " + this.message;
|
||||
}
|
||||
};
|
||||
|
||||
function isAtom(x) {
|
||||
return (typeof x === "number") ||
|
||||
(typeof x === "string") ||
|
||||
(typeof x === "boolean") ||
|
||||
(x === null) ||
|
||||
(typeof x === "object" && x instanceof RegExp);
|
||||
}
|
||||
|
||||
function isObject(x) {
|
||||
return (x !== null) && (typeof x === "object");
|
||||
}
|
||||
|
||||
function isArrayLike(x) {
|
||||
return isObject(x) && ("length" in x);
|
||||
}
|
||||
|
||||
function matchAtom(act, exp) {
|
||||
if ((typeof exp) === "number" && isNaN(exp)) {
|
||||
if ((typeof act) !== "number" || !isNaN(act))
|
||||
throw new MatchError("expected NaN, got: " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (exp === null) {
|
||||
if (act !== null)
|
||||
throw new MatchError("expected null, got: " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (exp instanceof RegExp) {
|
||||
if (!(act instanceof RegExp) || exp.source !== act.source)
|
||||
throw new MatchError("expected " + quote(exp) + ", got: " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (typeof exp) {
|
||||
case "string":
|
||||
if (act !== exp)
|
||||
throw new MatchError("expected " + exp.quote() + ", got " + quote(act));
|
||||
return true;
|
||||
case "boolean":
|
||||
case "number":
|
||||
if (exp !== act)
|
||||
throw new MatchError("expected " + exp + ", got " + quote(act));
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Error("bad pattern: " + exp.toSource());
|
||||
}
|
||||
|
||||
function matchObject(act, exp) {
|
||||
if (!isObject(act))
|
||||
throw new MatchError("expected object, got " + quote(act));
|
||||
|
||||
for (var key in exp) {
|
||||
if (!(key in act))
|
||||
throw new MatchError("expected property " + key.quote() + " not found in " + quote(act));
|
||||
match(act[key], exp[key]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function matchArray(act, exp) {
|
||||
if (!isObject(act) || !("length" in act))
|
||||
throw new MatchError("expected array-like object, got " + quote(act));
|
||||
|
||||
var length = exp.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (i in exp) {
|
||||
if (!(i in act))
|
||||
throw new MatchError("expected array property " + i + " not found in " + quote(act));
|
||||
match(act[i], exp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function match(act, exp) {
|
||||
if (exp === Pattern.ANY)
|
||||
return true;
|
||||
|
||||
if (exp instanceof Pattern)
|
||||
return exp.match(act);
|
||||
|
||||
if (isAtom(exp))
|
||||
return matchAtom(act, exp);
|
||||
|
||||
if (isArrayLike(exp))
|
||||
return matchArray(act, exp);
|
||||
|
||||
return matchObject(act, exp);
|
||||
}
|
||||
|
||||
return { Pattern: Pattern,
|
||||
MatchError: MatchError };
|
||||
|
||||
})();
|
|
@ -0,0 +1,437 @@
|
|||
FrJS = function() {
|
||||
// Used to disambiguate references to 'this' in inner classes.
|
||||
var mgr = this;
|
||||
|
||||
// INNER CLASSES --------------------------------
|
||||
|
||||
// Utility map class... because standard JS associative arrays don't work properly.
|
||||
this.Hash = function() {
|
||||
this.keys = new Array();
|
||||
this.values = new Array();
|
||||
|
||||
this.contains = function (key) {
|
||||
for(var i = 0; i < this.keys.length; i++) {
|
||||
if(this.keys[i] == key) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
this.get = function (key) {
|
||||
for(var i = 0; i < this.keys.length; i++) {
|
||||
if(this.keys[i] == key) {
|
||||
return this.values[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
this.put = function (key, value) {
|
||||
this.keys[this.keys.length] = key;
|
||||
this.values[this.values.length] = value;
|
||||
return value;
|
||||
};
|
||||
|
||||
this.toString = function () {
|
||||
var ans = "(";
|
||||
|
||||
if(this.keys.length > 0) {
|
||||
ans += this.keys[0] + ":" + this.values[0];
|
||||
|
||||
for(var i = 1; i < this.keys.length - 1; i++) {
|
||||
ans += "," + this.keys[i] + ":" + this.values[i];
|
||||
}
|
||||
}
|
||||
|
||||
return ans + ")";
|
||||
};
|
||||
};
|
||||
|
||||
// Class representing a signal.
|
||||
this.Signal = function(src, value, timestamp) {
|
||||
this.src = src;
|
||||
this.value = value;
|
||||
this.timestamp = timestamp;
|
||||
this.toString = function() {
|
||||
return "(Signal " + this.value + " " + this.timestamp + ")";
|
||||
};
|
||||
};
|
||||
|
||||
// Node (arrayof node) -> node
|
||||
//
|
||||
// Superclass of Event and Behaviour... contains code for receiving and
|
||||
// propagating signals.
|
||||
this.Node = function(prev) {
|
||||
this.next = new Array;
|
||||
|
||||
this.type = "Node";
|
||||
|
||||
this.addNext = function(n) {
|
||||
this.next[this.next.length] = n;
|
||||
};
|
||||
|
||||
this.propagate = function(signal) {
|
||||
for(var i = 0; i < this.next.length; i++) {
|
||||
this.next[i].onSignal(signal);
|
||||
}
|
||||
};
|
||||
|
||||
for(var i = 0; i < prev.length; i++) {
|
||||
prev[i].addNext(this);
|
||||
}
|
||||
};
|
||||
|
||||
// Event (arrayof node) -> event
|
||||
//
|
||||
// Class representing an event.
|
||||
//
|
||||
// Events receive incoming signals, process them and (if appropriate)
|
||||
// immediately send output signals. Values of output signals are based
|
||||
// directly on values of input signals.
|
||||
this.Event = function(prev) {
|
||||
this.superclass = mgr.Node;
|
||||
this.superclass(prev);
|
||||
|
||||
this.type = "Event";
|
||||
|
||||
this.onSignal = function(signal) {
|
||||
this.propagate(new mgr.Signal(this, signal.value, new Date));
|
||||
};
|
||||
|
||||
this.toString = function() {
|
||||
return "(" + this.type + ")";
|
||||
};
|
||||
};
|
||||
|
||||
// Event any (arrayof node) -> behaviour<any>
|
||||
//
|
||||
// Class representing a behaviour.
|
||||
//
|
||||
// Behaviours store persistent values that can be accessed by other
|
||||
// behaviours. They accept input signals and use them as cues to recalculate
|
||||
// their values. Stored values are not necessarily related to signal values:
|
||||
// they may depend on values from other nodes or other bits of JavaScript
|
||||
// data. Output signals are emitted only if the stored value changes.
|
||||
this.Behaviour = function(init, prev) {
|
||||
this.superclass = mgr.Node;
|
||||
this.superclass(prev);
|
||||
|
||||
this.type = "Behaviour";
|
||||
|
||||
this.value = init;
|
||||
|
||||
this.onSignal = function(signal) {
|
||||
this.setValue(signal.value);
|
||||
};
|
||||
|
||||
this.setValue = function(newValue) {
|
||||
if(this.value != newValue) {
|
||||
this.value = newValue;
|
||||
this.propagate(new mgr.Signal(this, newValue, new Date));
|
||||
}
|
||||
};
|
||||
|
||||
this.toString = function() {
|
||||
return "(" + this.type + " " + this.value + ")";
|
||||
};
|
||||
};
|
||||
|
||||
// FIELDS ---------------------------------------
|
||||
|
||||
this.domEventInputs = new mgr.Hash();
|
||||
this.domEventOutputs = new mgr.Hash();
|
||||
|
||||
// METHODS --------------------------------------
|
||||
|
||||
// getDomEventData element string (union mgr.DomEventInputs mgr.DomEventOutputs) -> (arrayof node)
|
||||
//
|
||||
// This internal function returns an array of nodes registered as
|
||||
// DomEventInputs or DomEventOutputs, depending on the value of the
|
||||
// third parameter.
|
||||
this.getDomEventData = function(id, type, data) {
|
||||
var temp = data.get(id);
|
||||
|
||||
if(temp == null) {
|
||||
temp = data.put(id, new mgr.Hash());
|
||||
}
|
||||
|
||||
var ans = temp.get(type);
|
||||
|
||||
if(ans == null) {
|
||||
ans = temp.put(type, new Array());
|
||||
}
|
||||
|
||||
return ans;
|
||||
};
|
||||
|
||||
// getDomEventInputs element string -> (arrayof node)
|
||||
//
|
||||
// This internal function returns an array in which nodes registered as
|
||||
// DomEventInputs for the specified event can be stored and retrieved.
|
||||
this.getDomEventInputs = function(id, type) {
|
||||
return this.getDomEventData(id, type, mgr.domEventInputs);
|
||||
};
|
||||
|
||||
// getDomEventOutputs element string -> (arrayof node)
|
||||
//
|
||||
// This internal function returns an array in which nodes registered as
|
||||
// DomEventOutputs for the specified event can be stored and retrieved.
|
||||
this.getDomEventOutputs = function(id, type) {
|
||||
return this.getDomEventData(id, type, mgr.domEventOutputs);
|
||||
};
|
||||
|
||||
// doDomEvent element domEvent -> void
|
||||
//
|
||||
// This internal function is bound to DOM event handlers such as
|
||||
// 'onsubmit' when they are attached to FrJS via createDomEventInput().
|
||||
this.doDomEvent = function(elem, domEvent) {
|
||||
var id = elem.id;
|
||||
var type = "on" + domEvent.type;
|
||||
|
||||
var inputs = mgr.getDomEventInputs(id, type);
|
||||
var outputs = mgr.getDomEventOutputs(id, type);
|
||||
|
||||
// alert("Manager: Handling {" + id + "} {" + type + "} {" + inputs + "} {" + outputs + "}");
|
||||
|
||||
for(var i = 0; i < inputs.length; i++) {
|
||||
inputs[i].doDomEvent(domEvent);
|
||||
}
|
||||
|
||||
if(outputs.length > 0) {
|
||||
var node1 = outputs["cancelBubble"];
|
||||
if(node1) domEvent.cancelBubble = node1.value;
|
||||
|
||||
var node2 = outputs["returnValue"];
|
||||
if(node2) {
|
||||
domEvent.returnValue = node2.value;
|
||||
return node2.value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// createDomEventInput
|
||||
// element
|
||||
// (union "onclick" ...)
|
||||
// [(domEvent -> <a>)]
|
||||
// -> node<a>
|
||||
//
|
||||
// Registers FrJS to handle a particular DOM event. Returns an Event that
|
||||
// receives an input signal whenever the specified event occurs.
|
||||
//
|
||||
// The third argument is a function mapping DOM events to signal values.
|
||||
// If no argument is supplied, all incoming signals have the boolean value
|
||||
// 'true'.
|
||||
this.createDomEventInput = function(elem, type) {
|
||||
var id = elem.id;
|
||||
|
||||
var valueFn = arguments.length == 3
|
||||
? function(domEvent) { eval("return domEvent." + arguments[2] + ";"); }
|
||||
: function(domEvent) { return true; };
|
||||
|
||||
var node = new mgr.Event(new Array);
|
||||
|
||||
node.type = "DomEventInput " + id + " " + type;
|
||||
|
||||
node.doDomEvent = function(domEvent) {
|
||||
// alert(this + ": Handling " + domEvent);
|
||||
this.propagate(new mgr.Signal(this, valueFn(domEvent), new Date));
|
||||
};
|
||||
|
||||
var inputs = mgr.getDomEventInputs(id, type);
|
||||
inputs[inputs.length] = node;
|
||||
|
||||
// alert("Registering {" + id + "} {" + type + "} {" + inputs + "}");
|
||||
|
||||
eval("elem." + type + " = function(domEvent) { return mgr.doDomEvent(elem, domEvent); };");
|
||||
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
// createDomEventOutput
|
||||
// element
|
||||
// (union "onclick" ...)
|
||||
// (union "resultValue" "cancelBubble")
|
||||
// node
|
||||
// -> void
|
||||
//
|
||||
// Specifies that a particular node should be used to pass a value back to
|
||||
// a DOM event object. When the event occurs and its input signal has been
|
||||
// processed by the network, the specified field ("returnValue" or
|
||||
// "cancelBubble") is set to the value of the specified node, allowing the
|
||||
// event to be cancelled in the relevant way.
|
||||
this.registerDomEventOutput = function(elem, type, field, node) {
|
||||
var id = elem.id;
|
||||
|
||||
var outputs = mgr.getDomEventOutputs(id, type);
|
||||
outputs[field] = node;
|
||||
|
||||
// alert("Registering {" + id + "} {" + type + "} {" + field + "} {" + node + "} {{" + outputs.field + "}} {" + mgr.domEventOutputs + "}");
|
||||
|
||||
eval("elem." + type + " = function(domEvent) { return mgr.doDomEvent(elem, domEvent); };");
|
||||
};
|
||||
|
||||
// createDomProperty element string -> node
|
||||
//
|
||||
// Creates a node whose value is echoed a property of an element of the DOM.
|
||||
// The initial value of the node is set from the DOM and any changes to the
|
||||
// node's value are copied to the DOM.
|
||||
this.createDomOutput = function(elem, prop, prev) {
|
||||
var id = elem.id;
|
||||
|
||||
var node = new mgr.Behaviour(eval("elem." + prop), prev);
|
||||
|
||||
node.type = "DomOutput " + id + " " + prop;
|
||||
|
||||
node.elem = elem;
|
||||
|
||||
node.setValue = function(newValue) {
|
||||
if(this.value != newValue) {
|
||||
this.value = newValue;
|
||||
eval("this.elem." + prop + " = newValue;");
|
||||
this.propagate(new mgr.Signal(this, newValue, new Date));
|
||||
}
|
||||
};
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
// filter (a -> boolean) (arrayof node<a>) -> node<b>
|
||||
//
|
||||
// Creates an event that filters input signals based on a predicate function.
|
||||
// The function (first parameter) must take a Signal as its single parameter.
|
||||
this.createFilter = function(filterFn, prev) {
|
||||
var node = new mgr.Event(prev);
|
||||
|
||||
node.type = "Filter " + filterFn;
|
||||
|
||||
node.onSignal = function(signal) {
|
||||
if(filterFn(signal.value)) {
|
||||
this.value = signal.value;
|
||||
this.propagate(new mgr.Signal(this, signal.value, new Date));
|
||||
}
|
||||
};
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// createMap (a -> b) (arrayof event<a>) -> event<b>
|
||||
//
|
||||
// Creates an event that maps input signal values to output signal values
|
||||
// using a Javascript mapping function.
|
||||
this.createMap = function(mapFn, prev) {
|
||||
var node = new mgr.Node(prev);
|
||||
|
||||
node.type = "Map " + mapFn;
|
||||
|
||||
node.onSignal = function(signal) {
|
||||
var newValue = mapFn(signal.value);
|
||||
|
||||
if(this.value != newValue) {
|
||||
this.value = newValue;
|
||||
this.propagate(new mgr.Signal(this, newValue, new Date));
|
||||
}
|
||||
};
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// createOnce (arrayof event<a>) -> event<a>
|
||||
this.createOnce = function(prev) {
|
||||
var node = new mgr.Event(prev);
|
||||
|
||||
node.type = "Once";
|
||||
|
||||
node.fired = false;
|
||||
|
||||
node.onSignal = function(signal) {
|
||||
if(!this.fired) {
|
||||
this.fired = true;
|
||||
this.propagate(new mgr.Signal(this, signal.value, new Date));
|
||||
}
|
||||
};
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
// createAlert (arrayof event<a>) -> event<a>
|
||||
//
|
||||
// Creates an event
|
||||
this.createAlert = function(prev) {
|
||||
var node = new mgr.Event(prev);
|
||||
|
||||
node.onSignal = function(signal) {
|
||||
alert(signal);
|
||||
this.propagate(new mgr.Signal(this, signal.value, new Date));
|
||||
};
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
this.createDelay = function(delay, prev) {
|
||||
var node = new mgr.Event(prev);
|
||||
|
||||
node.type = "Delay " + delay;
|
||||
|
||||
node.onSignal = function(signal) {
|
||||
window.setTimeout(delay, "this.propagate(new mgr.Signal(this, signal.value, new Date))");
|
||||
};
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
// createMerge (arrayof event<a>) -> event<a>
|
||||
this.createMerge = function(prev) {
|
||||
var node = new mgr.Event(prev);
|
||||
node.type = "Merge";
|
||||
return node;
|
||||
};
|
||||
|
||||
// createHold (arrayof event<a>) -> behaviour<a>
|
||||
this.createHold = function(init, prev) {
|
||||
var node = new mgr.Behaviour(prev);
|
||||
node.type = "Hold";
|
||||
return node;
|
||||
};
|
||||
|
||||
// createChanges (arrayof behaviour<a>) -> event<a>
|
||||
this.createChanges = function(prev) {
|
||||
var node = new mgr.Event(prev);
|
||||
node.type = "Changes";
|
||||
return node;
|
||||
};
|
||||
|
||||
this.createSwitch = function(init, prev) {
|
||||
var node = new mgr.Behaviour(init, prev);
|
||||
|
||||
node.type = "Switch";
|
||||
|
||||
node.onSignal = function(signal) {
|
||||
this.setValue(!this.value);
|
||||
};
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
// createFunction (void -> a) (arrayof node<a>) -> behaviour<a>
|
||||
//
|
||||
// Creates a behaviour whose value is determined by a JavaScript function.
|
||||
// Input signals trigger refreshes, but their values have no effect on the
|
||||
// value of the behaviour. Output signals are only created when the value of
|
||||
// the behaviour changes.
|
||||
this.createFunction = function(valueFn, prev) {
|
||||
var node = new mgr.Behaviour(valueFn(), prev);
|
||||
|
||||
node.type = "Function " + valueFn;
|
||||
|
||||
node.onSignal = function(signal) {
|
||||
this.setValue(valueFn());
|
||||
};
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
};
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,677 @@
|
|||
load(libdir + 'match.js');
|
||||
load(libdir + 'array.js');
|
||||
|
||||
var { Pattern, MatchError } = Match;
|
||||
|
||||
var _ = Pattern.ANY;
|
||||
|
||||
function program(elts) Pattern({ type: "Program", body: elts })
|
||||
function exprStmt(expr) Pattern({ type: "ExpressionStatement", expression: expr })
|
||||
function throwStmt(expr) Pattern({ type: "ThrowStatement", argument: expr })
|
||||
function returnStmt(expr) Pattern({ type: "ReturnStatement", argument: expr })
|
||||
function yieldExpr(expr) Pattern({ type: "YieldExpression", argument: expr })
|
||||
function lit(val) Pattern({ type: "Literal", value: val })
|
||||
function funDecl(id, params, body) Pattern({ type: "FunctionDeclaration",
|
||||
id: id,
|
||||
params: params,
|
||||
body: body,
|
||||
generator: false })
|
||||
function genFunDecl(id, params, body) Pattern({ type: "FunctionDeclaration",
|
||||
id: id,
|
||||
params: params,
|
||||
body: body,
|
||||
generator: true })
|
||||
function varDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" })
|
||||
function letDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "let" })
|
||||
function constDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "const" })
|
||||
function blockStmt(body) Pattern({ type: "BlockStatement", body: body })
|
||||
function ident(name) Pattern({ type: "Identifier", name: name })
|
||||
function dotExpr(obj, id) Pattern({ type: "MemberExpression", computed: false, object: obj, property: id })
|
||||
function memExpr(obj, id) Pattern({ type: "MemberExpression", computed: true, object: obj, property: id })
|
||||
function forStmt(init, test, update, body) Pattern({ type: "ForStatement", init: init, test: test, update: update, body: body })
|
||||
function forInStmt(lhs, rhs, body) Pattern({ type: "ForInStatement", left: lhs, right: rhs, body: body, each: false })
|
||||
function forEachInStmt(lhs, rhs, body) Pattern({ type: "ForInStatement", left: lhs, right: rhs, body: body, each: true })
|
||||
function breakStmt(lab) Pattern({ type: "BreakStatement", label: lab })
|
||||
function continueStmt(lab) Pattern({ type: "ContinueStatement", label: lab })
|
||||
function blockStmt(stmts) Pattern({ type: "BlockStatement", body: stmts })
|
||||
var emptyStmt = Pattern({ type: "EmptyStatement" })
|
||||
function ifStmt(test, cons, alt) Pattern({ type: "IfStatement", test: test, alternate: alt, consequent: cons })
|
||||
function labStmt(lab, stmt) Pattern({ type: "LabeledStatement", label: lab, body: stmt })
|
||||
function withStmt(obj, stmt) Pattern({ type: "WithStatement", object: obj, body: stmt })
|
||||
function whileStmt(test, stmt) Pattern({ type: "WhileStatement", test: test, body: stmt })
|
||||
function doStmt(stmt, test) Pattern({ type: "DoWhileStatement", test: test, body: stmt })
|
||||
function switchStmt(disc, cases) Pattern({ type: "SwitchStatement", discriminant: disc, cases: cases })
|
||||
function caseClause(test, stmts) Pattern({ type: "SwitchCase", test: test, consequent: stmts })
|
||||
function defaultClause(stmts) Pattern({ type: "SwitchCase", test: null, consequent: stmts })
|
||||
function catchClause(id, guard, body) Pattern({ type: "CatchClause", param: id, guard: guard, body: body })
|
||||
function tryStmt(body, catches, fin) Pattern({ type: "TryStatement", block: body, handler: catches, finalizer: fin })
|
||||
function funExpr(id, args, body, gen) Pattern({ type: "FunctionExpression",
|
||||
id: id,
|
||||
params: args,
|
||||
body: body,
|
||||
generator: false })
|
||||
function genFunExpr(id, args, body) Pattern({ type: "FunctionExpression",
|
||||
id: id,
|
||||
params: args,
|
||||
body: body,
|
||||
generator: true })
|
||||
|
||||
function unop(token) Pattern({ type: "UnaryOperator", token: token })
|
||||
function binop(token) Pattern({ type: "BinaryOperator", token: token })
|
||||
function aop(token) Pattern({ type: "AssignmentOperator", token: token })
|
||||
function updop(token) Pattern({ type: "UpdateOperator", token: token })
|
||||
function logop(token) Pattern({ type: "LogicalOperator", token: token })
|
||||
|
||||
function unExpr(op, arg) Pattern({ type: "UnaryExpression", operator: unop(op), argument: arg })
|
||||
function binExpr(op, left, right) Pattern({ type: "BinaryExpression", operator: binop(op), left: left, right: right })
|
||||
function aExpr(op, left, right) Pattern({ type: "AssignmentExpression", operator: aop(op), left: left, right: right })
|
||||
function updExpr(op, arg, prefix) Pattern({ type: "UpdateExpression", operator: updop(op), argument: arg, prefix: prefix })
|
||||
function logExpr(op, left, right) Pattern({ type: "LogicalExpression", operator: logop(op), left: left, right: right })
|
||||
|
||||
function condExpr(test, cons, alt) Pattern({ type: "ConditionalExpression", test: test, consequent: cons, alternate: alt })
|
||||
function seqExpr(exprs) Pattern({ type: "SequenceExpression", expressions: exprs })
|
||||
function newExpr(callee, args) Pattern({ type: "NewExpression", callee: callee, arguments: args })
|
||||
function callExpr(callee, args) Pattern({ type: "CallExpression", callee: callee, arguments: args })
|
||||
function arrExpr(elts) Pattern({ type: "ArrayExpression", elements: elts })
|
||||
function objExpr(elts) Pattern({ type: "ObjectExpression", properties: elts })
|
||||
function compExpr(body, blocks, filter) Pattern({ type: "ComprehensionExpression", body: body, blocks: blocks, filter: filter })
|
||||
function genExpr(body, blocks, filter) Pattern({ type: "GeneratorExpression", body: body, blocks: blocks, filter: filter })
|
||||
function graphExpr(idx, body) Pattern({ type: "GraphExpression", index: idx, expression: body })
|
||||
function idxExpr(idx) Pattern({ type: "GraphIndexExpression", index: idx })
|
||||
|
||||
function compBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: false })
|
||||
function compEachBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: true })
|
||||
|
||||
function arrPatt(elts) Pattern({ type: "ArrayPattern", elements: elts })
|
||||
function objPatt(elts) Pattern({ type: "ObjectPattern", properties: elts })
|
||||
|
||||
function localSrc(src) "(function(){ " + src + " })"
|
||||
function localPatt(patt) program([exprStmt(funExpr(null, [], blockStmt([patt])))])
|
||||
function blockSrc(src) "(function(){ { " + src + " } })"
|
||||
function blockPatt(patt) program([exprStmt(funExpr(null, [], blockStmt([blockStmt([patt])])))])
|
||||
|
||||
var xmlAnyName = Pattern({ type: "XMLAnyName" });
|
||||
|
||||
function xmlQualId(left, right, computed) Pattern({ type: "XMLQualifiedIdentifier", left: left, right: right, computed: computed })
|
||||
function xmlAttrSel(id) Pattern({ type: "XMLAttributeSelector", attribute: id })
|
||||
function xmlFilter(left, right) Pattern({ type: "XMLFilterExpression", left: left, right: right })
|
||||
function xmlPointTag(contents) Pattern({ type: "XMLPointTag", contents: contents })
|
||||
function xmlStartTag(contents) Pattern({ type: "XMLStartTag", contents: contents })
|
||||
function xmlEndTag(contents) Pattern({ type: "XMLEndTag", contents: contents })
|
||||
function xmlEscape(expr) Pattern({ type: "XMLEscape", expression: expr })
|
||||
function xmlElt(contents) Pattern({ type: "XMLElement", contents: contents })
|
||||
function xmlAttr(value) Pattern({ type: "XMLAttribute", value: value })
|
||||
function xmlText(text) Pattern({ type: "XMLText", text: text })
|
||||
function xmlPI(target, contents) Pattern({ type: "XMLProcessingInstruction", target: target, contents: contents })
|
||||
|
||||
function assertBlockStmt(src, patt) {
|
||||
blockPatt(patt).assert(Reflect.parse(blockSrc(src)));
|
||||
}
|
||||
|
||||
function assertBlockExpr(src, patt) {
|
||||
assertBlockStmt(src, exprStmt(patt));
|
||||
}
|
||||
|
||||
function assertBlockDecl(src, patt) {
|
||||
blockPatt(patt).assert(Reflect.parse(blockSrc(src)));
|
||||
}
|
||||
|
||||
function assertLocalStmt(src, patt) {
|
||||
localPatt(patt).assert(Reflect.parse(localSrc(src)));
|
||||
}
|
||||
|
||||
function assertLocalExpr(src, patt) {
|
||||
assertLocalStmt(src, exprStmt(patt));
|
||||
}
|
||||
|
||||
function assertLocalDecl(src, patt) {
|
||||
localPatt(patt).assert(Reflect.parse(localSrc(src)));
|
||||
}
|
||||
|
||||
function assertGlobalStmt(src, patt) {
|
||||
program([patt]).assert(Reflect.parse(src));
|
||||
}
|
||||
|
||||
function assertGlobalExpr(src, patt) {
|
||||
assertStmt(src, exprStmt(patt));
|
||||
}
|
||||
|
||||
function assertGlobalDecl(src, patt) {
|
||||
program([patt]).assert(Reflect.parse(src));
|
||||
}
|
||||
|
||||
function assertStmt(src, patt) {
|
||||
assertLocalStmt(src, patt);
|
||||
assertGlobalStmt(src, patt);
|
||||
assertBlockStmt(src, patt);
|
||||
}
|
||||
|
||||
function assertExpr(src, patt) {
|
||||
assertLocalExpr(src, patt);
|
||||
assertGlobalExpr(src, patt);
|
||||
assertBlockExpr(src, patt);
|
||||
}
|
||||
|
||||
function assertDecl(src, patt) {
|
||||
assertLocalDecl(src, patt);
|
||||
assertGlobalDecl(src, patt);
|
||||
assertBlockDecl(src, patt);
|
||||
}
|
||||
|
||||
|
||||
// general tests
|
||||
|
||||
program(_).assert(Reflect.parse(snarf('data/flapjax.txt')));
|
||||
program(_).assert(Reflect.parse(snarf('data/jquery-1.4.2.txt')));
|
||||
//program(_).assert(Reflect.parse(snarf('data/prototype.js')));
|
||||
//program(_).assert(Reflect.parse(snarf('data/dojo.js.uncompressed.js')));
|
||||
//program(_).assert(Reflect.parse(snarf('data/mootools-1.2.4-core-nc.js')));
|
||||
|
||||
|
||||
// declarations
|
||||
|
||||
assertDecl("var x = 1, y = 2, z = 3",
|
||||
varDecl([{ id: ident("x"), init: lit(1) },
|
||||
{ id: ident("y"), init: lit(2) },
|
||||
{ id: ident("z"), init: lit(3) }]));
|
||||
assertDecl("var x, y, z",
|
||||
varDecl([{ id: ident("x"), init: null },
|
||||
{ id: ident("y"), init: null },
|
||||
{ id: ident("z"), init: null }]));
|
||||
assertDecl("function foo() { }",
|
||||
funDecl(ident("foo"), [], blockStmt([])));
|
||||
assertDecl("function foo() { return 42 }",
|
||||
funDecl(ident("foo"), [], blockStmt([returnStmt(lit(42))])));
|
||||
|
||||
|
||||
// expressions
|
||||
|
||||
assertExpr("true", lit(true));
|
||||
assertExpr("false", lit(false));
|
||||
assertExpr("42", lit(42));
|
||||
assertExpr("(/asdf/)", lit(/asdf/));
|
||||
assertExpr("foo", ident("foo"));
|
||||
assertExpr("foo.bar", dotExpr(ident("foo"), ident("bar")));
|
||||
assertExpr("foo[bar]", memExpr(ident("foo"), ident("bar")));
|
||||
assertExpr("(function(){})", funExpr(null, [], blockStmt([])));
|
||||
assertExpr("(function f() {})", funExpr(ident("f"), [], blockStmt([])));
|
||||
assertExpr("(function f(x,y,z) {})", funExpr(ident("f"), [ident("x"),ident("y"),ident("z")], blockStmt([])));
|
||||
assertExpr("(++x)", updExpr("++", ident("x"), true));
|
||||
assertExpr("(x++)", updExpr("++", ident("x"), false));
|
||||
assertExpr("(+x)", unExpr("+", ident("x")));
|
||||
assertExpr("(-x)", unExpr("-", ident("x")));
|
||||
assertExpr("(!x)", unExpr("!", ident("x")));
|
||||
assertExpr("(~x)", unExpr("~", ident("x")));
|
||||
assertExpr("(delete x)", unExpr("delete", ident("x")));
|
||||
assertExpr("(typeof x)", unExpr("typeof", ident("x")));
|
||||
assertExpr("(void x)", unExpr("void", ident("x")));
|
||||
assertExpr("(x == y)", binExpr("==", ident("x"), ident("y")));
|
||||
assertExpr("(x != y)", binExpr("!=", ident("x"), ident("y")));
|
||||
assertExpr("(x === y)", binExpr("===", ident("x"), ident("y")));
|
||||
assertExpr("(x !== y)", binExpr("!==", ident("x"), ident("y")));
|
||||
assertExpr("(x < y)", binExpr("<", ident("x"), ident("y")));
|
||||
assertExpr("(x <= y)", binExpr("<=", ident("x"), ident("y")));
|
||||
assertExpr("(x > y)", binExpr(">", ident("x"), ident("y")));
|
||||
assertExpr("(x >= y)", binExpr(">=", ident("x"), ident("y")));
|
||||
assertExpr("(x << y)", binExpr("<<", ident("x"), ident("y")));
|
||||
assertExpr("(x >> y)", binExpr(">>", ident("x"), ident("y")));
|
||||
assertExpr("(x >>> y)", binExpr(">>>", ident("x"), ident("y")));
|
||||
assertExpr("(x + y)", binExpr("+", ident("x"), ident("y")));
|
||||
assertExpr("(w + x + y + z)", binExpr("+", ident("w"), binExpr("+", ident("x", binExpr("+", ident("y"), ident("z"))))))
|
||||
assertExpr("(x - y)", binExpr("-", ident("x"), ident("y")));
|
||||
assertExpr("(x * y)", binExpr("*", ident("x"), ident("y")));
|
||||
assertExpr("(x / y)", binExpr("/", ident("x"), ident("y")));
|
||||
assertExpr("(x % y)", binExpr("%", ident("x"), ident("y")));
|
||||
assertExpr("(x | y)", binExpr("|", ident("x"), ident("y")));
|
||||
assertExpr("(x ^ y)", binExpr("^", ident("x"), ident("y")));
|
||||
assertExpr("(x & y)", binExpr("&", ident("x"), ident("y")));
|
||||
assertExpr("(x in y)", binExpr("in", ident("x"), ident("y")));
|
||||
assertExpr("(x instanceof y)", binExpr("instanceof", ident("x"), ident("y")));
|
||||
assertExpr("(x = y)", aExpr("=", ident("x"), ident("y")));
|
||||
assertExpr("(x += y)", aExpr("+=", ident("x"), ident("y")));
|
||||
assertExpr("(x -= y)", aExpr("-=", ident("x"), ident("y")));
|
||||
assertExpr("(x *= y)", aExpr("*=", ident("x"), ident("y")));
|
||||
assertExpr("(x /= y)", aExpr("/=", ident("x"), ident("y")));
|
||||
assertExpr("(x %= y)", aExpr("%=", ident("x"), ident("y")));
|
||||
assertExpr("(x <<= y)", aExpr("<<=", ident("x"), ident("y")));
|
||||
assertExpr("(x >>= y)", aExpr(">>=", ident("x"), ident("y")));
|
||||
assertExpr("(x >>>= y)", aExpr(">>>=", ident("x"), ident("y")));
|
||||
assertExpr("(x |= y)", aExpr("|=", ident("x"), ident("y")));
|
||||
assertExpr("(x ^= y)", aExpr("^=", ident("x"), ident("y")));
|
||||
assertExpr("(x &= y)", aExpr("&=", ident("x"), ident("y")));
|
||||
assertExpr("(x || y)", logExpr("||", ident("x"), ident("y")));
|
||||
assertExpr("(x && y)", logExpr("&&", ident("x"), ident("y")));
|
||||
assertExpr("(w || x || y || z)", logExpr("||", ident("w"), logExpr("||", ident("x", logExpr("||", ident("y"), ident("z"))))))
|
||||
assertExpr("(x ? y : z)", condExpr(ident("x"), ident("y"), ident("z")));
|
||||
assertExpr("(x,y)", seqExpr([ident("x"),ident("y")]))
|
||||
assertExpr("(x,y,z)", seqExpr([ident("x"),ident("y"),ident("z")]))
|
||||
assertExpr("(a,b,c,d,e,f,g)", seqExpr([ident("a"),ident("b"),ident("c"),ident("d"),ident("e"),ident("f"),ident("g")]));
|
||||
assertExpr("(new Object)", newExpr(ident("Object"), []));
|
||||
assertExpr("(new Object())", newExpr(ident("Object"), []));
|
||||
assertExpr("(new Object(42))", newExpr(ident("Object"), [lit(42)]));
|
||||
assertExpr("(new Object(1,2,3))", newExpr(ident("Object"), [lit(1),lit(2),lit(3)]));
|
||||
assertExpr("(String())", callExpr(ident("String"), []));
|
||||
assertExpr("(String(42))", callExpr(ident("String"), [lit(42)]));
|
||||
assertExpr("(String(1,2,3))", callExpr(ident("String"), [lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[]", arrExpr([]));
|
||||
assertExpr("[1]", arrExpr([lit(1)]));
|
||||
assertExpr("[1,2]", arrExpr([lit(1),lit(2)]));
|
||||
assertExpr("[1,2,3]", arrExpr([lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[1,,2,3]", arrExpr([lit(1),null,lit(2),lit(3)]));
|
||||
assertExpr("[1,,,2,3]", arrExpr([lit(1),null,null,lit(2),lit(3)]));
|
||||
assertExpr("[1,,,2,,3]", arrExpr([lit(1),null,null,lit(2),null,lit(3)]));
|
||||
assertExpr("[1,,,2,,,3]", arrExpr([lit(1),null,null,lit(2),null,null,lit(3)]));
|
||||
assertExpr("[,1,2,3]", arrExpr([null,lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[,,1,2,3]", arrExpr([null,null,lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[,,,1,2,3]", arrExpr([null,null,null,lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[,,,1,2,3,]", arrExpr([null,null,null,lit(1),lit(2),lit(3)]));
|
||||
assertExpr("[,,,1,2,3,,]", arrExpr([null,null,null,lit(1),lit(2),lit(3),null]));
|
||||
assertExpr("[,,,1,2,3,,,]", arrExpr([null,null,null,lit(1),lit(2),lit(3),null,null]));
|
||||
assertExpr("[,,,,,]", arrExpr([null,null,null,null,null]));
|
||||
assertExpr("({})", objExpr([]));
|
||||
assertExpr("({x:1})", objExpr([{ key: ident("x"), value: lit(1) }]));
|
||||
assertExpr("({x:1, y:2})", objExpr([{ key: ident("x"), value: lit(1) },
|
||||
{ key: ident("y"), value: lit(2) } ]));
|
||||
assertExpr("({x:1, y:2, z:3})", objExpr([{ key: ident("x"), value: lit(1) },
|
||||
{ key: ident("y"), value: lit(2) },
|
||||
{ key: ident("z"), value: lit(3) } ]));
|
||||
assertExpr("({x:1, 'y':2, z:3})", objExpr([{ key: ident("x"), value: lit(1) },
|
||||
{ key: lit("y"), value: lit(2) },
|
||||
{ key: ident("z"), value: lit(3) } ]));
|
||||
assertExpr("({'x':1, 'y':2, z:3})", objExpr([{ key: lit("x"), value: lit(1) },
|
||||
{ key: lit("y"), value: lit(2) },
|
||||
{ key: ident("z"), value: lit(3) } ]));
|
||||
assertExpr("({'x':1, 'y':2, 3:3})", objExpr([{ key: lit("x"), value: lit(1) },
|
||||
{ key: lit("y"), value: lit(2) },
|
||||
{ key: lit(3), value: lit(3) } ]));
|
||||
|
||||
// statements
|
||||
|
||||
assertStmt("throw 42", throwStmt(lit(42)));
|
||||
assertStmt("for (;;) break", forStmt(null, null, null, breakStmt(null)));
|
||||
assertStmt("for (x; y; z) break", forStmt(ident("x"), ident("y"), ident("z"), breakStmt(null)));
|
||||
assertStmt("for (var x; y; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), ident("z")));
|
||||
assertStmt("for (var x = 42; y; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), ident("z")));
|
||||
assertStmt("for (x; ; z) break", forStmt(ident("x"), null, ident("z"), breakStmt(null)));
|
||||
assertStmt("for (var x; ; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), null, ident("z")));
|
||||
assertStmt("for (var x = 42; ; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), null, ident("z")));
|
||||
assertStmt("for (x; y; ) break", forStmt(ident("x"), ident("y"), null, breakStmt(null)));
|
||||
assertStmt("for (var x; y; ) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), null, breakStmt(null)));
|
||||
assertStmt("for (var x = 42; y; ) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), null, breakStmt(null)));
|
||||
assertStmt("for (var x in y) break", forInStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), breakStmt(null)));
|
||||
assertStmt("for (x in y) break", forInStmt(ident("x"), ident("y"), breakStmt(null)));
|
||||
assertStmt("{ }", blockStmt([]));
|
||||
assertStmt("{ throw 1; throw 2; throw 3; }", blockStmt([ throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]));
|
||||
assertStmt(";", emptyStmt);
|
||||
assertStmt("if (foo) throw 42;", ifStmt(ident("foo"), throwStmt(lit(42)), null));
|
||||
assertStmt("if (foo) throw 42; else true;", ifStmt(ident("foo"), throwStmt(lit(42)), exprStmt(lit(true))));
|
||||
assertStmt("if (foo) { throw 1; throw 2; throw 3; }",
|
||||
ifStmt(ident("foo"),
|
||||
blockStmt([throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]),
|
||||
null));
|
||||
assertStmt("if (foo) { throw 1; throw 2; throw 3; } else true;",
|
||||
ifStmt(ident("foo"),
|
||||
blockStmt([throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]),
|
||||
exprStmt(lit(true))));
|
||||
assertStmt("foo: for(;;) break foo;", labStmt(ident("foo"), forStmt(null, null, null, breakStmt(ident("foo")))));
|
||||
assertStmt("foo: for(;;) continue foo;", labStmt(ident("foo"), forStmt(null, null, null, continueStmt(ident("foo")))));
|
||||
assertStmt("with (obj) { }", withStmt(ident("obj"), blockStmt([])));
|
||||
assertStmt("with (obj) { obj; }", withStmt(ident("obj"), blockStmt([exprStmt(ident("obj"))])));
|
||||
assertStmt("while (foo) { }", whileStmt(ident("foo"), blockStmt([])));
|
||||
assertStmt("while (foo) { foo; }", whileStmt(ident("foo"), blockStmt([exprStmt(ident("foo"))])));
|
||||
assertStmt("do { } while (foo);", doStmt(blockStmt([]), ident("foo")));
|
||||
assertStmt("do { foo; } while (foo)", doStmt(blockStmt([exprStmt(ident("foo"))]), ident("foo")));
|
||||
assertStmt("switch (foo) { case 1: 1; break; case 2: 2; break; default: 3; }",
|
||||
switchStmt(ident("foo"),
|
||||
[ caseClause(lit(1), [ exprStmt(lit(1)), breakStmt(null) ]),
|
||||
caseClause(lit(2), [ exprStmt(lit(2)), breakStmt(null) ]),
|
||||
defaultClause([ exprStmt(lit(3)) ]) ]));
|
||||
assertStmt("switch (foo) { case 1: 1; break; case 2: 2; break; default: 3; case 42: 42; }",
|
||||
switchStmt(ident("foo"),
|
||||
[ caseClause(lit(1), [ exprStmt(lit(1)), breakStmt(null) ]),
|
||||
caseClause(lit(2), [ exprStmt(lit(2)), breakStmt(null) ]),
|
||||
defaultClause([ exprStmt(lit(3)) ]),
|
||||
caseClause(lit(42), [ exprStmt(lit(42)) ]) ]));
|
||||
assertStmt("try { } catch (e) { }",
|
||||
tryStmt(blockStmt([]),
|
||||
catchClause(ident("e"), null, blockStmt([])),
|
||||
null));
|
||||
assertStmt("try { } catch (e) { } finally { }",
|
||||
tryStmt(blockStmt([]),
|
||||
catchClause(ident("e"), null, blockStmt([])),
|
||||
blockStmt([])));
|
||||
assertStmt("try { } finally { }",
|
||||
tryStmt(blockStmt([]),
|
||||
null,
|
||||
blockStmt([])));
|
||||
assertStmt("try { } catch (e if foo) { } catch (e if bar) { } finally { }",
|
||||
tryStmt(blockStmt([]),
|
||||
[ catchClause(ident("e"), ident("foo"), blockStmt([])),
|
||||
catchClause(ident("e"), ident("bar"), blockStmt([])) ],
|
||||
blockStmt([])));
|
||||
assertStmt("try { } catch (e if foo) { } catch (e if bar) { } catch (e) { } finally { }",
|
||||
tryStmt(blockStmt([]),
|
||||
[ catchClause(ident("e"), ident("foo"), blockStmt([])),
|
||||
catchClause(ident("e"), ident("bar"), blockStmt([])),
|
||||
catchClause(ident("e"), null, blockStmt([])) ],
|
||||
blockStmt([])));
|
||||
|
||||
|
||||
assertDecl("var {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
|
||||
init: ident("foo") }]));
|
||||
|
||||
// global let is var
|
||||
assertGlobalDecl("let {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
|
||||
init: ident("foo") }]));
|
||||
// function-global let is var
|
||||
assertLocalDecl("let {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
|
||||
init: ident("foo") }]));
|
||||
// block-local let is let
|
||||
assertBlockDecl("let {x:y} = foo;", letDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
|
||||
init: ident("foo") }]));
|
||||
|
||||
assertDecl("const {x:y} = foo;", constDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
|
||||
init: ident("foo") }]));
|
||||
|
||||
|
||||
// various combinations of identifiers and destructuring patterns:
|
||||
function makePatternCombinations(id, destr)
|
||||
[
|
||||
[ id(1) ],
|
||||
[ id(1), id(2) ],
|
||||
[ id(1), id(2), id(3) ],
|
||||
[ id(1), id(2), id(3), id(4) ],
|
||||
[ id(1), id(2), id(3), id(4), id(5) ],
|
||||
|
||||
[ destr(1) ],
|
||||
[ destr(1), destr(2) ],
|
||||
[ destr(1), destr(2), destr(3) ],
|
||||
[ destr(1), destr(2), destr(3), destr(4) ],
|
||||
[ destr(1), destr(2), destr(3), destr(4), destr(5) ],
|
||||
|
||||
[ destr(1), id(2) ],
|
||||
|
||||
[ destr(1), id(2), id(3) ],
|
||||
[ destr(1), id(2), id(3), id(4) ],
|
||||
[ destr(1), id(2), id(3), id(4), id(5) ],
|
||||
[ destr(1), id(2), id(3), id(4), destr(5) ],
|
||||
[ destr(1), id(2), id(3), destr(4) ],
|
||||
[ destr(1), id(2), id(3), destr(4), id(5) ],
|
||||
[ destr(1), id(2), id(3), destr(4), destr(5) ],
|
||||
|
||||
[ destr(1), id(2), destr(3) ],
|
||||
[ destr(1), id(2), destr(3), id(4) ],
|
||||
[ destr(1), id(2), destr(3), id(4), id(5) ],
|
||||
[ destr(1), id(2), destr(3), id(4), destr(5) ],
|
||||
[ destr(1), id(2), destr(3), destr(4) ],
|
||||
[ destr(1), id(2), destr(3), destr(4), id(5) ],
|
||||
[ destr(1), id(2), destr(3), destr(4), destr(5) ],
|
||||
|
||||
[ id(1), destr(2) ],
|
||||
|
||||
[ id(1), destr(2), id(3) ],
|
||||
[ id(1), destr(2), id(3), id(4) ],
|
||||
[ id(1), destr(2), id(3), id(4), id(5) ],
|
||||
[ id(1), destr(2), id(3), id(4), destr(5) ],
|
||||
[ id(1), destr(2), id(3), destr(4) ],
|
||||
[ id(1), destr(2), id(3), destr(4), id(5) ],
|
||||
[ id(1), destr(2), id(3), destr(4), destr(5) ],
|
||||
|
||||
[ id(1), destr(2), destr(3) ],
|
||||
[ id(1), destr(2), destr(3), id(4) ],
|
||||
[ id(1), destr(2), destr(3), id(4), id(5) ],
|
||||
[ id(1), destr(2), destr(3), id(4), destr(5) ],
|
||||
[ id(1), destr(2), destr(3), destr(4) ],
|
||||
[ id(1), destr(2), destr(3), destr(4), id(5) ],
|
||||
[ id(1), destr(2), destr(3), destr(4), destr(5) ]
|
||||
]
|
||||
|
||||
|
||||
// destructuring function parameters
|
||||
|
||||
function testParamPatternCombinations(makePattSrc, makePattPatt) {
|
||||
var pattSrcs = makePatternCombinations(function(n) ("x" + n), makePattSrc);
|
||||
var pattPatts = makePatternCombinations(function(n) (ident("x" + n)), makePattPatt);
|
||||
|
||||
for (var i = 0; i < pattSrcs.length; i++) {
|
||||
function makeSrc(body) ("(function(" + pattSrcs[i].join(",") + ") " + body + ")")
|
||||
function makePatt(body) (funExpr(null, pattPatts[i], body))
|
||||
|
||||
// no upvars, block body
|
||||
assertExpr(makeSrc("{ }", makePatt(blockStmt([]))));
|
||||
// upvars, block body
|
||||
assertExpr(makeSrc("{ return [x1,x2,x3,x4,x5]; }"),
|
||||
makePatt(blockStmt([returnStmt(arrExpr([ident("x1"), ident("x2"), ident("x3"), ident("x4"), ident("x5")]))])));
|
||||
// no upvars, expression body
|
||||
assertExpr(makeSrc("(0)"), makePatt(lit(0)));
|
||||
// upvars, expression body
|
||||
assertExpr(makeSrc("[x1,x2,x3,x4,x5]"),
|
||||
makePatt(arrExpr([ident("x1"), ident("x2"), ident("x3"), ident("x4"), ident("x5")])));
|
||||
}
|
||||
}
|
||||
|
||||
testParamPatternCombinations(function(n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "}"),
|
||||
function(n) (objPatt([{ key: ident("a" + n), value: ident("x" + n) },
|
||||
{ key: ident("b" + n), value: ident("y" + n) },
|
||||
{ key: ident("c" + n), value: ident("z" + n) }])));
|
||||
|
||||
testParamPatternCombinations(function(n) ("[x" + n + "," + "y" + n + "," + "z" + n + "]"),
|
||||
function(n) (arrPatt([ident("x" + n), ident("y" + n), ident("z" + n)])));
|
||||
|
||||
|
||||
// destructuring variable declarations
|
||||
|
||||
function testVarPatternCombinations(makePattSrc, makePattPatt) {
|
||||
var pattSrcs = makePatternCombinations(function(n) ("x" + n), makePattSrc);
|
||||
var pattPatts = makePatternCombinations(function(n) ({ id: ident("x" + n), init: null }), makePattPatt);
|
||||
|
||||
for (var i = 0; i < pattSrcs.length; i++) {
|
||||
// variable declarations in blocks
|
||||
assertDecl("var " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i]));
|
||||
|
||||
assertGlobalDecl("let " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i]));
|
||||
assertLocalDecl("let " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i]));
|
||||
assertBlockDecl("let " + pattSrcs[i].join(",") + ";", letDecl(pattPatts[i]));
|
||||
|
||||
assertDecl("const " + pattSrcs[i].join(",") + ";", constDecl(pattPatts[i]));
|
||||
|
||||
// variable declarations in for-loop heads
|
||||
assertStmt("for (var " + pattSrcs[i].join(",") + "; foo; bar);",
|
||||
forStmt(varDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt));
|
||||
assertStmt("for (let " + pattSrcs[i].join(",") + "; foo; bar);",
|
||||
forStmt(letDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt));
|
||||
assertStmt("for (const " + pattSrcs[i].join(",") + "; foo; bar);",
|
||||
forStmt(constDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt));
|
||||
}
|
||||
}
|
||||
|
||||
testVarPatternCombinations(function (n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"),
|
||||
function (n) ({ id: objPatt([{ key: ident("a" + n), value: ident("x" + n) },
|
||||
{ key: ident("b" + n), value: ident("y" + n) },
|
||||
{ key: ident("c" + n), value: ident("z" + n) }]),
|
||||
init: lit(0) }));
|
||||
|
||||
testVarPatternCombinations(function(n) ("[x" + n + "," + "y" + n + "," + "z" + n + "] = 0"),
|
||||
function(n) ({ id: arrPatt([ident("x" + n), ident("y" + n), ident("z" + n)]),
|
||||
init: lit(0) }));
|
||||
|
||||
// destructuring assignment
|
||||
|
||||
function testAssignmentCombinations(makePattSrc, makePattPatt) {
|
||||
var pattSrcs = makePatternCombinations(function(n) ("x" + n + " = 0"), makePattSrc);
|
||||
var pattPatts = makePatternCombinations(function(n) (aExpr("=", ident("x" + n), lit(0))), makePattPatt);
|
||||
|
||||
for (var i = 0; i < pattSrcs.length; i++) {
|
||||
var src = pattSrcs[i].join(",");
|
||||
var patt = pattPatts[i].length === 1 ? pattPatts[i][0] : seqExpr(pattPatts[i]);
|
||||
|
||||
// assignment expression statement
|
||||
assertExpr("(" + src + ")", patt);
|
||||
|
||||
// for-loop head assignment
|
||||
assertStmt("for (" + src + "; foo; bar);",
|
||||
forStmt(patt, ident("foo"), ident("bar"), emptyStmt));
|
||||
}
|
||||
}
|
||||
|
||||
testAssignmentCombinations(function (n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"),
|
||||
function (n) (aExpr("=",
|
||||
objPatt([{ key: ident("a" + n), value: ident("x" + n) },
|
||||
{ key: ident("b" + n), value: ident("y" + n) },
|
||||
{ key: ident("c" + n), value: ident("z" + n) }]),
|
||||
lit(0))));
|
||||
|
||||
|
||||
// destructuring in for-in and for-each-in loop heads
|
||||
|
||||
var axbycz = objPatt([{ key: ident("a"), value: ident("x") },
|
||||
{ key: ident("b"), value: ident("y") },
|
||||
{ key: ident("c"), value: ident("z") }]);
|
||||
var xyz = arrPatt([ident("x"), ident("y"), ident("z")]);
|
||||
|
||||
assertStmt("for (var {a:x,b:y,c:z} in foo);", forInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for (let {a:x,b:y,c:z} in foo);", forInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for ({a:x,b:y,c:z} in foo);", forInStmt(axbycz, ident("foo"), emptyStmt));
|
||||
assertStmt("for (var [x,y,z] in foo);", forInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for (let [x,y,z] in foo);", forInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for ([x,y,z] in foo);", forInStmt(xyz, ident("foo"), emptyStmt));
|
||||
assertStmt("for each (var {a:x,b:y,c:z} in foo);", forEachInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for each (let {a:x,b:y,c:z} in foo);", forEachInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for each ({a:x,b:y,c:z} in foo);", forEachInStmt(axbycz, ident("foo"), emptyStmt));
|
||||
assertStmt("for each (var [x,y,z] in foo);", forEachInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for each (let [x,y,z] in foo);", forEachInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
|
||||
assertStmt("for each ([x,y,z] in foo);", forEachInStmt(xyz, ident("foo"), emptyStmt));
|
||||
|
||||
// expression closures
|
||||
|
||||
assertDecl("function inc(x) (x + 1)", funDecl(ident("inc"), [ident("x")], binExpr("+", ident("x"), lit(1))));
|
||||
assertExpr("(function(x) (x+1))", funExpr(null, [ident("x")], binExpr("+"), ident("x"), lit(1)));
|
||||
|
||||
// generators
|
||||
|
||||
assertDecl("function gen(x) { yield }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
|
||||
assertExpr("(function(x) { yield })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
|
||||
assertDecl("function gen(x) { yield 42 }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
|
||||
assertExpr("(function(x) { yield 42 })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
|
||||
|
||||
// getters and setters
|
||||
|
||||
assertExpr("({ get x() { return 42 } })",
|
||||
objExpr([ { key: ident("x"),
|
||||
value: funExpr(null, [], blockStmt([returnStmt(lit(42))])),
|
||||
kind: "get" } ]));
|
||||
assertExpr("({ set x(v) { return 42 } })",
|
||||
objExpr([ { key: ident("x"),
|
||||
value: funExpr(null, [ident("v")], blockStmt([returnStmt(lit(42))])),
|
||||
kind: "set" } ]));
|
||||
|
||||
// comprehensions
|
||||
|
||||
assertExpr("[ x for (x in foo)]",
|
||||
compExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], null));
|
||||
assertExpr("[ [x,y] for (x in foo) for (y in bar)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], null));
|
||||
assertExpr("[ [x,y,z] for (x in foo) for (y in bar) for (z in baz)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
|
||||
null));
|
||||
|
||||
assertExpr("[ x for (x in foo) if (p)]",
|
||||
compExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], ident("p")));
|
||||
assertExpr("[ [x,y] for (x in foo) for (y in bar) if (p)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], ident("p")));
|
||||
assertExpr("[ [x,y,z] for (x in foo) for (y in bar) for (z in baz) if (p) ]",
|
||||
compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
|
||||
ident("p")));
|
||||
|
||||
assertExpr("[ x for each (x in foo)]",
|
||||
compExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], null));
|
||||
assertExpr("[ [x,y] for each (x in foo) for each (y in bar)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], null));
|
||||
assertExpr("[ [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
|
||||
null));
|
||||
|
||||
assertExpr("[ x for each (x in foo) if (p)]",
|
||||
compExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], ident("p")));
|
||||
assertExpr("[ [x,y] for each (x in foo) for each (y in bar) if (p)]",
|
||||
compExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], ident("p")));
|
||||
assertExpr("[ [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz) if (p) ]",
|
||||
compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
|
||||
ident("p")));
|
||||
|
||||
// generator expressions
|
||||
|
||||
assertExpr("( x for (x in foo))",
|
||||
genExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], null));
|
||||
assertExpr("( [x,y] for (x in foo) for (y in bar))",
|
||||
genExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], null));
|
||||
assertExpr("( [x,y,z] for (x in foo) for (y in bar) for (z in baz))",
|
||||
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
|
||||
null));
|
||||
|
||||
assertExpr("( x for (x in foo) if (p))",
|
||||
genExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], ident("p")));
|
||||
assertExpr("( [x,y] for (x in foo) for (y in bar) if (p))",
|
||||
genExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], ident("p")));
|
||||
assertExpr("( [x,y,z] for (x in foo) for (y in bar) for (z in baz) if (p) )",
|
||||
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
|
||||
ident("p")));
|
||||
|
||||
assertExpr("( x for each (x in foo))",
|
||||
genExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], null));
|
||||
assertExpr("( [x,y] for each (x in foo) for each (y in bar))",
|
||||
genExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], null));
|
||||
assertExpr("( [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz))",
|
||||
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
|
||||
null));
|
||||
|
||||
assertExpr("( x for each (x in foo) if (p))",
|
||||
genExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], ident("p")));
|
||||
assertExpr("( [x,y] for each (x in foo) for each (y in bar) if (p))",
|
||||
genExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], ident("p")));
|
||||
assertExpr("( [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz) if (p) )",
|
||||
genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
|
||||
[compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
|
||||
ident("p")));
|
||||
|
||||
// NOTE: it would be good to test generator expressions both with and without upvars, just like functions above.
|
||||
|
||||
|
||||
// sharp variables
|
||||
|
||||
assertExpr("#1={me:#1#}", graphExpr(1, objExpr([{ key: ident("me"), value: idxExpr(1) }])))
|
||||
|
||||
|
||||
// E4X
|
||||
|
||||
assertExpr("x..tagName", binExpr("..", ident("x"), lit("tagName")));
|
||||
assertExpr("x.*", memExpr(ident("x"), xmlAnyName));
|
||||
assertExpr("x[*]", memExpr(ident("x"), xmlAnyName));
|
||||
assertExpr("x::y", xmlQualId(ident("x"), ident("y"), false));
|
||||
assertExpr("x::[foo]", xmlQualId(ident("x"), ident("foo"), true));
|
||||
assertExpr("x::[foo()]", xmlQualId(ident("x"), callExpr(ident("foo"), []), true));
|
||||
assertExpr("*::*", xmlQualId(xmlAnyName, ident("*"), false));
|
||||
assertExpr("*::[foo]", xmlQualId(xmlAnyName, ident("foo"), true));
|
||||
assertExpr("*::[foo()]", xmlQualId(xmlAnyName, callExpr(ident("foo"), []), true));
|
||||
assertExpr("@foo", xmlAttrSel(ident("foo")));
|
||||
assertExpr("x.(p)", xmlFilter(ident("x"), ident("p")));
|
||||
assertExpr("<{foo}/>", xmlPointTag([xmlEscape(ident("foo"))]));
|
||||
assertExpr("<{foo}></{foo}>", xmlElt([xmlStartTag([xmlEscape(ident("foo"))]),
|
||||
xmlEndTag([xmlEscape(ident("foo"))])]));
|
||||
assertExpr("<{foo} {attr}='attr'/>", xmlPointTag([xmlEscape(ident("foo")),
|
||||
xmlEscape(ident("attr")),
|
||||
xmlAttr("attr")]));
|
||||
assertExpr("<{foo}>text</{foo}>", xmlElt([xmlStartTag([xmlEscape(ident("foo"))]),
|
||||
xmlText("text"),
|
||||
xmlEndTag([xmlEscape(ident("foo"))])]));
|
||||
assertExpr("<?xml?>", xmlPI("xml", ""));
|
||||
assertExpr("<?xml version='1.0'?>", xmlPI("xml", "version='1.0'"));
|
||||
|
||||
// NOTE: We appear to be unable test XMLNAME, XMLCDATA, and XMLCOMMENT.
|
Загрузка…
Ссылка в новой задаче