mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 533874, r=jimb: expose the parser as a JS API
This commit is contained in:
parent
77d8fcb9e6
commit
484e1a2751
@ -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 \
|
||||
@ -633,7 +635,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) $<
|
||||
|
@ -333,3 +333,4 @@ MSG_DEF(JSMSG_INVALID_EVAL_SCOPE_ARG, 250, 0, JSEXN_EVALERR, "invalid eval scope
|
||||
MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS, 251, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}")
|
||||
MSG_DEF(JSMSG_THROW_TYPE_ERROR, 252, 0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them")
|
||||
MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP, 253, 0, JSEXN_TYPEERR, "toISOString property is not callable")
|
||||
MSG_DEF(JSMSG_BAD_PARSE_NODE, 254, 0, JSEXN_INTERNALERR, "bad parse node")
|
||||
|
115
js/src/jsast.tbl
Normal file
115
js/src/jsast.tbl
Normal file
@ -0,0 +1,115 @@
|
||||
/* -*- 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 ***** */
|
||||
|
||||
/* AST_ERROR = -1 */
|
||||
|
||||
ASTDEF(AST_PROGRAM, "Program")
|
||||
|
||||
ASTDEF(AST_IDENTIFIER, "Identifier")
|
||||
ASTDEF(AST_LITERAL, "Literal")
|
||||
ASTDEF(AST_PROPERTY, "Property")
|
||||
|
||||
ASTDEF(AST_FUNC_DECL, "FunctionDeclaration")
|
||||
ASTDEF(AST_VAR_DECL, "VariableDeclaration")
|
||||
ASTDEF(AST_VAR_DTOR, "VariableDeclarator")
|
||||
|
||||
ASTDEF(AST_LIST_EXPR, "SequenceExpression")
|
||||
ASTDEF(AST_COND_EXPR, "ConditionalExpression")
|
||||
ASTDEF(AST_UNARY_EXPR, "UnaryExpression")
|
||||
ASTDEF(AST_BINARY_EXPR, "BinaryExpression")
|
||||
ASTDEF(AST_ASSIGN_EXPR, "AssignmentExpression")
|
||||
ASTDEF(AST_LOGICAL_EXPR, "LogicalExpression")
|
||||
ASTDEF(AST_UPDATE_EXPR, "UpdateExpression")
|
||||
ASTDEF(AST_NEW_EXPR, "NewExpression")
|
||||
ASTDEF(AST_CALL_EXPR, "CallExpression")
|
||||
ASTDEF(AST_MEMBER_EXPR, "MemberExpression")
|
||||
ASTDEF(AST_FUNC_EXPR, "FunctionExpression")
|
||||
ASTDEF(AST_ARRAY_EXPR, "ArrayExpression")
|
||||
ASTDEF(AST_OBJECT_EXPR, "ObjectExpression")
|
||||
ASTDEF(AST_THIS_EXPR, "ThisExpression")
|
||||
ASTDEF(AST_GRAPH_EXPR, "GraphExpression")
|
||||
ASTDEF(AST_GRAPH_IDX_EXPR, "GraphIndexExpression")
|
||||
ASTDEF(AST_COMP_EXPR, "ComprehensionExpression")
|
||||
ASTDEF(AST_GENERATOR_EXPR, "GeneratorExpression")
|
||||
ASTDEF(AST_YIELD_EXPR, "YieldExpression")
|
||||
|
||||
ASTDEF(AST_EMPTY_STMT, "EmptyStatement")
|
||||
ASTDEF(AST_BLOCK_STMT, "BlockStatement")
|
||||
ASTDEF(AST_EXPR_STMT, "ExpressionStatement")
|
||||
ASTDEF(AST_LAB_STMT, "LabeledStatement")
|
||||
ASTDEF(AST_IF_STMT, "IfStatement")
|
||||
ASTDEF(AST_SWITCH_STMT, "SwitchStatement")
|
||||
ASTDEF(AST_WHILE_STMT, "WhileStatement")
|
||||
ASTDEF(AST_DO_STMT, "DoWhileStatement")
|
||||
ASTDEF(AST_FOR_STMT, "ForStatement")
|
||||
ASTDEF(AST_FOR_IN_STMT, "ForInStatement")
|
||||
ASTDEF(AST_BREAK_STMT, "BreakStatement")
|
||||
ASTDEF(AST_CONTINUE_STMT, "ContinueStatement")
|
||||
ASTDEF(AST_WITH_STMT, "WithStatement")
|
||||
ASTDEF(AST_RETURN_STMT, "ReturnStatement")
|
||||
ASTDEF(AST_TRY_STMT, "TryStatement")
|
||||
ASTDEF(AST_THROW_STMT, "ThrowStatement")
|
||||
ASTDEF(AST_DEBUGGER_STMT, "DebuggerStatement")
|
||||
|
||||
ASTDEF(AST_CASE, "SwitchCase")
|
||||
ASTDEF(AST_CATCH, "CatchClause")
|
||||
ASTDEF(AST_COMP_BLOCK, "ComprehensionBlock")
|
||||
|
||||
ASTDEF(AST_ARRAY_PATT, "ArrayPattern")
|
||||
ASTDEF(AST_OBJECT_PATT, "ObjectPattern")
|
||||
|
||||
ASTDEF(AST_XMLANYNAME, "XMLAnyName")
|
||||
ASTDEF(AST_XMLATTR_SEL, "XMLAttributeSelector")
|
||||
ASTDEF(AST_XMLESCAPE, "XMLEscape")
|
||||
ASTDEF(AST_XMLFILTER, "XMLFilterExpression")
|
||||
ASTDEF(AST_XMLDEFAULT, "XMLDefaultDeclaration")
|
||||
ASTDEF(AST_XMLQUAL, "XMLQualifiedIdentifier")
|
||||
ASTDEF(AST_XMLELEM, "XMLElement")
|
||||
ASTDEF(AST_XMLTEXT, "XMLText")
|
||||
ASTDEF(AST_XMLLIST, "XMLList")
|
||||
ASTDEF(AST_XMLSTART, "XMLStartTag")
|
||||
ASTDEF(AST_XMLEND, "XMLEndTag")
|
||||
ASTDEF(AST_XMLPOINT, "XMLPointTag")
|
||||
ASTDEF(AST_XMLNAME, "XMLName")
|
||||
ASTDEF(AST_XMLATTR, "XMLAttribute")
|
||||
ASTDEF(AST_XMLCDATA, "XMLCdata")
|
||||
ASTDEF(AST_XMLCOMMENT, "XMLComment")
|
||||
ASTDEF(AST_XMLPI, "XMLProcessingInstruction")
|
||||
|
||||
/* AST_LIMIT = last + 1 */
|
@ -60,7 +60,7 @@
|
||||
|
||||
#define STRING_TO_ATOM(str) (JS_ASSERT(str->isAtomized()), \
|
||||
(JSAtom *)str)
|
||||
#define ATOM_TO_STRING(atom) ((JSString *)atom)
|
||||
#define ATOM_TO_STRING(atom) ((JSString *)(atom))
|
||||
#define ATOM_TO_JSVAL(atom) STRING_TO_JSVAL(ATOM_TO_STRING(atom))
|
||||
|
||||
/* Engine-internal extensions of jsid */
|
||||
|
@ -2886,10 +2886,9 @@ Parser::functionDef(JSAtom *funAtom, FunctionType type, uintN lambda)
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
/*
|
||||
* If there were destructuring formal parameters, prepend the initializing
|
||||
* comma expression that we synthesized to body. If the body is a lexical
|
||||
* scope node, we must make a special TOK_SEQ node, to prepend the formal
|
||||
* parameter destructuring code without bracing the decompilation of the
|
||||
* function body's lexical scope.
|
||||
* comma expression that we synthesized to body. If the body is a return
|
||||
* node, we must make a special TOK_SEQ node, to prepend the destructuring
|
||||
* code without bracing the decompilation of the function body.
|
||||
*/
|
||||
if (prolog) {
|
||||
if (body->pn_arity != PN_LIST) {
|
||||
@ -7881,10 +7880,9 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
||||
* ARRAYPUSH node after we parse the rest of the comprehension.
|
||||
*/
|
||||
pnexp = pn->last();
|
||||
JS_ASSERT(pn->pn_count == 1 || pn->pn_count == 2);
|
||||
pn->pn_tail = (--pn->pn_count == 1)
|
||||
? &pn->pn_head->pn_next
|
||||
: &pn->pn_head;
|
||||
JS_ASSERT(pn->pn_count == 1);
|
||||
pn->pn_count = 0;
|
||||
pn->pn_tail = &pn->pn_head;
|
||||
*pn->pn_tail = NULL;
|
||||
|
||||
pntop = comprehensionTail(pnexp, pn->pn_blockid,
|
||||
|
@ -69,7 +69,10 @@ JS_BEGIN_EXTERN_C
|
||||
* pn_body: TOK_UPVARS if the function's source body
|
||||
* depends on outer names, else TOK_ARGSBODY
|
||||
* if formal parameters, else TOK_LC node for
|
||||
* function body statements
|
||||
* function body statements, else TOK_RETURN
|
||||
* for expression closure, else TOK_SEQ for
|
||||
* expression closure with destructured
|
||||
* formal parameters
|
||||
* pn_cookie: static level and var index for function
|
||||
* pn_dflags: PND_* definition/use flags (see below)
|
||||
* pn_blockid: block id number
|
||||
@ -84,7 +87,10 @@ JS_BEGIN_EXTERN_C
|
||||
*
|
||||
* <Statements>
|
||||
* TOK_LC list pn_head: list of pn_count statements
|
||||
* TOK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null
|
||||
* TOK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null.
|
||||
* In body of a comprehension or desugared generator
|
||||
* expression, pn_kid2 is TOK_YIELD, TOK_ARRAYPUSH,
|
||||
* or (if the push was optimized away) empty TOK_LC.
|
||||
* TOK_SWITCH binary pn_left: discriminant
|
||||
* pn_right: list of TOK_CASE nodes, with at most one
|
||||
* TOK_DEFAULT node, or if there are let bindings
|
||||
@ -128,7 +134,7 @@ JS_BEGIN_EXTERN_C
|
||||
* pn_expr: initializer or null
|
||||
* each assignment node has
|
||||
* pn_left: TOK_NAME with pn_used true and
|
||||
* pn_lexdef (NOT pn_expr) set
|
||||
* pn_lexdef (NOT pn_expr) set
|
||||
* pn_right: initializer
|
||||
* TOK_RETURN unary pn_kid: return expr or null
|
||||
* TOK_SEMI unary pn_kid: expr or null statement
|
||||
@ -207,6 +213,9 @@ JS_BEGIN_EXTERN_C
|
||||
* TOK_PRIMARY nullary pn_op: JSOp bytecode
|
||||
*
|
||||
* <E4X node descriptions>
|
||||
* TOK_DEFAULT name pn_atom: default XML namespace string literal
|
||||
* TOK_FILTER binary pn_left: container expr, pn_right: filter expr
|
||||
* TOK_DBLDOT binary pn_left: container expr, pn_right: selector expr
|
||||
* TOK_ANYNAME nullary pn_op: JSOP_ANYNAME
|
||||
* pn_atom: cx->runtime->atomState.starAtom
|
||||
* TOK_AT unary pn_op: JSOP_TOATTRNAME; pn_kid attribute id/expr
|
||||
@ -220,11 +229,13 @@ JS_BEGIN_EXTERN_C
|
||||
* pn_head: start tag, content1, ... contentN, end tag
|
||||
* pn_count: 2 + N where N is number of content nodes
|
||||
* N may be > x.length() if {expr} embedded
|
||||
* After constant folding, these contents may be
|
||||
* concatenated into string nodes.
|
||||
* TOK_XMLLIST list XML list node
|
||||
* pn_head: content1, ... contentN
|
||||
* TOK_XMLSTAGO, list XML start, end, and point tag contents
|
||||
* TOK_XMLETAGC, pn_head: tag name or {expr}, ... XML attrs ...
|
||||
* TOK_XMLPTAGO
|
||||
* TOK_XMLETAGO, pn_head: tag name or {expr}, ... XML attrs ...
|
||||
* TOK_XMLPTAGC
|
||||
* TOK_XMLNAME nullary pn_atom: XML name, with no {expr} embedded
|
||||
* TOK_XMLNAME list pn_head: tag name or {expr}, ... name or {expr}
|
||||
* TOK_XMLATTR, nullary pn_atom: attribute value string; pn_op: JSOP_STRING
|
||||
@ -267,10 +278,10 @@ JS_BEGIN_EXTERN_C
|
||||
* TOK_LEXICALSCOPE name pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR
|
||||
* pn_objbox: block object in JSObjectBox holder
|
||||
* pn_expr: block body
|
||||
* TOK_ARRAYCOMP list pn_head: list of pn_count (1 or 2) elements
|
||||
* if pn_count is 2, first element is #n=[...]
|
||||
* last element is block enclosing for loop(s)
|
||||
* and optionally if-guarded TOK_ARRAYPUSH
|
||||
* TOK_ARRAYCOMP list pn_count: 1
|
||||
* pn_head: list of 1 element, which is block
|
||||
* enclosing for loop(s) and optionally
|
||||
* if-guarded TOK_ARRAYPUSH
|
||||
* TOK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
|
||||
* pn_kid: array comprehension expression
|
||||
*/
|
||||
@ -532,6 +543,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 +999,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_InitReflectClass)
|
||||
JS_PROTO(ASTNode, 39, js_InitReflectClass)
|
||||
|
||||
#undef XML_INIT
|
||||
#undef NAMESPACE_INIT
|
||||
|
2691
js/src/jsreflect.cpp
Normal file
2691
js/src/jsreflect.cpp
Normal file
File diff suppressed because it is too large
Load Diff
138
js/src/jsreflect.h
Normal file
138
js/src/jsreflect.h
Normal file
@ -0,0 +1,138 @@
|
||||
/* -*- 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 {
|
||||
|
||||
enum ASTType {
|
||||
AST_ERROR = -1,
|
||||
#define ASTDEF(ast, str) ast,
|
||||
#include "jsast.tbl"
|
||||
#undef ASTDEF
|
||||
AST_LIMIT
|
||||
};
|
||||
|
||||
enum AssignmentOperator {
|
||||
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
|
||||
};
|
||||
|
||||
enum BinaryOperator {
|
||||
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
|
||||
};
|
||||
|
||||
enum UnaryOperator {
|
||||
UNOP_ERR = -1,
|
||||
|
||||
UNOP_DELETE = 0,
|
||||
UNOP_NEG,
|
||||
UNOP_POS,
|
||||
UNOP_NOT,
|
||||
UNOP_BITNOT,
|
||||
UNOP_TYPEOF,
|
||||
UNOP_VOID,
|
||||
|
||||
UNOP_LIMIT
|
||||
};
|
||||
|
||||
enum VarDeclKind {
|
||||
VARDECL_ERR = -1,
|
||||
VARDECL_VAR = 0,
|
||||
VARDECL_CONST,
|
||||
VARDECL_LET,
|
||||
VARDECL_LIMIT
|
||||
};
|
||||
|
||||
enum PropKind {
|
||||
PROP_ERR = -1,
|
||||
PROP_INIT = 0,
|
||||
PROP_GETTER,
|
||||
PROP_SETTER,
|
||||
PROP_LIMIT
|
||||
};
|
||||
|
||||
extern char const *aopNames[];
|
||||
extern char const *binopNames[];
|
||||
extern char const *unopNames[];
|
||||
extern char const *nodeTypeNames[];
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
extern js::Class js_ReflectClass;
|
||||
|
||||
extern JSObject *
|
||||
js_InitReflectClass(JSContext *cx, JSObject *obj);
|
||||
|
||||
|
||||
#endif /* jsreflect_h___ */
|
@ -261,6 +261,7 @@ typedef enum JSWhyMagic
|
||||
JS_FAST_CONSTRUCTOR, /* 'this' value for fast natives invoked with 'new' */
|
||||
JS_NO_CONSTANT, /* compiler sentinel value */
|
||||
JS_THIS_POISON, /* used in debug builds to catch tracing errors */
|
||||
JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */
|
||||
JS_GENERIC_MAGIC /* for local use */
|
||||
} JSWhyMagic;
|
||||
|
||||
|
@ -71,6 +71,7 @@
|
||||
#include "jsnum.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsparse.h"
|
||||
#include "jsreflect.h"
|
||||
#include "jsscope.h"
|
||||
#include "jsscript.h"
|
||||
#include "jstracer.h"
|
||||
@ -2706,6 +2707,23 @@ split_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
ResolveClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
|
||||
{
|
||||
if (!JS_ResolveStandardClass(cx, obj, id, resolved))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!*resolved) {
|
||||
if (JSID_IS_ATOM(id, CLASS_ATOM(cx, Reflect))) {
|
||||
if (!js_InitReflectClass(cx, obj))
|
||||
return JS_FALSE;
|
||||
*resolved = JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
split_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
|
||||
{
|
||||
@ -2736,7 +2754,7 @@ split_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **obj
|
||||
if (!(flags & JSRESOLVE_ASSIGNING)) {
|
||||
JSBool resolved;
|
||||
|
||||
if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
|
||||
if (!ResolveClass(cx, obj, id, &resolved))
|
||||
return JS_FALSE;
|
||||
|
||||
if (resolved) {
|
||||
@ -2962,7 +2980,7 @@ sandbox_resolve(JSContext *cx, JSObject *obj, jsid 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;
|
||||
@ -4711,7 +4729,7 @@ global_resolve(JSContext *cx, JSObject *obj, jsid 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;
|
||||
|
@ -12,4 +12,5 @@ script scripted-proxies.js
|
||||
script array-length-protochange.js
|
||||
script parseInt-octal.js
|
||||
script proxy-enumerateOwn-duplicates.js
|
||||
skip-if(!xulRuntime.shell) script reflect-parse.js
|
||||
script destructure-accessor.js
|
||||
|
703
js/src/tests/js1_8_5/extensions/reflect-parse.js
Normal file
703
js/src/tests/js1_8_5/extensions/reflect-parse.js
Normal file
@ -0,0 +1,703 @@
|
||||
/* -*- 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 { 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 })
|
||||
var thisExpr = Pattern({ type: "ThisExpression" });
|
||||
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 unExpr(op, arg) Pattern({ type: "UnaryExpression", operator: op, argument: arg })
|
||||
function binExpr(op, left, right) Pattern({ type: "BinaryExpression", operator: op, left: left, right: right })
|
||||
function aExpr(op, left, right) Pattern({ type: "AssignmentExpression", operator: op, left: left, right: right })
|
||||
function updExpr(op, arg, prefix) Pattern({ type: "UpdateExpression", operator: op, argument: arg, prefix: prefix })
|
||||
function logExpr(op, left, right) Pattern({ type: "LogicalExpression", operator: 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
|
||||
|
||||
// NB: These are useful but for now trace-test doesn't do I/O reliably.
|
||||
|
||||
//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("this", thisExpr);
|
||||
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 to test XMLNAME, XMLCDATA, and XMLCOMMENT.
|
||||
|
||||
|
||||
// Source location information
|
||||
|
||||
|
||||
var withoutFileOrLine = Reflect.parse("42");
|
||||
var withFile = Reflect.parse("42", "foo.js");
|
||||
var withFileAndLine = Reflect.parse("42", "foo.js", 111);
|
||||
|
||||
Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withoutFileOrLine.loc);
|
||||
Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withFile.loc);
|
||||
Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 111, column: 2 } }).match(withFileAndLine.loc);
|
||||
|
||||
var withoutFileOrLine2 = Reflect.parse("foo +\nbar");
|
||||
var withFile2 = Reflect.parse("foo +\nbar", "foo.js");
|
||||
var withFileAndLine2 = Reflect.parse("foo +\nbar", "foo.js", 111);
|
||||
|
||||
Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withoutFileOrLine2.loc);
|
||||
Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withFile2.loc);
|
||||
Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 112, column: 3 } }).match(withFileAndLine2.loc);
|
||||
|
||||
var nested = Reflect.parse("(-b + sqrt(sqr(b) - 4 * a * c)) / (2 * a)", "quad.js");
|
||||
var fourAC = nested.body[0].expression.left.right.arguments[0].right;
|
||||
|
||||
Pattern({ source: "quad.js", start: { line: 1, column: 20 }, end: { line: 1, column: 29 } }).match(fourAC.loc);
|
||||
|
||||
|
||||
reportCompare(true, true);
|
@ -17,3 +17,156 @@ if (typeof version != 'undefined')
|
||||
version(185);
|
||||
}
|
||||
|
||||
// A little pattern-matching library.
|
||||
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 };
|
||||
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user