package org.antlr.v4.codegen.target;
import org.antlr.v4.codegen.CodeGenerator;
import org.antlr.v4.codegen.Target;
import org.antlr.v4.codegen.UnicodeEscapes;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.atn.ATNDeserializer;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.atn.ATNType;
import org.antlr.v4.runtime.atn.ActionTransition;
import org.antlr.v4.runtime.atn.AtomTransition;
import org.antlr.v4.runtime.atn.BlockStartState;
import org.antlr.v4.runtime.atn.DecisionState;
import org.antlr.v4.runtime.atn.LexerAction;
import org.antlr.v4.runtime.atn.LexerChannelAction;
import org.antlr.v4.runtime.atn.LexerCustomAction;
import org.antlr.v4.runtime.atn.LexerModeAction;
import org.antlr.v4.runtime.atn.LexerPushModeAction;
import org.antlr.v4.runtime.atn.LexerTypeAction;
import org.antlr.v4.runtime.atn.LoopEndState;
import org.antlr.v4.runtime.atn.PrecedencePredicateTransition;
import org.antlr.v4.runtime.atn.PredicateTransition;
import org.antlr.v4.runtime.atn.RangeTransition;
import org.antlr.v4.runtime.atn.RuleStartState;
import org.antlr.v4.runtime.atn.RuleTransition;
import org.antlr.v4.runtime.atn.SetTransition;
import org.antlr.v4.runtime.atn.Transition;
import org.antlr.v4.runtime.misc.IntegerList;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.ast.GrammarAST;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.StringRenderer;
import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
public class SwiftTarget extends Target {
private static final ThreadLocal<STGroup> targetTemplates = new ThreadLocal<STGroup>();
protected static final String[] swiftKeywords = {
"associatedtype", "class", "deinit", "enum", "extension", "func", "import", "init", "inout", "internal",
"let", "operator", "private", "protocol", "public", "static", "struct", "subscript", "typealias", "var",
"break", "case", "continue", "default", "defer", "do", "else", "fallthrough", "for", "guard", "if",
"in", "repeat", "return", "switch", "where", "while",
"as", "catch", "dynamicType", "false", "is", "nil", "rethrows", "super", "self", "Self", "throw", "throws",
"true", "try", "__COLUMN__", "__FILE__", "__FUNCTION__","__LINE__", "#column", "#file", "#function", "#line", "_" , "#available", "#else", "#elseif", "#endif", "#if", "#selector",
"associativity", "convenience", "dynamic", "didSet", "final", "get", "infix", "indirect", "lazy",
"left", "mutating", "none", "nonmutating", "optional", "override", "postfix", "precedence",
"prefix", "Protocol", "required", "right", "set", "Type", "unowned", "weak", "willSet"
};
protected final Set<String> badWords = new HashSet<String>();
public String lexerAtnJSON = null;
public String parserAtnJSON = null;
public SwiftTarget(CodeGenerator gen) {
super(gen, "Swift");
}
@Override
public String getVersion() {
return "4.7.2";
}
public Set<String> getBadWords() {
if (badWords.isEmpty()) {
addBadWords();
}
return badWords;
}
protected void addBadWords() {
badWords.addAll(Arrays.asList(swiftKeywords));
badWords.add("rule");
badWords.add("parserRule");
}
@Override
public int getSerializedATNSegmentLimit() {
return 65535 / 3;
}
@Override
protected boolean visibleGrammarSymbolCausesIssueInGeneratedCode(GrammarAST idNode) {
return getBadWords().contains(idNode.getText());
}
@Override
protected void genFile(Grammar g,
ST outputFileST,
String fileName)
{
super.genFile(g,outputFileST,fileName);
if (g.isLexer() && lexerAtnJSON == null) {
lexerAtnJSON = getLexerOrParserATNJson(g, fileName);
}
else if (!g.isLexer() && parserAtnJSON == null && g.atn != null) {
parserAtnJSON = getLexerOrParserATNJson(g, fileName);
}
if (fileName.endsWith(CodeGenerator.VOCAB_FILE_EXTENSION)) {
String jsonFileName = fileName.substring(0,fileName.lastIndexOf(CodeGenerator.VOCAB_FILE_EXTENSION));
if (lexerAtnJSON != null) {
jsonFileName = jsonFileName + "ATN.swift";
writeFile(lexerAtnJSON,g,jsonFileName);
}
if (parserAtnJSON != null) {
jsonFileName = jsonFileName + "ParserATN.swift";
writeFile(parserAtnJSON,g,jsonFileName);
}
}
}
private String getLexerOrParserATNJson(Grammar g, String fileName) {
ST extST = getTemplates().getInstanceOf("codeFileExtension");
String className = fileName.substring(0,fileName.lastIndexOf(extST.render()));
String JSON = "class " + className + "ATN {\n" +
" let jsonString: String = \"" +
serializeTojson(g.atn).replaceAll("\"","\\\\\"") +"\"\n}" ;
return JSON;
}
private void writeFile(String content,Grammar g,String fileName) {
try {
Writer w = this.getCodeGenerator().tool.getOutputFileWriter(g, fileName);
w.write(content);
w.close();
}
catch (IOException ioe) {
this.getCodeGenerator().tool.errMgr.toolError(ErrorType.CANNOT_WRITE_FILE,
ioe,
fileName);
}
}
@Override
protected STGroup loadTemplates() {
STGroup result = targetTemplates.get();
if (result == null) {
result = super.loadTemplates();
result.registerRenderer(String.class, new SwiftStringRenderer(), true);
targetTemplates.set(result);
}
return result;
}
public String serializeTojson(ATN atn) {
JsonObjectBuilder builder = Json.createObjectBuilder();
builder.add("version", ATNDeserializer.SERIALIZED_VERSION);
builder.add("uuid", ATNDeserializer.SERIALIZED_UUID.toString());
builder.add("grammarType",atn.grammarType.ordinal());
builder.add("maxTokenType",atn.maxTokenType);
int nedges = 0;
Map<IntervalSet, Integer> setIndices = new HashMap<IntervalSet, Integer>();
List<IntervalSet> sets = new ArrayList<IntervalSet>();
JsonArrayBuilder statesBuilder = Json.createArrayBuilder() ;
IntegerList nonGreedyStates = new IntegerList();
IntegerList precedenceStates = new IntegerList();
for (ATNState s : atn.states) {
JsonObjectBuilder stateBuilder = Json.createObjectBuilder();
if ( s==null ) {
statesBuilder.addNull();
continue;
}
int stateType = s.getStateType();
stateBuilder.add("stateType",stateType);
stateBuilder.add("ruleIndex",s.ruleIndex);
if (s instanceof DecisionState && ((DecisionState)s).nonGreedy) {
nonGreedyStates.add(s.stateNumber);
}
if (s instanceof RuleStartState && ((RuleStartState)s).isLeftRecursiveRule) {
precedenceStates.add(s.stateNumber);
}
if ( s.getStateType() == ATNState.LOOP_END ) {
stateBuilder.add("detailStateNumber",((LoopEndState)s).loopBackState.stateNumber);
}
else if ( s instanceof BlockStartState ) {
stateBuilder.add("detailStateNumber",((BlockStartState)s).endState.stateNumber);
}
if (s.getStateType() != ATNState.RULE_STOP) {
nedges += s.getNumberOfTransitions();
}
for (int i=0; i<s.getNumberOfTransitions(); i++) {
Transition t = s.transition(i);
int edgeType = Transition.serializationTypes.get(t.getClass());
if ( edgeType == Transition.SET || edgeType == Transition.NOT_SET ) {
SetTransition st = (SetTransition)t;
if (!setIndices.containsKey(st.set)) {
sets.add(st.set);
setIndices.put(st.set, sets.size() - 1);
}
}
}
statesBuilder.add(stateBuilder);
}
builder.add("states",statesBuilder);
JsonArrayBuilder nonGreedyStatesBuilder = Json.createArrayBuilder() ;
for (int i = 0; i < nonGreedyStates.size(); i++) {
nonGreedyStatesBuilder.add(nonGreedyStates.get(i));
}
builder.add("nonGreedyStates",nonGreedyStatesBuilder);
JsonArrayBuilder precedenceStatesBuilder = Json.createArrayBuilder() ;
for (int i = 0; i < precedenceStates.size(); i++) {
precedenceStatesBuilder.add(precedenceStates.get(i));
}
builder.add("precedenceStates",precedenceStatesBuilder);
JsonArrayBuilder ruleToStartStateBuilder = Json.createArrayBuilder() ;
int nrules = atn.ruleToStartState.length;
for (int r=0; r<nrules; r++) {
JsonObjectBuilder stateBuilder = Json.createObjectBuilder();
ATNState ruleStartState = atn.ruleToStartState[r];
stateBuilder.add("stateNumber",ruleStartState.stateNumber);
if (atn.grammarType == ATNType.LEXER) {
stateBuilder.add("ruleToTokenType",atn.ruleToTokenType[r]);
}
ruleToStartStateBuilder.add(stateBuilder);
}
builder.add("ruleToStartState",ruleToStartStateBuilder);
JsonArrayBuilder modeToStartStateBuilder = Json.createArrayBuilder() ;
int nmodes = atn.modeToStartState.size();
if ( nmodes>0 ) {
for (ATNState modeStartState : atn.modeToStartState) {
modeToStartStateBuilder.add(modeStartState.stateNumber);
}
}
builder.add("modeToStartState",modeToStartStateBuilder);
JsonArrayBuilder nsetsBuilder = Json.createArrayBuilder() ;
int nsets = sets.size();
builder.add("nsets",nsets);
for (IntervalSet set : sets) {
JsonObjectBuilder setBuilder = Json.createObjectBuilder();
boolean containsEof = set.contains(Token.EOF);
if (containsEof && set.getIntervals().get(0).b == Token.EOF) {
setBuilder.add("size",set.getIntervals().size() - 1);
}
else {
setBuilder.add("size",set.getIntervals().size());
}
setBuilder.add("containsEof",containsEof ? 1 : 0);
JsonArrayBuilder IntervalsBuilder = Json.createArrayBuilder() ;
for (Interval I : set.getIntervals()) {
JsonObjectBuilder IntervalBuilder = Json.createObjectBuilder();
if (I.a == Token.EOF) {
if (I.b == Token.EOF) {
continue;
}
else {
IntervalBuilder.add("a",0);
}
}
else {
IntervalBuilder.add("a",I.a);
}
IntervalBuilder.add("b",I.b);
IntervalsBuilder.add(IntervalBuilder);
}
setBuilder.add("Intervals",IntervalsBuilder);
nsetsBuilder.add(setBuilder);
}
builder.add("IntervalSet",nsetsBuilder);
JsonArrayBuilder allTransitionsBuilder = Json.createArrayBuilder() ;
for (ATNState s : atn.states) {
if ( s==null ) {
continue;
}
if (s.getStateType() == ATNState.RULE_STOP) {
continue;
}
JsonArrayBuilder transitionsBuilder = Json.createArrayBuilder() ;
for (int i=0; i<s.getNumberOfTransitions(); i++) {
JsonObjectBuilder transitionBuilder = Json.createObjectBuilder();
Transition t = s.transition(i);
if (atn.states.get(t.target.stateNumber) == null) {
throw new IllegalStateException("Cannot serialize a transition to a removed state.");
}
int src = s.stateNumber;
int trg = t.target.stateNumber;
int edgeType = Transition.serializationTypes.get(t.getClass());
int arg1 = 0;
int arg2 = 0;
int arg3 = 0;
switch ( edgeType ) {
case Transition.RULE :
trg = ((RuleTransition)t).followState.stateNumber;
arg1 = ((RuleTransition)t).target.stateNumber;
arg2 = ((RuleTransition)t).ruleIndex;
arg3 = ((RuleTransition)t).precedence;
break;
case Transition.PRECEDENCE:
PrecedencePredicateTransition ppt = (PrecedencePredicateTransition)t;
arg1 = ppt.precedence;
break;
case Transition.PREDICATE :
PredicateTransition pt = (PredicateTransition)t;
arg1 = pt.ruleIndex;
arg2 = pt.predIndex;
arg3 = pt.isCtxDependent ? 1 : 0 ;
break;
case Transition.RANGE :
arg1 = ((RangeTransition)t).from;
arg2 = ((RangeTransition)t).to;
if (arg1 == Token.EOF) {
arg1 = 0;
arg3 = 1;
}
break;
case Transition.ATOM :
arg1 = ((AtomTransition)t).label;
if (arg1 == Token.EOF) {
arg1 = 0;
arg3 = 1;
}
break;
case Transition.ACTION :
ActionTransition at = (ActionTransition)t;
arg1 = at.ruleIndex;
arg2 = at.actionIndex;
arg3 = at.isCtxDependent ? 1 : 0 ;
break;
case Transition.SET :
arg1 = setIndices.get(((SetTransition)t).set);
break;
case Transition.NOT_SET :
arg1 = setIndices.get(((SetTransition)t).set);
break;
case Transition.WILDCARD :
break;
}
transitionBuilder.add("src",src);
transitionBuilder.add("trg",trg);
transitionBuilder.add("edgeType",edgeType);
transitionBuilder.add("arg1",arg1);
transitionBuilder.add("arg2",arg2);
transitionBuilder.add("arg3",arg3);
transitionsBuilder.add(transitionBuilder);
}
allTransitionsBuilder.add(transitionsBuilder);
}
builder.add("allTransitionsBuilder",allTransitionsBuilder);
int ndecisions = atn.decisionToState.size();
JsonArrayBuilder decisionToStateBuilder = Json.createArrayBuilder() ;
for (DecisionState decStartState : atn.decisionToState) {
decisionToStateBuilder.add(decStartState.stateNumber);
}
builder.add("decisionToState",decisionToStateBuilder);
JsonArrayBuilder lexerActionsBuilder = Json.createArrayBuilder() ;
if (atn.grammarType == ATNType.LEXER) {
for (LexerAction action : atn.lexerActions) {
JsonObjectBuilder lexerActionBuilder = Json.createObjectBuilder();
lexerActionBuilder.add("actionType",action.getActionType().ordinal());
switch (action.getActionType()) {
case CHANNEL:
int channel = ((LexerChannelAction)action).getChannel();
lexerActionBuilder.add("a",channel);
lexerActionBuilder.add("b",0);
break;
case CUSTOM:
int ruleIndex = ((LexerCustomAction)action).getRuleIndex();
int actionIndex = ((LexerCustomAction)action).getActionIndex();
lexerActionBuilder.add("a",ruleIndex);
lexerActionBuilder.add("b",actionIndex);
break;
case MODE:
int mode = ((LexerModeAction)action).getMode();
lexerActionBuilder.add("a",mode);
lexerActionBuilder.add("b",0);
break;
case MORE:
lexerActionBuilder.add("a",0);
lexerActionBuilder.add("b",0);
break;
case POP_MODE:
lexerActionBuilder.add("a",0);
lexerActionBuilder.add("b",0);
break;
case PUSH_MODE:
mode = ((LexerPushModeAction)action).getMode();
lexerActionBuilder.add("a",mode);
lexerActionBuilder.add("b",0);
break;
case SKIP:
lexerActionBuilder.add("a",0);
lexerActionBuilder.add("b",0);
break;
case TYPE:
int type = ((LexerTypeAction)action).getType();
lexerActionBuilder.add("a",type);
lexerActionBuilder.add("b",0);
break;
default:
String message = String.format(Locale.getDefault(), "The specified lexer action type %s is not valid.", action.getActionType());
throw new IllegalArgumentException(message);
}
lexerActionsBuilder.add(lexerActionBuilder);
}
}
builder.add("lexerActions",lexerActionsBuilder);
JsonObject data = builder.build();
return data.toString();
}
protected static class SwiftStringRenderer extends StringRenderer {
@Override
public String toString(Object o, String formatString, Locale locale) {
if ("java-escape".equals(formatString)) {
return ((String)o).replace("\\u", "\\u005Cu");
}
return super.toString(o, formatString, locale);
}
}
@Override
protected void appendUnicodeEscapedCodePoint(int codePoint, StringBuilder sb) {
UnicodeEscapes.appendSwiftStyleEscapedCodePoint(codePoint, sb);
}
}