You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cd...@apache.org on 2014/07/22 15:36:13 UTC
[47/51] [partial] - Migrated the directory structure to a more Maven
style structure. - Started migrating the Parser from Antlr2+3 and JFlex to
Antlr4.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/59f6373b/compiler/src/main/antlr4/org/apache/flex/compiler/internal/parsing/as/AS.g4
----------------------------------------------------------------------
diff --git a/compiler/src/main/antlr4/org/apache/flex/compiler/internal/parsing/as/AS.g4 b/compiler/src/main/antlr4/org/apache/flex/compiler/internal/parsing/as/AS.g4
new file mode 100644
index 0000000..1967aff
--- /dev/null
+++ b/compiler/src/main/antlr4/org/apache/flex/compiler/internal/parsing/as/AS.g4
@@ -0,0 +1,3207 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * This is a grammar for ActionScript.
+ */
+grammar AS;
+
+options
+{
+ language = Java;
+}
+
+tokens
+{
+ // These hidden tokens are matched by the raw tokenizer but are not sent to the parser.
+ HIDDEN_TOKEN_COMMENT,
+ HIDDEN_TOKEN_SINGLE_LINE_COMMENT,
+ HIDDEN_TOKEN_STAR_ASSIGNMENT,
+ HIDDEN_TOKEN_BUILTIN_NS,
+ HIDDEN_TOKEN_MULTI_LINE_COMMENT,
+
+ // These two tokens are used by code model's ASDoc tokenizer.
+ TOKEN_ASDOC_TAG,
+ TOKEN_ASDOC_TEXT,
+
+ // These tokens are transformed from reserved words by StreamingASTokenizer.
+ TOKEN_RESERVED_WORD_EACH,
+ TOKEN_RESERVED_WORD_CONFIG,
+ TOKEN_KEYWORD_INCLUDE,
+ TOKEN_RESERVED_WORD_GOTO
+}
+
+@header
+{
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * This file is generated from ASTreeAssembler.g
+ * DO NOT MAKE EDITS DIRECTLY TO THIS FILE. THEY WILL BE LOST WHEN THE FILE IS GENERATED AGAIN!!!
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.flex.compiler.tree.as.*;
+import org.apache.flex.compiler.workspaces.IWorkspace;
+import org.apache.flex.compiler.parsing.IASToken;
+import org.apache.flex.compiler.parsing.IASToken.ASTokenKind;
+import org.apache.flex.compiler.tree.as.IContainerNode.ContainerType;
+import org.apache.flex.compiler.tree.as.ILiteralNode.LiteralType;
+import org.apache.flex.compiler.internal.tree.as.*;
+import org.apache.flex.compiler.internal.tree.as.metadata.*;
+import org.apache.flex.compiler.asdoc.IASParserASDocDelegate;
+import org.apache.flex.compiler.constants.IASLanguageConstants;
+import org.apache.flex.compiler.problems.ICompilerProblem;
+import org.apache.flex.compiler.problems.*;
+
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+}
+
+/**
+ * ActionScript3 parser grammar. It consumes ASTokens and produces IASNode AST.
+ * The number of tokens in a single syntactic predicate can not be greater than
+ * StreamingTokenBuffer.REWIND_BUFFER_SIZE.
+ *
+ * @see <a href="https://zerowing.corp.adobe.com/display/FlashPlayer/ActionScript+Language+Specification">ActionScript Language Syntax Specification</a>
+ */
+/*class ASParser extends Parser("org.apache.flex.compiler.internal.parsing.as.BaseASParser");
+
+options
+{
+ exportVocab = AS;
+ defaultErrorHandler = false;
+}
+
+{
+
+ * Construct an AS3 parser from a token buffer.
+ public ASParser(IWorkspace workspace, IRepairingTokenBuffer buffer)
+ {
+ super(workspace, buffer);
+ tokenNames = _tokenNames;
+ }
+
+ * Construct an AS3 parser for parsing command line config args
+ public ASParser(IWorkspace workspace, IRepairingTokenBuffer buffer, boolean parsingProjectConfigVariables)
+ {
+ super(workspace, buffer, parsingProjectConfigVariables);
+ tokenNames = _tokenNames;
+ }
+}*/
+
+
+/*
+ * Matches multiple directives. This layer is added to handle parsing error in directives.
+ */
+fileLevelDirectives[ContainerNode c]
+ : (directive[c, -1])*
+ ;
+// exception catch [RecognitionException parserError] { handleParsingError(parserError); }
+
+/*
+ * Matches a "directive" level input.
+ * The first couple of alternatives gated with semantic predicates are used to
+ * either disambiguate inputs, or to trap erroneous syntax.
+ */
+directive[ContainerNode c, int endToken]
+/*{
+ final ASToken lt1 = LT(1);
+ final ASToken lt2 = LT(2);
+ final int la1 = LA(1);
+ final int la2 = LA(2);
+ final int la3 = LA(3);
+ final int la4 = LA(4);
+}*/
+ : { _input.LA(1) == TOKEN_BLOCK_OPEN }? groupDirective[c, endToken]
+ | { _input.LA(1) == TOKEN_RESERVED_WORD_NAMESPACE && _input.LA(2) == TOKEN_PAREN_OPEN }? statement[c, endToken]
+ | { _input.LA(1) == TOKEN_IDENTIFIER && _input.LA(2) == TOKEN_NAMESPACE_ANNOTATION && _input.LT(1).getLine() == _input.LT(2).getLine() }?
+ // Skip over the user-defined namespace name and continue.
+ /*nsT:*/TOKEN_IDENTIFIER attributedDefinition[c] /*{ trapInvalidNamespaceAttribute((ASToken)nsT); }*/
+ | asDocComment
+ | importDirective[c]
+ | useNamespaceDirective[c]
+ | { _input.LA(1) == TOKEN_NAMESPACE_NAME &&
+ _input.LA(2) == TOKEN_OPERATOR_NS_QUALIFIER &&
+ _input.LA(3) == TOKEN_IDENTIFIER &&
+ _input.LA(4) == TOKEN_BLOCK_OPEN}?
+ // ns::var { ... }
+ groupDirectiveWithConfigVariable[c, endToken]
+ | { _input.LA(1) == TOKEN_NAMESPACE_NAME &&
+ _input.LA(2) == TOKEN_OPERATOR_NS_QUALIFIER &&
+ _input.LA(3) == TOKEN_NAMESPACE_ANNOTATION }?
+ // ns::var private var foo:int;
+ attributedDefinition[c]
+ | { _input.LA(1) == TOKEN_NAMESPACE_NAME &&
+ _input.LA(2) == TOKEN_OPERATOR_NS_QUALIFIER }?
+ // "ns::var" or "ns::[x, y]"
+ statement[c,endToken]
+ | { !isFunctionClosure() }?
+ attributedDefinition[c]
+ | packageDirective[c]
+ | statement[c,endToken]
+ | configNamespace[c]
+ | includeDirective
+ // The following alternatives are error traps
+ | /*fT:*/TOKEN_KEYWORD_FINALLY /*{ reportUnexpectedTokenProblem((ASToken)fT); }*/
+ | /*cT:*/TOKEN_KEYWORD_CATCH /*{ reportUnexpectedTokenProblem((ASToken)cT); }*/
+ ;
+ /*exception catch [RecognitionException ex]
+ {
+ handleParsingError(ex, endToken);
+ consumeUntilKeywordOrIdentifier(endToken);
+ }*/
+
+/**
+ * Include processing is usually done in the lexer. However, this rule is added
+ * in order to support code model partitioner whose tokenizer is set to not
+ * "follow includes". In a normal AS3 compilation, the parser would never see
+ * the "include" token.
+ */
+includeDirective
+ : TOKEN_KEYWORD_INCLUDE TOKEN_LITERAL_STRING
+ ;
+
+/**
+ * Matches an attributed definition. An "attribute" can be a namespace or a
+ * modifier.
+ */
+attributedDefinition[ContainerNode c]
+/*{
+ List<INamespaceDecorationNode> namespaceAttributes = new ArrayList<INamespaceDecorationNode>();
+ List<ModifierNode> modifiers = new ArrayList<ModifierNode>();
+ INamespaceDecorationNode namespaceAttr = null;
+
+ boolean enabled = isDefinitionEnabled(c);
+ boolean eval = true;
+}*/
+ : (eval=configConditionOfDefinition)?
+ /*{
+ // A configuration condition variable can either be matched by
+ // the above rule or be transformed into a LiteralNode of boolean
+ // type. If either is evaluated to false, the definition is disabled.
+ enabled &= eval;
+ if (!enabled)
+ c = new ContainerNode();
+ }*/
+ (attribute[modifiers, namespaceAttributes])*
+ /*{
+ // Verify that at most one namespace attribute is matched.
+ verifyNamespaceAttributes(namespaceAttributes);
+
+ if (!namespaceAttributes.isEmpty())
+ namespaceAttr = namespaceAttributes.get(0);
+ }*/
+ definition[c, namespaceAttr, modifiers]
+/* exception catch [RecognitionException ex]
+ {
+ handleParsingError(ex);
+ }*/
+ ;
+
+/**
+ * Matches an attribute such as:
+ * - Modifiers: dynamic, final, native, override, static, virtual.
+ * - Namespace names.
+ * - Reserved namespace names: internal, private, public, protected.
+ *
+ * A definition can have at most one "namespace attribute".
+ * The matched attribute is added to the lists passed in as arguments.
+ */
+attribute [List<ModifierNode> modifiers, List<INamespaceDecorationNode> namespaceAttributes]
+/*{
+ ExpressionNodeBase namespaceNode = null;
+ ModifierNode modifierNode = null;
+}*/
+ : modifierNode=modifierAttribute
+ /*{
+ if (modifierNode != null)
+ modifiers.add(modifierNode);
+ }*/
+ | namespaceNode=namespaceModifier
+ /*{
+ if (namespaceNode instanceof INamespaceDecorationNode)
+ namespaceAttributes.add((INamespaceDecorationNode) namespaceNode);
+ }*/
+ ;
+
+
+/**
+ * Matches a definition of variable, function, namespace, class or interface.
+ */
+definition[ContainerNode c, INamespaceDecorationNode ns, List<ModifierNode> modList]
+ : variableDefinition[c, ns, modList]
+ | functionDefinition[c, ns, modList]
+ | namespaceDefinition[c, ns, modList]
+ | classDefinition[c, ns, modList]
+ | interfaceDefinition[c, ns, modList]
+ ;
+
+/**
+ * Matches a "group" in a "group directive".
+ * Entering a "Block" leaves the global context, but entering a "Group" doesn't.
+ */
+groupDirective[ContainerNode c, int endToken]
+/*{
+ BlockNode b = new BlockNode();
+ enterGroup();
+}*/
+ : /*openT:*/TOKEN_BLOCK_OPEN /*{ b.startAfter(openT); }*/
+ (directive[c, endToken])*
+ { if(b.getChildCount() > 0) c.addItem(b); }
+ /*closeT:*/TOKEN_BLOCK_CLOSE /*{ b.endBefore(closeT); leaveGroup(); }*/
+ ;
+
+/**
+ * Matches a config condition such as "CONFIG::debug". This rule only applies
+ * to blocks gated with configuration variable.
+ *
+ * @return Evaluated result of the configuration variable.
+ */
+configCondition returns [boolean result]
+/*{
+ result = false;
+}*/
+ : /*ns:*/TOKEN_NAMESPACE_NAME /*op:*/TOKEN_OPERATOR_NS_QUALIFIER /*id:*/TOKEN_IDENTIFIER
+ /*{
+ result = evaluateConfigurationVariable(ns.getText(), (ASToken) op, id.getText());
+ }*/
+ ;
+
+/**
+ * Similar to "configCondition", only that the token type after "::" is
+ * "TOKEN_NAMESPACE_ANNOTATION". This rule only applies to "attributed
+ * definitions".
+ */
+configConditionOfDefinition returns [boolean result]
+/*{
+ result = false;
+}*/
+ : /*ns:*/TOKEN_NAMESPACE_NAME /*op:*/TOKEN_OPERATOR_NS_QUALIFIER /*id:*/TOKEN_NAMESPACE_ANNOTATION
+ /*{
+ result = evaluateConfigurationVariable(ns.getText(), (ASToken) op, id.getText());
+ }*/
+ ;
+
+/**
+ * Matches a group of directives gated with configuration variable.
+ *
+ * CONFIG::debug {
+ * trace("debugging code");
+ * }
+ *
+ * If the configuration variable evaluates to false, the following block will
+ * not be added to the resulting AST.
+ */
+groupDirectiveWithConfigVariable [ContainerNode c, int endToken]
+/*{
+ boolean b;
+ ConfigConditionBlockNode block;
+ final Token lt = LT(1);
+}*/
+ : /*b=*/configCondition
+ /*{
+ block = new ConfigConditionBlockNode(b);
+ block.startBefore(lt);
+ c.addItem(block);
+ }*/
+ groupDirective[block, endToken]
+ ;
+
+/**
+ * Matches a statement.
+ *
+ * Note that the "SuperStatement" in ASL syntax spec is not explicitly defined.
+ * The "super" statements like <code>super(args);</code> are matched as regular
+ * "call" expressions.
+ */
+statement[ContainerNode c, int exitCondition]
+/*{
+ final int la1 = LA(1);
+ final int la2 = LA(2);
+}*/
+ : breakOrContinueStatement[c]
+ | defaultXMLNamespaceStatement[c]
+ | gotoStatement[c]
+ | emptyStatement
+ | { _input.LA(1) == TOKEN_IDENTIFIER && _input.LA(2) == TOKEN_COLON }? labeledStatement[c, exitCondition]
+ | { _input.LA(1) != TOKEN_SQUARE_OPEN &&
+ _input.LA(1) != TOKEN_OPERATOR_LESS_THAN &&
+ _input.LA(1) != TOKEN_BLOCK_OPEN }? expressionStatement[c]
+ | forStatement[c]
+ | ifStatement[c]
+ | meta[c]
+ | returnStatement[c]
+ | switchStatement[c]
+ | throwsStatement[c]
+ | tryStatement[c]
+ | whileStatement[c]
+ | doStatement[c]
+ | withStatement[c]
+ ;
+/* exception catch [RecognitionException ex]
+ {
+ handleParsingError(ex);
+ consumeUntilKeywordOrIdentifier(exitCondition);
+ }*/
+
+/**
+ * Matches an "expression statement". The ASL syntax specification says the
+ * lookahead can not be "[", "{" or "function". Legacy code requires that "<"
+ * be excluded as well.
+ */
+expressionStatement[ContainerNode c]
+/*{
+ ExpressionNodeBase e = null;
+
+ if (LA(1) == TOKEN_KEYWORD_FUNCTION)
+ {
+ // Recover: continue parsing function as an anonymous function.
+ logSyntaxError(LT(1));
+ }
+}*/
+ : /*e=*/expression
+ /*{
+ c.addItem(e);
+ if (!matchOptionalSemicolon())
+ {
+ recoverFromExpressionStatementMissingSemicolon(e);
+ }
+ }*/
+ ;
+
+/**
+ * <h1>From ASL syntax spec:</h1>
+ * <quote>
+ * InnerSubstatement is defined in the grammar for the sole purpose of
+ * specifying side conditions that disambiguate various syntactic ambiguities
+ * in a context-sensitive manner specified in Section 5.
+ * </quote>
+ *
+ * It is only used in "do statement" and "if statement" to loosen the following
+ * two cases allowed by AS3 but not by ECMA5.
+ *
+ * <code>
+ * do x++ while (x < 10); // ES5 would require a ; after x++
+ * if (x > 10) x++ else y++; // ES5 would require a ; after x++
+ * <code>
+ */
+innerSubstatement[ContainerNode c]
+ : substatement[c] /*{ afterInnerSubstatement(); }*/
+ ;
+
+/**
+ * Matches a sub-statement.
+ */
+substatement[ContainerNode c]
+ : ( { _input.LA(1) != TOKEN_BLOCK_OPEN }? statement[c, -1]
+ | block[c]
+ | variableDefinition[c, null, null]
+ )
+ {
+ if (c.getContainerType() == ContainerType.SYNTHESIZED)
+ c.setContainerType(ContainerType.IMPLICIT);
+ }
+ ;
+
+/**
+ * Matches a "labeled statement". For example:
+ *
+ * innerLoop: x++;
+ *
+ */
+labeledStatement[ContainerNode c, int exitCondition]
+/*{
+ LabeledStatementNode statementNode = null;
+ ASToken offendingNSToken = null;
+}*/
+ : /*labelT:*/TOKEN_IDENTIFIER TOKEN_COLON
+ /*{
+ final NonResolvingIdentifierNode labelNode =
+ new NonResolvingIdentifierNode(
+ labelT != null ? labelT.getText() : "",
+ labelT);
+ statementNode = new LabeledStatementNode(labelNode);
+ c.addItem(statementNode);
+ }*/
+ ( { _input.LA(1) == TOKEN_RESERVED_WORD_NAMESPACE && _input.LA(2) == TOKEN_IDENTIFIER }?
+ /*{ offendingNSToken = LT(1); }*/
+ namespaceDefinition[c, null, null]
+ /*{ trapInvalidSubstatement(offendingNSToken); }*/
+ | substatement[statementNode.getLabeledStatement()]
+ )
+ ;
+
+/**
+ * Matches a block.
+ */
+block[ContainerNode b]
+ : /*openT:*/TOKEN_BLOCK_OPEN
+ /*{
+ b.startAfter(openT);
+ b.setContainerType(ContainerType.BRACES);
+ }*/
+ (directive[b, TOKEN_BLOCK_CLOSE])*
+ /*closeT:*/TOKEN_BLOCK_CLOSE /*{ b.endBefore(closeT); }*/
+ ;
+/* exception catch [RecognitionException ex]
+ {
+ handleParsingError(ex);
+ consumeUntilKeywordOrIdentifier(TOKEN_BLOCK_CLOSE);
+ endContainerAtError(ex, b);
+ }*/
+
+/**
+ * Matches an import directive.
+ *
+ * import flash.display.Sprite;
+ * import flash.events.*;
+ */
+importDirective[ContainerNode c]
+/*{
+ ExpressionNodeBase n = null;
+ ImportNode i = null;
+}*/
+ : /*importT:*/TOKEN_KEYWORD_IMPORT
+ /*{
+ i = new ImportNode((ExpressionNodeBase) null);
+ i.startBefore(importT);
+ i.endAfter(importT);
+ c.addItem(i);
+ }*/
+
+ n=importName
+ /*{
+ if(n != null) {
+ i.setImportTarget(n);
+ i.setEnd(n.getEnd());
+ encounteredImport(i);
+ }
+ else {
+ i.setImportTarget(new IdentifierNode(""));
+ }
+ matchOptionalSemicolon();
+ }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches "use namespace ns" directive.
+ */
+useNamespaceDirective[ContainerNode c]
+/*{
+ ExpressionNodeBase n = null;
+ UseNamespaceNode u = null;
+}*/
+ : /*useT:*/YeTOKEN_KEYWORD_USE /*{ u = new UseNamespaceNode(n); u.startBefore(useT); c.addItem(u); }*/
+ /*nsT:*/TOKEN_RESERVED_WORD_NAMESPACE /*{ u.endAfter(nsT); }*/ n=restrictedName
+ /*{
+ u.setTargetNamespace(n);
+ u.setEnd(n.getEnd());
+ matchOptionalSemicolon();
+ }*/
+ ;
+/* exception catch [RecognitionException ex]
+ {
+ if (u != null && u.getTargetNamespace() == null)
+ u.setTargetNamespace(handleMissingIdentifier(ex));
+ else
+ handleParsingError(ex);
+ }*/
+
+/**
+ * Matches an ASDoc block.
+ */
+asDocComment
+ : /*asdocT:*/TOKEN_ASDOC_COMMENT
+ /*{
+ asDocDelegate.setCurrentASDocToken(asdocT);
+ }*/
+ ;
+
+/**
+ * Matches a "modifier attribute" such as "final", "dynamic", "override",
+ * "static" or "native".
+ */
+modifierAttribute returns [ModifierNode modifierNode]
+/*{
+ modifierNode = null;
+ final ASToken modifierT = LT(1);
+}*/
+ : ( TOKEN_MODIFIER_FINAL
+ | TOKEN_MODIFIER_DYNAMIC
+ | TOKEN_MODIFIER_OVERRIDE
+ | TOKEN_MODIFIER_STATIC
+ | TOKEN_MODIFIER_NATIVE
+ | TOKEN_MODIFIER_VIRTUAL
+ )
+ /*{ modifierNode = new ModifierNode((ASToken) modifierT); }*/
+ ;
+
+
+/**
+ * Matches a namespace modifier on an "attributed definition".
+ */
+namespaceModifier returns[ExpressionNodeBase n]
+/*{
+ n = null;
+}*/
+ : /*nsPart1T:*/TOKEN_NAMESPACE_ANNOTATION
+ /*{
+ // If our text token is a member access, then build a normal
+ // identifier. Otherwise, build a NS specific one.
+
+ if (LA(1) == TOKEN_OPERATOR_MEMBER_ACCESS)
+ {
+ n = new IdentifierNode((ASToken)nsPart1T) ;
+ }
+ else
+ {
+ final NamespaceIdentifierNode nsNode = new NamespaceIdentifierNode((ASToken)nsPart1T);
+ nsNode.setIsConfigNamespace(isConfigNamespace(nsNode));
+ n = nsNode;
+ }
+ }*/
+ (
+ /*dotT:*/TOKEN_OPERATOR_MEMBER_ACCESS
+ (
+ /*nsNameT:*/TOKEN_NAMESPACE_ANNOTATION
+ /*{
+ IdentifierNode id = new IdentifierNode((ASToken)nsNameT);
+ n = new FullNameNode(n, (ASToken) dotT, id);
+ }*/
+ )
+ )*
+ /*{
+ if (n instanceof FullNameNode)
+ n = new QualifiedNamespaceExpressionNode((FullNameNode)n);
+ }*/
+
+ ;
+
+/**
+ * Matches a "metadata statement".
+ *
+ * [ExcludeClass()]
+ * [Bindable]
+ */
+meta[ContainerNode c]
+/*{
+ ArrayLiteralNode al = new ArrayLiteralNode();
+ final ASToken lt = LT(1);
+}*/
+ : /*attributeT:*/TOKEN_ATTRIBUTE
+ /*{
+ // Note that a separate parser is invoked here for metadata.
+ parseMetadata(attributeT, errors);
+ preCheckMetadata(attributeT, c);
+ }*/
+ | { isIncompleteMetadataTagOnDefinition() }?
+ TOKEN_SQUARE_OPEN
+ // Error trap for "[" before a definition item.
+ { logSyntaxError(_input.LT(1)); }
+ | arrayInitializer[al]
+ // This is statement-level metadata.
+ /*{
+ // Synthesize a MetaTagsNode to hold the metadata offsets.
+ currentAttributes = new MetaTagsNode();
+ currentAttributes.span(al, al);
+ preCheckMetadata(lt, c);
+ }*/
+ ;
+/* exception catch [RecognitionException ex]
+ {
+ recoverFromMetadataTag(c, al);
+ }*/
+
+/**
+ * Matches a "config namespace foo" directive.
+ */
+configNamespace[ContainerNode c]
+ : TOKEN_RESERVED_WORD_CONFIG TOKEN_RESERVED_WORD_NAMESPACE /*configN:*/TOKEN_IDENTIFIER
+ /*{
+ NamespaceNode cNode = new ConfigNamespaceNode(new IdentifierNode((ASToken)configN));
+ addConditionalCompilationNamespace(cNode);
+ matchOptionalSemicolon();
+ }*/
+
+ ;
+/* exception catch [RecognitionException ex]
+ { handleParsingError(ex); }*/
+
+/**
+ * Matches a "package" block.
+ *
+ * package mx.controls { ... }
+ *
+ */
+packageDirective[ContainerNode c]
+/*{
+ PackageNode p = null;
+ ExpressionNodeBase name = null;
+ BlockNode b = null;
+}*/
+ : /*packageT:*/TOKEN_KEYWORD_PACKAGE /*{ enterPackage((ASToken)packageT); }*/
+ (name=packageName)?
+ /*{
+ p = new PackageNode(name != null ? name : IdentifierNode.createEmptyIdentifierNodeAfterToken(packageT), (ASToken)packageT);
+ p.startBefore(packageT);
+ c.addItem(p);
+ b = p.getScopedNode();
+ }*/
+ ( /*openT:*/TOKEN_BLOCK_OPEN /*{ b.startAfter(openT); }*/
+ packageContents[b]
+ )
+ /*{ leavePackage(); }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); leavePackage(); }
+
+/**
+ * Matches a package name such as:
+ * org.apache.flex
+ *
+ * A Whitespace or LineTerminator is allowed around a . in a PackageName.
+ * For example, the following is a syntactically valid
+ * <pre>
+ * package a .
+ * b
+ * { }
+ * </pre>
+ * The resulting PackageName value is equivalent to a PackageName without any intervening Whitespace and LineTerminators.
+ */
+packageName returns [ExpressionNodeBase n]
+/*{
+ n = null;
+ ExpressionNodeBase e = null;
+}*/
+ : /*n=*/identifier
+ (options{greedy=true;}: { _input.LA(2) != TOKEN_OPERATOR_STAR }?
+ /*dotT:*/TOKEN_OPERATOR_MEMBER_ACCESS
+ /*{
+ n = new FullNameNode(n, (ASToken) dotT, null);
+ }*/
+ /*e=*/identifier
+ /*{
+ ((FullNameNode)n).setRightOperandNode(e);
+ }*/
+ )*
+ ;
+// exception catch [RecognitionException ex] { return handleMissingIdentifier(ex, n); }
+
+/**
+ * Matches contents in a package block.
+ */
+packageContents[ContainerNode b]
+ : (directive[b, TOKEN_BLOCK_CLOSE])*
+ /*closeT:*/TOKEN_BLOCK_CLOSE /*{ b.endBefore(closeT); }*/
+ ;
+/* exception catch [RecognitionException ex]
+ {
+ if(handleParsingError(ex))
+ {
+ //attempt to recover from the error so we can keep parsing within the block
+ packageContents(b);
+ }
+ else
+ {
+ endContainerAtError(ex, b);
+ }
+ }*/
+
+/**
+ * Matches a namespace definition.
+ *
+ * namespace ns1;
+ */
+namespaceDefinition[ContainerNode c, INamespaceDecorationNode namespace, List<ModifierNode> modList]
+/*{
+ NamespaceNode n = null;
+ IdentifierNode id = null;
+ ExpressionNodeBase v = null;
+}*/
+ : /*nsT:*/TOKEN_RESERVED_WORD_NAMESPACE id=identifier
+ /*{
+ n = new NamespaceNode(id);
+ n.startBefore(nsT);
+ storeDecorations(n, c, namespace, modList);
+ checkNamespaceDefinition(n);
+ }*/
+ (initializer[n])?
+ /*{
+ c.addItem(n);
+ matchOptionalSemicolon();
+ }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches an interface definition.
+ *
+ * interface IFoo extends IBar {...}
+ */
+interfaceDefinition[ContainerNode c, INamespaceDecorationNode namespace, List<ModifierNode> modList]
+/*{
+ InterfaceNode interfaceNode = null;
+ IdentifierNode intName = null;
+ ExpressionNodeBase baseInterfaceName = null;
+ BlockNode b = null;
+ enterInterfaceDefinition(LT(1));
+}*/
+ : /*intT:*/TOKEN_KEYWORD_INTERFACE intName=identifier
+ /*{
+ interfaceNode = new InterfaceNode(intName);
+ interfaceNode.setInterfaceKeyword((IASToken)intT);
+ storeDecorations(interfaceNode, c, namespace, modList);
+ c.addItem(interfaceNode);
+
+ // Recover from invalid interface name.
+ final int la1 = LA(1);
+ if (la1 != TOKEN_RESERVED_WORD_EXTENDS && la1 != TOKEN_BLOCK_OPEN)
+ {
+ addProblem(new SyntaxProblem(LT(1)));
+ consumeUntilKeywordOr(TOKEN_BLOCK_OPEN);
+ }
+ }*/
+ ( /*extendsT:*/TOKEN_RESERVED_WORD_EXTENDS
+ /*{ interfaceNode.setExtendsKeyword((ASToken)extendsT); }*/
+ ( baseInterfaceName=restrictedName
+ /*{
+ interfaceNode.addBaseInterface(baseInterfaceName);
+ interfaceNode.setEnd(baseInterfaceName.getEnd());
+ }*/
+
+ ( /*commaT:*/TOKEN_COMMA
+ /*{ interfaceNode.endAfter(commaT); }*/
+ ( baseInterfaceName=restrictedName
+ /*{
+ interfaceNode.addBaseInterface(baseInterfaceName);
+ interfaceNode.setEnd(baseInterfaceName.getEnd());
+ }*/
+ )
+ )*
+ )
+ )?
+
+ /*{
+ b = interfaceNode.getScopedNode();
+ }*/
+
+ /*openT:*/TOKEN_BLOCK_OPEN
+ /*{ b.startAfter(openT); }*/
+ classOrInterfaceBlock[b]
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a class definition. For example:
+ *
+ * class Player extends my_ns::GameObject implements IPlayer { ... }
+ *
+ */
+classDefinition [ContainerNode c, INamespaceDecorationNode namespace, List<ModifierNode> modList]
+/*{
+ IdentifierNode className = null;
+ ExpressionNodeBase superName = null;
+ ExpressionNodeBase interfaceName = null;
+ ClassNode classNode = null;
+ disableSemicolonInsertion();
+ enterClassDefinition(LT(1));
+}*/
+ : /*classT:*/TOKEN_KEYWORD_CLASS className=identifier
+ /*{
+ // When class name is empty, it is a synthesized IdentifierNode
+ // created by the error recovery logic in "identifier" rule.
+ // In such case, we fast-forward the token stream to the next
+ // keyword to recover.
+ if (className.getName().isEmpty())
+ {
+ // If the parser recover from "extends", "implements" or "{",
+ // we are could continue parsing the class definition, because
+ // these tokens are the "follow set" of a class name token.
+ // Otherwise, the next keyword is still a good starting point.
+ consumeUntilKeywordOr(TOKEN_BLOCK_OPEN);
+ }
+
+ insideClass = true;
+ classNode = new ClassNode(className);
+ classNode.setSourcePath(((IASToken)classT).getSourcePath());
+ classNode.setClassKeyword((IASToken)classT);
+ storeDecorations(classNode, c, namespace, modList);
+ c.addItem(classNode);
+ }*/
+
+ ( /*extendsT:*/TOKEN_RESERVED_WORD_EXTENDS
+ /*{ classNode.setExtendsKeyword((ASToken)extendsT); }*/
+ // The rule for super type should be "restrictedName". However, in
+ // order to trap errors like "class Foo extends Vector.<T>", the
+ // parser has to allow parameterized type as super name. It's up to
+ // semantic analysis to report this problem.
+ superName=type
+ /*{
+ classNode.setBaseClass(superName);
+ classNode.setEnd(superName.getEnd());
+ }*/
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+ )?
+
+ ( /*impT:*/ TOKEN_RESERVED_WORD_IMPLEMENTS
+ /*{ classNode.setImplementsKeyword((ASToken)impT); }*/
+ ( interfaceName=restrictedName
+ /*{
+ classNode.addInterface(interfaceName);
+ classNode.setEnd(interfaceName.getEnd());
+ }*/
+ ( /*commaT:*/TOKEN_COMMA
+ /*{ classNode.endAfter(commaT); }*/
+ interfaceName=restrictedName
+ /*{
+ classNode.addInterface(interfaceName);
+ classNode.setEnd(interfaceName.getEnd());
+ }*/
+ )*
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+ )
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+ )?
+
+ /*openT:*/TOKEN_BLOCK_OPEN
+ /*{ classNode.getScopedNode().startAfter(openT); }*/
+ classOrInterfaceBlock[classNode.getScopedNode()]
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches the content block of a class definition or an interface definition.
+ */
+classOrInterfaceBlock[BlockNode b]
+// { enableSemicolonInsertion(); }
+
+ : (directive[b, TOKEN_BLOCK_CLOSE])*
+ /*closeT:*/TOKEN_BLOCK_CLOSE
+ /*{ b.endBefore(closeT); }*/
+ ;
+/* exception catch [RecognitionException ex]
+ {
+ if(handleParsingError(ex)) {
+ classOrInterfaceBlock(b); //attempt to retry
+ } else {
+ endContainerAtError(ex, b);
+ }
+ }*/
+
+/**
+ * Matches an anonymous function (function closure).
+ */
+functionExpression returns [FunctionObjectNode n]
+/*{
+ n = null;
+ BlockNode b = null;
+ FunctionNode f = null;
+ IdentifierNode name=null;
+ ContainerNode p = null;
+}*/
+ : /*functionT:*/TOKEN_KEYWORD_FUNCTION
+
+ // optional function name
+ (name=identifier)?
+ /*{
+ if(name == null)
+ name = IdentifierNode.createEmptyIdentifierNodeAfterToken(functionT);
+ f = new FunctionNode((ASToken)functionT, name);
+ n = new FunctionObjectNode(f);
+ f.startBefore(functionT);
+ n.startBefore(functionT);
+ b = f.getScopedNode();
+ disableSemicolonInsertion();
+ }*/
+
+ // function signature
+ /*lpT:*/TOKEN_PAREN_OPEN
+ /*{
+ p = f.getParametersContainerNode();
+ p.startAfter(lpT);
+ }*/
+ formalParameters[p]
+ /*rpT:*/TOKEN_PAREN_CLOSE
+ /*{ p.endBefore(rpT); }*/
+ (resultType[f])?
+ /*{ enableSemicolonInsertion(); }*/
+
+ // non-optional function body
+ /*lbT:*/TOKEN_BLOCK_OPEN
+ /*{ b.startAfter(lbT);}*/
+ functionBlock[f, (ASToken)lbT]
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a function block, excluding the open "{" but including the closing "}".
+ */
+functionBlock[FunctionNode f, ASToken openT]
+/*{
+ final BlockNode b = f.getScopedNode();
+ b.setContainerType(IContainerNode.ContainerType.BRACES);
+ skipFunctionBody(f, openT);
+}*/
+ : (directive[b, TOKEN_BLOCK_CLOSE])*
+ /*rbT:*/TOKEN_BLOCK_CLOSE
+ /*{ b.endBefore(rbT); }*/
+ ;
+/* exception catch [RecognitionException ex]
+ {
+ IASToken prev = buffer.previous();
+ if (prev.getType() != ASTokenTypes.EOF)
+ b.endAfter(prev);
+ else
+ b.setEnd(b.getStart());
+ if(handleParsingError(ex)) {
+ functionBlock(f, openT); //attempt to retry
+ }
+ }*/
+
+/**
+ * Matches an optional function body. It can either be a "block" or a
+ * "semicolon".
+ */
+optionalFunctionBody [FunctionNode f]
+/*{
+ BlockNode blockNode = f.getScopedNode();
+ enableSemicolonInsertion();
+}*/
+ : { _input.LA(1) == TOKEN_BLOCK_OPEN }? /*lbT:*/TOKEN_BLOCK_OPEN
+ /*{ blockNode.startAfter(lbT); }*/
+ functionBlock[f, (ASToken)lbT]
+ | { buffer.matchOptionalSemicolon() }? // Matches a function without body.
+ | /*{
+ final Token lt = LT(1);
+ blockNode.startBefore(lt);
+ blockNode.endBefore(lt);
+
+ // Report missing left-curly problem if there's no other syntax
+ // problems in the function definition.
+ reportFunctionBodyMissingLeftBraceProblem();
+ }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a function definition. For example:
+ *
+ * private function myFunction(name:String) : void
+ * {
+ * return;
+ * }
+ *
+ */
+functionDefinition[ContainerNode c, INamespaceDecorationNode namespace, List<ModifierNode> modList]
+/*{
+ IdentifierNode name=null;
+ disableSemicolonInsertion();
+}*/
+ : ( /*functionT:*/TOKEN_KEYWORD_FUNCTION
+
+ // optional accessors:
+ // Although "get" and "set" can be identifiers as well, here
+ // they can only be the reserved words, unless it's a function
+ // called "get()" or "set()". As a result, the parser
+ // needs to match it in a "greedy" fashion.
+ (options{greedy=true;}:
+ { _input.LA(2) != TOKEN_PAREN_OPEN}? /*getT:*/TOKEN_RESERVED_WORD_GET
+ | { _input.LA(2) != TOKEN_PAREN_OPEN}? /*setT:*/TOKEN_RESERVED_WORD_SET
+ )?
+
+ // non-optional function name:
+ name=identifier
+ //we need to be able to keep going in case we are in the processing of typing a function name
+// exception catch [RecognitionException ex] { name = handleMissingIdentifier(ex); }
+ )
+/* {
+ final FunctionNode n ;
+ if (getT != null)
+ n = new GetterNode((ASToken)functionT, (ASToken)getT, name);
+ else if (setT != null)
+ n = new SetterNode((ASToken)functionT, (ASToken)setT, name);
+ else
+ n = new FunctionNode((ASToken)functionT, name);
+
+ storeDecorations(n, c, namespace, modList);
+ c.addItem(n);
+ }*/
+
+ // function signature:
+ /*lpT:*/TOKEN_PAREN_OPEN
+ /*{
+ final ContainerNode parameters = n.getParametersContainerNode();
+ parameters.startAfter(lpT);
+ }*/
+ formalParameters[parameters]
+ ( /*rpT:*/TOKEN_PAREN_CLOSE
+ /*{ parameters.endBefore(rpT); }*/
+ // error recovery for typing in-progress function definitions
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+ )
+ (resultType[n])?
+
+ optionalFunctionBody[n]
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches the parameters of a function definition signature (excluding the parenthesis).
+ *
+ * arg1:int, arg2:String
+ */
+formalParameters[ContainerNode c]
+ : (formal[c] (TOKEN_COMMA formal[c])*)?
+ ;
+// exception catch [RecognitionException ex] {handleParsingError(ex); }
+
+/**
+ * Matches a single parameter in a function definition.
+ */
+formal[ContainerNode c]
+/* { ParameterNode p = null; }*/
+
+ :(/*p=*/restParameter | /*p=*/parameter)
+ /*{ if (p != null) c.addItem(p); }*/
+ ;
+
+/**
+ * Matches the "rest parameters" in a function definition.
+ *
+ * ...args
+ */
+restParameter returns [ParameterNode p]
+/* { p = null; }*/
+
+ : /*e:*/TOKEN_ELLIPSIS /*p=*/parameter
+ /*{
+ if (p != null){
+ // ??? following is an override on default type-specification
+ // ??? and should be pulled soon as that gets resolved.
+ if (p.getTypeNode() == null){
+ p.span(e);
+ }
+ p.setIsRestParameter(true);
+ }
+ }*/
+ ;
+
+/**
+ * Matches a parameter in a function definition.
+ */
+parameter returns [ParameterNode p]
+/*{
+ p = null;
+ ASToken t = null;
+ IdentifierNode name = null;
+}*/
+ : ( /*t=*/varOrConst
+ /*{
+ // const allowed here, var is not...log error, keep going
+ if (t.getType() == TOKEN_KEYWORD_VAR)
+ handleParsingError(new RecognitionException());
+ }*/
+ )?
+
+ /*name=*/identifier
+ /*{
+ p = new ParameterNode(name);
+ if (t != null && t.getType() == TOKEN_KEYWORD_CONST)
+ p.setKeyword(t);
+ }*/
+
+ (resultType[p])?
+ (initializer[p])?
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches keyword "var" or keyword "const".
+ */
+varOrConst returns[ASToken token]
+/*{
+ token = LT(1);
+}*/
+ : TOKEN_KEYWORD_VAR
+ | TOKEN_KEYWORD_CONST
+ ;
+
+/**
+ * Matches a result type: either a "void" keyword or a restricted name.
+ *
+ * :void
+ * :String
+ * :int
+ *
+ */
+resultType [BaseTypedDefinitionNode result]
+/*{
+ ExpressionNodeBase t = null;
+}*/
+ : /*colon:*/TOKEN_COLON
+ ( ( t=voidLiteral | t=type )
+/* exception catch [RecognitionException ex]
+ { t = handleMissingIdentifier(ex); }*/
+ )
+ /*{
+ if(t.getStart() == -1)
+ t.startAfter(colon);
+
+ if (t.getEnd() == -1)
+ t.endAfter(colon);
+
+ result.endAfter(colon);
+ result.setType((ASToken) colon, t);
+ }*/
+ ;
+
+/**
+ * Matches an initializer in a variable/constant definition.
+ */
+initializer [IInitializableDefinitionNode v]
+/*{
+ ExpressionNodeBase e = null;
+}*/
+ : /*assignT:*/TOKEN_OPERATOR_ASSIGNMENT
+ e=assignmentRightValue
+ /*{ v.setAssignedValue((IASToken) assignT, e); }*/
+ ;
+// exception catch [RecognitionException ex] {handleParsingError(ex); }
+
+/**
+ * Matches a variable/constant definition.
+ */
+variableDefinition[ContainerNode c, INamespaceDecorationNode namespace, List<ModifierNode> modList]
+/*{
+ VariableNode v = null;
+ ChainedVariableNode v2 = null;
+ ASToken tok = null;
+ asDocDelegate.beforeVariable();
+}*/
+ : tok=varOrConst v=singleVariable[(ASToken)tok, namespace]
+ /*{
+ asDocDelegate.afterVariable();
+ storeVariableDecorations(v, c, namespace, modList);
+ if(v instanceof ConfigConstNode) {
+ addConfigConstNode((ConfigConstNode)v);
+ } else {
+ c.addItem(v);
+ }
+ }*/
+ // don't allow chain after a config
+ ( {!(v instanceof ConfigConstNode)}?
+ TOKEN_COMMA /*v2=*/chainedVariable[c]
+ /*{
+ if(v2 != null)
+ {
+ v.addChainedVariableNode(v2);
+ storeEmbedDecoration(v2, v.getMetaTags());
+ }
+ }*/
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+ )*
+ /*{ matchOptionalSemicolon(); setAllowErrorsInContext(true); }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); setAllowErrorsInContext(true); }
+
+/**
+ * Matches a single variable/constant definition.
+ */
+singleVariable[IASToken keyword, INamespaceDecorationNode namespace] returns [VariableNode v]
+/*{
+ v = null;
+ IdentifierNode name = null;
+}*/
+ : /*name=*/identifier
+ /*{
+ if(namespaceIsConfigNamespace(namespace)) {
+ v = new ConfigConstNode(name);
+ } else {
+ v = new VariableNode(name);
+ }
+ v.setKeyword(keyword);
+ v.setIsConst(keyword.getType() == TOKEN_KEYWORD_CONST);
+ if(name.getStart() == -1) {
+ name.startAfter(keyword);
+ name.endAfter(keyword);
+ }
+ }*/
+
+ (resultType[v])?
+ (initializer[v])?
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a chained variable/constant definition.
+ */
+chainedVariable[ContainerNode c] returns [ChainedVariableNode v]
+/*{
+ v = null;
+ IdentifierNode name = null;
+}*/
+ : /*name=*/identifier
+ /*{ v = new ChainedVariableNode(name); }*/
+
+ (resultType[v])?
+ (initializer[v])?
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches variable definitions in a for loop.
+ */
+variableDefExpression returns[NodeBase v]
+/*{
+ v = null;
+ ContainerNode c = null;
+ NodeBase v1 = null;
+ ASToken varT = null;
+}*/
+ : /*varT=*/varOrConst /*v=*/singleVariableDefExpression[varT, varT.getType() == TOKEN_KEYWORD_CONST]
+ ( TOKEN_COMMA /*v1=*/singleVariableDefExpression[null, varT.getType() == TOKEN_KEYWORD_CONST]
+ /*{
+ if (c == null) {
+ c = new ContainerNode();
+ c.setStart(v.getStart());
+ c.addItem(v);
+ v = c;
+ }
+ c.addItem(v1);
+ c.setEnd(v1.getEnd());
+ }*/
+ )*
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a single variable definition in a for loop.
+ */
+singleVariableDefExpression[ASToken varToken, boolean isConst] returns [ExpressionNodeBase n]
+/*{
+ n = null;
+ VariableNode variable = null;
+ IdentifierNode varName = null;
+ ExpressionNodeBase value = null;
+}*/
+ : /*varName=*/identifier
+ /*{
+ variable = new VariableNode(varName);
+ if(varToken != null)
+ variable.setKeyword(varToken);
+ variable.setIsConst(isConst);
+ n = new VariableExpressionNode(variable);
+ }*/
+
+ (resultType[variable])?
+
+ (initializer[variable])?
+ ;
+
+/**
+ * Matches a default XML namespace statement. For example:
+ *
+ * default xml namespace = "domain";
+ *
+ */
+defaultXMLNamespaceStatement[ContainerNode c]
+/* { ExpressionNodeBase e = null; }*/
+
+ : /*defT:*/TOKEN_DIRECTIVE_DEFAULT_XML TOKEN_OPERATOR_ASSIGNMENT e=assignmentExpression
+ /*{
+ DefaultXMLNamespaceNode n = new DefaultXMLNamespaceNode(new KeywordNode((IASToken)defT));
+ c.addItem(n);
+ n.setExpressionNode(e);
+ matchOptionalSemicolon();
+ }*/
+ ;
+
+/**
+ * Matches an expression in a pair of parenthesis. It's usually used as a
+ * condition expression in {@code if (...)}, {@code while (...)}, etc.
+ *
+ * (....)
+ */
+statementParenExpression returns [ExpressionNodeBase e]
+/*{
+ e = null;
+}*/
+ : TOKEN_PAREN_OPEN { disableSemicolonInsertion(); }
+ /*e=*/expression
+ TOKEN_PAREN_CLOSE { enableSemicolonInsertion(); }
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); enableSemicolonInsertion(); }
+
+
+/**
+ * Matches an empty statement which is an explicit semicolon.
+ */
+emptyStatement
+ : TOKEN_SEMICOLON
+ ;
+
+/**
+ * Matches a "return" statement.
+ */
+returnStatement[ContainerNode c]
+/*{
+ ExpressionNodeBase n = null;
+ ExpressionNodeBase e = null;
+}*/
+ : /*returnT:*/TOKEN_KEYWORD_RETURN
+ /*{
+ n = new ReturnNode((ASToken)returnT);
+ c.addItem(n);
+ afterRestrictedToken((ASToken)returnT);
+ }*/
+
+ /*e=*/optExpression
+ /*{
+ ((ReturnNode)n).setStatementExpression(e);
+ }*/
+ /*{ matchOptionalSemicolon(); }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a "throw" statement.
+ */
+throwsStatement[ContainerNode c]
+/*{
+ ExpressionNodeBase n = null;
+ ExpressionNodeBase e = null;
+}*/
+ : /*throwT:*/TOKEN_KEYWORD_THROW
+ /*{
+ n = new ThrowNode((ASToken)throwT);
+ c.addItem(n);
+ afterRestrictedToken((ASToken)throwT);
+ }*/
+
+ ( /*e=*/expression
+ /*{
+ ((ThrowNode)n).setStatementExpression(e);
+ }*/
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+ )
+ /*{ matchOptionalSemicolon(); }*/
+ ;
+
+/**
+ * Matches a "for loop" statement.
+ */
+forStatement[ContainerNode c]
+/*{
+ ForLoopNode node = null;
+ ContainerNode forContainer = null;
+ BlockNode b = null;
+ NodeBase fi = null;
+ ExpressionNodeBase e = null;
+ BinaryOperatorNodeBase inNode = null;
+}*/
+ : /*forKeyword:*/TOKEN_KEYWORD_FOR /*lparenT:*/TOKEN_PAREN_OPEN
+ /*{
+ node = new ForLoopNode((ASToken)forKeyword);
+ c.addItem(node);
+ forContainer = node.getConditionalsContainerNode();
+ b = node.getContentsNode();
+ forContainer.startAfter(lparenT);
+ }*/
+
+ /*{
+ expressionMode = ExpressionMode.noIn;
+ }*/
+ /*fi=*/forInitializer
+ /*{
+ expressionMode = ExpressionMode.normal;
+ }*/
+
+ ( TOKEN_SEMICOLON /*{ forContainer.addItem(fi); }*/
+ forCondition[forContainer]
+ TOKEN_SEMICOLON
+ forStep[forContainer]
+ | /*in:*/TOKEN_KEYWORD_IN
+ /*{
+ final ExpressionNodeBase leftOfIn;
+ if (fi instanceof ExpressionNodeBase)
+ {
+ leftOfIn = (ExpressionNodeBase) fi;
+ }
+ else
+ {
+ // for...in doesn't allow multiple variable definition in the initializer clause
+ addProblem(new InvalidForInInitializerProblem(node));
+ if (fi instanceof ContainerNode &&
+ fi.getChildCount() > 0 &&
+ ((ContainerNode)fi).getChild(0) instanceof ExpressionNodeBase)
+ {
+ // Recover by taking the first variable initializer and
+ // drop the rest.
+ leftOfIn = (ExpressionNodeBase)((ContainerNode)fi).getChild(0);
+ }
+ else
+ {
+ // No valid variable initializer found: recover by adding
+ // an empty identifier node.
+ leftOfIn = IdentifierNode.createEmptyIdentifierNodeAfterToken((ASToken)lparenT);
+ }
+ }
+ inNode = BinaryOperatorNodeBase.create((ASToken)in, leftOfIn, null);
+ forContainer.addItem(inNode);
+ }*/
+ /*e=*/optExpression
+ /*{ inNode.setRightOperandNode(e); }*/
+ )? // Make optional for error handling.
+
+ /*{
+ if (forContainer.getChildCount() == 0 && fi != null)
+ forContainer.addItem(fi);
+ }*/
+
+ ( /*rparenT:*/TOKEN_PAREN_CLOSE
+ /*{
+ forContainer.endBefore(rparenT);
+ }*/
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+ )
+ substatement[b]
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches the "initializer" part in a for loop.
+ */
+forInitializer returns [NodeBase n]
+/*{
+ n = null;
+}*/
+ : /*n=*/variableDefExpression
+ | /*n=*/optExpression
+ ;
+// exception catch [RecognitionException ex] {handleParsingError(ex); }
+
+/**
+ * Matches the "condition" part in a for loop.
+ */
+forCondition[ContainerNode c]
+/*{
+ ExpressionNodeBase e = null;
+}*/
+ : /*e=*/optExpression
+ /*{if (e != null) c.addItem(e);}*/
+ ;
+// exception catch [RecognitionException ex] {handleParsingError(ex); }
+
+/**
+ * Matches the "step" part in a for loop.
+ */
+forStep[ContainerNode c]
+/*{
+ ExpressionNodeBase e = null;
+}*/
+ : /*e=*/optExpression
+ /*{if (e != null) c.addItem(e);}*/
+ ;
+// exception catch [RecognitionException ex] {handleParsingError(ex); }
+
+/**
+ * Matches a "do...while" statement.
+ */
+doStatement[ContainerNode c]
+/*{
+ DoWhileLoopNode n = null;
+ ExpressionNodeBase e = null;
+ BlockNode b = null;
+}*/
+ : /*doT:*/TOKEN_KEYWORD_DO
+ /*{
+ n = new DoWhileLoopNode((ASToken)doT);
+ c.addItem(n);
+ b = n.getContentsNode();
+ }*/
+
+ innerSubstatement[b]
+
+ TOKEN_KEYWORD_WHILE /*e=*/statementParenExpression
+ /*{
+ n.setConditionalExpression(e);
+ matchOptionalSemicolon();
+ }*/
+ ;
+// exception catch [RecognitionException ex] {handleParsingError(ex); }
+
+/**
+ * Matches a "while" loop statement.
+ *
+ * while (x > 1) { x--; }
+ */
+whileStatement[ContainerNode c]
+/*{
+ WhileLoopNode n = null;
+ ExpressionNodeBase e = null;
+ BlockNode b = null;
+}*/
+ : /*whileT:*/TOKEN_KEYWORD_WHILE /*e=*/statementParenExpression
+ /*{
+ n = new WhileLoopNode((ASToken)whileT);
+ n.setConditionalExpression(e);
+ c.addItem(n);
+ b = n.getContentsNode();
+ }*/
+
+ substatement[b]
+ ;
+// exception catch [RecognitionException ex] {handleParsingError(ex); }
+
+
+/**
+ * Matches a "break statement" or a "continue statement". For example:
+ *
+ * break;
+ * break innerLoop;
+ * continue;
+ * continue outerLoop;
+ *
+ */
+breakOrContinueStatement[ContainerNode c]
+/*{
+ IdentifierNode id = null;
+ IterationFlowNode n = null;
+ final ASToken t = LT(1);
+}*/
+ : ( TOKEN_KEYWORD_CONTINUE | TOKEN_KEYWORD_BREAK )
+ /*{
+ n = new IterationFlowNode(t);
+ c.addItem(n);
+ afterRestrictedToken(t);
+ }*/
+
+ // "greedy" mode is required to associate the following ID with the flow control.
+ (options{greedy=true;}:
+ /*id=*/identifier
+ /*{ n.setLabel(id); }*/
+ )?
+ /*{ matchOptionalSemicolon(); }*/
+ ;
+// exception catch [RecognitionException ex] {handleParsingError(ex); }
+
+/**
+ * Matches a "goto" statement.
+ */
+gotoStatement[ContainerNode c]
+/*{
+ IdentifierNode id = null;
+ IterationFlowNode n = null;
+ final ASToken t = LT(1);
+}*/
+ : TOKEN_RESERVED_WORD_GOTO /*id=*/identifier
+ /*{
+ n = new IterationFlowNode(t);
+ c.addItem(n);
+ n.setLabel(id);
+ matchOptionalSemicolon();
+ }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a "with" statement.
+ */
+withStatement[ContainerNode c]
+/*{
+ WithNode n = null;
+ ExpressionNodeBase e = null;
+ BlockNode b = null;
+}*/
+ : /*withT:*/TOKEN_KEYWORD_WITH /*e=*/statementParenExpression
+ /*{
+ n = new WithNode((ASToken)withT);
+ n.setConditionalExpression(e);
+ c.addItem(n);
+ b = n.getContentsNode();
+ }*/
+ substatement[b]
+ ;
+
+/**
+ * Matches a "try...catch...finally" statement.
+ */
+tryStatement[ContainerNode c]
+/*{
+ TryNode n = null;
+ BlockNode b = null;
+}*/
+ : /*tryT:*/TOKEN_KEYWORD_TRY
+ /*{
+ n = new TryNode((ASToken)tryT);
+ b = n.getContentsNode();
+ c.addItem(n);
+ }*/
+
+ block[b]
+
+ ( options { greedy=true;}:
+ catchBlock[n]
+ )*
+
+ ( options { greedy=true;}:
+ /*finallyT:*/TOKEN_KEYWORD_FINALLY
+ /*{
+ TerminalNode t = new TerminalNode((ASToken)finallyT);
+ n.addFinallyBlock(t);
+ b = t.getContentsNode();
+ }*/
+ block[b]
+ )?
+ ;
+
+/**
+ * Matches the "catch" block in a "try" statement.
+ */
+catchBlock[TryNode tryNode]
+/*{
+ CatchNode n = null;
+ ParameterNode arg = null;
+ BlockNode b = null;
+}*/
+ : /*catchT:*/TOKEN_KEYWORD_CATCH TOKEN_PAREN_OPEN
+ /*{ disableSemicolonInsertion(); }*/
+
+ /*arg=*/catchBlockArgument
+ /*{
+ n = new CatchNode(arg);
+ tryNode.addCatchClause(n);
+ b = n.getContentsNode();
+ n.startBefore(catchT);
+ }*/
+
+ ( /*rpT:*/TOKEN_PAREN_CLOSE
+ /*{
+ enableSemicolonInsertion();
+ n.endAfter(rpT);
+ }*/
+
+// exception catch [RecognitionException ex] {handleParsingError(ex); enableSemicolonInsertion(); }
+ )
+
+ block[b]
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches the argument in the "try...catch(arg)" statement.
+ */
+catchBlockArgument returns [ParameterNode p]
+/*{
+ p = null;
+ IdentifierNode name = null;
+ ExpressionNodeBase t = null;
+}*/
+ : /*name=*/identifier
+ /*{ p = new ParameterNode(name); }*/
+
+ ( /*colonT:*/TOKEN_COLON
+ /*{ p.setType((ASToken)colonT, null); }*/
+ /*t=*/type
+ /*{ p.setType((ASToken)colonT, t); }*/
+ )?
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches an "if" statement.
+ */
+ifStatement[ContainerNode c]
+/*{
+ IfNode i = null;
+ ExpressionNodeBase cond = null;
+ ContainerNode b = null;
+ boolean hasElse = false;
+}*/
+ : /*ifT:*/TOKEN_KEYWORD_IF cond=statementParenExpression
+ /*{
+ i = new IfNode((ASToken)ifT);
+ ConditionalNode cNode = new ConditionalNode((ASToken)ifT);
+ cNode.setConditionalExpression(cond);
+ b = cNode.getContentsNode();
+ i.addBranch(cNode);
+ c.addItem(i);
+ }*/
+ innerSubstatement[b]
+
+ (options{greedy=true;}:
+ /*hasElse=*/elsePart[i]
+ /*{ if (hasElse == true) return; }*/
+ )*
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches the optional "else" block of an "if" statement.
+ *
+ * @return true if there is an "else" block.
+ */
+elsePart[IfNode i] returns [boolean hasElse]
+/*{
+ hasElse = false;
+ ContainerNode b = null;
+ ExpressionNodeBase cond = null;
+ ConditionalNode elseIf = null;
+}*/
+
+ : /*elseT:*/TOKEN_KEYWORD_ELSE
+ (options{greedy=true;}:
+ TOKEN_KEYWORD_IF /*cond=*/statementParenExpression
+ /*{
+ elseIf = new ConditionalNode((ASToken) elseT);
+ elseIf.setConditionalExpression(cond);
+ i.addBranch(elseIf);
+ b = elseIf.getContentsNode();
+ }*/
+ )?
+
+ /*{
+ if (elseIf == null){
+ hasElse = true;
+ TerminalNode t = new TerminalNode((ASToken) elseT);
+ i.addBranch(t);
+ b = t.getContentsNode();
+ }
+ }*/
+ substatement[b]
+ ;
+// exception catch [RecognitionException ex] {handleParsingError(ex); }
+
+/**
+ * Matches a "switch" statement.
+ */
+switchStatement[ContainerNode c]
+/*{
+ SwitchNode sw = null;
+ ExpressionNodeBase e = null;
+}*/
+ : /*switchT:*/TOKEN_KEYWORD_SWITCH /*e=*/statementParenExpression
+ /*{
+ sw = new SwitchNode((ASToken)switchT);
+ c.addItem(sw);
+ if(e != null)
+ sw.setConditionalExpression(e);
+ }*/
+
+ cases[sw]
+ ;
+
+/**
+ * Matches the "case" block in a "switch" statement.
+ */
+cases[SwitchNode sw]
+/*{
+ final ContainerNode b = sw.getContentsNode();
+}*/
+ : TOKEN_BLOCK_OPEN caseClauses[b] TOKEN_BLOCK_CLOSE
+ ;
+
+/**
+ * Matches the "case" clauses in a "switch" statement.
+ */
+caseClauses[ContainerNode swb]
+ : (caseClause[swb])*
+ ;
+
+/**
+ * Matches a single "case" clause in a "switch" statement.
+ */
+caseClause[ContainerNode swb]
+/*{
+ ExpressionNodeBase e = null;
+ ContainerNode b = null;
+}*/
+ : /*caseT:*/TOKEN_KEYWORD_CASE /*e=*/expression colon
+ /*{
+ ConditionalNode cond = new ConditionalNode((ASToken) caseT);
+ cond.setConditionalExpression(e);
+ swb.addItem(cond);
+ b = cond.getContentsNode();
+ }*/
+ caseStatementList[b]
+
+ | /*defaultT:*/TOKEN_KEYWORD_DEFAULT colon
+ /*{
+ TerminalNode t = new TerminalNode((ASToken)defaultT);
+ swb.addItem(t);
+ b = t.getContentsNode();
+ }*/
+ caseStatementList[b]
+ ;
+// exception catch [RecognitionException ex] {handleParsingError(ex); }
+
+/**
+ * Matches a colon token ":" or recover from a missing colon.
+ */
+colon
+ : TOKEN_COLON
+ ;
+// exception catch [RecognitionException ex] { addProblem(unexpectedTokenProblem(LT(1), ASTokenKind.COLON)); }
+
+/**
+ * Matches the statements in a "case" clause.
+ */
+caseStatementList[ContainerNode b]
+ : (directive[b, TOKEN_BLOCK_CLOSE])*
+ ;
+// exception catch [RecognitionException ex] {handleParsingError(ex); }
+
+/**
+ * Matches an identifier token. An identifier can come from different token
+ * types such as:
+ *
+ * - IDENTIFIER
+ * - namespace
+ * - get
+ * - set
+ *
+ * This is because in AS3, these elements are not reserved keyword. However they
+ * have special meaning in some syntactic contexts.
+ * See "AS3 syntax spec - 3.5 Keywords and Punctuators" for details.
+ */
+identifier returns [IdentifierNode n]
+/*{
+ n = null;
+ final ASToken token = LT(1);
+}*/
+ : ( TOKEN_IDENTIFIER
+ | TOKEN_RESERVED_WORD_NAMESPACE
+ | TOKEN_RESERVED_WORD_GET
+ | TOKEN_RESERVED_WORD_SET
+ )
+ /*{ n = new IdentifierNode(token); }*/
+ ;
+/* exception
+ catch [NoViableAltException e1] { n = expectingIdentifier(e1); }
+ catch [RecognitionException e2] { n = handleMissingIdentifier(e2); }*/
+
+/**
+ * Matches an "import-able" name.
+ *
+ * flash.display.Sprite;
+ * flash.events.*;
+ */
+importName returns [ExpressionNodeBase n]
+/*{
+ n=null;
+ ExpressionNodeBase e = null;
+}*/
+
+ : /*n=*/packageName
+ ( /*dot:*/TOKEN_OPERATOR_MEMBER_ACCESS
+ /*{
+ n = new FullNameNode(n, (ASToken) dot, null);
+ }*/
+ /*e=*/starLiteral
+ /*{
+ ((FullNameNode)n).setRightOperandNode(e);
+ }*/
+ )?
+ ;
+// exception catch [RecognitionException ex] { return handleMissingIdentifier(ex, n); }
+
+/**
+ * Matches a restricted name. For example:
+ *
+ * my.package.name.Clock;
+ * private::myPrivateVar;
+ * UnqualifiedTypeClock;
+ *
+ */
+restrictedName returns [ExpressionNodeBase ne]
+/*{
+ nameExpression = null;
+ IdentifierNode placeHolderRightNode = null;
+ ASToken opToken = null;
+ ExpressionNodeBase part = null;
+}*/
+ : /*nameExpression=*/restrictedNamePart
+
+ // LL(1) grammar can only branch on the next token.
+ // The LA(2) semantic predicate is used to disambiguate:
+ // 1. "foo.bar" - a restricted name consisting two identifiers
+ // 2. "foo.(bar)" - a member expression whose left-hand side is an identifier
+ // and the right-hand side is a parenthesis expression
+ (options { greedy=true; }: { _input.LA(2) != TOKEN_PAREN_OPEN }?
+ /*{
+ opToken = LT(1);
+
+ // The place-holder node is a safe-net in case parsing the
+ // "right" node fails, so that we will still have a balanced
+ // FullNameNode.
+ placeHolderRightNode = IdentifierNode.createEmptyIdentifierNodeAfterToken(opToken);
+
+ final ExpressionNodeBase nameLeft = nameExpression;
+ }*/
+ ( TOKEN_OPERATOR_MEMBER_ACCESS
+ /*{ nameExpression = new FullNameNode(nameLeft, opToken, placeHolderRightNode); }*/
+ | TOKEN_OPERATOR_NS_QUALIFIER
+ /*{ nameExpression = new NamespaceAccessExpressionNode(nameLeft, opToken, placeHolderRightNode); }*/
+ )
+
+ ( { opToken.getType() == TOKEN_OPERATOR_NS_QUALIFIER && _input.LA(1) == TOKEN_SQUARE_OPEN }?
+ // matches ns::["var_in_ns"]
+ /*nameExpression=*/bracketExpression[nameLeft]
+ | /*part=*/restrictedNamePart
+ /*{
+ ((BinaryOperatorNodeBase)nameExpression).setRightOperandNode(part);
+ checkForChainedNamespaceQualifierProblem(opToken, part);
+ }*/
+ )
+ )*
+ ;
+/* exception catch [RecognitionException ex]
+ {
+ if (nameExpression == null)
+ nameExpression = handleMissingIdentifier(ex);
+ else
+ consumeParsingError(ex);
+ }*/
+
+
+/**
+ * Matches the identifier part of a restricted name. For example:
+ *
+ * private
+ * public
+ * foo
+ * MyType
+ *
+ */
+restrictedNamePart returns [IdentifierNode id]
+/*{
+ id = null;
+ final ASToken lt = LT(1);
+}*/
+ : /*id=*/identifier
+ | TOKEN_NAMESPACE_NAME
+ /*{ id = new IdentifierNode(lt); }*/
+ | TOKEN_KEYWORD_SUPER
+ /*{ id = LanguageIdentifierNode.buildSuper(lt); }*/
+ ;
+ // "identifier", "namespace name" and "super" are all "identifiers" to
+ // the user. So we override the default error handling in order to emit
+ // "expecting identifier but found ..." syntax problem.
+// exception catch [NoViableAltException ex] { id = expectingIdentifier(ex); }
+
+/**
+ * Keep legacy rule for Falcon-JS.
+ */
+typedNameOrStar returns [ExpressionNodeBase n]
+ : /*n=*/type
+ ;
+
+/**
+ * Matches a type reference.
+ *
+ * String
+ * int
+ * *
+ * Vector.<Clock>
+ * foo.bar.Vector.<T>
+ *
+ */
+type returns [ExpressionNodeBase n]
+/*{
+ n = null;
+}*/
+ : /*n=*/starLiteral
+ | /*n=*/restrictedName ( /*n=*/typeApplication[n] )?
+ ;
+// exception catch [RecognitionException ex] { n = handleMissingIdentifier(ex); }
+
+/**
+ * Matches a "type application" part>
+ *
+ * .<String>
+ * .<Clock>
+ * .<uint>
+ *
+ */
+typeApplication [ExpressionNodeBase root] returns[TypedExpressionNode n]
+/*{
+ n = null;
+ ExpressionNodeBase t = null;
+ Token closeT = null;
+ enterTypeApplication(root);
+}*/
+ : /*openT:*/TOKEN_TYPED_COLLECTION_OPEN
+ /*t=*/type
+ /*{
+ n = new TypedExpressionNode(root, t, (ASToken)openT);
+ closeT = LT(1);
+ }*/
+ ( TOKEN_TYPED_COLLECTION_CLOSE | TOKEN_OPERATOR_GREATER_THAN )
+ /*{ n.endAfter(closeT); }*/
+ ;
+// exception catch [RecognitionException ex] { consumeParsingError(ex); }
+
+
+/**
+ * Matches an optional expression.
+ * @return NilNode or ExpressionNodeBase.
+ */
+optExpression returns[ExpressionNodeBase e]
+/*{
+ e = null;
+}*/
+ : (options{greedy=true;}: /*e=*/expression)?
+ /*{ if (e == null) e = new NilNode(); }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches an expression or a comma-separated expression list.
+ */
+expression returns [ExpressionNodeBase n]
+/*{
+ n = null;
+ ExpressionNodeBase e1 = null;
+}*/
+ : /*n=*/assignmentExpression
+ (options{greedy=true;}:
+ /*op:*/TOKEN_COMMA
+ /*e1=*/assignmentExpression
+ /*{ n = BinaryOperatorNodeBase.create((ASToken)op,n,e1); }*/
+ )*
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches an "assignment expression".
+ *
+ * According to ASL sytax spec, the productions for an "assignment expression"
+ * is either a "conditional expression" or a "left-hand side expression" followed
+ * by an "assignment operator" and an "assignment expression". However, since
+ * "assignmentExpression" and "conditionaExpression" is ambiguous at indefinite
+ * look-ahead distance, this LL(1) grammar can't decide which alternative to
+ * choose. As a result, the implementation is more lenient in that an AST node
+ * for an assignment binary node will be built even the left-hand side expression
+ * is not a valid "LeftHandSideExpression", such as a constant.
+ *
+ * For example:
+ * <code>100 = "hello";</code>
+ * This statement will be parsed without syntax error, generating tree like:
+ * <pre>
+ * =
+ * / \
+ * 100 "hello"
+ * </pre>
+ *
+ * A possible solution to this is to find out the difference between "conditional
+ * expression" and "left-hand side expression", then insert a semantic predicate
+ * before matching a "assignment operator".
+ */
+assignmentExpression returns [ExpressionNodeBase n]
+/*{
+ n = null;
+ ASToken op = null;
+ ExpressionNodeBase r = null;
+}*/
+ : /*n=*/condExpr
+ (options{greedy=true;}:
+ /*op=*/assignOp
+ /*r=*/assignmentRightValue
+ /*{ n = BinaryOperatorNodeBase.create(op,n,r); }*/
+ )?
+ ;
+
+/**
+ * Matches the right-hand side of an assignment expression.
+ * "public" namespace is allowed as an R-value for backward compatibility.
+ * @see "CMP-335 and ASLSPEC-19"
+ */
+assignmentRightValue returns [ExpressionNodeBase rightExpr]
+/*{
+ rightExpr = null;
+}*/
+ : { isNextTokenPublicNamespace() }? /*p:*/TOKEN_NAMESPACE_ANNOTATION
+ /*{ rightExpr = new NamespaceIdentifierNode((ASToken)p); }*/
+ | /*rightExpr=*/assignmentExpression
+ ;
+
+assignOp returns [ASToken op]
+/*{
+ op = LT(1);
+}*/
+ : TOKEN_OPERATOR_ASSIGNMENT
+ | TOKEN_OPERATOR_LOGICAL_AND_ASSIGNMENT
+ | TOKEN_OPERATOR_LOGICAL_OR_ASSIGNMENT
+ | TOKEN_OPERATOR_PLUS_ASSIGNMENT
+ | TOKEN_OPERATOR_MINUS_ASSIGNMENT
+ | TOKEN_OPERATOR_MULTIPLICATION_ASSIGNMENT
+ | TOKEN_OPERATOR_DIVISION_ASSIGNMENT
+ | TOKEN_OPERATOR_MODULO_ASSIGNMENT
+ | TOKEN_OPERATOR_BITWISE_AND_ASSIGNMENT
+ | TOKEN_OPERATOR_BITWISE_OR_ASSIGNMENT
+ | TOKEN_OPERATOR_BITWISE_XOR_ASSIGNMENT
+ | TOKEN_OPERATOR_BITWISE_LEFT_SHIFT_ASSIGNMENT
+ | TOKEN_OPERATOR_BITWISE_RIGHT_SHIFT_ASSIGNMENT
+ | TOKEN_OPERATOR_BITWISE_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT
+ ;
+
+/**
+ * Matches a ternary expression such as:
+ *
+ * (x > 2) ? "greater" : "smaller"
+ */
+condExpr returns [ExpressionNodeBase n]
+/*{
+ n = null;
+ ExpressionNodeBase trueExpr = null;
+ ExpressionNodeBase falseExpr = null;
+ TernaryOperatorNode ternary = null;
+}*/
+ : /*n=*/binaryExpr
+ ( /*op:*/TOKEN_OPERATOR_TERNARY
+ /*{
+ ternary = new TernaryOperatorNode((ASToken)op,n,null,null);
+ n = ternary;
+ }*/
+ /*trueExpr=*/assignmentExpression /*{ ternary.setLeftOperandNode(trueExpr); }*/
+ TOKEN_COLON
+ /*falseExpr=*/assignmentExpression /*{ ternary.setRightOperandNode(falseExpr); }*/
+ )?
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+ ;
+
+/**
+ * Binary expression uses operator precedence parser in BaseASParser.
+ */
+binaryExpr returns [ExpressionNodeBase n]
+/*{
+ n = precedenceParseExpression(4);
+ if (true) return n;
+}*/
+ : fakeExpr
+ ;
+
+/**
+ * fakeExpr simulates the set of allowable follow tokens in an expression context, which allows antlr to function.
+ * It is unreachable.
+ */
+fakeExpr
+/*{
+ ExpressionNodeBase n = null;
+}*/
+ : /*n=*/unaryExpr (options{greedy=true;}: binaryOperators fakeExpr)?
+ ;
+
+/**
+ * Declares all the binary operators.
+ */
+binaryOperators
+ : TOKEN_OPERATOR_LOGICAL_OR
+ | TOKEN_OPERATOR_LOGICAL_AND
+ | TOKEN_OPERATOR_BITWISE_OR
+ | TOKEN_OPERATOR_BITWISE_XOR
+ | TOKEN_OPERATOR_BITWISE_AND
+ | TOKEN_OPERATOR_EQUAL
+ | TOKEN_OPERATOR_NOT_EQUAL
+ | TOKEN_OPERATOR_STRICT_EQUAL
+ | TOKEN_OPERATOR_STRICT_NOT_EQUAL
+ | TOKEN_OPERATOR_GREATER_THAN
+ | TOKEN_OPERATOR_GREATER_THAN_EQUALS
+ | TOKEN_OPERATOR_LESS_THAN
+ | TOKEN_OPERATOR_LESS_THAN_EQUALS
+ | TOKEN_KEYWORD_INSTANCEOF
+ | TOKEN_KEYWORD_IS
+ | TOKEN_KEYWORD_AS
+ | TOKEN_KEYWORD_IN
+ | TOKEN_OPERATOR_BITWISE_LEFT_SHIFT
+ | TOKEN_OPERATOR_BITWISE_RIGHT_SHIFT
+ | TOKEN_OPERATOR_BITWISE_UNSIGNED_RIGHT_SHIFT
+ | TOKEN_OPERATOR_MINUS
+ | TOKEN_OPERATOR_PLUS
+ | TOKEN_OPERATOR_DIVISION
+ | TOKEN_OPERATOR_MODULO
+ | TOKEN_OPERATOR_STAR
+ ;
+
+/**
+ * Matches a "prefix expression".
+ *
+ * delete x[i]
+ * ++i
+ * --i
+ *
+ * The distinction between this rule and "unary expression" makes the parser
+ * more strict about what expressions can follow what tokens.
+ */
+prefixExpression returns [ExpressionNodeBase n]
+/*{
+ n = null;
+ final ASToken op = LT(1);
+}*/
+ : /*n=*/postfixExpr
+ | ( TOKEN_KEYWORD_DELETE /*n=*/postfixExpr
+ | TOKEN_OPERATOR_INCREMENT /*n=*/lhsExpr
+ | TOKEN_OPERATOR_DECREMENT /*n=*/lhsExpr
+ )
+ /*{
+ if (n == null)
+ n = IdentifierNode.createEmptyIdentifierNodeAfterToken(op);
+ n = UnaryOperatorNodeBase.createPrefix(op, n);
+ }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a "unary expression".
+ *
+ * This rule is called out of the precedence parser in BaseASParser.
+ * If you need to change the name of this rule, you'll also need to update
+ * the base class.
+ */
+unaryExpr returns [ExpressionNodeBase n]
+/*{
+ n = null;
+ ASToken op = null;
+}*/
+ : ( /*n=*/prefixExpression
+ | /*op=*/unaryOp /*n=*/unaryExpr
+ /*{
+ if (n == null)
+ n = IdentifierNode.createEmptyIdentifierNodeAfterToken(op);
+ n = UnaryOperatorNodeBase.createPrefix(op, n);
+ }*/
+ )
+ (options { greedy = true; }:
+ /*n=*/propertyAccessExpression[n]
+ | /*n=*/arguments[n]
+ )*
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a unary operator.
+ */
+unaryOp returns [ASToken op]
+/*{
+ op = LT(1);
+}*/
+ : TOKEN_KEYWORD_VOID
+ | TOKEN_KEYWORD_TYPEOF
+ | TOKEN_OPERATOR_PLUS
+ | TOKEN_OPERATOR_MINUS
+ | TOKEN_OPERATOR_BITWISE_NOT
+ | TOKEN_OPERATOR_LOGICAL_NOT
+ ;
+
+/**
+ * Matches "Postfix Expression" such as: i++, i--
+ *
+ * Since ECMA semicolon insertion rule requires that if a "++" or "--" is not
+ * on the same line as its left-hand side expression, a semicolon is inserted
+ * before the "--" or "++" token. The side-effect of the inserted semicolon is
+ * to terminate the expression parsing at this point. As a result, we have to
+ * return "null" to stop parsing the expression. An upstream production will
+ * pickup the "--" or "++" by starting a new expression.
+ *
+ * A good test case for such situation would be:
+ *
+ * var i = 99
+ * ++i
+ *
+ * A semicolon should be inserted after "99", resulting in two separate ASTs
+ * for "var i=99" and "++i". Otherwise, "var i=99++" is a bad recognition.
+ */
+postfixExpr returns [ExpressionNodeBase n]
+/*{
+ n = null;
+ boolean isSemicolonInserted = false;
+}*/
+ : /*n=*/lhsExpr
+ /*{
+ final ASToken nextToken = LT(1);
+ if (nextToken.getType() == ASTokenTypes.TOKEN_OPERATOR_INCREMENT ||
+ nextToken.getType() == ASTokenTypes.TOKEN_OPERATOR_DECREMENT)
+ isSemicolonInserted = beforeRestrictedToken(nextToken);
+ }*/
+ ( {!isSemicolonInserted}? (options{greedy=true;}: /*n=*/postfixOp[n])?
+ | // Do nothing if optional semicolon is inserted.
+ // This empty alternative is required because otherwise a semantic
+ // predicate exception will be thrown, leading the code enter error
+ // handling, which will create incorrect tree shape.
+ )
+ ;
+
+/**
+ * Matches a "postfix" operator such as: ++, --
+ * The parameter "n" is the expression the postfix operator acts on.
+ * The return value "top" is a UnaryOperatorNode.
+ */
+postfixOp[ExpressionNodeBase n] returns [UnaryOperatorNodeBase top]
+/*{
+ final ASToken op = LT(1);
+ top = null;
+}*/
+ : ( TOKEN_OPERATOR_INCREMENT
+ | TOKEN_OPERATOR_DECREMENT )
+ /*{ top = UnaryOperatorNodeBase.createPostfix(op, n); }*/
+ ;
+
+/**
+ * Matches a primary expression.
+ */
+primaryExpression returns [ExpressionNodeBase n]
+/*{
+ n = null;
+ ASToken token = LT(1);
+}*/
+ : TOKEN_KEYWORD_NULL
+ /*{ n = new LiteralNode(token, LiteralType.NULL); }*/
+ | TOKEN_KEYWORD_TRUE
+ /*{ n = new LiteralNode(token, LiteralType.BOOLEAN); }*/
+ | TOKEN_KEYWORD_FALSE
+ /*{ n = new LiteralNode(token, LiteralType.BOOLEAN); }*/
+ | TOKEN_KEYWORD_THIS
+ /*{ n = LanguageIdentifierNode.buildThis(token); }*/
+ | token=numericLiteral
+ /*{ n = new NumericLiteralNode(token); }*/
+ | TOKEN_LITERAL_STRING
+ /*{ n = new LiteralNode(token, LiteralType.STRING); }*/
+ | TOKEN_VOID_0
+ /*{ n = new LiteralNode(token, LiteralType.OBJECT); }*/
+ | TOKEN_LITERAL_REGEXP
+ /*{ n = new RegExpLiteralNode(token, this); }*/
+ | /*{ n = new ArrayLiteralNode(); }*/ arrayInitializer[(ArrayLiteralNode)n]
+ | /*n=*/objectLiteralExpression
+ | /*n=*/xmlInitializer /*{ leaveXMLLiteral(); }*/
+ | /*n=*/xmlListInitializer /*{ leaveXMLLiteral(); }*/
+ | /*n=*/functionExpression
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a numeric literal token.
+ */
+numericLiteral returns [ASToken op]
+/*{
+ op = LT(1);
+}*/
+ : TOKEN_LITERAL_NUMBER
+ | TOKEN_LITERAL_HEX_NUMBER
+ ;
+
+/**
+ * Matches an "object literal".
+ */
+objectLiteralExpression returns [ExpressionNodeBase n]
+/*{
+ ObjectLiteralNode o = new ObjectLiteralNode();
+ n = o;
+ ContainerNode b = o.getContentsNode();
+ ExpressionNodeBase vp = null;
+}*/
+ : /*openT:*/TOKEN_BLOCK_OPEN /*{ n.startAfter(openT); }*/
+ ( /*vp=*/objectLiteralValuePair /*{ b.addItem(vp); }*/
+ ( TOKEN_COMMA /*vp=*/objectLiteralValuePair
+ /*{ if (vp != null) b.addItem(vp); }*/
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+ )*
+ )?
+ /*closeT:*/TOKEN_BLOCK_CLOSE /*{ n.endAfter(closeT); }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a "field" in an "object literal".
+ * The "field" can be gated with a "config condition". If the condition is
+ * "false", return "null" value; Otherwise, return the expression node of the
+ * key/value pair.
+ */
+objectLiteralValuePair returns [ExpressionNodeBase n]
+/*{
+ ExpressionNodeBase v = null;
+ n = null;
+ boolean condition = true;
+ ASToken numberT = null;
+}*/
+ : ( { isConfigCondition() && _input.LA(4) != TOKEN_COLON && _input.LA(4) != TOKEN_BLOCK_CLOSE }?
+ /*condition=*/configCondition
+ | // Skip - no config varaible.
+ )
+
+ // Field name:
+ ( /*nameT:*/TOKEN_IDENTIFIER
+ /*{ n = new NonResolvingIdentifierNode(nameT != null ? nameT.getText() : "",nameT); }*/
+ | /*numberT=*/numericLiteral
+ /*{ n = new NumericLiteralNode(numberT); }*/
+ | /*stringT:*/TOKEN_LITERAL_STRING
+ /*{ n = new LiteralNode(LiteralType.STRING, stringT); }*/
+ )
+
+ /*c:*/TOKEN_COLON
+
+ // Field value:
+ /*v=*/assignmentExpression
+ /*{
+ if (condition)
+ n = new ObjectLiteralValuePairNode((ASToken)c,n,v);
+ else
+ n = null;
+ }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+
+/**
+ * Matches array literal. For example:
+ *
+ * []
+ * ["hello", 3.14, foo]
+ * [ , x, y]
+ * [ , ,]
+ *
+ * "Holes" (empty array elements) are allowed. See "arrayElements" rule for details.
+ */
+arrayInitializer [ArrayLiteralNode node]
+/* {
+ final ContainerNode contents = node.getContentsNode();
+ }*/
+ : /*open:*/TOKEN_SQUARE_OPEN /*{ contents.startAfter(open); }*/
+ arrayElements[contents]
+ /*close:*/TOKEN_SQUARE_CLOSE /*{ contents.endBefore(close); }*/
+ ;
+/* exception catch [RecognitionException ex]
+ {
+ // Do not convert keywords to identifiers.
+ // This is for recovering from:
+ // [
+ // var x:int;
+ handleParsingError(ex);
+ // Notify the caller that the array literal failed.
+ throw ex;
+ }*/
+
+/**
+ * Matches all the elements in an "arrayInitializer". For example:
+ *
+ * x,y,z
+ * x,,
+ * (empty)
+ * ,,,,,,
+ *
+ * "Holes" are compiled as "undefined".
+ * Leading "holes" are kept as "undefined" values.
+ * "Holes" in the middle are kept as "undefined" values.
+ * Trailing "holes" are kept as "undefined" values except that the last "hole"
+ * is dropped.
+ *
+ * For example: x=[,,1,,,2,,,] has 2 leading holes, 2 holes in the middle, and 3
+ * holes at the end. All the holes except for the last trailing holes are kept
+ * as undefined values:
+ *
+ * x[0]=undefined
+ * x[1]=undefined
+ * x[2]=1
+ * x[3]=undefined
+ * x[4]=undefined
+ * x[5]=2
+ * x[6]=undefined
+ * x[7]=undefined
+ * (end)
+ *
+ */
+arrayElements[ContainerNode b]
+/*{
+ ExpressionNodeBase e = null;
+}*/
+ : ( TOKEN_COMMA /*{ b.addItem(new NilNode()); }*/ )*
+ ( { _input.LA(1) != TOKEN_SQUARE_CLOSE}?
+ /*e=*/arrayElement /*{ b.addItem(e); }*/
+ ( TOKEN_COMMA
+ ( { _input.LA(1) != TOKEN_SQUARE_CLOSE && _input.LA(1) != TOKEN_COMMA }? /*e=*/arrayElement /*{ b.addItem(e); }*/
+
+ | { _input.LA(1) != TOKEN_SQUARE_CLOSE && _input.LA(1) == TOKEN_COMMA }? /*{ b.addItem(new NilNode()); }*/
+ | // Next token is "]" - pass.
+ )
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+ )*
+ | // Next token is "]" - the initializer is a list of commas: [,,,,,]
+ )
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches an "array element" in an "array literal". An array element can be
+ * gated with a config variable. If the config variable is false, the element
+ * will be matched as a "hole" in the array literal.
+ */
+arrayElement returns [ExpressionNodeBase e]
+/*{
+ e = null;
+ boolean c = true; // config variable
+}*/
+ : ( { isConfigCondition() && _input.LA(4) != TOKEN_COMMA && _input.LA(4) != TOKEN_SQUARE_CLOSE }?
+ c=configCondition
+ | // Skip - no config varaible.
+ )
+ /*e=*/assignmentExpression
+ /*{
+ if (!c)
+ {
+ final NilNode nilNode = new NilNode();
+ nilNode.span(e, e);
+ e = nilNode;
+ }
+ }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a "vector initializer".
+ */
+vectorLiteralExpression returns [VectorLiteralNode node]
+/*{
+ node = new VectorLiteralNode();
+ ContainerNode b = node.getContentsNode();
+ ExpressionNodeBase type = null;
+}*/
+ : /*open:*/TOKEN_TYPED_LITERAL_OPEN /*{ node.endAfter(open); }*/
+ /*type=*/type /*{ node.setCollectionTypeNode(type); }*/
+ /*close:*/TOKEN_TYPED_LITERAL_CLOSE /*{ node.endAfter(close); }*/
+ /*openT:*/TOKEN_SQUARE_OPEN /*{ b.startAfter(openT); }*/
+ (vectorLiteralContents[b])?
+ /*closeT:*/TOKEN_SQUARE_CLOSE /*{ b.endBefore(closeT); }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a "vector element" in a vector initializer.
+ */
+vectorLiteralContents[ContainerNode b]
+/*{
+ ExpressionNodeBase e = null;
+}*/
+ : /*e=*/arrayElement /*{ b.addItem(e); }*/
+ ( TOKEN_COMMA
+ /*{
+ // A trailing comma is allowed, but
+ // an intermediate comma is not.
+ if ( LA(1) != TOKEN_SQUARE_CLOSE ){
+ e=arrayElement();
+ b.addItem(e);
+ }
+ }*/
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+ )*
+ ;
+
+/**
+ * Matches "XML literal expression".
+ */
+xmlInitializer returns [XMLLiteralNode n]
+/*{
+ n = new XMLLiteralNode();
+ final ASToken lt = LT(1);
+ enterXMLLiteral();
+}*/
+ : { _input.LA(1) == TOKEN_E4X_COMMENT ||
+ _input.LA(1) == TOKEN_E4X_CDATA ||
+ _input.LA(1) == TOKEN_E4X_PROCESSING_INSTRUCTION
+ }?
+ xmlMarkup
+ /*{ n.appendLiteralToken(lt); }*/
+ xmlWhitespace[n]
+ | (options { greedy = true; }: xmlElementContent[n] )+
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Match XML whitespace tokens. If {@code ContainerNode} is null, drop the
+ * whitespace tokens.
+ */
+xmlWhitespace [BaseLiteralContainerNode n]
+ : (options { greedy = true; }:
+ /*ws:*/TOKEN_E4X_WHITESPACE
+ /*{
+ if (n != null)
+ n.appendLiteralToken((ASToken)ws);
+ }*/
+ )*
+ ;
+
+/**
+ * Matches an XML comment, XML CDATA or XML PI token.
+ */
+xmlMarkup
+ : TOKEN_E4X_COMMENT
+ | TOKEN_E4X_CDATA
+ | TOKEN_E4X_PROCESSING_INSTRUCTION
+ ;
+
+/**
+ * Matches an E4X token that can be aggregated in "xmlTokenAggregated".
+ * Instead of a full recursive descent parser for XML tags, the base class
+ * uses a tag name stack to check matching tags. A complete parse tree with
+ * XML structure is unnecessary and adds extra overhead to the parser.
+ */
+xmlToken [BaseLiteralContainerNode n]
+/*{
+ final ASToken t = LT(1);
+}*/
+ : ( xmlMarkup
+ | TOKEN_E4X_WHITESPACE
+ | TOKEN_E4X_ENTITY
+ | TOKEN_E4X_DECIMAL_ENTITY
+ | TOKEN_E4X_HEX_ENTITY
+ | TOKEN_E4X_TEXT
+ | TOKEN_E4X_STRING
+ )
+ /*{ n.appendLiteralToken(t); }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches an XML tag.
+ *
+ * <foo>
+ * </foo>
+ * <foo />
+ * <{name}>
+ * <foo name={nameValue}>
+ * <foo {attrs}>
+ */
+xmlTag [BaseLiteralContainerNode n]
+ : ( /*openT:*/TOKEN_E4X_OPEN_TAG_START // <foo
+ /*{
+ xmlTagOpen((ASToken)openT);
+ n.appendLiteralToken((ASToken)openT);
+ }*/
+ | /*closeT:*/TOKEN_E4X_CLOSE_TAG_START // </foo
+ /*{
+ xmlTagClose((ASToken)closeT);
+ n.appendLiteralToken((ASToken)closeT);
+ }*/
+ | /*openNoNameT:*/HIDDEN_TOKEN_E4X // <
+ /*{
+ xmlTagOpenBinding((ASToken)openNoNameT);
+ n.appendLiteralToken((ASToken)openNoNameT);
+ }*/
+
+ // Note about compatibility:
+ // x = < tagName foo="bar" />;
+ // ^
+ // Whitespace isn't allowed here according to ASL spec.
+ // Avik from AS3 spec team confirmed it was a bug that the old ASC allowed it.
+
+ ( xmlContentBlock[n]
+ | /*nT:*/TOKEN_E4X_NAME
+ /*{ n.appendLiteralToken((ASToken)nT); }*/
+ )
+ )
+ xmlWhitespace[n]
+ ( ( xmlAttribute[n] | xmlContentBlock[n] )
+ xmlWhitespace[n]
+ )*
+ ( /*endT:*/TOKEN_E4X_TAG_END // >
+ /*{ n.appendLiteralToken((ASToken)endT); }*/
+ | /*emptyEndT:*/TOKEN_E4X_EMPTY_TAG_END // />
+ /*{
+ xmlEmptyTagEnd((ASToken)emptyEndT);
+ n.appendLiteralToken((ASToken)emptyEndT);
+ }*/
+ )
+ ;
+
+/**
+ * Matches an XML attribute.
+ *
+ * name="value"
+ * name='value'
+ * name={value}
+ */
+xmlAttribute [BaseLiteralContainerNode n]
+ : ( /*nT:*/TOKEN_E4X_NAME
+ /*{ n.appendLiteralToken((ASToken)nT); }*/
+ | /*nsT:*/TOKEN_E4X_XMLNS
+ /*{ n.appendLiteralToken((ASToken)nsT); }*/
+ )
+ ( /*dT:*/TOKEN_E4X_NAME_DOT
+ /*{ n.appendLiteralToken((ASToken)dT); }*/
+ /*dnT:*/TOKEN_E4X_DOTTED_NAME_PART
+ /*{ n.appendLiteralToken((ASToken)dnT); }*/
+ )*
+ xmlWhitespace[n]
+ /*eqT:*/TOKEN_E4X_EQUALS
+ /*{ n.appendLiteralToken((ASToken)eqT); }*/
+ xmlWhitespace[n]
+ (options { greedy = true; }:
+ /*strT:*/TOKEN_E4X_STRING
+ /*{ n.appendLiteralToken((ASToken)strT); }*/
+ | /*eT:*/TOKEN_E4X_ENTITY
+ /*{ n.appendLiteralToken((ASToken)eT); }*/
+ | /*hexT:*/TOKEN_E4X_HEX_ENTITY
+ /*{ n.appendLiteralToken((ASToken)hexT); }*/
+ | xmlContentBlock[n]
+ )+
+ ;
+
+/**
+ * Matches an expression block in XML literals.
+ *
+ * <foo>{ this.fooValue }</foo>
+ */
+xmlElementContent [BaseLiteralContainerNode n]
+ : xmlToken[n]
+ | xmlContentBlock[n]
+ | xmlTag[n]
+ ;
+
+/**
+ * Matches an E4X XML list expression.
+ */
+xmlListInitializer returns [XMLListLiteralNode n]
+/*{
+ n = new XMLListLiteralNode();
+ enterXMLLiteral();
+}*/
+ : /*xmlListT:*/TOKEN_LITERAL_XMLLIST
+ /*{ n.getContentsNode().addItem(new LiteralNode(LiteralType.XML, xmlListT)); }*/
+ ( xmlElementContent[n] )*
+ /*closeT: */TOKEN_E4X_XMLLIST_CLOSE
+ /*{ n.getContentsNode().addItem(new LiteralNode(LiteralType.XML, closeT)); }*/
+ xmlWhitespace[null]
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a binding expression in an XML literal.
+ */
+xmlContentBlock[BaseLiteralContainerNode n]
+/*{
+ ExpressionNodeBase e = null;
+}*/
+ : TOKEN_E4X_BINDING_OPEN
+ /*e=*/expression
+ /*{
+ if(e != null)
+ n.getContentsNode().addItem(e);
+ }*/
+ TOKEN_E4X_BINDING_CLOSE
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+
+/**
+ * Matches a left-hand side (of asssignment) expression.
+ */
+lhsExpr returns [ExpressionNodeBase n]
+/*{
+ n = null;
+}*/
+ : ( /*n=*/newExpression
+ | /*n=*/parenExpression
+ | /*n=*/nameExpression
+ | /*n=*/primaryExpression
+ | /*n=*/xmlAttributeName
+ )
+ (options { greedy = true; }:
+ /*n=*/propertyAccessExpression[n]
+ | /*n=*/arguments[n]
+ )*
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a member expression. See ASL syntax spec for details.
+ */
+memberExpression returns [ExpressionNodeBase n]
+ : ( /*n=*/primaryExpression
+ | /*n=*/parenExpression
+ | /*n=*/propertyName
+ | /*n=*/newExpression
+ )
+ ( options { greedy = true; }: /*n=*/propertyAccessExpression[n] )*
+ ;
+
+/**
+ * Matches a new expression. See ASL syntax spec for details.
+ */
+newExpression returns[ExpressionNodeBase n]
+/*{
+ n = null;
+}*/
+ : /*newT:*/TOKEN_KEYWORD_NEW
+ ( { _input.LA(1) != TOKEN_KEYWORD_FUNCTION }?
+ ( /*n=*/vectorLiteralExpression
+ | /*n=*/memberExpression
+ )
+ /*{
+ if (n == null)
+ n= handleMissingIdentifier(null);
+ else
+ n = FullNameNode.toMemberAccessExpressionNode(n);
+ n = new FunctionCallNode((ASToken)newT, n);
+ }*/
+ (options{greedy=true;}: /*n=*/arguments[n])?
+ | /*n=*/functionExpression /*{ n = new FunctionCallNode((ASToken)newT, n); }*/
+ )
+/* exception catch [RecognitionException ex] {
+ //if we have the 'new' keyword, but no expression, drop in a dummy identifier
+ if(newT != null && n == null) {
+ IdentifierNode identifier = handleMissingIdentifier(ex);
+ if(identifier != null) {
+ //if we're here, that means identifier fixup is turned on
+ n = new FunctionCallNode((ASToken)newT, identifier);
+ }
+ } else {
+ handleParsingError(ex);
+ }
+ }*/
+ ;
+
+/**
+ * Matches an expression with parenthesis.
+ *
+ * (id)
+ * (1 + 2)
+ * (name == "hello")
+ *
+ */
+parenExpression returns[ExpressionNodeBase n]
+/*{
+ n = null;
+}*/
+ : TOKEN_PAREN_OPEN /*n=*/expression TOKEN_PAREN_CLOSE
+ /*{ if(n != null) n.setHasParenthesis(true); }*/
+ ;
+// exception catch [RecognitionException ex] { handleParsingError(ex); }
+
+/**
+ * Matches a property name in a member expression.
+ */
+propertyName returns [ExpressionNodeBase n]
+/*{
+ n = null;
+}*/
+ : /*n=*/starLiteral // *
+ | /*n=*/restrictedName // qualified & unqualified name
+ | /*n=*/xmlAttributeName // e4x attribute
+ ;
+
+/**
+ * This is a non-greedy and non-aggregating version of "restricted name".
+ * It is defined in addition to "propertyName" in order to get correct
+ * precedence in the name expressions and expected tree shapes.
+ */
+nameExpression returns[ExpressionNodeBase n]
+/* { n = null; }*/
+
+ : /*n=*/identifier
+ | /*n=*/starLiteral
+ | /*superT:*/TOKEN_KEYWORD_SUPER
+ /*{ n = LanguageIdentifierNode.buildSuper((IASToken)superT); }*/
+ | /*nsT:*/TOKEN_NAMESPACE_NAME
+ /*{
+ n = new NamespaceIdentifierNode((ASToken)nsT);
+ ((NamespaceIdentifierNode)n).setIsConfigNamespace(isConfigNamespace((NamespaceIdentifierNode)n));
+ }*/
+ ;
+
+
+/**
+ * Matches an E4X attribute name. For example:
+ *
+ * "@*", @data, @[foo="hello"]
+ *
+ */
+xmlAttributeName returns [ExpressionNodeBase result]
+/*{
+ result = UnaryOperatorNodeBase.createPrefix(LT(1), null);
+ ExpressionNodeBase e = null;
+}*/
+ : TOKEN_OPERATOR_ATSIGN
+ ( ( /*e=*/starLiteral
+ | /*e=*/identifier
+ | /*nsT:*/TOKEN_NAMESPACE_NAME /*{ e = new NamespaceIdentifierNode((ASToken)nsT); }*/
+ )
+ /*{
+ ((UnaryOperatorNodeBase)result).setExpression(e);
+ }*/
+ | /*result=*/bracketExpression[result]
+ )
+ ;
+
+/**
+ * Matches a property access expression:
+ * For example: (assuming
<TRUNCATED>