mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 16:28:38 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
fee810585e
66 changed files with 1969 additions and 94 deletions
|
|
@ -1462,7 +1462,9 @@ DebuggerServerConnection.prototype = {
|
|||
},
|
||||
|
||||
send(packet) {
|
||||
this.transport.send(packet);
|
||||
if (this.transport) {
|
||||
this.transport.send(packet);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include "nsIUnicodeDecoder.h"
|
||||
#include "nsIUnicodeEncoder.h"
|
||||
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsDOMString.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsReadableUtils.h"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
#include "GetFilesTask.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/dom/DirectoryBinding.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "FileSystemUtils.h"
|
||||
#include "OSFileSystem.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
#include "nsTArray.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "nsContentTypeParser.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
|
||||
#ifdef LOG
|
||||
#undef LOG
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ LOCAL_INCLUDES += [
|
|||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [ '-Wno-deprecated-declarations' ]
|
||||
CXXFLAGS += [
|
||||
'-Wno-attributes',
|
||||
'-Wno-deprecated-declarations',
|
||||
]
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-unknown-attributes',
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ LOCAL_INCLUDES += [
|
|||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [ '-Wno-deprecated-declarations' ]
|
||||
CXXFLAGS += [
|
||||
'-Wno-attributes',
|
||||
'-Wno-deprecated-declarations',
|
||||
]
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-unknown-attributes',
|
||||
|
|
|
|||
|
|
@ -28,7 +28,10 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [ '-Wno-deprecated-declarations' ]
|
||||
CXXFLAGS += [
|
||||
'-Wno-attributes',
|
||||
'-Wno-deprecated-declarations',
|
||||
]
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-unknown-attributes',
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ LOCAL_INCLUDES += [
|
|||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [ '-Wno-deprecated-declarations' ]
|
||||
CXXFLAGS += [
|
||||
'-Wno-attributes',
|
||||
'-Wno-deprecated-declarations',
|
||||
]
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-unknown-attributes',
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ enum BinaryOperator {
|
|||
/* binary */
|
||||
BINOP_BITOR, BINOP_BITXOR, BINOP_BITAND,
|
||||
/* misc */
|
||||
BINOP_IN, BINOP_INSTANCEOF,
|
||||
BINOP_IN, BINOP_INSTANCEOF, BINOP_COALESCE,
|
||||
|
||||
BINOP_LIMIT
|
||||
};
|
||||
|
|
@ -153,6 +153,7 @@ static const char* const binopNames[] = {
|
|||
"&", /* BINOP_BITAND */
|
||||
"in", /* BINOP_IN */
|
||||
"instanceof", /* BINOP_INSTANCEOF */
|
||||
"??" /* BINOP_COALESCE */
|
||||
};
|
||||
|
||||
static const char* const unopNames[] = {
|
||||
|
|
@ -564,7 +565,7 @@ class NodeBuilder
|
|||
MOZ_MUST_USE bool updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos* pos,
|
||||
MutableHandleValue dst);
|
||||
|
||||
MOZ_MUST_USE bool logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos* pos,
|
||||
MOZ_MUST_USE bool logicalExpression(ParseNodeKind kind, HandleValue left, HandleValue right, TokenPos* pos,
|
||||
MutableHandleValue dst);
|
||||
|
||||
MOZ_MUST_USE bool conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt,
|
||||
|
|
@ -1086,12 +1087,35 @@ NodeBuilder::updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos
|
|||
}
|
||||
|
||||
bool
|
||||
NodeBuilder::logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos* pos,
|
||||
NodeBuilder::logicalExpression(ParseNodeKind kind,
|
||||
HandleValue left,
|
||||
HandleValue right,
|
||||
TokenPos* pos,
|
||||
MutableHandleValue dst)
|
||||
{
|
||||
RootedValue opName(cx);
|
||||
if (!atomValue(lor ? "||" : "&&", &opName))
|
||||
return false;
|
||||
switch (kind) {
|
||||
case PNK_COALESCE:
|
||||
if (!atomValue("??", &opName)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case PNK_OR:
|
||||
if (!atomValue("||", &opName)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case PNK_AND:
|
||||
if (!atomValue("&&", &opName)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOCAL_NOT_REACHED("unexpected logical operator type");
|
||||
}
|
||||
|
||||
RootedValue cb(cx, callbacks[AST_LOGICAL_EXPR]);
|
||||
if (!cb.isNull())
|
||||
|
|
@ -1989,6 +2013,8 @@ ASTSerializer::binop(ParseNodeKind kind, JSOp op)
|
|||
return BINOP_IN;
|
||||
case PNK_INSTANCEOF:
|
||||
return BINOP_INSTANCEOF;
|
||||
case PNK_COALESCE:
|
||||
return BINOP_COALESCE;
|
||||
default:
|
||||
return BINOP_ERR;
|
||||
}
|
||||
|
|
@ -2648,8 +2674,9 @@ ASTSerializer::leftAssociate(ParseNode* pn, MutableHandleValue dst)
|
|||
MOZ_ASSERT(pn->pn_count >= 1);
|
||||
|
||||
ParseNodeKind kind = pn->getKind();
|
||||
bool lor = kind == PNK_OR;
|
||||
bool logop = lor || (kind == PNK_AND);
|
||||
bool logop = (kind == PNK_COALESCE ||
|
||||
kind == PNK_OR ||
|
||||
kind == PNK_AND);
|
||||
|
||||
ParseNode* head = pn->pn_head;
|
||||
RootedValue left(cx);
|
||||
|
|
@ -2663,7 +2690,7 @@ ASTSerializer::leftAssociate(ParseNode* pn, MutableHandleValue dst)
|
|||
TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end);
|
||||
|
||||
if (logop) {
|
||||
if (!builder.logicalExpression(lor, left, right, &subpos, &left))
|
||||
if (!builder.logicalExpression(kind, left, right, &subpos, &left))
|
||||
return false;
|
||||
} else {
|
||||
BinaryOperator op = binop(pn->getKind(), pn->getOp());
|
||||
|
|
@ -2876,6 +2903,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
|||
builder.conditionalExpression(test, cons, alt, &pn->pn_pos, dst);
|
||||
}
|
||||
|
||||
case PNK_COALESCE:
|
||||
case PNK_OR:
|
||||
case PNK_AND:
|
||||
return leftAssociate(pn, dst);
|
||||
|
|
|
|||
|
|
@ -3334,6 +3334,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
|||
case PNK_CATCHLIST:
|
||||
// Strict equality operations and logical operators are well-behaved and
|
||||
// perform no conversions.
|
||||
case PNK_COALESCE:
|
||||
case PNK_OR:
|
||||
case PNK_AND:
|
||||
case PNK_STRICTEQ:
|
||||
|
|
@ -11355,6 +11356,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
|
|||
return false;
|
||||
break;
|
||||
|
||||
case PNK_COALESCE:
|
||||
case PNK_OR:
|
||||
case PNK_AND:
|
||||
if (!emitLogical(pn))
|
||||
|
|
|
|||
|
|
@ -326,6 +326,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
|
|||
case PNK_POSTINCREMENT:
|
||||
case PNK_PREDECREMENT:
|
||||
case PNK_POSTDECREMENT:
|
||||
case PNK_COALESCE:
|
||||
case PNK_OR:
|
||||
case PNK_AND:
|
||||
case PNK_BITOR:
|
||||
|
|
@ -482,15 +483,19 @@ IsEffectless(ParseNode* node)
|
|||
enum Truthiness { Truthy, Falsy, Unknown };
|
||||
|
||||
static Truthiness
|
||||
Boolish(ParseNode* pn)
|
||||
Boolish(ParseNode* pn, bool isNullish = false)
|
||||
{
|
||||
switch (pn->getKind()) {
|
||||
case PNK_NUMBER:
|
||||
return (pn->pn_dval != 0 && !IsNaN(pn->pn_dval)) ? Truthy : Falsy;
|
||||
case PNK_NUMBER: {
|
||||
bool isNonZeroNumber = (pn->pn_dval != 0 && !IsNaN(pn->pn_dval));
|
||||
return (isNullish || isNonZeroNumber) ? Truthy : Falsy;
|
||||
}
|
||||
|
||||
case PNK_STRING:
|
||||
case PNK_TEMPLATE_STRING:
|
||||
return (pn->pn_atom->length() > 0) ? Truthy : Falsy;
|
||||
case PNK_TEMPLATE_STRING: {
|
||||
bool isNonZeroLengthString = (pn->pn_atom->length() > 0);
|
||||
return (isNullish || isNonZeroLengthString) ? Truthy : Falsy;
|
||||
}
|
||||
|
||||
case PNK_TRUE:
|
||||
case PNK_FUNCTION:
|
||||
|
|
@ -498,6 +503,8 @@ Boolish(ParseNode* pn)
|
|||
return Truthy;
|
||||
|
||||
case PNK_FALSE:
|
||||
return isNullish ? Truthy : Falsy;
|
||||
|
||||
case PNK_NULL:
|
||||
case PNK_RAW_UNDEFINED:
|
||||
return Falsy;
|
||||
|
|
@ -752,21 +759,24 @@ FoldIncrementDecrement(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHa
|
|||
}
|
||||
|
||||
static bool
|
||||
FoldAndOr(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& parser,
|
||||
FoldLogical(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& parser,
|
||||
bool inGenexpLambda)
|
||||
{
|
||||
ParseNode* node = *nodePtr;
|
||||
|
||||
MOZ_ASSERT(node->isKind(PNK_AND) || node->isKind(PNK_OR));
|
||||
bool isCoalesceNode = node->isKind(PNK_COALESCE);
|
||||
bool isOrNode = node->isKind(PNK_OR);
|
||||
bool isAndNode = node->isKind(PNK_AND);
|
||||
|
||||
MOZ_ASSERT(isCoalesceNode || isOrNode || isAndNode);
|
||||
MOZ_ASSERT(node->isArity(PN_LIST));
|
||||
|
||||
bool isOrNode = node->isKind(PNK_OR);
|
||||
ParseNode** elem = &node->pn_head;
|
||||
do {
|
||||
if (!Fold(cx, elem, parser, inGenexpLambda))
|
||||
return false;
|
||||
|
||||
Truthiness t = Boolish(*elem);
|
||||
Truthiness t = Boolish(*elem, isCoalesceNode);
|
||||
|
||||
// If we don't know the constant-folded node's truthiness, we can't
|
||||
// reduce this node with its surroundings. Continue folding any
|
||||
|
|
@ -776,11 +786,16 @@ FoldAndOr(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& p
|
|||
continue;
|
||||
}
|
||||
|
||||
bool terminateEarly = (isOrNode && t == Truthy) ||
|
||||
(isAndNode && t == Falsy) ||
|
||||
(isCoalesceNode && t == Truthy);
|
||||
|
||||
// If the constant-folded node's truthiness will terminate the
|
||||
// condition -- `a || true || expr` or |b && false && expr| -- then
|
||||
// trailing nodes will never be evaluated. Truncate the list after
|
||||
// the known-truthiness node, as it's the overall result.
|
||||
if ((t == Truthy) == isOrNode) {
|
||||
// condition -- `a || true || expr` or `b && false && expr` or
|
||||
// `false ?? c ?? expr` -- then trailing nodes will never be
|
||||
// evaluated. Truncate the list after the known-truthiness node,
|
||||
// as it's the overall result.
|
||||
if (terminateEarly) {
|
||||
ParseNode* afterNext;
|
||||
for (ParseNode* next = (*elem)->pn_next; next; next = afterNext) {
|
||||
afterNext = next->pn_next;
|
||||
|
|
@ -795,8 +810,6 @@ FoldAndOr(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& p
|
|||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSERT((t == Truthy) == !isOrNode);
|
||||
|
||||
// We've encountered a vacuous node that'll never short- circuit
|
||||
// evaluation.
|
||||
if ((*elem)->pn_next) {
|
||||
|
|
@ -1738,9 +1751,10 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
|
|||
return Fold(cx, &expr, parser, inGenexpLambda);
|
||||
return true;
|
||||
|
||||
case PNK_COALESCE:
|
||||
case PNK_AND:
|
||||
case PNK_OR:
|
||||
return FoldAndOr(cx, pnp, parser, inGenexpLambda);
|
||||
return FoldLogical(cx, pnp, parser, inGenexpLambda);
|
||||
|
||||
case PNK_FUNCTION:
|
||||
return FoldFunction(cx, pn, parser, inGenexpLambda);
|
||||
|
|
|
|||
|
|
@ -663,6 +663,7 @@ class NameResolver
|
|||
break;
|
||||
|
||||
// Nodes with arbitrary-expression children.
|
||||
case PNK_COALESCE:
|
||||
case PNK_OR:
|
||||
case PNK_AND:
|
||||
case PNK_BITOR:
|
||||
|
|
|
|||
|
|
@ -426,6 +426,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
|
|||
}
|
||||
|
||||
// List nodes with all non-null children.
|
||||
case PNK_COALESCE:
|
||||
case PNK_OR:
|
||||
case PNK_AND:
|
||||
case PNK_BITOR:
|
||||
|
|
|
|||
|
|
@ -130,8 +130,12 @@ class ObjectBox;
|
|||
\
|
||||
/* \
|
||||
* Binary operators. \
|
||||
* These must be in the same order as TOK_OR and friends in TokenStream.h. \
|
||||
* These must be in the same order in several places: \
|
||||
* - the precedence table and JSOp code list in Parser.cpp \
|
||||
* - the binary operators in TokenKind.h \
|
||||
* - the first and last binary operator markers in ParseNode.h \
|
||||
*/ \
|
||||
F(COALESCE) \
|
||||
F(OR) \
|
||||
F(AND) \
|
||||
F(BITOR) \
|
||||
|
|
@ -189,7 +193,13 @@ enum ParseNodeKind
|
|||
FOR_EACH_PARSE_NODE_KIND(EMIT_ENUM)
|
||||
#undef EMIT_ENUM
|
||||
PNK_LIMIT, /* domain size */
|
||||
PNK_BINOP_FIRST = PNK_OR,
|
||||
/*
|
||||
* Binary operator markers.
|
||||
* These must be in the same order in several places:
|
||||
* - the precedence table and JSOp code list in Parser.cpp
|
||||
* - the binary operators in ParseNode.h and TokenKind.h
|
||||
*/
|
||||
PNK_BINOP_FIRST = PNK_COALESCE,
|
||||
PNK_BINOP_LAST = PNK_POW,
|
||||
PNK_ASSIGNMENT_START = PNK_ASSIGN,
|
||||
PNK_ASSIGNMENT_LAST = PNK_POWASSIGN
|
||||
|
|
@ -329,8 +339,9 @@ IsTypeofKind(ParseNodeKind kind)
|
|||
* PNK_POWASSIGN
|
||||
* PNK_CONDITIONAL ternary (cond ? trueExpr : falseExpr)
|
||||
* pn_kid1: cond, pn_kid2: then, pn_kid3: else
|
||||
* PNK_OR, list pn_head; list of pn_count subexpressions
|
||||
* PNK_AND, All of these operators are left-associative except (**).
|
||||
* PNK_COALESCE, list pn_head; list of pn_count subexpressions
|
||||
* PNK_OR, All of these operators are left-associative except (**).
|
||||
* PNK_AND
|
||||
* PNK_BITOR,
|
||||
* PNK_BITXOR,
|
||||
* PNK_BITAND,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "frontend/Parser.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h" // mozilla::ArrayLength
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
||||
#include <new>
|
||||
|
|
@ -46,6 +47,7 @@
|
|||
using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::Move;
|
||||
using mozilla::Nothing;
|
||||
|
|
@ -7844,7 +7846,13 @@ Parser<ParseHandler>::expr(InHandling inHandling, YieldHandling yieldHandling,
|
|||
return seq;
|
||||
}
|
||||
|
||||
/* These must be in the same order in several places:
|
||||
* - the precedence table in Parser.cpp
|
||||
* - the binary operators in ParseNode.h and TokenKind.h
|
||||
* - the first and last binary operator markers in ParseNode.h
|
||||
*/
|
||||
static const JSOp ParseNodeKindToJSOp[] = {
|
||||
JSOP_COALESCE,
|
||||
JSOP_OR,
|
||||
JSOP_AND,
|
||||
JSOP_BITOR,
|
||||
|
|
@ -7876,6 +7884,11 @@ BinaryOpParseNodeKindToJSOp(ParseNodeKind pnk)
|
|||
{
|
||||
MOZ_ASSERT(pnk >= PNK_BINOP_FIRST);
|
||||
MOZ_ASSERT(pnk <= PNK_BINOP_LAST);
|
||||
#ifdef DEBUG
|
||||
int jsopArraySize = ArrayLength(ParseNodeKindToJSOp);
|
||||
int parseNodeKindListSize = PNK_BINOP_LAST - PNK_BINOP_FIRST + 1;
|
||||
MOZ_ASSERT(jsopArraySize == parseNodeKindListSize);
|
||||
#endif
|
||||
return ParseNodeKindToJSOp[pnk - PNK_BINOP_FIRST];
|
||||
}
|
||||
|
||||
|
|
@ -7886,34 +7899,39 @@ BinaryOpTokenKindToParseNodeKind(TokenKind tok)
|
|||
return ParseNodeKind(PNK_BINOP_FIRST + (tok - TOK_BINOP_FIRST));
|
||||
}
|
||||
|
||||
/* These must be in the same order in several places:
|
||||
* - the JSOp code list in Parser.cpp
|
||||
* - the binary operators in ParseNode.h and TokenKind.h
|
||||
*/
|
||||
static const int PrecedenceTable[] = {
|
||||
1, /* PNK_OR */
|
||||
2, /* PNK_AND */
|
||||
3, /* PNK_BITOR */
|
||||
4, /* PNK_BITXOR */
|
||||
5, /* PNK_BITAND */
|
||||
6, /* PNK_STRICTEQ */
|
||||
6, /* PNK_EQ */
|
||||
6, /* PNK_STRICTNE */
|
||||
6, /* PNK_NE */
|
||||
7, /* PNK_LT */
|
||||
7, /* PNK_LE */
|
||||
7, /* PNK_GT */
|
||||
7, /* PNK_GE */
|
||||
7, /* PNK_INSTANCEOF */
|
||||
7, /* PNK_IN */
|
||||
8, /* PNK_LSH */
|
||||
8, /* PNK_RSH */
|
||||
8, /* PNK_URSH */
|
||||
9, /* PNK_ADD */
|
||||
9, /* PNK_SUB */
|
||||
10, /* PNK_STAR */
|
||||
10, /* PNK_DIV */
|
||||
10, /* PNK_MOD */
|
||||
11 /* PNK_POW */
|
||||
1, /* PNK_COALESCE */
|
||||
2, /* PNK_OR */
|
||||
3, /* PNK_AND */
|
||||
4, /* PNK_BITOR */
|
||||
5, /* PNK_BITXOR */
|
||||
6, /* PNK_BITAND */
|
||||
7, /* PNK_STRICTEQ */
|
||||
7, /* PNK_EQ */
|
||||
7, /* PNK_STRICTNE */
|
||||
7, /* PNK_NE */
|
||||
8, /* PNK_LT */
|
||||
8, /* PNK_LE */
|
||||
8, /* PNK_GT */
|
||||
8, /* PNK_GE */
|
||||
8, /* PNK_INSTANCEOF */
|
||||
8, /* PNK_IN */
|
||||
9, /* PNK_LSH */
|
||||
9, /* PNK_RSH */
|
||||
9, /* PNK_URSH */
|
||||
10, /* PNK_ADD */
|
||||
10, /* PNK_SUB */
|
||||
11, /* PNK_STAR */
|
||||
11, /* PNK_DIV */
|
||||
11, /* PNK_MOD */
|
||||
12 /* PNK_POW */
|
||||
};
|
||||
|
||||
static const int PRECEDENCE_CLASSES = 11;
|
||||
static const int PRECEDENCE_CLASSES = 12;
|
||||
|
||||
static int
|
||||
Precedence(ParseNodeKind pnk) {
|
||||
|
|
@ -7928,6 +7946,8 @@ Precedence(ParseNodeKind pnk) {
|
|||
return PrecedenceTable[pnk - PNK_BINOP_FIRST];
|
||||
}
|
||||
|
||||
enum class EnforcedParentheses : uint8_t { CoalesceExpr, AndOrExpr, None };
|
||||
|
||||
template <typename ParseHandler>
|
||||
MOZ_ALWAYS_INLINE typename ParseHandler::Node
|
||||
Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling,
|
||||
|
|
@ -7944,6 +7964,7 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling
|
|||
ParseNodeKind kindStack[PRECEDENCE_CLASSES];
|
||||
int depth = 0;
|
||||
Node pn;
|
||||
EnforcedParentheses unparenthesizedExpression = EnforcedParentheses::None;
|
||||
for (;;) {
|
||||
pn = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked);
|
||||
if (!pn)
|
||||
|
|
@ -7961,11 +7982,42 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling
|
|||
// pending expression error now.
|
||||
if (possibleError && !possibleError->checkForExpressionError())
|
||||
return null();
|
||||
// Report an error for unary expressions on the LHS of **.
|
||||
if (tok == TOK_POW && handler.isUnparenthesizedUnaryExpression(pn)) {
|
||||
error(JSMSG_BAD_POW_LEFTSIDE);
|
||||
return null();
|
||||
|
||||
switch (tok) {
|
||||
// Report an error for unary expressions on the LHS of **.
|
||||
case TOK_POW:
|
||||
if (handler.isUnparenthesizedUnaryExpression(pn)) {
|
||||
error(JSMSG_BAD_POW_LEFTSIDE);
|
||||
return null();
|
||||
}
|
||||
break;
|
||||
case TOK_OR:
|
||||
case TOK_AND:
|
||||
// Report an error if ?? is on the LHS of the expression.
|
||||
// Mixing other logical operators with the nullish coalescing
|
||||
// operator is disallowed unless one expression is parenthesized.
|
||||
if (unparenthesizedExpression == EnforcedParentheses::CoalesceExpr) {
|
||||
error(JSMSG_BAD_COALESCE_MIXING);
|
||||
return null();
|
||||
}
|
||||
// If we have not detected a mixing error at this point, record that
|
||||
// we have an unparenthesized expression, in case we have one later.
|
||||
unparenthesizedExpression = EnforcedParentheses::AndOrExpr;
|
||||
break;
|
||||
case TOK_COALESCE:
|
||||
if (unparenthesizedExpression == EnforcedParentheses::AndOrExpr) {
|
||||
error(JSMSG_BAD_COALESCE_MIXING);
|
||||
return null();
|
||||
}
|
||||
// If we have not detected a mixing error at this point, record that
|
||||
// we have an unparenthesized expression, in case we have one later.
|
||||
unparenthesizedExpression = EnforcedParentheses::CoalesceExpr;
|
||||
break;
|
||||
default:
|
||||
// Do nothing in other cases.
|
||||
break;
|
||||
}
|
||||
|
||||
pnk = BinaryOpTokenKindToParseNodeKind(tok);
|
||||
} else {
|
||||
tok = TOK_EOF;
|
||||
|
|
|
|||
|
|
@ -152,11 +152,15 @@
|
|||
* range-testing. \
|
||||
*/ \
|
||||
/* \
|
||||
* Binary operators tokens, TOK_OR thru TOK_POW. These must be in the same \
|
||||
* order as F(OR) and friends in FOR_EACH_PARSE_NODE_KIND in ParseNode.h. \
|
||||
* Binary operators tokens. \
|
||||
* These must be in the same order in several places: \
|
||||
* - the precedence table and JSOp code list in Parser.cpp \
|
||||
* - the binary operators in ParseNode.h \
|
||||
* - the first and last binary operator markers in ParseNode.h \
|
||||
*/ \
|
||||
macro(COALESCE, "'\?\?'") /* escapes to avoid trigraphs warning */ \
|
||||
range(BINOP_FIRST, COALESCE) \
|
||||
macro(OR, "'||'") /* logical or */ \
|
||||
range(BINOP_FIRST, OR) \
|
||||
macro(AND, "'&&'") /* logical and */ \
|
||||
macro(BITOR, "'|'") /* bitwise-or */ \
|
||||
macro(BITXOR, "'^'") /* bitwise-xor */ \
|
||||
|
|
@ -196,7 +200,7 @@
|
|||
macro(DIV, "'/'") \
|
||||
macro(MOD, "'%'") \
|
||||
macro(POW, "'**'") \
|
||||
range(BINOP_LAST, POW) \
|
||||
range(BINOP_LAST, POW) \
|
||||
\
|
||||
/* Unary operation tokens. */ \
|
||||
macro(TYPEOF, "keyword 'typeof'") \
|
||||
|
|
|
|||
|
|
@ -1260,8 +1260,8 @@ enum FirstCharKind {
|
|||
LastCharKind = Other
|
||||
};
|
||||
|
||||
// OneChar: 40, 41, 44, 58, 59, 63, 91, 93, 123, 125, 126:
|
||||
// '(', ')', ',', ':', ';', '?', '[', ']', '{', '}', '~'
|
||||
// OneChar: 40, 41, 44, 58, 59, 91, 93, 123, 125, 126:
|
||||
// '(', ')', ',', ':', ';', '[', ']', '{', '}', '~'
|
||||
// Ident: 36, 65..90, 95, 97..122: '$', 'A'..'Z', '_', 'a'..'z'
|
||||
// Dot: 46: '.'
|
||||
// Equals: 61: '='
|
||||
|
|
@ -1811,7 +1811,7 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
|
|||
tp->type = TOK_OPTCHAIN;
|
||||
}
|
||||
} else {
|
||||
tp->type = TOK_HOOK;
|
||||
tp->type = matchChar('?') ? TOK_COALESCE : TOK_HOOK;
|
||||
}
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -1252,6 +1252,25 @@ BaselineCompiler::emit_JSOP_IFNE()
|
|||
return emitTest(true);
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_COALESCE() {
|
||||
// COALESCE leaves the original value on the stack.
|
||||
frame.syncStack(0);
|
||||
|
||||
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
|
||||
|
||||
Label undefinedOrNull;
|
||||
|
||||
masm.branchTestUndefined(Assembler::Equal, R0, &undefinedOrNull);
|
||||
masm.branchTestNull(Assembler::Equal, R0, &undefinedOrNull);
|
||||
|
||||
jsbytecode* target = pc + GET_JUMP_OFFSET(pc);
|
||||
masm.jump(labelOf(target));
|
||||
|
||||
masm.bind(&undefinedOrNull);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emitAndOr(bool branchIfTrue)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ namespace jit {
|
|||
_(JSOP_GOTO) \
|
||||
_(JSOP_IFEQ) \
|
||||
_(JSOP_IFNE) \
|
||||
_(JSOP_COALESCE) \
|
||||
_(JSOP_AND) \
|
||||
_(JSOP_OR) \
|
||||
_(JSOP_NOT) \
|
||||
|
|
|
|||
|
|
@ -11517,6 +11517,24 @@ CodeGenerator::visitIsObjectAndBranch(LIsObjectAndBranch* ins)
|
|||
testObjectEmitBranch(Assembler::Equal, value, ins->ifTrue(), ins->ifFalse());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitIsNullOrUndefined(LIsNullOrUndefined* ins)
|
||||
{
|
||||
Register output = ToRegister(ins->output());
|
||||
ValueOperand value = ToValue(ins, LIsNullOrUndefined::Input);
|
||||
|
||||
Label isNotNull, done;
|
||||
masm.branchTestNull(Assembler::NotEqual, value, &isNotNull);
|
||||
|
||||
masm.move32(Imm32(1), output);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&isNotNull);
|
||||
masm.testUndefinedSet(Assembler::Equal, value, output);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::loadOutermostJSScript(Register reg)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -376,6 +376,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
void visitOutOfLineIsConstructor(OutOfLineIsConstructor* ool);
|
||||
void visitIsObject(LIsObject* lir);
|
||||
void visitIsObjectAndBranch(LIsObjectAndBranch* lir);
|
||||
void visitIsNullOrUndefined(LIsNullOrUndefined* ins);
|
||||
void visitHasClass(LHasClass* lir);
|
||||
void visitGuardToClass(LGuardToClass* lir);
|
||||
void visitWasmParameter(LWasmParameter* lir);
|
||||
|
|
|
|||
|
|
@ -276,10 +276,10 @@ IonBuilder::CFGState::IfElse(jsbytecode* trueEnd, jsbytecode* falseEnd, MTest* t
|
|||
}
|
||||
|
||||
IonBuilder::CFGState
|
||||
IonBuilder::CFGState::AndOr(jsbytecode* join, MBasicBlock* lhs)
|
||||
IonBuilder::CFGState::Logical(jsbytecode* join, MBasicBlock* lhs)
|
||||
{
|
||||
CFGState state;
|
||||
state.state = AND_OR;
|
||||
state.state = LOGICAL;
|
||||
state.stopAt = join;
|
||||
state.branch.ifFalse = lhs;
|
||||
state.branch.test = nullptr;
|
||||
|
|
@ -1737,9 +1737,10 @@ IonBuilder::inspectOpcode(JSOp op)
|
|||
case JSOP_TOSTRING:
|
||||
return jsop_tostring();
|
||||
|
||||
case JSOP_COALESCE:
|
||||
case JSOP_AND:
|
||||
case JSOP_OR:
|
||||
return jsop_andor(op);
|
||||
return jsop_logical(op);
|
||||
|
||||
case JSOP_DEFVAR:
|
||||
return jsop_defvar(GET_UINT32_INDEX(pc));
|
||||
|
|
@ -2345,8 +2346,8 @@ IonBuilder::processCfgEntry(CFGState& state)
|
|||
case CFGState::COND_SWITCH_BODY:
|
||||
return processCondSwitchBody(state);
|
||||
|
||||
case CFGState::AND_OR:
|
||||
return processAndOrEnd(state);
|
||||
case CFGState::LOGICAL:
|
||||
return processLogicalEnd(state);
|
||||
|
||||
case CFGState::LABEL:
|
||||
return processLabelEnd(state);
|
||||
|
|
@ -2948,7 +2949,7 @@ IonBuilder::processNextTableSwitchCase(CFGState& state)
|
|||
}
|
||||
|
||||
IonBuilder::ControlStatus
|
||||
IonBuilder::processAndOrEnd(CFGState& state)
|
||||
IonBuilder::processLogicalEnd(CFGState& state)
|
||||
{
|
||||
MOZ_ASSERT(current);
|
||||
MBasicBlock* lhs = state.branch.ifFalse;
|
||||
|
|
@ -4413,9 +4414,9 @@ IonBuilder::processCondSwitchBody(CFGState& state)
|
|||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_andor(JSOp op)
|
||||
IonBuilder::jsop_logical(JSOp op)
|
||||
{
|
||||
MOZ_ASSERT(op == JSOP_AND || op == JSOP_OR);
|
||||
MOZ_ASSERT(op == JSOP_AND || op == JSOP_OR || op == JSOP_COALESCE);
|
||||
|
||||
jsbytecode* rhsStart = pc + CodeSpec[op].length;
|
||||
jsbytecode* joinStart = pc + GetJumpOffset(pc);
|
||||
|
|
@ -4429,9 +4430,24 @@ IonBuilder::jsop_andor(JSOp op)
|
|||
if (!evalLhs || !evalRhs)
|
||||
return false;
|
||||
|
||||
MTest* test = (op == JSOP_AND)
|
||||
? newTest(lhs, evalRhs, evalLhs)
|
||||
: newTest(lhs, evalLhs, evalRhs);
|
||||
MTest* test;
|
||||
switch (op) {
|
||||
case JSOP_COALESCE: {
|
||||
MIsNullOrUndefined* isNullOrUndefined =
|
||||
MIsNullOrUndefined::New(alloc(), lhs);
|
||||
current->add(isNullOrUndefined);
|
||||
test = newTest(isNullOrUndefined, evalLhs, evalRhs);
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_AND:
|
||||
test = newTest(lhs, evalRhs, evalLhs);
|
||||
break;
|
||||
|
||||
case JSOP_OR:
|
||||
test = newTest(lhs, evalLhs, evalRhs);
|
||||
break;
|
||||
}
|
||||
current->end(test);
|
||||
|
||||
// Create the lhs block and specialize.
|
||||
|
|
@ -4442,7 +4458,7 @@ IonBuilder::jsop_andor(JSOp op)
|
|||
return false;
|
||||
|
||||
// Create the rhs block.
|
||||
if (!cfgStack_.append(CFGState::AndOr(joinStart, evalLhs)))
|
||||
if (!cfgStack_.append(CFGState::Logical(joinStart, evalLhs)))
|
||||
return false;
|
||||
|
||||
if (!setCurrentAndSpecializePhis(evalRhs))
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ class IonBuilder
|
|||
TABLE_SWITCH, // switch() { x }
|
||||
COND_SWITCH_CASE, // switch() { case X: ... }
|
||||
COND_SWITCH_BODY, // switch() { case ...: X }
|
||||
AND_OR, // && x, || x
|
||||
LOGICAL, // && x, || x, ?? x
|
||||
LABEL, // label: x
|
||||
TRY // try { x } catch(e) { }
|
||||
};
|
||||
|
|
@ -197,7 +197,7 @@ class IonBuilder
|
|||
|
||||
static CFGState If(jsbytecode* join, MTest* test);
|
||||
static CFGState IfElse(jsbytecode* trueEnd, jsbytecode* falseEnd, MTest* test);
|
||||
static CFGState AndOr(jsbytecode* join, MBasicBlock* lhs);
|
||||
static CFGState Logical(jsbytecode* join, MBasicBlock* lhs);
|
||||
static CFGState TableSwitch(jsbytecode* exitpc, MTableSwitch* ins);
|
||||
static CFGState CondSwitch(IonBuilder* builder, jsbytecode* exitpc, jsbytecode* defaultTarget);
|
||||
static CFGState Label(jsbytecode* exitpc);
|
||||
|
|
@ -257,7 +257,7 @@ class IonBuilder
|
|||
ControlStatus processCondSwitchBody(CFGState& state);
|
||||
ControlStatus processSwitchBreak(JSOp op);
|
||||
ControlStatus processSwitchEnd(DeferredEdge* breaks, jsbytecode* exitpc);
|
||||
ControlStatus processAndOrEnd(CFGState& state);
|
||||
ControlStatus processLogicalEnd(CFGState& state);
|
||||
ControlStatus processLabelEnd(CFGState& state);
|
||||
ControlStatus processTryEnd(CFGState& state);
|
||||
ControlStatus processReturn(JSOp op);
|
||||
|
|
@ -712,7 +712,7 @@ class IonBuilder
|
|||
MOZ_MUST_USE bool jsop_try();
|
||||
MOZ_MUST_USE bool jsop_label();
|
||||
MOZ_MUST_USE bool jsop_condswitch();
|
||||
MOZ_MUST_USE bool jsop_andor(JSOp op);
|
||||
MOZ_MUST_USE bool jsop_logical(JSOp op);
|
||||
MOZ_MUST_USE bool jsop_dup2();
|
||||
MOZ_MUST_USE bool jsop_loophead(jsbytecode* pc);
|
||||
MOZ_MUST_USE bool jsop_compare(JSOp op);
|
||||
|
|
|
|||
|
|
@ -4162,6 +4162,16 @@ LIRGenerator::visitIsObject(MIsObject* ins)
|
|||
define(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitIsNullOrUndefined(MIsNullOrUndefined* ins)
|
||||
{
|
||||
MDefinition* opd = ins->input();
|
||||
MOZ_ASSERT(opd->type() == MIRType::Value);
|
||||
LIsNullOrUndefined* lir =
|
||||
new(alloc()) LIsNullOrUndefined(useBoxAtStart(opd));
|
||||
define(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitHasClass(MHasClass* ins)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitIsCallable(MIsCallable* ins);
|
||||
void visitIsConstructor(MIsConstructor* ins);
|
||||
void visitIsObject(MIsObject* ins);
|
||||
void visitIsNullOrUndefined(MIsNullOrUndefined* ins);
|
||||
void visitHasClass(MHasClass* ins);
|
||||
void visitGuardToClass(MGuardToClass* ins);
|
||||
void visitWasmAddOffset(MWasmAddOffset* ins);
|
||||
|
|
|
|||
|
|
@ -13156,6 +13156,30 @@ class MIsObject
|
|||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
class MIsNullOrUndefined
|
||||
: public MUnaryInstruction,
|
||||
public BoxInputsPolicy::Data
|
||||
{
|
||||
explicit MIsNullOrUndefined(MDefinition* object)
|
||||
: MUnaryInstruction(object)
|
||||
{
|
||||
setResultType(MIRType::Boolean);
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(IsNullOrUndefined)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, object))
|
||||
|
||||
bool congruentTo(const MDefinition* ins) const override {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
class MHasClass
|
||||
: public MUnaryInstruction,
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ namespace jit {
|
|||
_(IsConstructor) \
|
||||
_(IsCallable) \
|
||||
_(IsObject) \
|
||||
_(IsNullOrUndefined) \
|
||||
_(HasClass) \
|
||||
_(GuardToClass) \
|
||||
_(CopySign) \
|
||||
|
|
|
|||
|
|
@ -7851,6 +7851,21 @@ class LIsObjectAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 0>
|
|||
}
|
||||
};
|
||||
|
||||
class LIsNullOrUndefined : public LInstructionHelper<1, BOX_PIECES, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(IsNullOrUndefined);
|
||||
static const size_t Input = 0;
|
||||
|
||||
explicit LIsNullOrUndefined(const LBoxAllocation& input) {
|
||||
setBoxOperand(Input, input);
|
||||
}
|
||||
|
||||
MIsNullOrUndefined* mir() const {
|
||||
return mir_->toIsNullOrUndefined();
|
||||
}
|
||||
};
|
||||
|
||||
class LHasClass : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -385,6 +385,7 @@
|
|||
_(IsConstructor) \
|
||||
_(IsObject) \
|
||||
_(IsObjectAndBranch) \
|
||||
_(IsNullOrUndefined) \
|
||||
_(HasClass) \
|
||||
_(GuardToClass) \
|
||||
_(RecompileCheck) \
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used
|
|||
MSG_DEF(JSMSG_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "await is only valid in async functions")
|
||||
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
|
||||
MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
|
||||
MSG_DEF(JSMSG_BAD_COALESCE_MIXING, 0, JSEXN_SYNTAXERR, "cannot use `??` unparenthesized within `||` and `&&` expressions")
|
||||
MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration")
|
||||
MSG_DEF(JSMSG_BAD_CONTINUE, 0, JSEXN_SYNTAXERR, "continue must be inside loop")
|
||||
MSG_DEF(JSMSG_BAD_DESTRUCT_ASS, 0, JSEXN_REFERENCEERR, "invalid destructuring assignment operator")
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ GetDefCount(JSScript* script, unsigned offset)
|
|||
* in the pushed array of stack values for type inference.
|
||||
*/
|
||||
switch (JSOp(*pc)) {
|
||||
case JSOP_COALESCE:
|
||||
case JSOP_OR:
|
||||
case JSOP_AND:
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,31 @@ assertExpr("foo[bar]", memExpr(ident("foo"), ident("bar")));
|
|||
assertExpr("foo['bar']", memExpr(ident("foo"), lit("bar")));
|
||||
assertExpr("foo[42]", memExpr(ident("foo"), lit(42)));
|
||||
|
||||
// optional member expressions
|
||||
assertExpr("foo?.bar", optExpr(optDotExpr(ident("foo"), ident("bar"))));
|
||||
assertExpr("foo?.bar.baz", optExpr(dotExpr(optDotExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("foo.bar?.baz", optExpr(optDotExpr(dotExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("foo?.bar?.baz", optExpr(optDotExpr(optDotExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("foo?.[bar].baz", optExpr(dotExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("foo.bar?.[baz]", optExpr(optMemExpr(dotExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("foo[bar]?.[baz]", optExpr(optMemExpr(memExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("foo?.[bar][baz]", optExpr(memExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("foo?.['bar']?.['baz']", optExpr(optMemExpr(optMemExpr(ident("foo"), lit("bar")), lit("baz"))));
|
||||
assertExpr("foo?.[bar]?.baz", optExpr(optDotExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
|
||||
// delete optional expressions
|
||||
assertExpr("\ndelete [] ?. [1]", delOptExpr(optMemExpr(arrExpr([]), lit(1))));
|
||||
assertExpr("delete foo?.bar", delOptExpr(optDotExpr(ident("foo"), ident("bar"))));
|
||||
assertExpr("delete foo?.bar.baz", delOptExpr(dotExpr(optDotExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("delete foo.bar?.baz", delOptExpr(optDotExpr(dotExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("delete foo?.bar?.baz", delOptExpr(optDotExpr(optDotExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("delete foo?.[bar].baz", delOptExpr(dotExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("delete foo.bar?.[baz]", delOptExpr(optMemExpr(dotExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("delete foo[bar]?.[baz]", delOptExpr(optMemExpr(memExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("delete foo?.[bar][baz]", delOptExpr(memExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
assertExpr("delete foo?.['bar']?.['baz']", delOptExpr(optMemExpr(optMemExpr(ident("foo"), lit("bar")), lit("baz"))));
|
||||
assertExpr("delete foo?.[bar]?.baz", delOptExpr(optDotExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz"))));
|
||||
|
||||
// function expressions
|
||||
assertExpr("(function(){})", funExpr(null, [], blockStmt([])));
|
||||
assertExpr("(function f() {})", funExpr(ident("f"), [], blockStmt([])));
|
||||
|
|
@ -86,6 +111,7 @@ assertExpr("(x &= y)", aExpr("&=", ident("x"), ident("y")));
|
|||
// Conditional expressions
|
||||
assertExpr("(x || y)", logExpr("||", 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("||", logExpr("||", logExpr("||", ident("w"), ident("x")), ident("y")), ident("z")))
|
||||
assertExpr("(x ? y : z)", condExpr(ident("x"), ident("y"), ident("z")));
|
||||
|
||||
|
|
@ -103,6 +129,15 @@ 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)]));
|
||||
|
||||
// Optional Call expressions
|
||||
assertExpr("(String?.())", optExpr(optCallExpr(ident("String"), [])));
|
||||
assertExpr("(String?.(42))", optExpr(optCallExpr(ident("String"), [lit(42)])));
|
||||
assertExpr("(String?.(1,2,3))", optExpr(optCallExpr(ident("String"), [lit(1),lit(2),lit(3)])));
|
||||
assertExpr("(String?.foo?.())", optExpr(optCallExpr(optDotExpr(ident("String"), ident("foo")), [])));
|
||||
assertExpr("(String.foo?.())", optExpr(optCallExpr(dotExpr(ident("String"), ident("foo")), [])));
|
||||
assertExpr("(String?.foo)()", callExpr(optExpr(optDotExpr(ident("String"), ident("foo"))), []));
|
||||
assertExpr("(String?.foo)?.()", optExpr(optCallExpr(optExpr(optDotExpr(ident("String"), ident("foo"))), [])));
|
||||
|
||||
// Array expressions
|
||||
assertExpr("[]", arrExpr([]));
|
||||
assertExpr("[1]", arrExpr([lit(1)]));
|
||||
|
|
|
|||
112
js/src/tests/non262/expressions/nullish-coalescing.js
Normal file
112
js/src/tests/non262/expressions/nullish-coalescing.js
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
var BUGNUMBER = 1566141;
|
||||
var summary = "Implement the Nullish Coalescing operator (??) proposal";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
// These tests are originally from webkit.
|
||||
// webkit specifics have been removed and a test for `document.all` has
|
||||
// been added.
|
||||
function shouldBe(actual, expected) {
|
||||
if (actual !== expected)
|
||||
throw new Error(`expected ${expected} but got ${actual}`);
|
||||
}
|
||||
|
||||
function shouldNotThrow(script) {
|
||||
eval(script);
|
||||
}
|
||||
|
||||
function shouldThrowSyntaxError(script) {
|
||||
let error;
|
||||
try {
|
||||
eval(script);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
if (!(error instanceof SyntaxError))
|
||||
throw new Error('Expected SyntaxError!');
|
||||
}
|
||||
|
||||
function testBasicCases() {
|
||||
shouldBe(undefined ?? 3, 3);
|
||||
shouldBe(null ?? 3, 3);
|
||||
shouldBe(true ?? 3, true);
|
||||
shouldBe(false ?? 3, false);
|
||||
shouldBe(0 ?? 3, 0);
|
||||
shouldBe(1 ?? 3, 1);
|
||||
shouldBe('' ?? 3, '');
|
||||
shouldBe('hi' ?? 3, 'hi');
|
||||
shouldBe(({} ?? 3) instanceof Object, true);
|
||||
shouldBe(({ x: 'hi' } ?? 3).x, 'hi');
|
||||
shouldBe(([] ?? 3) instanceof Array, true);
|
||||
shouldBe((['hi'] ?? 3)[0], 'hi');
|
||||
// test document.all, which has odd behavior
|
||||
//shouldBe(typeof(createIsHTMLDDA() ?? 3), "undefined");
|
||||
}
|
||||
|
||||
for (let i = 0; i < 1e5; i++)
|
||||
testBasicCases();
|
||||
|
||||
shouldBe(1 | null ?? 3, 1);
|
||||
shouldBe(1 ^ null ?? 3, 1);
|
||||
shouldBe(1 & null ?? 3, 0);
|
||||
shouldBe(3 == null ?? 3, false);
|
||||
shouldBe(3 != null ?? 3, true);
|
||||
shouldBe(3 === null ?? 3, false);
|
||||
shouldBe(3 !== null ?? 3, true);
|
||||
shouldBe(1 < null ?? 3, false);
|
||||
shouldBe(1 > null ?? 3, true);
|
||||
shouldBe(1 <= null ?? 3, false);
|
||||
shouldBe(1 >= null ?? 3, true);
|
||||
shouldBe(1 << null ?? 3, 1);
|
||||
shouldBe(1 >> null ?? 3, 1);
|
||||
shouldBe(1 >>> null ?? 3, 1);
|
||||
shouldBe(1 + null ?? 3, 1);
|
||||
shouldBe(1 - null ?? 3, 1);
|
||||
shouldBe(1 * null ?? 3, 0);
|
||||
shouldBe(1 / null ?? 3, Infinity);
|
||||
shouldBe(isNaN(1 % null ?? 3), true);
|
||||
shouldBe(1 ** null ?? 3, 1);
|
||||
shouldBe((void 0) ?? 3, 3);
|
||||
|
||||
const obj = {
|
||||
count: 0,
|
||||
get x() { this.count++; return 'x'; }
|
||||
};
|
||||
false ?? obj.x;
|
||||
shouldBe(obj.count, 0);
|
||||
null ?? obj.x;
|
||||
shouldBe(obj.count, 1);
|
||||
obj.x ?? obj.x;
|
||||
shouldBe(obj.count, 2);
|
||||
|
||||
shouldThrowSyntaxError('0 || 1 ?? 2');
|
||||
shouldThrowSyntaxError('0 && 1 ?? 2');
|
||||
shouldThrowSyntaxError('0 ?? 1 || 2');
|
||||
shouldThrowSyntaxError('0 ?? 1 && 2');
|
||||
shouldNotThrow('(0 || 1) ?? 2');
|
||||
shouldNotThrow('0 || (1 ?? 2)');
|
||||
shouldNotThrow('(0 && 1) ?? 2');
|
||||
shouldNotThrow('0 && (1 ?? 2)');
|
||||
shouldNotThrow('(0 ?? 1) || 2');
|
||||
shouldNotThrow('0 ?? (1 || 2)');
|
||||
shouldNotThrow('(0 ?? 1) && 2');
|
||||
shouldNotThrow('0 ?? (1 && 2)');
|
||||
|
||||
shouldNotThrow('0 || 1 && 2 | 3 ^ 4 & 5 == 6 != 7 === 8 !== 9 < 0 > 1 <= 2 >= 3 << 4 >> 5 >>> 6 + 7 - 8 * 9 / 0 % 1 ** 2');
|
||||
shouldThrowSyntaxError('0 || 1 && 2 | 3 ^ 4 & 5 == 6 != 7 === 8 !== 9 < 0 > 1 <= 2 >= 3 << 4 >> 5 >>> 6 + 7 - 8 * 9 / 0 % 1 ** 2 ?? 3');
|
||||
shouldThrowSyntaxError('3 ?? 2 ** 1 % 0 / 9 * 8 - 7 + 6 >>> 5 >> 4 << 3 >= 2 <= 1 > 0 < 9 !== 8 === 7 != 6 == 5 & 4 ^ 3 | 2 && 1 || 0');
|
||||
|
||||
shouldBe(null?.x ?? 3, 3);
|
||||
shouldBe(({})?.x ?? 3, 3);
|
||||
shouldBe(({ x: 0 })?.x ?? 3, 0);
|
||||
shouldBe(null?.() ?? 3, 3);
|
||||
shouldBe((() => 0)?.() ?? 3, 0);
|
||||
shouldBe(({ x: 0 })?.[null?.a ?? 'x'] ?? 3, 0);
|
||||
shouldBe((() => 0)?.(null?.a ?? 'x') ?? 3, 0);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Abrupt completions are also a Short circuit and prevent evaluation of the right-side expressions
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
function poison() {
|
||||
throw new Test262Error('poison handled');
|
||||
}
|
||||
|
||||
function morePoison() {
|
||||
throw 'poison!!!!';
|
||||
}
|
||||
|
||||
x = undefined;
|
||||
assert.throws(Test262Error, function() {
|
||||
undefined ?? poison() ?? morePoison();
|
||||
}, 'undefined ?? poison() ?? morePoison();');
|
||||
|
||||
x = undefined;
|
||||
assert.throws(Test262Error, function() {
|
||||
null ?? poison() ?? morePoison();
|
||||
}, 'null ?? poison() ?? morePoison();');
|
||||
|
||||
assert.throws(Test262Error, function() {
|
||||
poison() ?? morePoison();
|
||||
}, 'poison() ?? morePoison();');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Cannot immediately contain, or be contained within, an && or || operation.
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
features: [coalesce-expression]
|
||||
negative:
|
||||
phase: early
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
0 && 0 ?? true;
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Cannot immediately contain, or be contained within, an && or || operation.
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
features: [coalesce-expression]
|
||||
negative:
|
||||
phase: early
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
0 || 0 ?? true;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
If the CoalesceExpressionHead is undefined or null, follow return the right-side value.
|
||||
Otherwise, return the left-side value.
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
features: [coalesce-expression]
|
||||
negative:
|
||||
phase: early
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
0 ?? 0 && true;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// |reftest| error:SyntaxError
|
||||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
If the CoalesceExpressionHead is undefined or null, follow return the right-side value.
|
||||
Otherwise, return the left-side value.
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
features: [coalesce-expression]
|
||||
negative:
|
||||
phase: early
|
||||
type: SyntaxError
|
||||
---*/
|
||||
|
||||
0 ?? 0 || true;
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
CoalesceExpression is chainable with the LogicalANDExpression is any is covered.
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = undefined;
|
||||
x = (null ?? 41) && 42;
|
||||
assert.sameValue(x, 42, '(null ?? 41) && 42');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? (41 && 42);
|
||||
assert.sameValue(x, 42, 'null ?? (41 && 42)`');
|
||||
|
||||
x = undefined;
|
||||
x = (41 && 42) ?? null;
|
||||
assert.sameValue(x, 42, '(41 && 42) ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = 41 && (null ?? 42);
|
||||
assert.sameValue(x, 42, '41 && (null ?? 42)`');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
CoalesceExpression is chainable with the LogicalORExpression is any is covered.
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = undefined;
|
||||
x = (null ?? 42) || 43;
|
||||
assert.sameValue(x, 42, '(null ?? 42) || 43');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? (42 || 43);
|
||||
assert.sameValue(x, 42, 'null ?? (42 || 43)`');
|
||||
|
||||
x = undefined;
|
||||
x = (null || 42) ?? 43;
|
||||
assert.sameValue(x, 42, '(null || 42) ?? 43');
|
||||
|
||||
x = undefined;
|
||||
x = null || (42 ?? 43);
|
||||
assert.sameValue(x, 42, 'null || (42 ?? 43)`');
|
||||
|
||||
x = undefined;
|
||||
x = (42 || 43) ?? null;
|
||||
assert.sameValue(x, 42, '(42 || 43) ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = 42 || (null ?? 43);
|
||||
assert.sameValue(x, 42, '42 || (null ?? 43)');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
CoalesceExpression is chainable with the BitwiseANDExpression
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = null ?? 42 & 43;
|
||||
assert.sameValue(x, 42, 'null ?? 42 & 43');
|
||||
|
||||
x = undefined ?? 42 & 43;
|
||||
assert.sameValue(x, 42, 'null ?? 42 & 43');
|
||||
|
||||
x = false ?? 42 & 43;
|
||||
assert.sameValue(x, false, 'false ?? 42 & 43');
|
||||
|
||||
x = true ?? 42 & 43;
|
||||
assert.sameValue(x, true, 'true ?? 42 & 43');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
CoalesceExpression is chainable with the BitwiseORExpression
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = null ?? 1 | 42;
|
||||
assert.sameValue(x, 43, 'null ?? 1 | 42');
|
||||
|
||||
x = undefined ?? 1 | 42;
|
||||
assert.sameValue(x, 43, 'null ?? 1 | 42');
|
||||
|
||||
x = false ?? 1 | 42;
|
||||
assert.sameValue(x, false, 'false ?? 1 | 42');
|
||||
|
||||
x = true ?? 1 | 42;
|
||||
assert.sameValue(x, true, 'true ?? 1 | 42');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
CoalesceExpression is chainable with the BitwiseXORExpression
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = null ?? 1 ^ 42;
|
||||
assert.sameValue(x, 43, 'null ?? 1 ^ 42');
|
||||
|
||||
x = undefined ?? 1 ^ 42;
|
||||
assert.sameValue(x, 43, 'null ?? 1 ^ 42');
|
||||
|
||||
x = false ?? 1 ^ 42;
|
||||
assert.sameValue(x, false, 'false ?? 1 ^ 42');
|
||||
|
||||
x = true ?? 1 ^ 42;
|
||||
assert.sameValue(x, true, 'true ?? 1 ^ 42');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
If the CoalesceExpressionHead is undefined or null, follow return the right-side value.
|
||||
Otherwise, return the left-side value.
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = null ?? undefined ?? 42;
|
||||
assert.sameValue(x, 42, 'null ?? undefined ?? 42');
|
||||
|
||||
x = undefined ?? null ?? 42;
|
||||
assert.sameValue(x, 42, 'undefined ?? null ?? 42');
|
||||
|
||||
x = null ?? null ?? 42;
|
||||
assert.sameValue(x, 42, 'null ?? null ?? 42');
|
||||
|
||||
x = undefined ?? undefined ?? 42;
|
||||
assert.sameValue(x, 42, 'null ?? null ?? 42');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
If the CoalesceExpressionHead is null, follow return the right-side eval.
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = null ?? 42;
|
||||
assert.sameValue(x, 42, 'null ?? 42');
|
||||
|
||||
x = null ?? undefined;
|
||||
assert.sameValue(x, undefined, 'null ?? undefined');
|
||||
|
||||
x = null ?? null;
|
||||
assert.sameValue(x, null, 'null ?? null');
|
||||
|
||||
x = null ?? false;
|
||||
assert.sameValue(x, false, 'null ?? false');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
If the CoalesceExpressionHead is undefined, follow return the right-side eval.
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = undefined ?? 42;
|
||||
assert.sameValue(x, 42, 'undefined ?? 42');
|
||||
|
||||
x = undefined ?? undefined;
|
||||
assert.sameValue(x, undefined, 'undefined ?? undefined');
|
||||
|
||||
x = undefined ?? null;
|
||||
assert.sameValue(x, null, 'undefined ?? null');
|
||||
|
||||
x = undefined ?? false;
|
||||
assert.sameValue(x, false, 'undefined ?? false');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Short circuit if the CoalesceExpressionHead is not undefined or null (0)
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = undefined;
|
||||
x = 0 ?? 1;
|
||||
assert.sameValue(x, 0, '0 ?? 1');
|
||||
|
||||
x = undefined;
|
||||
x = 0 ?? null;
|
||||
assert.sameValue(x, 0, '0 ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = 0 ?? undefined;
|
||||
assert.sameValue(x, 0, '0 ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = 0 ?? null ?? undefined;
|
||||
assert.sameValue(x, 0, '0 ?? null ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = 0 ?? undefined ?? null;
|
||||
assert.sameValue(x, 0, '0 ?? undefined ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = 0 ?? null ?? null;
|
||||
assert.sameValue(x, 0, '0 ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = 0 ?? undefined ?? undefined;
|
||||
assert.sameValue(x, 0, '0 ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? 0 ?? null;
|
||||
assert.sameValue(x, 0, 'null ?? 0 ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? 0 ?? undefined;
|
||||
assert.sameValue(x, 0, 'null ?? 0 ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? 0 ?? null;
|
||||
assert.sameValue(x, 0, 'undefined ?? 0 ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? 0 ?? undefined;
|
||||
assert.sameValue(x, 0, 'undefined ?? 0 ?? undefined');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Short circuit if the CoalesceExpressionHead is not undefined or null (42)
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = undefined;
|
||||
x = 42 ?? 1;
|
||||
assert.sameValue(x, 42, '42 ?? 1');
|
||||
|
||||
x = undefined;
|
||||
x = 42 ?? null;
|
||||
assert.sameValue(x, 42, '42 ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = 42 ?? undefined;
|
||||
assert.sameValue(x, 42, '42 ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = 42 ?? null ?? undefined;
|
||||
assert.sameValue(x, 42, '42 ?? null ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = 42 ?? undefined ?? null;
|
||||
assert.sameValue(x, 42, '42 ?? undefined ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = 42 ?? null ?? null;
|
||||
assert.sameValue(x, 42, '42 ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = 42 ?? undefined ?? undefined;
|
||||
assert.sameValue(x, 42, '42 ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? 42 ?? null;
|
||||
assert.sameValue(x, 42, 'null ?? 42 ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? 42 ?? undefined;
|
||||
assert.sameValue(x, 42, 'null ?? 42 ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? 42 ?? null;
|
||||
assert.sameValue(x, 42, 'undefined ?? 42 ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? 42 ?? undefined;
|
||||
assert.sameValue(x, 42, 'undefined ?? 42 ?? undefined');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Short circuit if the CoalesceExpressionHead is not undefined or null (the empty string)
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
var str = '';
|
||||
|
||||
x = undefined;
|
||||
x = str ?? 1;
|
||||
assert.sameValue(x, str, 'str ?? 1');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? null;
|
||||
assert.sameValue(x, str, 'str ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? undefined;
|
||||
assert.sameValue(x, str, 'str ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? null ?? undefined;
|
||||
assert.sameValue(x, str, 'str ?? null ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? undefined ?? null;
|
||||
assert.sameValue(x, str, 'str ?? undefined ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? null ?? null;
|
||||
assert.sameValue(x, str, 'str ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? undefined ?? undefined;
|
||||
assert.sameValue(x, str, 'str ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? str ?? null;
|
||||
assert.sameValue(x, str, 'null ?? str ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? str ?? undefined;
|
||||
assert.sameValue(x, str, 'null ?? str ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? str ?? null;
|
||||
assert.sameValue(x, str, 'undefined ?? str ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? str ?? undefined;
|
||||
assert.sameValue(x, str, 'undefined ?? str ?? undefined');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Short circuit if the CoalesceExpressionHead is not undefined or null (false)
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = undefined;
|
||||
x = false ?? 1;
|
||||
assert.sameValue(x, false, 'false ?? 1');
|
||||
|
||||
x = undefined;
|
||||
x = false ?? null;
|
||||
assert.sameValue(x, false, 'false ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = false ?? undefined;
|
||||
assert.sameValue(x, false, 'false ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = false ?? null ?? undefined;
|
||||
assert.sameValue(x, false, 'false ?? null ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = false ?? undefined ?? null;
|
||||
assert.sameValue(x, false, 'false ?? undefined ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = false ?? null ?? null;
|
||||
assert.sameValue(x, false, 'false ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = false ?? undefined ?? undefined;
|
||||
assert.sameValue(x, false, 'false ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? false ?? null;
|
||||
assert.sameValue(x, false, 'null ?? false ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? false ?? undefined;
|
||||
assert.sameValue(x, false, 'null ?? false ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? false ?? null;
|
||||
assert.sameValue(x, false, 'undefined ?? false ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? false ?? undefined;
|
||||
assert.sameValue(x, false, 'undefined ?? false ?? undefined');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Short circuit if the CoalesceExpressionHead is not undefined or null (object)
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
var obj = {
|
||||
toString() {
|
||||
return null;
|
||||
},
|
||||
valueOf() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
x = undefined;
|
||||
x = obj ?? 1;
|
||||
assert.sameValue(x, obj, 'obj ?? 1');
|
||||
|
||||
x = undefined;
|
||||
x = obj ?? null;
|
||||
assert.sameValue(x, obj, 'obj ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = obj ?? undefined;
|
||||
assert.sameValue(x, obj, 'obj ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = obj ?? null ?? undefined;
|
||||
assert.sameValue(x, obj, 'obj ?? null ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = obj ?? undefined ?? null;
|
||||
assert.sameValue(x, obj, 'obj ?? undefined ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = obj ?? null ?? null;
|
||||
assert.sameValue(x, obj, 'obj ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = obj ?? undefined ?? undefined;
|
||||
assert.sameValue(x, obj, 'obj ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? obj ?? null;
|
||||
assert.sameValue(x, obj, 'null ?? obj ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? obj ?? undefined;
|
||||
assert.sameValue(x, obj, 'null ?? obj ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? obj ?? null;
|
||||
assert.sameValue(x, obj, 'undefined ?? obj ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? obj ?? undefined;
|
||||
assert.sameValue(x, obj, 'undefined ?? obj ?? undefined');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Short circuit if the CoalesceExpressionHead is not undefined or null (string)
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
var str = 'undefined';
|
||||
|
||||
x = undefined;
|
||||
x = str ?? 1;
|
||||
assert.sameValue(x, str, 'str ?? 1');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? null;
|
||||
assert.sameValue(x, str, 'str ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? undefined;
|
||||
assert.sameValue(x, str, 'str ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? null ?? undefined;
|
||||
assert.sameValue(x, str, 'str ?? null ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? undefined ?? null;
|
||||
assert.sameValue(x, str, 'str ?? undefined ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? null ?? null;
|
||||
assert.sameValue(x, str, 'str ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = str ?? undefined ?? undefined;
|
||||
assert.sameValue(x, str, 'str ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? str ?? null;
|
||||
assert.sameValue(x, str, 'null ?? str ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? str ?? undefined;
|
||||
assert.sameValue(x, str, 'null ?? str ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? str ?? null;
|
||||
assert.sameValue(x, str, 'undefined ?? str ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? str ?? undefined;
|
||||
assert.sameValue(x, str, 'undefined ?? str ?? undefined');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Short circuit if the CoalesceExpressionHead is not undefined or null (Symbol)
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
var s = Symbol();
|
||||
|
||||
x = undefined;
|
||||
x = s ?? 1;
|
||||
assert.sameValue(x, s, 's ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = s ?? null;
|
||||
assert.sameValue(x, s, 's ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = s ?? undefined;
|
||||
assert.sameValue(x, s, 's ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = s ?? null ?? undefined;
|
||||
assert.sameValue(x, s, 's ?? null ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = s ?? undefined ?? null;
|
||||
assert.sameValue(x, s, 's ?? undefined ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = s ?? null ?? null;
|
||||
assert.sameValue(x, s, 's ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = s ?? undefined ?? undefined;
|
||||
assert.sameValue(x, s, 's ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? s ?? null;
|
||||
assert.sameValue(x, s, 'null ?? s ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? s ?? undefined;
|
||||
assert.sameValue(x, s, 'null ?? s ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? s ?? null;
|
||||
assert.sameValue(x, s, 'undefined ?? s ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? s ?? undefined;
|
||||
assert.sameValue(x, s, 'undefined ?? s ?? undefined');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Short circuit if the CoalesceExpressionHead is not undefined or null (true)
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = undefined;
|
||||
x = true ?? 1;
|
||||
assert.sameValue(x, true, 'true ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = true ?? null;
|
||||
assert.sameValue(x, true, 'true ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = true ?? undefined;
|
||||
assert.sameValue(x, true, 'true ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = true ?? null ?? undefined;
|
||||
assert.sameValue(x, true, 'true ?? null ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = true ?? undefined ?? null;
|
||||
assert.sameValue(x, true, 'true ?? undefined ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = true ?? null ?? null;
|
||||
assert.sameValue(x, true, 'true ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = true ?? undefined ?? undefined;
|
||||
assert.sameValue(x, true, 'true ?? null ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? true ?? null;
|
||||
assert.sameValue(x, true, 'null ?? true ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? true ?? undefined;
|
||||
assert.sameValue(x, true, 'null ?? true ?? undefined');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? true ?? null;
|
||||
assert.sameValue(x, true, 'undefined ?? true ?? null');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? true ?? undefined;
|
||||
assert.sameValue(x, true, 'undefined ?? true ?? undefined');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
Short circuit can prevent evaluation of the right-side expressions
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
Runtime Semantics: Evaluation
|
||||
|
||||
CoalesceExpression:CoalesceExpressionHead??BitwiseORExpression
|
||||
|
||||
1. Let lref be the result of evaluating CoalesceExpressionHead.
|
||||
2. Let lval be ? GetValue(lref).
|
||||
3. If lval is undefined or null,
|
||||
a. Let rref be the result of evaluating BitwiseORExpression.
|
||||
b. Return ? GetValue(rref).
|
||||
4. Otherwise, return lval.
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
function poison() {
|
||||
throw new Test262Error('should not evaluate poison');
|
||||
}
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? 42 ?? undefined ?? poison();
|
||||
assert.sameValue(x, 42);
|
||||
|
||||
x = undefined;
|
||||
x = 42 ?? undefined ?? poison();
|
||||
assert.sameValue(x, 42);
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? 42 ?? poison();
|
||||
assert.sameValue(x, 42);
|
||||
|
||||
x = undefined;
|
||||
x = 42 ?? poison();
|
||||
assert.sameValue(x, 42);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// |reftest| skip -- tail-call-optimization is not supported
|
||||
'use strict';
|
||||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: Expression is a candidate for tail-call optimization.
|
||||
esid: sec-static-semantics-hascallintailposition
|
||||
info: |
|
||||
Expression Rules
|
||||
|
||||
CoalesceExpression : CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
1. Return HasCallInTailPosition of BitwiseORExpression with argument call.
|
||||
flags: [onlyStrict]
|
||||
features: [tail-call-optimization, coalesce-expression]
|
||||
includes: [tcoHelper.js]
|
||||
---*/
|
||||
|
||||
var callCount = 0;
|
||||
(function f(n) {
|
||||
if (n === 0) {
|
||||
callCount += 1
|
||||
return;
|
||||
}
|
||||
return null ?? f(n - 1);
|
||||
}($MAX_ITERATIONS));
|
||||
assert.sameValue(callCount, 1);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// |reftest| skip -- tail-call-optimization is not supported
|
||||
'use strict';
|
||||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: Expression is a candidate for tail-call optimization.
|
||||
esid: sec-static-semantics-hascallintailposition
|
||||
info: |
|
||||
Expression Rules
|
||||
|
||||
CoalesceExpression : CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
1. Return HasCallInTailPosition of BitwiseORExpression with argument call.
|
||||
flags: [onlyStrict]
|
||||
features: [tail-call-optimization, coalesce-expression]
|
||||
includes: [tcoHelper.js]
|
||||
---*/
|
||||
|
||||
var callCount = 0;
|
||||
(function f(n) {
|
||||
if (n === 0) {
|
||||
callCount += 1
|
||||
return;
|
||||
}
|
||||
return undefined ?? f(n - 1);
|
||||
}($MAX_ITERATIONS));
|
||||
assert.sameValue(callCount, 1);
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (C) 2019 Leo Balter. All rights reserved.
|
||||
// This code is governed by the BSD license found in the LICENSE file.
|
||||
|
||||
/*---
|
||||
description: >
|
||||
ShortCircuitExpression in the Conditional Expression (? :)
|
||||
esid: sec-conditional-operator
|
||||
info: |
|
||||
ShortCircuitExpression :
|
||||
LogicalORExpression
|
||||
CoalesceExpression
|
||||
|
||||
CoalesceExpression :
|
||||
CoalesceExpressionHead ?? BitwiseORExpression
|
||||
|
||||
CoalesceExpressionHead :
|
||||
CoalesceExpression
|
||||
BitwiseORExpression
|
||||
|
||||
ConditionalExpression :
|
||||
ShortCircuitExpression
|
||||
ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
|
||||
features: [coalesce-expression]
|
||||
---*/
|
||||
|
||||
var x;
|
||||
|
||||
x = undefined ?? true ? 0 : 42;
|
||||
assert.sameValue(x, 0, 'undefined ?? true ? 0 : 42');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? true ? 0 : 42;
|
||||
assert.sameValue(x, 0, 'null ?? true ? 0 : 42');
|
||||
|
||||
x = undefined;
|
||||
x = undefined ?? false ? 0 : 42;
|
||||
assert.sameValue(x, 42, 'undefined ?? false ? 0 : 42');
|
||||
|
||||
x = undefined;
|
||||
x = null ?? false ? 0 : 42;
|
||||
assert.sameValue(x, 42, 'null ?? false ? 0 : 42');
|
||||
|
||||
x = undefined;
|
||||
x = false ?? true ? 0 : 42;
|
||||
assert.sameValue(x, 42, 'false ?? true ? 0 : 42');
|
||||
|
||||
x = undefined;
|
||||
x = 0 ?? true ? 0 : 42;
|
||||
assert.sameValue(x, 42, '0 ?? true ? 0 : 42');
|
||||
|
||||
x = undefined;
|
||||
x = 1 ?? false ? 0 : 42;
|
||||
assert.sameValue(x, 0, '1 ?? false ? 0 : 42');
|
||||
|
||||
x = undefined;
|
||||
x = true ?? false ? 0 : 42;
|
||||
assert.sameValue(x, 0, 'true ?? false ? 0 : 42');
|
||||
|
||||
x = undefined;
|
||||
x = true ?? true ? 0 : 42;
|
||||
assert.sameValue(x, 0, 'true ?? true ? 0 : 42');
|
||||
|
||||
x = undefined;
|
||||
x = '' ?? true ? 0 : 42;
|
||||
assert.sameValue(x, 42, '"" ?? true ? 0 : 42');
|
||||
|
||||
x = undefined;
|
||||
x = Symbol() ?? false ? 0 : 42;
|
||||
assert.sameValue(x, 0, 'Symbol() ?? false ? 0 : 42');
|
||||
|
||||
x = undefined;
|
||||
x = {} ?? false ? 0 : 42;
|
||||
assert.sameValue(x, 0, 'object ?? false ? 0 : 42');
|
||||
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -2128,6 +2128,16 @@ CASE(JSOP_IFNE)
|
|||
}
|
||||
END_CASE(JSOP_IFNE)
|
||||
|
||||
CASE(JSOP_COALESCE)
|
||||
{
|
||||
MutableHandleValue res = REGS.stackHandleAt(-1);
|
||||
bool cond = !res.isNullOrUndefined();
|
||||
if (cond) {
|
||||
ADVANCE_AND_DISPATCH(GET_JUMP_OFFSET(REGS.pc));
|
||||
}
|
||||
}
|
||||
END_CASE(JSOP_COALESCE)
|
||||
|
||||
CASE(JSOP_OR)
|
||||
{
|
||||
bool cond = ToBoolean(REGS.stackHandleAt(-1));
|
||||
|
|
|
|||
|
|
@ -2315,7 +2315,7 @@
|
|||
* Operands:
|
||||
* Stack: =>
|
||||
*/ \
|
||||
macro(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 1, 0, 0, JOF_BYTE)\
|
||||
macro(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
/*
|
||||
* Like JSOP_CALL, but tells the function that the return value is ignored.
|
||||
* stack.
|
||||
|
|
@ -2325,14 +2325,22 @@
|
|||
* Stack: callee, this, args[0], ..., args[argc-1] => rval
|
||||
* nuses: (argc+2)
|
||||
*/ \
|
||||
macro(JSOP_CALL_IGNORES_RV, 231, "call-ignores-rv", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
|
||||
|
||||
macro(JSOP_CALL_IGNORES_RV, 231, "call-ignores-rv", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
|
||||
/*
|
||||
* If the value on top of the stack is not null or undefined, jumps to a 32-bit offset from the
|
||||
* current bytecode.
|
||||
*
|
||||
* Category: Statements
|
||||
* Type: Jumps
|
||||
* Operands: int32_t offset
|
||||
* Stack: cond => cond
|
||||
*/ \
|
||||
macro(JSOP_COALESCE, 232, "coalesce", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING)
|
||||
/*
|
||||
* In certain circumstances it may be useful to "pad out" the opcode space to
|
||||
* a power of two. Use this macro to do so.
|
||||
*/
|
||||
#define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
|
||||
macro(232) \
|
||||
macro(233) \
|
||||
macro(234) \
|
||||
macro(235) \
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Due to duplicate file names, we compile libavutil/x86 in its own
|
||||
# Due to duplicate file names, we compile libavcodec/x86 in its own
|
||||
# moz.build file.
|
||||
if CONFIG['FFVPX_ASFLAGS']:
|
||||
DIRS += ['x86']
|
||||
|
|
@ -160,6 +160,9 @@ SOURCES += [
|
|||
SYMBOLS_FILE = 'avcodec.symbols'
|
||||
NO_VISIBILITY_FLAGS = True
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-attributes']
|
||||
|
||||
# GCC 10 defaults -fno-common, we don't care to solve this "properly" yet
|
||||
# so use GCC < 10 behavior.
|
||||
if CONFIG['GNU_CC'] and CONFIG['CC_VERSION'] >= '10.0.0':
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue