org.antlr.v4.codegen.ActionTranslator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of antlr4 Show documentation
Show all versions of antlr4 Show documentation
The ANTLR 4 grammar compiler.
/*
* [The "BSD license"]
* Copyright (c) 2012 Terence Parr
* Copyright (c) 2012 Sam Harwell
* 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.
*/
package org.antlr.v4.codegen;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.Token;
import org.antlr.v4.codegen.model.RuleFunction;
import org.antlr.v4.codegen.model.chunk.ActionChunk;
import org.antlr.v4.codegen.model.chunk.ActionText;
import org.antlr.v4.codegen.model.chunk.ArgRef;
import org.antlr.v4.codegen.model.chunk.LabelRef;
import org.antlr.v4.codegen.model.chunk.ListLabelRef;
import org.antlr.v4.codegen.model.chunk.LocalRef;
import org.antlr.v4.codegen.model.chunk.NonLocalAttrRef;
import org.antlr.v4.codegen.model.chunk.QRetValueRef;
import org.antlr.v4.codegen.model.chunk.RetValueRef;
import org.antlr.v4.codegen.model.chunk.RulePropertyRef;
import org.antlr.v4.codegen.model.chunk.RulePropertyRef_ctx;
import org.antlr.v4.codegen.model.chunk.RulePropertyRef_start;
import org.antlr.v4.codegen.model.chunk.RulePropertyRef_stop;
import org.antlr.v4.codegen.model.chunk.RulePropertyRef_text;
import org.antlr.v4.codegen.model.chunk.SetAttr;
import org.antlr.v4.codegen.model.chunk.SetNonLocalAttr;
import org.antlr.v4.codegen.model.chunk.ThisRulePropertyRef_ctx;
import org.antlr.v4.codegen.model.chunk.ThisRulePropertyRef_start;
import org.antlr.v4.codegen.model.chunk.ThisRulePropertyRef_stop;
import org.antlr.v4.codegen.model.chunk.ThisRulePropertyRef_text;
import org.antlr.v4.codegen.model.chunk.TokenPropertyRef;
import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_channel;
import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_index;
import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_int;
import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_line;
import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_pos;
import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_text;
import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_type;
import org.antlr.v4.codegen.model.chunk.TokenRef;
import org.antlr.v4.codegen.model.decl.StructDecl;
import org.antlr.v4.parse.ActionSplitter;
import org.antlr.v4.parse.ActionSplitterListener;
import org.antlr.v4.tool.Attribute;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.ActionAST;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** */
public class ActionTranslator implements ActionSplitterListener {
public static final Map> thisRulePropToModelMap =
new HashMap>();
static {
thisRulePropToModelMap.put("start", ThisRulePropertyRef_start.class);
thisRulePropToModelMap.put("stop", ThisRulePropertyRef_stop.class);
thisRulePropToModelMap.put("text", ThisRulePropertyRef_text.class);
thisRulePropToModelMap.put("ctx", ThisRulePropertyRef_ctx.class);
}
public static final Map> rulePropToModelMap =
new HashMap>();
static {
rulePropToModelMap.put("start", RulePropertyRef_start.class);
rulePropToModelMap.put("stop", RulePropertyRef_stop.class);
rulePropToModelMap.put("text", RulePropertyRef_text.class);
rulePropToModelMap.put("ctx", RulePropertyRef_ctx.class);
}
public static final Map> tokenPropToModelMap =
new HashMap>();
static {
tokenPropToModelMap.put("text", TokenPropertyRef_text.class);
tokenPropToModelMap.put("type", TokenPropertyRef_type.class);
tokenPropToModelMap.put("line", TokenPropertyRef_line.class);
tokenPropToModelMap.put("index", TokenPropertyRef_index.class);
tokenPropToModelMap.put("pos", TokenPropertyRef_pos.class);
tokenPropToModelMap.put("channel", TokenPropertyRef_channel.class);
tokenPropToModelMap.put("int", TokenPropertyRef_int.class);
}
CodeGenerator gen;
ActionAST node;
RuleFunction rf;
List chunks = new ArrayList();
OutputModelFactory factory;
StructDecl nodeContext;
public ActionTranslator(OutputModelFactory factory, ActionAST node) {
this.factory = factory;
this.node = node;
this.gen = factory.getGenerator();
}
public static String toString(List chunks) {
StringBuilder buf = new StringBuilder();
for (ActionChunk c : chunks) buf.append(c.toString());
return buf.toString();
}
public static List translateAction(OutputModelFactory factory,
RuleFunction rf,
Token tokenWithinAction,
ActionAST node)
{
String action = tokenWithinAction.getText();
if ( action.charAt(0)=='{' ) {
int firstCurly = action.indexOf('{');
int lastCurly = action.lastIndexOf('}');
if ( firstCurly>=0 && lastCurly>=0 ) {
action = action.substring(firstCurly+1, lastCurly); // trim {...}
}
}
return translateActionChunk(factory, rf, action, node);
}
public static List translateActionChunk(OutputModelFactory factory,
RuleFunction rf,
String action,
ActionAST node)
{
Token tokenWithinAction = node.token;
ActionTranslator translator = new ActionTranslator(factory, node);
translator.rf = rf;
factory.getGrammar().tool.log("action-translator", "translate " + action);
String altLabel = node.getAltLabel();
if ( rf!=null ) translator.nodeContext = rf.ruleCtx;
if ( altLabel!=null ) translator.nodeContext = rf.altLabelCtxs.get(altLabel);
ANTLRStringStream in = new ANTLRStringStream(action);
in.setLine(tokenWithinAction.getLine());
in.setCharPositionInLine(tokenWithinAction.getCharPositionInLine());
ActionSplitter trigger = new ActionSplitter(in, translator);
// forces eval, triggers listener methods
trigger.getActionTokens();
return translator.chunks;
}
@Override
public void attr(String expr, Token x) {
gen.g.tool.log("action-translator", "attr "+x);
Attribute a = node.resolver.resolveToAttribute(x.getText(), node);
if ( a!=null ) {
switch ( a.dict.type ) {
case ARG: chunks.add(new ArgRef(nodeContext,x.getText())); break;
case RET: chunks.add(new RetValueRef(rf.ruleCtx, x.getText())); break;
case LOCAL: chunks.add(new LocalRef(nodeContext,x.getText())); break;
case PREDEFINED_RULE: chunks.add(getRulePropertyRef(x)); break;
}
}
if ( node.resolver.resolvesToToken(x.getText(), node) ) {
chunks.add(new TokenRef(nodeContext,getTokenLabel(x.getText()))); // $label
return;
}
if ( node.resolver.resolvesToLabel(x.getText(), node) ) {
chunks.add(new LabelRef(nodeContext,getTokenLabel(x.getText()))); // $x for x=ID etc...
return;
}
if ( node.resolver.resolvesToListLabel(x.getText(), node) ) {
chunks.add(new ListLabelRef(nodeContext,x.getText())); // $ids for ids+=ID etc...
return;
}
Rule r = factory.getGrammar().getRule(x.getText());
if ( r!=null ) {
chunks.add(new LabelRef(nodeContext,getRuleLabel(x.getText()))); // $r for r rule ref
}
}
@Override
public void qualifiedAttr(String expr, Token x, Token y) {
gen.g.tool.log("action-translator", "qattr "+x+"."+y);
if ( node.resolver.resolveToAttribute(x.getText(), node)!=null ) {
// must be a member access to a predefined attribute like $ctx.foo
attr(expr, x);
chunks.add(new ActionText(nodeContext, "."+y.getText()));
return;
}
Attribute a = node.resolver.resolveToAttribute(x.getText(), y.getText(), node);
switch ( a.dict.type ) {
case ARG: chunks.add(new ArgRef(nodeContext,y.getText())); break; // has to be current rule
case RET:
if ( factory.getCurrentRuleFunction()!=null &&
factory.getCurrentRuleFunction().name.equals(x.getText()) )
{
chunks.add(new RetValueRef(rf.ruleCtx, y.getText())); break;
}
else {
chunks.add(new QRetValueRef(nodeContext, getRuleLabel(x.getText()), y.getText())); break;
}
case PREDEFINED_RULE:
if ( factory.getCurrentRuleFunction()!=null &&
factory.getCurrentRuleFunction().name.equals(x.getText()) )
{
chunks.add(getRulePropertyRef(y));
}
else {
chunks.add(getRulePropertyRef(x, y));
}
break;
case TOKEN:
chunks.add(getTokenPropertyRef(x, y));
break;
}
}
@Override
public void setAttr(String expr, Token x, Token rhs) {
gen.g.tool.log("action-translator", "setAttr "+x+" "+rhs);
List rhsChunks = translateActionChunk(factory,rf,rhs.getText(),node);
SetAttr s = new SetAttr(nodeContext, x.getText(), rhsChunks);
chunks.add(s);
}
@Override
public void nonLocalAttr(String expr, Token x, Token y) {
gen.g.tool.log("action-translator", "nonLocalAttr "+x+"::"+y);
Rule r = factory.getGrammar().getRule(x.getText());
chunks.add(new NonLocalAttrRef(nodeContext, x.getText(), y.getText(), r.index));
}
@Override
public void setNonLocalAttr(String expr, Token x, Token y, Token rhs) {
gen.g.tool.log("action-translator", "setNonLocalAttr "+x+"::"+y+"="+rhs);
Rule r = factory.getGrammar().getRule(x.getText());
List rhsChunks = translateActionChunk(factory,rf,rhs.getText(),node);
SetNonLocalAttr s = new SetNonLocalAttr(nodeContext, x.getText(), y.getText(), r.index, rhsChunks);
chunks.add(s);
}
@Override
public void text(String text) {
chunks.add(new ActionText(nodeContext,text));
}
TokenPropertyRef getTokenPropertyRef(Token x, Token y) {
try {
Class extends TokenPropertyRef> c = tokenPropToModelMap.get(y.getText());
Constructor extends TokenPropertyRef> ctor = c.getConstructor(StructDecl.class, String.class);
TokenPropertyRef ref =
ctor.newInstance(nodeContext, getTokenLabel(x.getText()));
return ref;
}
catch (Exception e) {
factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, e);
}
return null;
}
// $text
RulePropertyRef getRulePropertyRef(Token prop) {
try {
Class extends RulePropertyRef> c = thisRulePropToModelMap.get(prop.getText());
Constructor extends RulePropertyRef> ctor = c.getConstructor(StructDecl.class, String.class);
RulePropertyRef ref =
ctor.newInstance(nodeContext, getRuleLabel(prop.getText()));
return ref;
}
catch (Exception e) {
factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, e);
}
return null;
}
RulePropertyRef getRulePropertyRef(Token x, Token prop) {
Grammar g = factory.getGrammar();
try {
Class extends RulePropertyRef> c = rulePropToModelMap.get(prop.getText());
Constructor extends RulePropertyRef> ctor = c.getConstructor(StructDecl.class, String.class);
RulePropertyRef ref =
ctor.newInstance(nodeContext, getRuleLabel(x.getText()));
return ref;
}
catch (Exception e) {
g.tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, e, prop.getText());
}
return null;
}
public String getTokenLabel(String x) {
if ( node.resolver.resolvesToLabel(x, node) ) return x;
return factory.getGenerator().getTarget().getImplicitTokenLabel(x);
}
public String getRuleLabel(String x) {
if ( node.resolver.resolvesToLabel(x, node) ) return x;
return factory.getGenerator().getTarget().getImplicitRuleLabel(x);
}
}