/******************************************************************************* * Copyright (c) 2013, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package dtool.parser; import static melnorme.utilbox.core.Assert.AssertNamespace.assertFail; import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull; import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue; import static melnorme.utilbox.core.Assert.AssertNamespace.assertUnreachable; import java.util.ArrayList; import dtool.ast.declarations.DeclBlock; import dtool.ast.declarations.StaticIfExpIs; import dtool.ast.declarations.StaticIfExpIs.StaticIfExpIsDefUnit; import dtool.ast.definitions.CStyleRootRef; import dtool.ast.definitions.IFunctionAttribute; import dtool.ast.definitions.IFunctionParameter; import dtool.ast.definitions.ITemplateParameter; import dtool.ast.definitions.Symbol; import dtool.ast.expressions.ExpArrayLength; import dtool.ast.expressions.ExpAssert; import dtool.ast.expressions.ExpCall; import dtool.ast.expressions.ExpCast; import dtool.ast.expressions.ExpCastQual; import dtool.ast.expressions.ExpCastQual.CastQualifiers; import dtool.ast.expressions.ExpConditional; import dtool.ast.expressions.ExpFunctionLiteral; import dtool.ast.expressions.ExpImportString; import dtool.ast.expressions.ExpIndex; import dtool.ast.expressions.ExpInfix; import dtool.ast.expressions.ExpInfix.InfixOpType; import dtool.ast.expressions.ExpIs; import dtool.ast.expressions.ExpIs.ExpIsSpecialization; import dtool.ast.expressions.ExpLiteralArray; import dtool.ast.expressions.ExpLiteralBool; import dtool.ast.expressions.ExpLiteralChar; import dtool.ast.expressions.ExpLiteralFloat; import dtool.ast.expressions.ExpLiteralInteger; import dtool.ast.expressions.ExpLiteralMapArray; import dtool.ast.expressions.ExpLiteralMapArray.MapArrayLiteralKeyValue; import dtool.ast.expressions.ExpLiteralString; import dtool.ast.expressions.ExpMixinString; import dtool.ast.expressions.ExpNew; import dtool.ast.expressions.ExpNewAnonClass; import dtool.ast.expressions.ExpNull; import dtool.ast.expressions.ExpParentheses; import dtool.ast.expressions.ExpPostfixOperator; import dtool.ast.expressions.ExpPostfixOperator.PostfixOpType; import dtool.ast.expressions.ExpPrefix; import dtool.ast.expressions.ExpPrefix.EPrefixOpType; import dtool.ast.expressions.ExpReference; import dtool.ast.expressions.ExpSimpleLambda; import dtool.ast.expressions.ExpSimpleLambda.SimpleLambdaDefUnit; import dtool.ast.expressions.ExpSuper; import dtool.ast.expressions.ExpThis; import dtool.ast.expressions.ExpTraits; import dtool.ast.expressions.ExpTypeId; import dtool.ast.expressions.Expression; import dtool.ast.expressions.MissingExpression; import dtool.ast.expressions.MissingParenthesesExpression; import dtool.ast.expressions.Resolvable; import dtool.ast.references.IQualifierNode; import dtool.ast.references.ITemplateRefNode; import dtool.ast.references.RefIdentifier; import dtool.ast.references.RefIndexing; import dtool.ast.references.RefModuleQualified; import dtool.ast.references.RefPrimitive; import dtool.ast.references.RefQualified; import dtool.ast.references.RefSlice; import dtool.ast.references.RefTemplateInstance; import dtool.ast.references.RefTypeDynArray; import dtool.ast.references.RefTypeModifier; import dtool.ast.references.RefTypeModifier.TypeModifierKinds; import dtool.ast.references.RefTypePointer; import dtool.ast.references.RefTypeof; import dtool.ast.references.Reference; import dtool.ast.statements.IFunctionBody; import dtool.parser.DeeParser_Parameters.DeeParser_RuleParameters; import dtool.parser.DeeParser_Parameters.TplOrFnMode; import dtool.parser.common.BaseLexElement; import dtool.parser.common.IToken; import dtool.parser.common.LexElement; import melnorme.lang.tooling.ast.ParserErrorTypes; import melnorme.lang.tooling.ast.SourceRange; import melnorme.lang.tooling.ast.util.NodeVector; import melnorme.lang.tooling.common.ParserError; import melnorme.utilbox.concurrency.OperationCancellation; import melnorme.utilbox.misc.ArrayUtil; public abstract class DeeParser_RefOrExp extends DeeParser_Common { /* -------------------- reference parsing --------------------- */ public static final ParseRuleDescription RULE_REFERENCE = new ParseRuleDescription("Reference", "Reference"); public static final ParseRuleDescription RULE_TPL_SINGLE_ARG = new ParseRuleDescription("TplSingleArg", "TemplateSingleArgument"); public NodeResult<Reference> parseTypeReference() throws OperationCancellation { return parseTypeReference_start(RefParseRestrictions.PARSE_ANY); } public NodeResult<Reference> parseTypeReference(boolean createMissing, boolean reportMissingError) throws OperationCancellation { return parseTypeReference(createMissing, reportMissingError, false); } public NodeResult<Reference> parseTypeReference(boolean createMissing, boolean reportMissingError, boolean brokenIfMissing) throws OperationCancellation { NodeResult<Reference> typeRef = parseTypeReference(); if(isNull(typeRef) && createMissing) { return result(brokenIfMissing, parseMissingTypeReference(reportMissingError)); } return typeRef; } public NodeResult<Reference> parseTypeReference_ToMissing() throws OperationCancellation { return parseTypeReference(true, true); } public NodeResult<Reference> parseTypeReference_ToMissing(boolean brokenIfMissing) throws OperationCancellation { return parseTypeReference(true, true, brokenIfMissing); } public Reference parseMissingTypeReference(boolean reportMissingError) throws OperationCancellation { ParseRuleDescription expectedRule = reportMissingError ? RULE_REFERENCE : null; return parseMissingTypeReference(expectedRule); } public Reference parseMissingTypeReference(ParseRuleDescription expectedRule) throws OperationCancellation { SourceRange sourceRange = consumeSubChannelTokensNoError().getSourceRange(); ParserError error = expectedRule != null ? createErrorExpectedRule(expectedRule) : null; return createMissingTypeReferenceNode(sourceRange, error); } public Reference createMissingTypeReferenceNode(SourceRange sourceRange, ParserError error) throws OperationCancellation { RefIdentifier refMissing = new RefIdentifier(null); refMissing.setSourceRange(sourceRange); assertTrue(refMissing.isMissing()); return conclude(error, refMissing); } public static enum RefParseRestrictions { PARSE_ANY, EXP_ONLY, TEMPLATE_ONLY, ; public boolean templateOnly() { return this == TEMPLATE_ONLY; } public boolean canParsePointer() { return this == PARSE_ANY; } public boolean canParseBracketRef() { return this == PARSE_ANY; } public boolean canParseFunctionTypes() { return this == PARSE_ANY; } } public NodeResult<Reference> parseTypeReference_start(RefParseRestrictions refRestrictions) throws OperationCancellation { DeeTokens lookAhead = lookAhead(); NodeResult<Reference> result = parseTypeReference_start_do(refRestrictions); assertTrue(canParseTypeReferenceStart(lookAhead) == (result.node != null)); return result; } protected NodeResult<Reference> parseTypeReference_start_do(RefParseRestrictions refRestrictions) throws OperationCancellation { NodeResult<? extends Reference> refParseResult; TypeModifierKinds typeModifier = determineTypeModifier(lookAhead()); if(typeModifier != null) { refParseResult = parseRefTypeModifier_start(typeModifier); } else { switch (lookAhead().getGroupingToken()) { case IDENTIFIER: return parseTypeReference_withLeftReference(parseRefIdentifier(), refRestrictions); case GROUP_PRIMITIVE_KW: return parseTypeReference_withLeftReference(parseRefPrimitive_start(lookAhead()), refRestrictions); case DOT: refParseResult = parseRefModuleQualified(); break; case KW_TYPEOF: refParseResult = parseRefTypeof(); break; default: return nullResult(); } } if(refParseResult.ruleBroken) return refParseResult.<Reference>upcastTypeParam(); return parseTypeReference_withLeftReference(refParseResult.node, refRestrictions); } protected static boolean canParseTypeReferenceStart(DeeTokens lookAhead) { TypeModifierKinds typeModifier = determineTypeModifier(lookAhead); if(typeModifier != null) { return true; } else { switch (lookAhead.getGroupingToken()) { case IDENTIFIER: case GROUP_PRIMITIVE_KW: case DOT: case KW_TYPEOF: return true; default: return false; } } } public static TypeModifierKinds determineTypeModifier(DeeTokens tokenType) { switch (tokenType) { case KW_CONST: return TypeModifierKinds.CONST; case KW_IMMUTABLE: return TypeModifierKinds.IMMUTABLE; case KW_SHARED: return TypeModifierKinds.SHARED; case KW_INOUT: return TypeModifierKinds.INOUT; case KW___VECTOR: return TypeModifierKinds.VECTOR; default: return null; } } protected static boolean isTypeModifier(DeeTokens tokenType) { return determineTypeModifier(tokenType) != null; } /** Note: consider interaction with {@link #determineTypeModifier(DeeTokens)} */ protected static boolean isImmutabilitySpecifier(DeeTokens tokenType) { switch (tokenType) { case KW_CONST: case KW_IMMUTABLE: case KW_SHARED: case KW_INOUT: return true; default: return false; } } public RefIdentifier attemptParseRefIdentifier() throws OperationCancellation { if(lookAhead() != DeeTokens.IDENTIFIER) { return null; } return parseRefIdentifier(); } public RefIdentifier parseRefIdentifier() throws OperationCancellation { BaseLexElement id = consumeExpectedContentToken(DeeTokens.IDENTIFIER); return conclude(id.getMissingError(), srEffective(id, new RefIdentifier(idTokenToString(id)))); } protected RefPrimitive parseRefPrimitive_start(DeeTokens primitiveType) throws OperationCancellation { LexElement primitive = consumeLookAhead(primitiveType); return conclude(srOf(primitive, new RefPrimitive(primitive))); } public NodeResult<RefModuleQualified> parseRefModuleQualified() throws OperationCancellation { if(!tryConsume(DeeTokens.DOT)) return nullResult(); int nodeStart = lastLexElement().getStartPos(); RefIdentifier id = parseRefIdentifier(); return resultConclude(id.isMissing(), srToPosition(nodeStart, new RefModuleQualified(id))); } public NodeResult<RefTypeof> parseRefTypeof() throws OperationCancellation { if(!tryConsume(DeeTokens.KW_TYPEOF)) return null; ParseHelper parse = new ParseHelper(); Expression exp = null; parsing: { if(parse.consumeRequired(DeeTokens.OPEN_PARENS).ruleBroken) break parsing; if(tryConsume(DeeTokens.KW_RETURN)) { exp = conclude(srOf(lastLexElement(), new RefTypeof.ExpRefReturn())); } else { exp = parseExpression_toMissing(); } parse.consumeRequired(DeeTokens.CLOSE_PARENS); } return parse.resultConclude(new RefTypeof(exp)); } protected NodeResult<RefTypeModifier> parseRefTypeModifier_start(TypeModifierKinds modKind) throws OperationCancellation { assertTrue(lookAhead().sourceValue.equals(modKind.sourceValue)); consumeLookAhead(); ParseHelper parse = new ParseHelper(); Reference ref = null; boolean hasParens = false; if(parse.consumeOptional(DeeTokens.OPEN_PARENS)) { ref = parseTypeReference_ToMissing().node; parse.consumeRequired(DeeTokens.CLOSE_PARENS); hasParens = true; } else { if(modKind == TypeModifierKinds.VECTOR) { parse.consumeRequired(DeeTokens.OPEN_PARENS); } else { ref = parse.checkResult(parseTypeReference_ToMissing(true)); } } return parse.resultConclude(new RefTypeModifier(modKind, ref, hasParens)); } protected NodeResult<Reference> parseTypeReference_withLeftReference(Reference leftRef, RefParseRestrictions refRestrictions) throws OperationCancellation { assertNotNull(leftRef); ParseHelper parse = new ParseHelper(leftRef.getStartPos()); if(isTemplateInstanceLookahead() && isValidTemplateReferenceSyntax(leftRef)){ // template instance consumeLookAhead(); ITemplateRefNode tplRef = (ITemplateRefNode) leftRef; NodeVector<Resolvable> tplArgs = null; Resolvable singleArg = null; if(tryConsume(DeeTokens.OPEN_PARENS)) { tplArgs = parseTypeOrExpArgumentList(parse, DeeTokens.COMMA, DeeTokens.CLOSE_PARENS); } else { if(leftRef instanceof RefTemplateInstance) { RefTemplateInstance refTplInstance = (RefTemplateInstance) leftRef; if(refTplInstance.isSingleArgSyntax()) { parse.storeError(createError(ParserErrorTypes.NO_CHAINED_TPL_SINGLE_ARG, refTplInstance.getSourceRange(), null)); } } if(lookAhead().getGroupingToken() == DeeTokens.GROUP_PRIMITIVE_KW) { singleArg = parseRefPrimitive_start(lookAhead()); } else if(lookAhead() == DeeTokens.IDENTIFIER) { singleArg = parseRefIdentifier(); } else { singleArg = nullExpToParseMissing(parseSimpleLiteral(), RULE_TPL_SINGLE_ARG); } } leftRef = parse.conclude(new RefTemplateInstance(tplRef, singleArg, tplArgs)); } else if(refRestrictions.templateOnly()) { return result(false, leftRef); } else if(lookAhead() == DeeTokens.DOT && leftRef instanceof IQualifierNode) { if(lookAhead(1) == DeeTokens.KW_NEW && refRestrictions == RefParseRestrictions.EXP_ONLY) { return result(false, leftRef); } IQualifierNode qualifier = (IQualifierNode) leftRef; assertTrue(!RefQualified.isExpressionQualifier(qualifier)); leftRef = parseRefQualified(parse, qualifier); } else if(refRestrictions.canParsePointer() && tryConsume(DeeTokens.STAR)) { leftRef = conclude(srToPosition(leftRef, new RefTypePointer(leftRef))); } else if(refRestrictions.canParseBracketRef() && lookAhead() == DeeTokens.OPEN_BRACKET) { leftRef = parseBracketReference(leftRef, parse); } else if(refRestrictions.canParseFunctionTypes() && (tryConsume(DeeTokens.KW_FUNCTION) || tryConsume(DeeTokens.KW_DELEGATE))) { leftRef = parse.checkResult(thisParser().parseRefTypeFunction_afterReturnType(leftRef)); } else { return result(false, leftRef); } if(parse.ruleBroken) return result(true, leftRef); return parseTypeReference_withLeftReference(leftRef, refRestrictions); } public Reference parseRefQualified(ParseHelper parse, IQualifierNode qualifier) throws OperationCancellation { LexElement dotToken = consumeLookAhead(DeeTokens.DOT); RefIdentifier qualifiedId = parseRefIdentifier(); parse.setRuleBroken(qualifiedId.isMissing()); return parse.conclude(new RefQualified(qualifier, dotToken.getStartPos(), qualifiedId)); } public Reference parseBracketReference(Reference leftRef, ParseHelper parse) throws OperationCancellation { consumeLookAhead(DeeTokens.OPEN_BRACKET); TypeOrExpResult argTypeOrExp = parseTypeOrExpression(InfixOpType.ASSIGN); if(lookAhead() == DeeTokens.DOUBLE_DOT) { Expression startIndex = nullExpToParseMissing(argTypeOrExp.toExpression().node); consumeLookAhead(DeeTokens.DOUBLE_DOT); Expression endIndex = parseAssignExpression_toMissing(); parse.consumeRequired(DeeTokens.CLOSE_BRACKET); return parse.conclude(new RefSlice(leftRef, startIndex, endIndex)); } parse.consumeRequired(DeeTokens.CLOSE_BRACKET); Resolvable resolvable = argTypeOrExp.toFinalResult(true).node; if(resolvable == null) { return parse.conclude(new RefTypeDynArray(leftRef)); } else { return parse.conclude(new RefIndexing(leftRef, resolvable)); } } public boolean isTemplateInstanceLookahead() { return lookAhead() == DeeTokens.NOT && !(lookAhead(1) == DeeTokens.KW_IN || lookAhead(1) == DeeTokens.KW_IS); } public boolean isValidTemplateReferenceSyntax(Reference leftRef) { return leftRef instanceof ITemplateRefNode; } public Reference parseCStyleSuffix(ParseHelper parse) throws OperationCancellation { if(lookAhead() != DeeTokens.OPEN_BRACKET) { parse.requireBrokenCheck(); return null; } CStyleRootRef cstyleRootRef = conclude(srAt(lookAheadElement().getStartPos()), new CStyleRootRef()); NodeResult<Reference> cstyleDeclaratorSuffix = parseCStyleDeclaratorSuffix(cstyleRootRef); parse.requireBrokenCheck(); return parse.checkResult(cstyleDeclaratorSuffix); } protected NodeResult<Reference> parseCStyleDeclaratorSuffix(Reference leftRef) throws OperationCancellation { if(lookAhead() != DeeTokens.OPEN_BRACKET) { return result(false, leftRef); } ParseHelper parse = new ParseHelper(leftRef.getStartPos()); leftRef = parseBracketReference(leftRef, parse); if(parse.ruleBroken) return result(true, leftRef); return parseCStyleDeclaratorSuffix(leftRef); } /* --------------------- EXPRESSIONS --------------------- */ public static final ParseRuleDescription RULE_EXPRESSION = new ParseRuleDescription("Expression", "Expression"); public static final ParseRuleDescription RULE_TYPE_OR_EXP = new ParseRuleDescription("ToE", "TypeRerefence or Expression"); public static final InfixOpType ANY_OPERATOR = InfixOpType.COMMA; public final NodeResult<Expression> parseExpression() throws OperationCancellation { return parseExpression(ANY_OPERATOR); } public final NodeResult<Expression> parseExpression_toMissing(boolean breakOnMissing, ParseRuleDescription expectedRule) throws OperationCancellation { return nullExpToParseMissing(parseExpression(), breakOnMissing, expectedRule); } public final Expression parseExpression_toMissing() throws OperationCancellation { return nullExpToParseMissing(parseExpression().node); } public final NodeResult<Expression> parseAssignExpression() throws OperationCancellation { return parseExpression(InfixOpType.ASSIGN); } public final NodeResult<Expression> parseAssignExpression_toMissing(boolean breakOnMissing, ParseRuleDescription expectedRule) throws OperationCancellation { return nullExpToParseMissing(parseAssignExpression(), breakOnMissing, expectedRule); } public final Expression parseAssignExpression_toMissing() throws OperationCancellation { return nullExpToParseMissing(parseAssignExpression().node); } protected NodeResult<Expression> parseExpression(InfixOpType precedenceLimit) throws OperationCancellation { return new ParseRule_Expression().rule_parseExpression(precedenceLimit); } protected Expression parseExpression_toMissing(InfixOpType precedenceLimit) throws OperationCancellation { return nullExpToParseMissing(parseExpression(precedenceLimit).node); } /* ---------------- Missing stuff ---------------- */ protected Expression nullExpToParseMissing(Expression exp) throws OperationCancellation { return nullExpToParseMissing(exp, RULE_EXPRESSION); } protected Expression nullExpToParseMissing(Expression exp, ParseRuleDescription expectedRule) throws OperationCancellation { return exp != null ? exp : parseMissingExpression(expectedRule); } public final NodeResult<Expression> nullExpToParseMissing(NodeResult<Expression> expResult, boolean breakOnMissing, ParseRuleDescription expectedRule) throws OperationCancellation { return expResult.node != null ? expResult : result(expResult.ruleBroken || breakOnMissing, parseMissingExpression(expectedRule)); } protected Expression parseMissingExpression(ParseRuleDescription expectedRule) throws OperationCancellation { return parseMissingExpression(expectedRule, true); } protected Expression parseMissingExpression(ParseRuleDescription expectedRule, boolean consumeIgnoreTokens) throws OperationCancellation { int nodeStart = getSourcePosition(); if(consumeIgnoreTokens) { advanceSubChannelTokens(); } int nodeEnd = getSourcePosition(); return createMissingExpression(expectedRule, lastLexElement(), nodeStart, nodeEnd); } protected Expression createMissingExpression(ParseRuleDescription expectedRule, LexElement previousToken, int nodeStart, int nodeEnd) throws OperationCancellation { ParserError error = expectedRule != null ? createErrorExpectedRule(expectedRule, previousToken.getSourceRange()) : null; return conclude(error, srBounds(nodeStart, nodeEnd, new MissingExpression())); } public boolean isMissing(Expression exp) { return exp == null || exp instanceof MissingExpression; } public Expression createExpReference(Reference reference) throws OperationCancellation { ExpReference node = new ExpReference(reference); node.setSourceRange(reference.getSourceRange()); ExpReference expReference = node; return conclude(expReference); } protected ParserError createErrorTypeAsExpValue(Reference reference) { return createError(ParserErrorTypes.TYPE_USED_AS_EXP_VALUE, reference.getSourceRange(), null); } /* ============================ TypeOrExp ============================ */ /** Note: Whenever this class is instantiated, then it must be called only with one of the rule_* methods, * this is to ensure that the parser state is restored properly when {@link ParseRule_Expression} is done. */ protected class ParseRule_Expression { public boolean breakRule; public ParseRule_Expression() { breakRule = false; } public NodeResult<Expression> rule_parseExpression(InfixOpType precedenceLimit) throws OperationCancellation { return toResult(parseTypeOrExpression_start(precedenceLimit)); } public NodeResult<Expression> rule_parseUnaryExpression() throws OperationCancellation { return toResult(parseUnaryExpression()); } public NodeResult<Expression> rule_parseTypeOrExpression_fromUnary(InfixOpType precedenceLimit, Expression unaryExp) throws OperationCancellation { return toResult(parseTypeOrExpression_fromUnary(precedenceLimit, unaryExp)); } public NodeResult<Expression> toResult(Expression exp) { if(breakRule) { setEnabled(true); } assertTrue(isEnabled()); return result(breakRule, exp); } protected boolean shouldReturnToParseRuleTopLevel(@SuppressWarnings("unused") Expression expSoFar) { assertTrue(isEnabled() == !breakRule); return breakRule; } protected void setToEParseBroken(boolean parseBroken) { this.breakRule = parseBroken; if(breakRule) { setEnabled(false); } } protected Expression expConclude(NodeResult<? extends Expression> result) { setToEParseBroken(result.ruleBroken); return result.node; } protected Expression parseTypeOrExpression_start(InfixOpType precedenceLimit) throws OperationCancellation { Expression prefixExp; Resolvable prefixExpResolvable = parsePrimaryExpression(); if(prefixExpResolvable == null || prefixExpResolvable instanceof Expression) { prefixExp = (Expression) prefixExpResolvable; } else { Reference ref = (Reference) prefixExpResolvable; // boolean isTypeAsExpError = !refIsAllowedInExp(ref, breakRule || lookAhead() == DeeTokens.OPEN_PARENS); prefixExp = createExpReference(ref); } if(prefixExp == null || shouldReturnToParseRuleTopLevel(prefixExp)) { return prefixExp; } return parseTypeOrExpression_fromUnary(precedenceLimit, prefixExp); } public Expression parseTypeOrExpression_fromUnary(InfixOpType precedenceLimit, Expression unaryExp) throws OperationCancellation { unaryExp = parsePostfixExpression(unaryExp); if(shouldReturnToParseRuleTopLevel(unaryExp)) { return unaryExp; } return parseInfixOperators(precedenceLimit, unaryExp); } protected Expression parseUnaryExpression() throws OperationCancellation { return parseTypeOrExpression_start(InfixOpType.NULL); } protected Resolvable parsePrimaryExpression() throws OperationCancellation { Expression simpleLiteral = parseSimpleLiteral(); if(simpleLiteral != null) { return simpleLiteral; } switch (lookAhead()) { case KW_ASSERT: return expConclude(parseAssertExpression()); case KW_MIXIN: return expConclude(parseMixinExpression()); case KW_IMPORT: return expConclude(parseImportExpression()); case KW_TYPEID: return expConclude(parseTypeIdExpression()); case KW_NEW: return expConclude(parseNewExpression()); case KW_CAST: return expConclude(parseCastExpression()); case KW_IS: return expConclude(parseIsExpression()); case KW___TRAITS: return expConclude(parseTraitsExpression()); case AND: case INCREMENT: case DECREMENT: case STAR: case MINUS: case PLUS: case NOT: case CONCAT: case KW_DELETE: { LexElement prefixExpOpToken = consumeLookAhead(); EPrefixOpType prefixOpType = EPrefixOpType.tokenToPrefixOpType(prefixExpOpToken.type); Expression exp = parseUnaryExpression(); if(exp == null) { exp = parseMissingExpression(RULE_EXPRESSION); setToEParseBroken(true); } return conclude(srToPosition(prefixExpOpToken, new ExpPrefix(prefixOpType, exp))); } case OPEN_PARENS: return expConclude(matchParenthesesStart()); case OPEN_BRACE: { int startPos = lookAheadElement().getStartPos(); return expConclude(parseFunctionLiteral_atFunctionBody(startPos, null, null, null, null)); } case KW_FUNCTION: case KW_DELEGATE: return expConclude(parseFunctionLiteral_start()); case OPEN_BRACKET: return parseBracketList(null); case IDENTIFIER: if(lookAhead(1) == DeeTokens.LAMBDA) { return expConclude(parseSimpleLambdaLiteral_start()); } // else fallthrough to TypeReference: default: NodeResult<Reference> typeRefResult = parseTypeReference_start(RefParseRestrictions.EXP_ONLY); Reference ref = typeRefResult.node; if(!(ref instanceof RefQualified || ref instanceof RefModuleQualified)) { setToEParseBroken(typeRefResult.ruleBroken); } return ref; } } protected Expression parsePostfixExpression(Expression exp) throws OperationCancellation { switch (lookAhead()) { case DECREMENT: case INCREMENT: { exp = parsePostfixOpExpression_atOperator(exp); return parsePostfixExpression(exp); } case POW: { return parseInfixOperator(exp, InfixOpType.POW); } case OPEN_PARENS: { exp = expConclude(parseCallExpression_atParenthesis(exp)); if(shouldReturnToParseRuleTopLevel(exp)) return exp; return parsePostfixExpression(exp); } case OPEN_BRACKET: { exp = parseBracketList(exp); if(shouldReturnToParseRuleTopLevel(exp)) { return exp; } return parsePostfixExpression(exp); } case DOT: { ParseHelper parse = new ParseHelper(exp.getStartPos()); if(lookAhead(1) == DeeTokens.KW_NEW) { consumeLookAhead(DeeTokens.DOT); consumeLookAhead(DeeTokens.KW_NEW); return expConclude(parseNewExpression_do(parse, exp)); } final Expression qualifier = exp; exp = null; if(qualifier instanceof ExpReference) { ExpReference expReference = (ExpReference) qualifier; if(expReference.ref instanceof RefQualified) { RefQualified refQualified = (RefQualified) expReference.ref; if(refQualified.qualifiedId.isMissing()) { // Special case, if refQualified.qualifiedId was missing, // the we don't try to continue parsing the expression. return qualifier; } assertTrue(refQualified.isExpressionQualifier); } else if(expReference.ref instanceof RefTemplateInstance) { } else { assertFail(); // ...otherwise refqualified would have been parsed already } } Reference ref = parseRefQualified(parse, qualifier); if(!parse.ruleBroken) { ref = parseTypeReference_withLeftReference(ref, RefParseRestrictions.TEMPLATE_ONLY).node; } return parsePostfixExpression(createExpReference(ref)); } default: return exp; } } protected Expression parseInfixOperators(InfixOpType precedenceLimit, final Expression leftExp) throws OperationCancellation { DeeTokens gla = lookAheadGrouped(); InfixOpType infixOpAhead = InfixOpType.tokenToInfixOpType(gla); if(lookAhead() == DeeTokens.NOT) { if(lookAhead(1) == DeeTokens.KW_IS) { infixOpAhead = InfixOpType.NOT_IS; } else if(lookAhead(1) == DeeTokens.KW_IN) { infixOpAhead = InfixOpType.NOT_IN; } } if(infixOpAhead == null) { return leftExp; } // If lower precedence it can't be parsed to right expression, // instead this expression must become left children of new parent if(infixOpAhead.precedence < precedenceLimit.precedence) return leftExp; Expression exp = parseInfixOperator(leftExp, infixOpAhead); if(shouldReturnToParseRuleTopLevel(exp)) { return exp; } return parseInfixOperators(precedenceLimit, exp); } public InfixOpType getPrecedenceForInfixOpRightExp(InfixOpType infixOpLA) { switch (infixOpLA.category) { case SLICE: return InfixOpType.SLICE; case COMMA: return InfixOpType.COMMA; case ASSIGN: return InfixOpType.ASSIGN; case CONDITIONAL: return InfixOpType.CONDITIONAL; case LOGICAL_OR: return InfixOpType.LOGICAL_AND; case LOGICAL_AND: return InfixOpType.OR; case OR: return InfixOpType.XOR; case XOR: return InfixOpType.AND; case AND: return InfixOpType.EQUALS; case EQUALS: return InfixOpType.SHIFT; case SHIFT: return InfixOpType.ADD; case ADD: return InfixOpType.MUL; case MUL: return InfixOpType.NULL; case POW: return InfixOpType.NULL; default: throw assertUnreachable(); } } public Expression parseInfixOperator(final Expression leftExp, final InfixOpType opType) throws OperationCancellation { ParseHelper parse = new ParseHelper(assertNotNull(leftExp)); Expression rightExp = null; consumeLookAhead(); if(opType == InfixOpType.NOT_IS || opType == InfixOpType.NOT_IN) { consumeLookAhead(); // consume second token } if(opType != InfixOpType.MUL) { parse.storeError(checkValidAssociativityN(leftExp, opType)); } else { assertTrue(lastLexElement().type == DeeTokens.STAR); } Expression middleExp = null; parsing: { if(opType == InfixOpType.CONDITIONAL) { middleExp = nullExpToParseMissing(parseExpression().node); if(parse.consumeRequired(DeeTokens.COLON).ruleBroken) { setToEParseBroken(true); break parsing; } } InfixOpType rightExpPrecedence = getPrecedenceForInfixOpRightExp(opType); NodeResult<Expression> expResult = parseExpression(rightExpPrecedence); setToEParseBroken(expResult.ruleBroken); rightExp = expResult.node; if(isMissing(rightExp)) { rightExp = parseMissingExpression(RULE_EXPRESSION); setToEParseBroken(true); } else { parse.storeError(checkValidAssociativityN(rightExp, opType)); } } if(opType == InfixOpType.CONDITIONAL) { return parse.conclude(new ExpConditional(leftExp, middleExp, rightExp)); } return parse.conclude(new ExpInfix(leftExp, opType, rightExp)); } protected ParserError checkValidAssociativityN(Expression exp, InfixOpType op) { // Check for some syntax situations which are technically not allowed by the grammar: switch (op.category) { case OR: case XOR: case AND: case EQUALS: if(exp instanceof ExpInfix && ((ExpInfix) exp).kind.category == InfixOpType.EQUALS) { return createError(ParserErrorTypes.EXP_MUST_HAVE_PARENTHESES, exp.getSourceRange(), op.sourceValue); } default: return null; } } public Expression parseArrayLiteral() throws OperationCancellation { return parseBracketList(null); } protected Expression parseBracketList(Expression calleeExp) throws OperationCancellation { if(tryConsume(DeeTokens.OPEN_BRACKET) == false) return null; final boolean isExpIndexing = calleeExp != null; ParseHelper parse = isExpIndexing ? new ParseHelper(calleeExp) : new ParseHelper(); ArrayList<Expression> elements = new ArrayList<Expression>(4); ArrayList<MapArrayLiteralKeyValue> mapElements = null; boolean firstElement = true; while(true) { Expression exp1; Expression exp2 = null; ParseHelper exp2parse = null; exp1 = parseExpression(InfixOpType.SLICE).node; if(lookAhead() == DeeTokens.COMMA) { exp1 = nullExpToParseMissing(exp1); } if(firstElement) { if(!isExpIndexing && lookAhead() == DeeTokens.COLON) { exp1 = nullExpToParseMissing(exp1); consumeLookAhead(DeeTokens.COLON); exp2parse = new ParseHelper(exp1); exp2 = parseAssignExpression_toMissing(); mapElements = new ArrayList<MapArrayLiteralKeyValue>(); } else if(exp1 == null) { break; } } else { if(mapElements != null) { if(lookAhead() == DeeTokens.COLON) { exp1 = nullExpToParseMissing(exp1); } if(exp1 != null) { exp2parse = new ParseHelper(exp1); if(exp2parse.consumeExpected(DeeTokens.COLON)) { exp2 = parseAssignExpression_toMissing(); } } } } firstElement = false; if(mapElements == null ) { elements.add(exp1); } else { if(exp2parse == null) { mapElements.add(null); } else { mapElements.add(exp2parse.conclude(new MapArrayLiteralKeyValue(exp1, exp2))); } } if(tryConsume(DeeTokens.COMMA)) { assertTrue(exp1 != null); continue; } break; } parse.consumeRequired(DeeTokens.CLOSE_BRACKET); setToEParseBroken(parse.ruleBroken); if(calleeExp == null) { if(mapElements != null ) { return parse.conclude(new ExpLiteralMapArray(nodeListView(mapElements))); } else { return parse.conclude(new ExpLiteralArray(nodeListView(elements))); } } return parse.conclude(new ExpIndex(calleeExp, nodeListView(elements))); } } /* ---------------- ParseRule_TypeOrExp END----------------*/ @Deprecated protected static boolean refIsAllowedInExp(Reference ref, boolean allowOpCallTypeRefs) { switch (ref.getNodeType()) { case REF_TYPE_FUNCTION: return false; case REF_MODIFIER: if(allowOpCallTypeRefs == false) return false; RefTypeModifier refModifier = (RefTypeModifier) ref; return refModifier.ref == null ? true : refIsAllowedInExp(refModifier.ref, true); case REF_TYPE_DYN_ARRAY: case REF_TYPE_POINTER: case REF_INDEXING: return false; // These don't generate parser errors. Semantic analysis should be responsible for errors in invalid cases. // This simplifies the parser. case REF_PRIMITIVE: return true; case REF_TYPEOF: return true; default: return true; } } /* ---------------- parse TypeOrExp ----------------*/ public NodeResult<Resolvable> parseTypeOrExpression() throws OperationCancellation { return parseTypeOrExpression(true); } public NodeResult<Resolvable> parseTypeOrExpression(boolean ambiguousToRef) throws OperationCancellation { return parseTypeOrExpression(ANY_OPERATOR, ambiguousToRef); } public NodeResult<Resolvable> parseTypeOrAssignExpression(boolean ambiguousToRef) throws OperationCancellation { return parseTypeOrExpression(InfixOpType.ASSIGN, ambiguousToRef); } public NodeResult<Resolvable> parseTypeOrExpression(InfixOpType precedenceLimit, boolean ambiguousToRef) throws OperationCancellation { return parseTypeOrExpression(precedenceLimit).toFinalResult(ambiguousToRef).upcastTypeParam(); } protected Resolvable nullTypeOrExpToParseMissing(Resolvable exp) throws OperationCancellation { return exp != null ? exp : parseMissingExpression(RULE_TYPE_OR_EXP); } protected TypeOrExpResult parseTypeOrExpression(InfixOpType precedenceLimit) throws OperationCancellation { ParserState initialState = saveParserState(); NodeResult<Reference> refResult = parseTypeReference(); ParserState refResultState = saveParserState(); assertTrue(isEnabled()); restoreOriginalState(initialState); NodeResult<Expression> expResult = parseExpression(precedenceLimit); int expResultLexPosition = getEnabledLexSource().getLexElementPosition(); int refResultLexPosition = refResultState.lexSource.getLexElementPosition(); if(expResultLexPosition > refResultLexPosition) { return new TypeOrExpResult(null, expResult); } else if(refResultLexPosition > expResultLexPosition) { restoreOriginalState(refResultState); return new TypeOrExpResult(refResult, null); } else { return new TypeOrExpResult(refResult, expResult); } } protected final class TypeOrExpResult { private NodeResult<Reference> refResult; private NodeResult<Expression> expResult; public TypeOrExpResult(NodeResult<Reference> refResult, NodeResult<Expression> expResult) { this.refResult = refResult; this.expResult = expResult; } public boolean isNull() { return (refResult == null && expResult == null) || (refResult != null && expResult != null && refResult.node == null); } public boolean isExpOnly() { return !isNull() && refResult == null; } public boolean isRefOnly() { return !isNull() && expResult == null; } public NodeResult<Reference> toReference() { assertTrue(!isExpOnly()); if(isNull()) { return nullResult(); } return refResult; } public NodeResult<Expression> toExpression() { assertTrue(!isRefOnly()); if(isNull()) { return nullResult(); } return assertNotNull(expResult); } public NodeResult<? extends Resolvable> toFinalResult(boolean ambiguousToRef) { if(isRefOnly()) { return refResult; } if(isExpOnly()) { return expResult; } return ambiguousToRef ? refResult : expResult; } } protected Expression resolvableToExp(Resolvable resolvable) throws OperationCancellation { if(resolvable instanceof Reference) { Reference reference = (Reference) resolvable; return createExpReference(reference); } return (Expression) resolvable; } public NodeResult<Expression> parseUnaryExpression_toMissing() throws OperationCancellation { NodeResult<Expression> result = new ParseRule_Expression().rule_parseUnaryExpression(); return nullExpToParseMissing(result, false, RULE_EXPRESSION); } public NodeResult<Expression> parseExpression_fromUnary(InfixOpType precedenceLimit, Expression unaryExp) throws OperationCancellation { return new ParseRule_Expression().rule_parseTypeOrExpression_fromUnary(precedenceLimit, unaryExp); } public Expression parseSimpleLiteral() throws OperationCancellation { switch (lookAheadGrouped()) { case KW_TRUE: case KW_FALSE: consumeLookAhead(); return conclude(srOf(lastLexElement(), new ExpLiteralBool(lastLexElement().type == DeeTokens.KW_TRUE))); case KW_THIS: consumeLookAhead(); return conclude(srOf(lastLexElement(), new ExpThis())); case KW_SUPER: consumeLookAhead(); return conclude(srOf(lastLexElement(), new ExpSuper())); case KW_NULL: consumeLookAhead(); return conclude(srOf(lastLexElement(), new ExpNull())); case DOLLAR: consumeLookAhead(); return conclude(srOf(lastLexElement(), new ExpArrayLength())); case GROUP_INTEGER: consumeLookAhead(); return conclude(srOf(lastLexElement(), new ExpLiteralInteger(lastLexElement()))); case CHARACTER: consumeLookAhead(); return conclude(srOf(lastLexElement(), new ExpLiteralChar(lastLexElement()))); case GROUP_FLOAT: consumeLookAhead(); return conclude(srOf(lastLexElement(), new ExpLiteralFloat(lastLexElement()))); case GROUP_STRING: return parseStringLiteral(); default: return null; } } public Expression parseStringLiteral() throws OperationCancellation { ArrayList<IToken> stringTokens = new ArrayList<IToken>(1); while(lookAheadGrouped() == DeeTokens.GROUP_STRING) { IToken string = consumeLookAhead(); stringTokens.add(string); } IToken[] tokenStrings = ArrayUtil.createFrom(stringTokens, IToken.class); return conclude(srToPosition(tokenStrings[0].getStartPos(), new ExpLiteralString(tokenStrings))); } protected ExpPostfixOperator parsePostfixOpExpression_atOperator(Expression exp) throws OperationCancellation { LexElement op = consumeLookAhead(); return conclude(srToPosition(exp, new ExpPostfixOperator(exp, PostfixOpType.tokenToPrefixOpType(op.type)))); } protected NodeResult<ExpCall> parseCallExpression_atParenthesis(Expression callee) throws OperationCancellation { ParseHelper parse = new ParseHelper(callee); NodeVector<Expression> args = parseParenthesesDelimited_ExpArgumentList(parse); return parse.resultConclude(new ExpCall(callee, args)); } protected NodeVector<Expression> parseExpArgumentList(ParseHelper parse, boolean canBeEmpty, DeeTokens tokenLISTCLOSE) throws OperationCancellation { SimpleListParseHelper<Expression> elementListParse = new SimpleListParseHelper<Expression>() { @Override protected Expression parseElement(boolean createMissing) throws OperationCancellation { Expression arg = parseAssignExpression().node; return createMissing ? nullExpToParseMissing(arg) : arg; } }; elementListParse.parseSimpleList(DeeTokens.COMMA, canBeEmpty, true); parse.consumeRequired(tokenLISTCLOSE); return elementListParse.members; } protected final NodeVector<Expression> parseParenthesesDelimited_ExpArgumentList(ParseHelper parse) throws OperationCancellation { if(tryConsume(DeeTokens.OPEN_PARENS)) { return parseExpArgumentList(parse, true, DeeTokens.CLOSE_PARENS); } else { return null; } } protected final class TypeOrExpArgumentListSimpleParse extends SimpleListParseHelper<Resolvable> { @Override protected Resolvable parseElement(boolean createMissing) throws OperationCancellation { Resolvable arg = parseTypeOrAssignExpression(true).node; return createMissing ? nullTypeOrExpToParseMissing(arg) : arg; } } protected final NodeVector<Resolvable> parseTypeOrExpArgumentList(ParseHelper parse, DeeTokens tkSEP, DeeTokens tkCLOSE) throws OperationCancellation { SimpleListParseHelper<Resolvable> elementListParse = new TypeOrExpArgumentListSimpleParse(); elementListParse.parseSimpleList(tkSEP, true, true); parse.consumeRequired(tkCLOSE); return elementListParse.members; } protected NodeResult<? extends Expression> matchParenthesesStart() throws OperationCancellation { assertTrue(lookAhead() == DeeTokens.OPEN_PARENS); ParseHelper parse = new ParseHelper(lookAheadElement()); ParserState savedParserState = saveParserState(); DeeParser_RuleParameters fnParametersRule = thisParser().new DeeParser_RuleParameters(TplOrFnMode.FN); fnParametersRule.parseParameters(parse); if(!parse.ruleBroken) { NodeVector<IFunctionAttribute> fnAttributes = thisParser().parseFunctionAttributes(); if(lookAhead() == DeeTokens.OPEN_BRACE || lookAhead() == DeeTokens.LAMBDA) { NodeVector<IFunctionParameter> fnParams = fnParametersRule.getAsFunctionParameters(); return parseFunctionLiteral_atFunctionBody(parse.nodeStart, null, null, fnParams, fnAttributes); } } restoreOriginalState(savedParserState); return parseParenthesesExp(); } protected NodeResult<ExpSimpleLambda> parseSimpleLambdaLiteral_start() throws OperationCancellation { ProtoDefSymbol defId = parseDefId(); consumeLookAhead(DeeTokens.LAMBDA); ParseHelper parse = new ParseHelper(defId.getStartPos()); Expression bodyExp = parse.checkResult(parseAssignExpression_toMissing(true, RULE_EXPRESSION)); SimpleLambdaDefUnit lambdaDef = conclude(defId.nameSourceRange, new SimpleLambdaDefUnit(defId.createDefId())); return parse.resultConclude(new ExpSimpleLambda(lambdaDef, bodyExp)); } public NodeResult<ExpFunctionLiteral> parseFunctionLiteral_start() throws OperationCancellation { assertTrue(lookAhead() == DeeTokens.KW_FUNCTION || lookAhead() == DeeTokens.KW_DELEGATE); consumeLookAhead(); boolean isFunctionKeyword = lastLexElement().type == DeeTokens.KW_FUNCTION; ParseHelper parse = new ParseHelper(); Reference retType = parseTypeReference().node; NodeVector<IFunctionParameter> fnParams = null; NodeVector<IFunctionAttribute> fnAttributes = null; parsing: { fnParams = thisParser().parseFunctionParameters(parse); if(parse.ruleBroken) break parsing; fnAttributes = thisParser().parseFunctionAttributes(); return parseFunctionLiteral_atFunctionBody(parse.nodeStart, isFunctionKeyword, retType, fnParams, fnAttributes); } return parse.resultConclude( new ExpFunctionLiteral(isFunctionKeyword, retType, fnParams, fnAttributes, null, null)); } protected NodeResult<ExpFunctionLiteral> parseFunctionLiteral_atFunctionBody(int nodeStart, Boolean isFunctionKeyword, Reference retType, NodeVector<IFunctionParameter> fnParams, NodeVector<IFunctionAttribute> fnAttributes) throws OperationCancellation { if(tryConsume(DeeTokens.LAMBDA)) { assertTrue(fnParams != null); NodeResult<Expression> litBody = parseAssignExpression_toMissing(true, RULE_EXPRESSION); return resultConclude(litBody.ruleBroken, srToPosition(nodeStart, new ExpFunctionLiteral(isFunctionKeyword, retType, fnParams, fnAttributes, null, litBody.node))); } else { NodeResult<? extends IFunctionBody> litBody = thisParser().parseBlockStatement(true, true); return resultConclude(litBody.ruleBroken, srToPosition(nodeStart, new ExpFunctionLiteral(isFunctionKeyword, retType, fnParams, fnAttributes, litBody.node, null))); } } public NodeResult<ExpParentheses> parseParenthesesExp() throws OperationCancellation { if(!tryConsume(DeeTokens.OPEN_PARENS)) return null; ParseHelper parse = new ParseHelper(); TypeOrExpResult arg = parseTypeOrExpression(ANY_OPERATOR); Resolvable resolvable; boolean isDotAfterParensSyntax = lookAhead() == DeeTokens.CLOSE_PARENS && lookAhead(1) == DeeTokens.DOT; if(isDotAfterParensSyntax) { resolvable = nullTypeOrExpToParseMissing(arg.toFinalResult(true).node); } else { resolvable = nullExpToParseMissing(resolvableToExp(arg.toFinalResult(false).node)); } parse.consumeRequired(DeeTokens.CLOSE_PARENS); return parse.resultConclude(new ExpParentheses(isDotAfterParensSyntax, resolvable)); } public NodeResult<ExpAssert> parseAssertExpression() throws OperationCancellation { if(tryConsume(DeeTokens.KW_ASSERT) == false) return null; ParseHelper parse = new ParseHelper(); Expression exp = null; Expression msg = null; parsing: { if(parse.consumeRequired(DeeTokens.OPEN_PARENS).ruleBroken) break parsing; exp = parseAssignExpression_toMissing(); if(tryConsume(DeeTokens.COMMA)) { msg = parseAssignExpression_toMissing(); } parse.consumeRequired(DeeTokens.CLOSE_PARENS); } return parse.resultConclude(new ExpAssert(exp, msg)); } public NodeResult<ExpImportString> parseImportExpression() throws OperationCancellation { if(tryConsume(DeeTokens.KW_IMPORT) == false) return null; ParseHelper parse = new ParseHelper(); Expression expParentheses = parseExpressionAroundParentheses(parse, true, true); return parse.resultConclude(new ExpImportString(expParentheses)); } public NodeResult<ExpMixinString> parseMixinExpression() throws OperationCancellation { if(tryConsume(DeeTokens.KW_MIXIN) == false) return null; ParseHelper parse = new ParseHelper(); Expression expParentheses = parseExpressionAroundParentheses(parse, true, true); return parse.resultConclude(new ExpMixinString(expParentheses)); } public Expression parseExpressionAroundParentheses(ParseHelper parse, boolean isRequired, boolean brokenIfMissing) throws OperationCancellation { boolean isOptional = !isRequired; if(parse.consume(DeeTokens.OPEN_PARENS, isOptional, brokenIfMissing) == false) { if(!isOptional) { return conclude(srToPosition(getSourcePosition(), new MissingParenthesesExpression())); } return null; } else { Expression exp = parseExpression_toMissing(); parse.consumeRequired(DeeTokens.CLOSE_PARENS); return exp; } } public NodeResult<ExpTypeId> parseTypeIdExpression() throws OperationCancellation { if(tryConsume(DeeTokens.KW_TYPEID) == false) return null; ParseHelper parse = new ParseHelper(); Reference ref = null; Expression exp = null; parsing: { if(parse.consumeRequired(DeeTokens.OPEN_PARENS).ruleBroken) break parsing; Resolvable resolvable = nullTypeOrExpToParseMissing(parseTypeOrExpression(true).node); if(resolvable instanceof Reference) { ref = (Reference) resolvable; } else { exp = (Expression) resolvable; } parse.consumeRequired(DeeTokens.CLOSE_PARENS); } if(ref != null) { return parse.resultConclude(new ExpTypeId(ref)); } return parse.resultConclude(new ExpTypeId(exp)); } public NodeResult<? extends Expression> parseNewExpression() throws OperationCancellation { if(!tryConsume(DeeTokens.KW_NEW)) return nullResult(); ParseHelper parse = new ParseHelper(); Expression outerClass = null; return parseNewExpression_do(parse, outerClass); } public NodeResult<? extends Expression> parseNewExpression_do(ParseHelper parse, Expression outerClass) throws OperationCancellation { NodeVector<Expression> allocArgs = null; Reference type = null; NodeVector<Expression> args = null; parsing: { assertTrue(!parse.ruleBroken); allocArgs = parseParenthesesDelimited_ExpArgumentList(parse); if(parse.ruleBroken) break parsing; if(outerClass == null && parse.consumeOptional(DeeTokens.KW_CLASS)) { return parseNewAnonClassExpression_afterClassKeyword(parse, allocArgs); } type = parse.checkResult(parseTypeReference_ToMissing(true)); if(parse.ruleBroken) break parsing; args = parseParenthesesDelimited_ExpArgumentList(parse); } return parse.resultConclude(new ExpNew(outerClass, allocArgs, type, args)); } protected NodeResult<ExpNewAnonClass> parseNewAnonClassExpression_afterClassKeyword(ParseHelper parse, NodeVector<Expression> allocArgs) throws OperationCancellation { NodeVector<Expression> args = null; SimpleListParseHelper<Reference> baseClasses = thisParser().new TypeReferenceSimpleListParse(); DeclBlock declBody = null; parsing: { args = parseParenthesesDelimited_ExpArgumentList(parse); if(parse.ruleBroken) break parsing; baseClasses.parseSimpleList(DeeTokens.COMMA, true, false); declBody = parse.parseRequiredRule(thisParser().parseDeclarationBlock(), DeeParser.RULE_DECLARATION_BLOCK); } return parse.resultConclude(new ExpNewAnonClass(allocArgs, args, baseClasses.members, declBody)); } public NodeResult<? extends Expression> parseCastExpression() throws OperationCancellation { if(!tryConsume(DeeTokens.KW_CAST)) return null; ParseHelper parse = new ParseHelper(); Reference type = null; CastQualifiers qualifier = null; Expression exp = null; parsing: { if(parse.consumeRequired(DeeTokens.OPEN_PARENS).ruleBroken) break parsing; qualifier = parseCastQualifier(); if(qualifier == null) { type = parseTypeReference(true, false).node; } if(parse.consumeRequired(DeeTokens.CLOSE_PARENS).ruleBroken) break parsing; exp = parse.checkResult(parseUnaryExpression_toMissing()); } if(qualifier != null) { return parse.resultConclude(new ExpCastQual(qualifier, exp)); } else { return parse.resultConclude(new ExpCast(type, exp)); } } public CastQualifiers parseCastQualifier() { switch (lookAhead()) { case KW_CONST: return parseCastQualifier(DeeTokens.KW_SHARED, CastQualifiers.CONST_SHARED, CastQualifiers.CONST); case KW_INOUT: return parseCastQualifier(DeeTokens.KW_SHARED, CastQualifiers.INOUT_SHARED, CastQualifiers.INOUT); case KW_SHARED: if(lookAhead(2) == DeeTokens.CLOSE_PARENS && tryConsume(DeeTokens.KW_SHARED, DeeTokens.KW_CONST)) return CastQualifiers.SHARED_CONST; return parseCastQualifier(DeeTokens.KW_INOUT, CastQualifiers.SHARED_INOUT, CastQualifiers.SHARED); case KW_IMMUTABLE: if(lookAhead(1) == DeeTokens.CLOSE_PARENS) { consumeLookAhead(); return CastQualifiers.IMMUTABLE; } default: return null; } } public CastQualifiers parseCastQualifier(DeeTokens token1, CastQualifiers altDouble, CastQualifiers altSingle) { if(lookAhead(2) == DeeTokens.CLOSE_PARENS && lookAhead(1) == token1) { consumeLookAhead(); consumeLookAhead(); return altDouble; } else if(lookAhead(1) == DeeTokens.CLOSE_PARENS) { consumeLookAhead(); return altSingle; } else { return null; } } public static final ParseRuleDescription RULE_IS_TYPE_SPEC = new ParseRuleDescription("IsTypeSpecialization", "IsTypeSpecialization"); public NodeResult<? extends Expression> parseIsExpression() throws OperationCancellation { if(!tryConsume(DeeTokens.KW_IS)) return null; ParseHelper parse = new ParseHelper(); Reference typeRef = null; StaticIfExpIsDefUnit isExpDefUnit = null; ExpIsSpecialization specKind = null; Reference specTypeRef = null; NodeVector<ITemplateParameter> tplParams = null; parsing: { if(parse.consumeRequired(DeeTokens.OPEN_PARENS).ruleBroken) break parsing; typeRef = parseTypeReference_ToMissing().node; if(lookAhead() == DeeTokens.IDENTIFIER) { ProtoDefSymbol defId = parseDefId(); isExpDefUnit = concludeNode(srOf(lastLexElement(), new StaticIfExpIsDefUnit(defId.createDefId()))); } if(tryConsume(DeeTokens.COLON)) { specKind = ExpIsSpecialization.TYPE_SUBTYPE; specTypeRef = parseTypeReference_ToMissing().node; } else if(tryConsume(DeeTokens.EQUALS)) { specKind = determineIsExpArchetype(); if(specKind != null ) { consumeLookAhead(); } else { specKind = ExpIsSpecialization.TYPE_EXACT; specTypeRef = parseTypeReference().node; if(specTypeRef == null) { specTypeRef = parseMissingTypeReference(RULE_IS_TYPE_SPEC); } } } if((specKind == ExpIsSpecialization.TYPE_SUBTYPE || specKind == ExpIsSpecialization.TYPE_EXACT) && tryConsume(DeeTokens.COMMA)) { tplParams = thisParser().parseTemplateParametersList(); } parse.consumeRequired(DeeTokens.CLOSE_PARENS); } if(isExpDefUnit != null || tplParams != null) { return parse.resultConclude(new StaticIfExpIs(typeRef, isExpDefUnit, specKind, specTypeRef, tplParams)); } else { return parse.resultConclude(new ExpIs(typeRef, specKind, specTypeRef)); } } protected ExpIsSpecialization determineIsExpArchetype() { if(isImmutabilitySpecifier(lookAhead()) && (lookAhead(1) == DeeTokens.OPEN_PARENS || canParseTypeReferenceStart(lookAhead(1)))) return null; switch (lookAhead()) { case KW_STRUCT: return ExpIsSpecialization.STRUCT; case KW_UNION: return ExpIsSpecialization.UNION; case KW_CLASS: return ExpIsSpecialization.CLASS; case KW_INTERFACE: return ExpIsSpecialization.INTERFACE; case KW_ENUM: return ExpIsSpecialization.ENUM; case KW_FUNCTION: return ExpIsSpecialization.FUNCTION; case KW_TYPEDEF: return ExpIsSpecialization.TYPEDEF; case KW_DELEGATE: return ExpIsSpecialization.DELEGATE; case KW_SUPER: return ExpIsSpecialization.SUPER; case KW_CONST: return ExpIsSpecialization.CONST; case KW_IMMUTABLE: return ExpIsSpecialization.IMMUTABLE; case KW_INOUT: return ExpIsSpecialization.INOUT; case KW_SHARED: return ExpIsSpecialization.SHARED; case KW_RETURN: return ExpIsSpecialization.RETURN; case IDENTIFIER: if(lookAheadElement().getSourceValue().equals("__parameters")) return ExpIsSpecialization.__PARAMETERS; default: return null; } } public NodeResult<ExpTraits> parseTraitsExpression() throws OperationCancellation { if(!tryConsume(DeeTokens.KW___TRAITS)) return null; ParseHelper parse = new ParseHelper(); Symbol traitsId = null; NodeVector<Resolvable> args = null; parsing: { if(parse.consumeRequired(DeeTokens.OPEN_PARENS).ruleBroken) break parsing; traitsId = parseTraitsId(); if(parse.consumeExpected(DeeTokens.COMMA)) { SimpleListParseHelper<Resolvable> elementListParse = new TypeOrExpArgumentListSimpleParse(); elementListParse.parseSimpleList(DeeTokens.COMMA, true, true); args = elementListParse.members; } parse.consumeRequired(DeeTokens.CLOSE_PARENS); } return parse.resultConclude(new ExpTraits(traitsId, args)); } public Symbol parseTraitsId() throws OperationCancellation { BaseLexElement traitsId = consumeExpectedContentToken(DeeTokens.IDENTIFIER); ParserError error = DeeTokenSemantics.checkTraitsId(traitsId); return conclude(error, srOf(traitsId, new Symbol(traitsId.getSourceValue()))); } }