in AjaxMinDll/JavaScript/jsparser.cs [3489:3670]
private AstNode ParseUnaryExpression(out bool isLeftHandSideExpr, bool isMinus)
{
isLeftHandSideExpr = false;
bool dummy = false;
Context exprCtx = null;
AstNode expr = null;
TryItAgain:
AstNode ast = null;
var opToken = m_currentToken.Token;
switch (opToken)
{
case JSToken.RestSpread:
// technically, we don't want rest operators ANYWHERE. But we need to handle them
// here specifically for formal parameter lists for arrow functions.
// TODO: we want to error if we aren't immediately preceeded by a comma operator,
// and if after parsing the next unary expression, we're aren't at a closing parenthesis.
ParsedVersion = ScriptVersion.EcmaScript6;
goto case JSToken.Void;
case JSToken.Void:
case JSToken.TypeOf:
case JSToken.Plus:
case JSToken.Minus:
case JSToken.BitwiseNot:
case JSToken.LogicalNot:
case JSToken.Delete:
case JSToken.Increment:
case JSToken.Decrement:
// normal unary operators all follow the same pattern
exprCtx = m_currentToken.Clone();
GetNextToken();
expr = ParseUnaryExpression(out dummy, false);
ast = new UnaryOperator(exprCtx.CombineWith(expr.Context))
{
Operand = expr,
OperatorContext = exprCtx,
OperatorToken = opToken
};
break;
case JSToken.ConditionalCommentStart:
// skip past the start to the next token
exprCtx = m_currentToken.Clone();
GetNextToken();
if (m_currentToken.Is(JSToken.ConditionalCommentEnd))
{
// empty conditional-compilation comment -- ignore
GetNextToken();
goto TryItAgain;
}
else if (m_currentToken.Is(JSToken.ConditionalCompilationOn))
{
// /*@cc_on -- check for @IDENT@*/ or !@*/
GetNextToken();
if (m_currentToken.Is(JSToken.ConditionalCompilationVariable))
{
// /*@cc_on@IDENT -- check for @*/
ast = new ConstantWrapperPP(m_currentToken.Clone())
{
VarName = m_currentToken.Code,
ForceComments = true
};
GetNextToken();
if (m_currentToken.Is(JSToken.ConditionalCommentEnd))
{
// skip the close and keep going
GetNextToken();
}
else
{
// too complicated
CCTooComplicated(null);
goto TryItAgain;
}
}
else if (m_currentToken.Is(JSToken.LogicalNot))
{
// /*@cc_on! -- check for @*/
var operatorContext = m_currentToken.Clone();
GetNextToken();
if (m_currentToken.Is(JSToken.ConditionalCommentEnd))
{
// we have /*@cc_on!@*/
GetNextToken();
expr = ParseUnaryExpression(out dummy, false);
exprCtx.UpdateWith(expr.Context);
var unary = new UnaryOperator(exprCtx)
{
Operand = expr,
OperatorContext = operatorContext,
OperatorToken = JSToken.LogicalNot
};
unary.OperatorInConditionalCompilationComment = true;
unary.ConditionalCommentContainsOn = true;
ast = unary;
}
else
{
// too complicated
CCTooComplicated(null);
goto TryItAgain;
}
}
else
{
// too complicated
CCTooComplicated(null);
goto TryItAgain;
}
}
else if (m_currentToken.Is(JSToken.LogicalNot))
{
// /*@! -- check for @*/
var operatorContext = m_currentToken.Clone();
GetNextToken();
if (m_currentToken.Is(JSToken.ConditionalCommentEnd))
{
// we have /*@!@*/
GetNextToken();
expr = ParseUnaryExpression(out dummy, false);
exprCtx.UpdateWith(expr.Context);
var unary = new UnaryOperator(exprCtx)
{
Operand = expr,
OperatorContext = operatorContext,
OperatorToken = JSToken.LogicalNot
};
unary.OperatorInConditionalCompilationComment = true;
ast = unary;
}
else
{
// too complicated
CCTooComplicated(null);
goto TryItAgain;
}
}
else if (m_currentToken.Is(JSToken.ConditionalCompilationVariable))
{
// @IDENT -- check for @*/
ast = new ConstantWrapperPP(m_currentToken.Clone())
{
VarName = m_currentToken.Code,
ForceComments = true
};
GetNextToken();
if (m_currentToken.Is(JSToken.ConditionalCommentEnd))
{
// skip the close and keep going
GetNextToken();
}
else
{
// too complicated
CCTooComplicated(null);
goto TryItAgain;
}
}
else
{
// we ONLY support /*@id@*/ or /*@cc_on@id@*/ or /*@!@*/ or /*@cc_on!@*/ in expressions right now.
// throw an error, skip to the end of the comment, then ignore it and start
// looking for the next token.
CCTooComplicated(null);
goto TryItAgain;
}
break;
default:
ast = ParseLeftHandSideExpression(isMinus);
ast = ParsePostfixExpression(ast, out isLeftHandSideExpr);
break;
}
return ast;
}