IElementType FAILBACK = new MathematicaElementType("FAILBACK");
class Factory {
public static PsiElement create(ASTNode node) {
IElementType type = node.getElementType();
if (type.equals(GROUP_EXPRESSION)) return new GroupImpl(node);
if (type.equals(FUNCTION_CALL_EXPRESSION)) return new FunctionCallImpl(node);
// Basic types
if (type.equals(SYMBOL_EXPRESSION)) return new SymbolImpl(node);
if (type.equals(STRINGIFIED_SYMBOL_EXPRESSION)) return new StringifiedSymbolImpl(node);
if (SLOTS.contains(type)) return new SlotImpl(node);
if (type.equals(NUMBER_EXPRESSION)) return new NumberImpl(node);
if (type.equals(STRING_LITERAL_EXPRESSION)) return new StringImpl(node);
// Arithmetic operations
if (type.equals(DIVIDE_EXPRESSION)) return new DivideImpl(node);
if (type.equals(DOT_EXPRESSION)) return new DotImpl(node);
if (type.equals(FACTORIAL_POSTFIX)) return new FactorialImpl(node);
if (type.equals(MINUS_EXPRESSION)) return new MinusImpl(node);
if (type.equals(PLUS_EXPRESSION)) return new PlusImpl(node);
if (type.equals(POWER_EXPRESSION)) return new PowerImpl(node);
if (type.equals(TIMES_EXPRESSION)) return new TimesImpl(node);
if (type.equals(UNARY_MINUS_PREFIX)) return new UnaryMinusImpl(node);
if (type.equals(UNARY_PLUS_PREFIX)) return new UnaryPlusImpl(node);
// Assignments
if (type.equals(ADD_TO_EXPRESSION)) return new AddToImpl(node);
if (type.equals(DECREMENT_POSTFIX)) return new DecrementImpl(node);
if (type.equals(DIVIDE_BY_EXPRESSION)) return new DivideByImpl(node);
if (type.equals(INCREMENT_POSTFIX)) return new IncrementImpl(node);
if (type.equals(PRE_INCREMENT_PREFIX)) return new PreIncrementImpl(node);
if (type.equals(PRE_DECREMENT_PREFIX)) return new PreDecrementImpl(node);
if (type.equals(SET_DELAYED_EXPRESSION)) return new SetDelayedImpl(node);
if (type.equals(SET_EXPRESSION)) return new SetImpl(node);
if (type.equals(SUBTRACT_FROM_EXPRESSION)) return new SubtractFromImpl(node);
if (type.equals(TAG_SET_EXPRESSION)) return new TagSetImpl(node);
if (type.equals(TAG_SET_DELAYED_EXPRESSION)) return new TagSetDelayedImpl(node);
if (type.equals(TAG_UNSET_EXPRESSION)) return new TagUnsetImpl(node);
if (type.equals(TIMES_BY_EXPRESSION)) return new TimesByImpl(node);
if (type.equals(UNSET_EXPRESSION)) return new UnsetImpl(node);
if (type.equals(UP_SET_DELAYED_EXPRESSION)) return new UpSetDelayedImpl(node);
if (type.equals(UP_SET_EXPRESSION)) return new UpSetImpl(node);
// Comparisons
if (type.equals(EQUAL_EXPRESSION)) return new EqualImpl(node);
if (type.equals(GREATER_EQUAL_EXPRESSION)) return new GreaterEqualImpl(node);
if (type.equals(GREATER_EXPRESSION)) return new GreaterImpl(node);
if (type.equals(LESS_EQUAL_EXPRESSION)) return new LessEqualImpl(node);
if (type.equals(LESS_EXPRESSION)) return new LessImpl(node);
if (type.equals(SAME_Q_EXPRESSION)) return new SameQImpl(node);
if (type.equals(UNEQUAL_EXPRESSION)) return new UnequalImpl(node);
if (type.equals(UNSAME_Q_EXPRESSION)) return new UnsameQImpl(node);
// File operations
if (type.equals(GET_PREFIX)) return new GetImpl(node);
if (type.equals(PUT_APPEND_EXPRESSION)) return new PutAppendImpl(node);
if (type.equals(PUT_EXPRESSION)) return new PutImpl(node);
// Function related
if (type.equals(APPLY1_EXPRESSION)) return new Apply1Impl(node);
if (type.equals(APPLY_EXPRESSION)) return new ApplyImpl(node);
if (type.equals(INFIX_CALL_EXPRESSION)) return new InfixImpl(node);
if (type.equals(MAP_ALL_EXPRESSION)) return new MapAllImpl(node);
if (type.equals(MAP_EXPRESSION)) return new MapImpl(node);
if (type.equals(POSTFIX_EXPRESSION)) return new PostfixImpl(node);
if (type.equals(PREFIX_CALL_EXPRESSION)) return new PrefixImpl(node);
if (type.equals(FUNCTION_POSTFIX)) return new FunctionImpl(node);
if (type.equals(DERIVATIVE_EXPRESSION)) return new DerivativeImpl(node);
if (type.equals(COMPOSITION_EXPRESSION)) return new CompositionImpl(node);
if (type.equals(RIGHT_COMPOSITION_EXPRESSION)) return new RightCompositionImpl(node);
// List or Association related
if (type.equals(LIST_EXPRESSION)) return new ListImpl(node);
if (type.equals(ASSOCIATION_EXPRESSION)) return new AssociationImpl(node);
if (type.equals(PART_EXPRESSION)) return new PartImpl(node);
if (type.equals(SPAN_EXPRESSION)) return new SpanImpl(node);
// Logical operations
if (type.equals(AND_EXPRESSION)) return new AndImpl(node);
if (type.equals(OR_EXPRESSION)) return new OrImpl(node);
if (type.equals(NOT_PREFIX)) return new NotImpl(node);
// Patterns
if (type.equals(ALTERNATIVE_EXPRESSION)) return new AlternativeImpl(node);
if (type.equals(BLANK_EXPRESSION)) return new BlankImpl(node);
if (type.equals(BLANK_NULL_SEQUENCE_EXPRESSION)) return new BlankNullSequenceImpl(node);
if (type.equals(BLANK_SEQUENCE_EXPRESSION)) return new BlankSequenceImpl(node);
if (type.equals(CONDITION_EXPRESSION)) return new ConditionImpl(node);
if (type.equals(OPTIONAL_EXPRESSION)) return new OptionalImpl(node);
if (type.equals(PATTERN_EXPRESSION)) return new PatternImpl(node);
if (type.equals(PATTERN_TEST_EXPRESSION)) return new PatternTestImpl(node);
if (type.equals(REPEATED_POSTFIX)) return new RepeatedImpl(node);
if (type.equals(REPEATED_NULL_POSTFIX)) return new RepeatedNullImpl(node);
if (type.equals(DEFAULT_EXPRESSION)) return new DefaultImpl(node);
// Rules
if (type.equals(REPLACE_ALL_EXPRESSION)) return new ReplaceAllImpl(node);
if (type.equals(REPLACE_REPEATED_EXPRESSION)) return new ReplaceRepeatedImpl(node);
if (type.equals(RULE_DELAYED_EXPRESSION)) return new RuleDelayedImpl(node);
if (type.equals(RULE_EXPRESSION)) return new RuleImpl(node);
// MString stuff
if (type.equals(STRING_EXPRESSION_EXPRESSION)) return new StringExpressionImpl(node);
if (type.equals(STRING_JOIN_EXPRESSION)) return new StringJoinImpl(node);
if (type.equals(MESSAGE_NAME_EXPRESSION)) return new MessageNameImpl(node);
if (type.equals(COMPOUND_EXPRESSION_EXPRESSION)) return new CompoundExpressionImpl(node);
// At least everything is an expression
return new ExpressionImpl(node);
}