| /* |
| * [The "BSD license"] |
| * Copyright (c) 2007-2008 Johannes Luber |
| * Copyright (c) 2005-2007 Kunle Odutola |
| * Copyright (c) 2011 Sam Harwell |
| * Copyright (c) 2011 Terence Parr |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| @outputFile.imports() ::= << |
| <@super.imports()> |
| |
| <if(!TREE_PARSER)> |
| <! tree parser would already have imported !> |
| using Antlr.Runtime.Tree; |
| using RewriteRuleITokenStream = Antlr.Runtime.Tree.RewriteRuleTokenStream; |
| <endif> |
| >> |
| |
| @genericParser.members() ::= << |
| <@super.members()> |
| <parserMembers()> |
| >> |
| |
| parserCtorBody() ::= <% |
| <super.parserCtorBody()><\n> |
| TreeAdaptor = |
| <if(actions.(actionScope).treeAdaptorInitializer)> |
| <actions.(actionScope).treeAdaptorInitializer> |
| <else> |
| new <actions.(actionScope).treeAdaptorType; null="CommonTreeAdaptor">() |
| <end> |
| ; |
| %> |
| |
| /** Add an adaptor property that knows how to build trees */ |
| parserMembers() ::= << |
| private <treeAdaptorType()> adaptor; |
| |
| public <treeAdaptorType()> TreeAdaptor |
| { |
| get |
| { |
| return adaptor; |
| } |
| |
| set |
| { |
| this.adaptor = value; |
| <grammar.directDelegates:{g|<g:delegateName()>.TreeAdaptor = this.adaptor;}> |
| } |
| } |
| >> |
| |
| treeAdaptorType() ::= << |
| <actions.(actionScope).treeAdaptorType; null="ITreeAdaptor"> |
| >> |
| |
| ruleReturnBaseType() ::= <% |
| Ast<if(TREE_PARSER)>Tree<else>Parser<endif>RuleReturnScope\<<ASTLabelType>, <labelType>> |
| %> |
| |
| /** Add a variable to track rule's return AST */ |
| ruleDeclarations() ::= << |
| <super.ruleDeclarations()> |
| <ASTLabelType> root_0 = default(<ASTLabelType>);<\n> |
| >> |
| |
| ruleLabelDefs() ::= << |
| <super.ruleLabelDefs()> |
| <[ruleDescriptor.tokenLabels,ruleDescriptor.wildcardTreeLabels,ruleDescriptor.wildcardTreeListLabels] |
| :{it|<ASTLabelType> <it.label.text>_tree = default(<ASTLabelType>);}; separator="\n"> |
| <ruleDescriptor.tokenListLabels:{it|<ASTLabelType> <it.label.text>_tree = default(<ASTLabelType>);}; separator="\n"> |
| <ruleDescriptor.allTokenRefsInAltsWithRewrites |
| :{it|RewriteRule<rewriteElementType>Stream stream_<it>=new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>");}; separator="\n"> |
| <ruleDescriptor.allRuleRefsInAltsWithRewrites |
| :{it|RewriteRuleSubtreeStream stream_<it>=new RewriteRuleSubtreeStream(adaptor,"rule <it>");}; separator="\n"> |
| >> |
| |
| /** When doing auto AST construction, we must define some variables; |
| * These should be turned off if doing rewrites. This must be a "mode" |
| * as a rule could have both rewrite and AST within the same alternative |
| * block. |
| */ |
| @alt.declarations() ::= << |
| <if(autoAST)> |
| <if(outerAlt)> |
| <if(!rewriteMode)> |
| root_0 = (<ASTLabelType>)adaptor.Nil(); |
| <endif> |
| <endif> |
| <endif> |
| >> |
| |
| // T r a c k i n g R u l e E l e m e n t s |
| |
| /** ID and track it for use in a rewrite rule */ |
| tokenRefTrack(token,label,elementIndex,terminalOptions) ::= << |
| <tokenRefBang(...)> <! Track implies no auto AST construction!> |
| <if(backtracking)>if (<actions.(actionScope).synpredgate>) <endif>stream_<token>.Add(<label>);<\n> |
| >> |
| |
| /** ids+=ID and track it for use in a rewrite rule; adds to ids *and* |
| * to the tracking list stream_ID for use in the rewrite. |
| */ |
| tokenRefTrackAndListLabel(token,label,elementIndex,terminalOptions) ::= << |
| <tokenRefTrack(...)> |
| <listLabelElem(elem=label,elemType=labelType,...)> |
| >> |
| |
| /** ^(ID ...) track for rewrite */ |
| tokenRefRuleRootTrack(token,label,elementIndex,terminalOptions) ::= << |
| <tokenRefBang(...)> |
| <if(backtracking)>if (<actions.(actionScope).synpredgate>) <endif>stream_<token>.Add(<label>); |
| >> |
| |
| /** Match ^(label+=TOKEN ...) track for rewrite */ |
| tokenRefRuleRootTrackAndListLabel(token,label,elementIndex,terminalOptions) ::= << |
| <tokenRefRuleRootTrack(...)> |
| <listLabelElem(elem=label,elemType=labelType,...)> |
| >> |
| |
| /** rule when output=AST and tracking for rewrite */ |
| ruleRefTrack(rule,label,elementIndex,args,scope) ::= << |
| <super.ruleRef(...)> |
| <if(backtracking)>if (<actions.(actionScope).synpredgate>) <endif>stream_<rule.name>.Add(<label>.Tree); |
| >> |
| |
| /** x+=rule when output=AST and tracking for rewrite */ |
| ruleRefTrackAndListLabel(rule,label,elementIndex,args,scope) ::= << |
| <ruleRefTrack(...)> |
| <listLabelElem(elem={<label>.Tree},elemType=ASTLabelType,...)> |
| >> |
| |
| /** ^(rule ...) rewrite */ |
| ruleRefRuleRootTrack(rule,label,elementIndex,args,scope) ::= << |
| <ruleRefRuleRoot(...)> |
| <if(backtracking)>if (<actions.(actionScope).synpredgate>) <endif>stream_<rule>.Add(<label>.Tree); |
| >> |
| |
| /** ^(x+=rule ...) rewrite */ |
| ruleRefRuleRootTrackAndListLabel(rule,label,elementIndex,args,scope) ::= << |
| <ruleRefRuleRootTrack(...)> |
| <listLabelElem(elem={<label>.Tree},elemType=ASTLabelType,...)> |
| >> |
| |
| // R e w r i t e |
| |
| rewriteCode( |
| alts, description, |
| referencedElementsDeep, // ALL referenced elements to right of -> |
| referencedTokenLabels, |
| referencedTokenListLabels, |
| referencedRuleLabels, |
| referencedRuleListLabels, |
| referencedWildcardLabels, |
| referencedWildcardListLabels, |
| rewriteBlockLevel, enclosingTreeLevel, treeLevel) ::= << |
| <\n>{ |
| // AST REWRITE |
| // elements: <referencedElementsDeep; separator=", "> |
| // token labels: <referencedTokenLabels; separator=", "> |
| // rule labels: <referencedRuleLabels; separator=", "> |
| // token list labels: <referencedTokenListLabels; separator=", "> |
| // rule list labels: <referencedRuleListLabels; separator=", "> |
| // wildcard labels: <[referencedWildcardLabels,referencedWildcardListLabels]; separator=", "> |
| <if(backtracking)> |
| if (<actions.(actionScope).synpredgate>) { |
| <endif> |
| <prevRuleRootRef()>.Tree = root_0; |
| <rewriteCodeLabels()> |
| root_0 = (<ASTLabelType>)adaptor.Nil(); |
| <alts:rewriteAlt(); separator="else "> |
| <! if tree parser and rewrite=true !> |
| <if(TREE_PARSER&&rewriteMode)> |
| <prevRuleRootRef()>.Tree = (<ASTLabelType>)adaptor.RulePostProcessing(root_0); |
| input.ReplaceChildren(adaptor.GetParent(retval.Start), |
| adaptor.GetChildIndex(retval.Start), |
| adaptor.GetChildIndex(_last), |
| retval.Tree); |
| <endif> |
| <! if parser or tree-parser && rewrite!=true, we need to set result !> |
| <if(!TREE_PARSER||!rewriteMode)> |
| <prevRuleRootRef()>.Tree = root_0; |
| <endif> |
| <if(backtracking)> |
| } |
| <endif> |
| } |
| |
| >> |
| |
| rewriteCodeLabels() ::= << |
| <referencedTokenLabels |
| :{it|RewriteRule<rewriteElementType>Stream stream_<it>=new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>",<it>);}; |
| separator="\n" |
| > |
| <referencedTokenListLabels |
| :{it|RewriteRule<rewriteElementType>Stream stream_<it>=new RewriteRule<rewriteElementType>Stream(adaptor,"token <it>", list_<it>);}; |
| separator="\n" |
| > |
| <referencedWildcardLabels |
| :{it|RewriteRuleSubtreeStream stream_<it>=new RewriteRuleSubtreeStream(adaptor,"wildcard <it>",<it>);}; |
| separator="\n" |
| > |
| <referencedWildcardListLabels |
| :{it|RewriteRuleSubtreeStream stream_<it>=new RewriteRuleSubtreeStream(adaptor,"wildcard <it>",list_<it>);}; |
| separator="\n" |
| > |
| <referencedRuleLabels |
| :{it|RewriteRuleSubtreeStream stream_<it>=new RewriteRuleSubtreeStream(adaptor,"rule <it>",<it>!=null?<it>.Tree:null);}; |
| separator="\n" |
| > |
| <referencedRuleListLabels |
| :{it|RewriteRuleSubtreeStream stream_<it>=new RewriteRuleSubtreeStream(adaptor,"token <it>",list_<it>);}; |
| separator="\n" |
| > |
| >> |
| |
| /** Generate code for an optional rewrite block; note it uses the deep ref'd element |
| * list rather shallow like other blocks. |
| */ |
| rewriteOptionalBlock( |
| alt,rewriteBlockLevel, |
| referencedElementsDeep, // all nested refs |
| referencedElements, // elements in immediately block; no nested blocks |
| description) ::= |
| << |
| // <fileName>:<description> |
| if (<referencedElementsDeep:{el | stream_<el>.HasNext}; separator="||">) |
| { |
| <alt> |
| } |
| <referencedElementsDeep:{el | stream_<el>.Reset();<\n>}> |
| >> |
| |
| rewriteClosureBlock( |
| alt,rewriteBlockLevel, |
| referencedElementsDeep, // all nested refs |
| referencedElements, // elements in immediately block; no nested blocks |
| description) ::= |
| << |
| // <fileName>:<description> |
| while ( <referencedElements:{el | stream_<el>.HasNext}; separator="||"> ) |
| { |
| <alt> |
| } |
| <referencedElements:{el | stream_<el>.Reset();<\n>}> |
| >> |
| |
| rewritePositiveClosureBlock( |
| alt,rewriteBlockLevel, |
| referencedElementsDeep, // all nested refs |
| referencedElements, // elements in immediately block; no nested blocks |
| description) ::= |
| << |
| if (!(<referencedElements:{el | stream_<el>.HasNext}; separator="||">)) |
| { |
| throw new RewriteEarlyExitException(); |
| } |
| while ( <referencedElements:{el | stream_<el>.HasNext}; separator="||"> ) |
| { |
| <alt> |
| } |
| <referencedElements:{el | stream_<el>.Reset();<\n>}> |
| >> |
| |
| rewriteAlt(a) ::= << |
| // <a.description> |
| <if(a.pred)> |
| if (<a.pred>) |
| { |
| <a.alt> |
| } |
| <else> |
| { |
| <a.alt> |
| } |
| <endif> |
| >> |
| |
| /** For empty rewrites: "r : ... -> ;" */ |
| rewriteEmptyAlt() ::= "root_0 = null;" |
| |
| rewriteTree(root,children,description,enclosingTreeLevel,treeLevel) ::= << |
| // <fileName>:<description> |
| { |
| <ASTLabelType> root_<treeLevel> = (<ASTLabelType>)adaptor.Nil(); |
| <root:rewriteElement()> |
| <children:rewriteElement()> |
| adaptor.AddChild(root_<enclosingTreeLevel>, root_<treeLevel>); |
| }<\n> |
| >> |
| |
| rewriteElementList(elements) ::= "<elements:rewriteElement()>" |
| |
| rewriteElement(e) ::= <% |
| <@pregen()> |
| DebugLocation(<e.line>, <e.pos>);<\n> |
| <e.el> |
| %> |
| |
| /** Gen ID or ID[args] */ |
| rewriteTokenRef(token,elementIndex,terminalOptions,args) ::= << |
| adaptor.AddChild(root_<treeLevel>, <createRewriteNodeFromElement(...)>);<\n> |
| >> |
| |
| /** Gen $label ... where defined via label=ID */ |
| rewriteTokenLabelRef(label,elementIndex) ::= << |
| adaptor.AddChild(root_<treeLevel>, stream_<label>.NextNode());<\n> |
| >> |
| |
| /** Gen $label ... where defined via label+=ID */ |
| rewriteTokenListLabelRef(label,elementIndex) ::= << |
| adaptor.AddChild(root_<treeLevel>, stream_<label>.NextNode());<\n> |
| >> |
| |
| /** Gen ^($label ...) */ |
| rewriteTokenLabelRefRoot(label,elementIndex) ::= << |
| root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<label>.NextNode(), root_<treeLevel>);<\n> |
| >> |
| |
| /** Gen ^($label ...) where label+=... */ |
| rewriteTokenListLabelRefRoot ::= rewriteTokenLabelRefRoot |
| |
| /** Gen ^(ID ...) or ^(ID[args] ...) */ |
| rewriteTokenRefRoot(token,elementIndex,terminalOptions,args) ::= << |
| root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<createRewriteNodeFromElement(...)>, root_<treeLevel>);<\n> |
| >> |
| |
| rewriteImaginaryTokenRef(args,token,terminalOptions,elementIndex) ::= << |
| adaptor.AddChild(root_<treeLevel>, <createImaginaryNode(tokenType=token, ...)>);<\n> |
| >> |
| |
| rewriteImaginaryTokenRefRoot(args,token,terminalOptions,elementIndex) ::= << |
| root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<createImaginaryNode(tokenType=token, ...)>, root_<treeLevel>);<\n> |
| >> |
| |
| /** plain -> {foo} action */ |
| rewriteAction(action) ::= << |
| root_0 = <action>;<\n> |
| >> |
| |
| /** What is the name of the previous value of this rule's root tree? This |
| * let's us refer to $rule to mean previous value. I am reusing the |
| * variable 'tree' sitting in retval struct to hold the value of root_0 right |
| * before I set it during rewrites. The assign will be to retval.tree. |
| */ |
| prevRuleRootRef() ::= "retval" |
| |
| rewriteRuleRef(rule) ::= << |
| adaptor.AddChild(root_<treeLevel>, stream_<rule>.NextTree());<\n> |
| >> |
| |
| rewriteRuleRefRoot(rule) ::= << |
| root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<rule>.NextNode(), root_<treeLevel>);<\n> |
| >> |
| |
| rewriteNodeAction(action) ::= << |
| adaptor.AddChild(root_<treeLevel>, <action>);<\n> |
| >> |
| |
| rewriteNodeActionRoot(action) ::= << |
| root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(<action>, root_<treeLevel>);<\n> |
| >> |
| |
| /** Gen $ruleLabel ... where defined via ruleLabel=rule */ |
| rewriteRuleLabelRef(label) ::= << |
| adaptor.AddChild(root_<treeLevel>, stream_<label>.NextTree());<\n> |
| >> |
| |
| /** Gen $ruleLabel ... where defined via ruleLabel+=rule */ |
| rewriteRuleListLabelRef(label) ::= << |
| adaptor.AddChild(root_<treeLevel>, stream_<label>.NextTree());<\n> |
| >> |
| |
| /** Gen ^($ruleLabel ...) where ruleLabel=rule */ |
| rewriteRuleLabelRefRoot(label) ::= << |
| root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<label>.NextNode(), root_<treeLevel>);<\n> |
| >> |
| |
| /** Gen ^($ruleLabel ...) where ruleLabel+=rule */ |
| rewriteRuleListLabelRefRoot(label) ::= << |
| root_<treeLevel> = (<ASTLabelType>)adaptor.BecomeRoot(stream_<label>.NextNode(), root_<treeLevel>);<\n> |
| >> |
| |
| rewriteWildcardLabelRef(label) ::= << |
| adaptor.AddChild(root_<treeLevel>, stream_<label>.NextTree());<\n> |
| >> |
| |
| createImaginaryNode(tokenType,terminalOptions,args) ::= <% |
| <if(terminalOptions.node)> |
| <! new MethodNode(IDLabel, args) !> |
| new <terminalOptions.node>(<tokenType><if(args)>, <args; separator=", "><endif>) |
| <else> |
| (<ASTLabelType>)adaptor.Create(<tokenType>, <args; separator=", "><if(!args)>"<tokenType>"<endif>) |
| <endif> |
| %> |
| |
| createRewriteNodeFromElement(token,terminalOptions,args) ::= <% |
| <if(terminalOptions.node)> |
| new <terminalOptions.node>(stream_<token>.NextToken()<if(args)>, <args; separator=", "><endif>) |
| <else> |
| <if(args)> <! must create new node from old !> |
| adaptor.Create(<token>, <args; separator=", ">) |
| <else> |
| stream_<token>.NextNode() |
| <endif> |
| <endif> |
| %> |