diff --git a/runtime/Java/src/org/antlr/v4/runtime/atn/ATNSimulator.java b/runtime/Java/src/org/antlr/v4/runtime/atn/ATNSimulator.java index a2a03da16..e24d5c82d 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/atn/ATNSimulator.java +++ b/runtime/Java/src/org/antlr/v4/runtime/atn/ATNSimulator.java @@ -349,6 +349,7 @@ public abstract class ATNSimulator { return c==65535 ? -1 : c; } + @NotNull public static Transition edgeFactory(@NotNull ATN atn, int type, int src, int trg, int arg1, int arg2, int arg3, @@ -372,11 +373,12 @@ public abstract class ATNSimulator { case Transition.NOT_SET : return new NotSetTransition(target, sets.get(arg1)); case Transition.WILDCARD : return new WildcardTransition(target); } - return null; + + throw new IllegalArgumentException("The specified transition type is not valid."); } public static ATNState stateFactory(int type, int stateNumber) { - ATNState s = null; + ATNState s; switch (type) { case ATNState.INVALID_TYPE: return null; case ATNState.BASIC : s = new ATNState(); break; @@ -392,9 +394,10 @@ public abstract class ATNSimulator { case ATNState.PLUS_LOOP_BACK : s = new PlusLoopbackState(); break; case ATNState.LOOP_END : s = new LoopEndState(); break; default : - System.err.println("invalid state type in ATN deserialization: "+type+" for state "+stateNumber); - break; + String message = String.format("The specified state type %d for state %d is not valid.", type, stateNumber); + throw new IllegalArgumentException(message); } + s.stateNumber = stateNumber; return s; } diff --git a/tool/src/org/antlr/v4/automata/ParserATNFactory.java b/tool/src/org/antlr/v4/automata/ParserATNFactory.java index c880090d3..c17cb9ca3 100644 --- a/tool/src/org/antlr/v4/automata/ParserATNFactory.java +++ b/tool/src/org/antlr/v4/automata/ParserATNFactory.java @@ -77,6 +77,7 @@ import org.antlr.v4.tool.ast.QuantifierAST; import org.antlr.v4.tool.ast.TerminalAST; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.List; @@ -621,9 +622,13 @@ public class ParserATNFactory implements ATNFactory { return t; } - // TODO (sam): should we allow this to throw an exception instead of returning null? - @Nullable + @NotNull public T newState(@NotNull Class nodeType, GrammarAST node) { + if (!ATNState.class.isAssignableFrom(nodeType)) { + throw new IllegalArgumentException(String.format("%s is not a %s.", nodeType.getName(), ATNState.class.getName())); + } + + Exception cause; try { Constructor ctor = nodeType.getConstructor(); T s = ctor.newInstance(); @@ -631,11 +636,22 @@ public class ParserATNFactory implements ATNFactory { else s.setRuleIndex(currentRule.index); atn.addState(s); return s; + } catch (InstantiationException ex) { + cause = ex; + } catch (IllegalAccessException ex) { + cause = ex; + } catch (IllegalArgumentException ex) { + cause = ex; + } catch (InvocationTargetException ex) { + cause = ex; + } catch (NoSuchMethodException ex) { + cause = ex; + } catch (SecurityException ex) { + cause = ex; } - catch (Exception e) { - ErrorManager.internalError("can't create ATN node: "+nodeType.getName(), e); - } - return null; + + String message = String.format("Could not create %s of type %s.", ATNState.class.getName(), nodeType.getName()); + throw new UnsupportedOperationException(message, cause); } @NotNull