/* * Copyright (c) 2013 Patrick Scheibe * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package de.halirutan.mathematica.parsing.prattparser; import com.intellij.lang.PsiBuilder; import com.intellij.psi.tree.IElementType; import de.halirutan.mathematica.parsing.MathematicaElementTypes; import de.halirutan.mathematica.parsing.prattparser.parselets.*; import java.util.HashMap; import java.util.Map; /** * This works like a singleton but instead of providing an instance of the class, you can access the Mathematica * operator properties (precedences, parselets, Psi-tree elements) which is initialized only once. This class is * basically the center of the parser because it provides the {@link MathematicaParser} with all the small parselets * which finally do the work of parsing specific expressions. <p>Therefore, I first need to select the appropriate * parselet for a lexer token. This parselet parses then the specific expression and marks the node in the AST. </p> * * @author patrick (3/27/13) */ public class ParseletProvider { private static final Map<IElementType, PrefixParselet> IELEMENT_TO_PREFIX = new HashMap<IElementType, PrefixParselet>(); private static final Map<IElementType, InfixParselet> IELEMENT_TO_INFIX = new HashMap<IElementType, InfixParselet>(); private static final Map<PrefixParselet, IElementType> PREFIX_TO_IELEMENT = new HashMap<PrefixParselet, IElementType>(); private static final Map<InfixParselet, IElementType> INFIX_TO_IELEMENT = new HashMap<InfixParselet, IElementType>(); static { register(MathematicaElementTypes.LEFT_PAR, MathematicaElementTypes.GROUP_EXPRESSION, new GroupParselet(85)); // Group(() register(MathematicaElementTypes.LEFT_BRACE, MathematicaElementTypes.LIST_EXPRESSION, new ListParselet(82)); // Group(() register(MathematicaElementTypes.LEFT_ASSOCIATION, MathematicaElementTypes.ASSOCIATION_EXPRESSION, new AssociationParselet(82)); // Association <|"foo"->1|> register(MathematicaElementTypes.NUMBER, MathematicaElementTypes.NUMBER_EXPRESSION, new NumberParselet(80)); // Number(123) register(MathematicaElementTypes.IDENTIFIER, MathematicaElementTypes.SYMBOL_EXPRESSION, new SymbolParselet(80)); // Symbol($var) register(MathematicaElementTypes.STRINGIFIED_IDENTIFIER, MathematicaElementTypes.STRINGIFIED_SYMBOL_EXPRESSION, new SymbolParselet(80)); // Symbol($var) register(MathematicaElementTypes.STRING_LITERAL_BEGIN, MathematicaElementTypes.STRING_LITERAL_EXPRESSION, new StringParselet(80)); // MString(abc) register(MathematicaElementTypes.DOUBLE_COLON, MathematicaElementTypes.MESSAGE_NAME_EXPRESSION, new MessageNameParselet(78)); // MessageName(::) register(MathematicaElementTypes.SLOT_SEQUENCE, MathematicaElementTypes.SLOT_SEQUENCE, new SlotParselet(77)); // ##n expressions register(MathematicaElementTypes.SLOT, MathematicaElementTypes.SLOT, new SlotParselet(77)); // ##n expressions register(MathematicaElementTypes.ASSOCIATION_SLOT, MathematicaElementTypes.ASSOCIATION_SLOT, new SlotParselet(77)); // #foo123 expressions register(MathematicaElementTypes.BLANK, MathematicaElementTypes.BLANK_EXPRESSION, new BlankParselet(76)); // Blank(_) register(MathematicaElementTypes.BLANK, MathematicaElementTypes.BLANK_EXPRESSION, new PrefixBlankParselet(76)); // Blank(_) register(MathematicaElementTypes.BLANK_SEQUENCE, MathematicaElementTypes.BLANK_SEQUENCE_EXPRESSION, new BlankSequenceParselet(76)); // BlankSequence(__) register(MathematicaElementTypes.BLANK_SEQUENCE, MathematicaElementTypes.BLANK_SEQUENCE_EXPRESSION, new PrefixBlankSequenceParselet(76)); // BlankSequence(__) register(MathematicaElementTypes.BLANK_NULL_SEQUENCE, MathematicaElementTypes.BLANK_NULL_SEQUENCE_EXPRESSION, new BlankNullSequenceParselet(76)); // BlankNullSequence(___) register(MathematicaElementTypes.BLANK_NULL_SEQUENCE, MathematicaElementTypes.BLANK_NULL_SEQUENCE_EXPRESSION, new PrefixBlankNullSequenceParselet(76)); // BlankNullSequence(___) postfix(MathematicaElementTypes.DEFAULT, MathematicaElementTypes.DEFAULT_EXPRESSION, 76); // Default(_.) register(MathematicaElementTypes.DEFAULT, MathematicaElementTypes.DEFAULT_EXPRESSION, new PrefixDefaultParselet(76)); // Default(_.) register(MathematicaElementTypes.GET, MathematicaElementTypes.GET_PREFIX, new PrefixGetParselet(74)); // Get(<<) infixLeft(MathematicaElementTypes.QUESTION_MARK, MathematicaElementTypes.PATTERN_TEST_EXPRESSION, 72); // PatternTest(?) register(MathematicaElementTypes.LEFT_BRACKET, MathematicaElementTypes.FUNCTION_CALL_EXPRESSION, new FunctionCallParselet(70)); // FunctionCall([) infixLeft(MathematicaElementTypes.COMPOSITION, MathematicaElementTypes.COMPOSITION_EXPRESSION, 69); // Composition (@*) infixLeft(MathematicaElementTypes.RIGHT_COMPOSITION, MathematicaElementTypes.RIGHT_COMPOSITION_EXPRESSION, 69); // RightComposition (/*) postfix(MathematicaElementTypes.INCREMENT, MathematicaElementTypes.INCREMENT_POSTFIX, 68); postfix(MathematicaElementTypes.DECREMENT, MathematicaElementTypes.DECREMENT_POSTFIX, 68); prefix(MathematicaElementTypes.INCREMENT, MathematicaElementTypes.PRE_INCREMENT_PREFIX, 66); // PreIncrement(++) prefix(MathematicaElementTypes.DECREMENT, MathematicaElementTypes.PRE_DECREMENT_PREFIX, 66); // PreDecrement(--) infixRight(MathematicaElementTypes.PREFIX_CALL, MathematicaElementTypes.PREFIX_CALL_EXPRESSION, 64); // PrefixCall(@) register(MathematicaElementTypes.INFIX_CALL, MathematicaElementTypes.INFIX_CALL_EXPRESSION, new InfixCallParselet(62)); // InfixCall(~) infixRight(MathematicaElementTypes.MAP, MathematicaElementTypes.MAP_EXPRESSION, 60); // Map(/@) infixRight(MathematicaElementTypes.MAP_ALL, MathematicaElementTypes.MAP_ALL_EXPRESSION, 60); // MapAll(//@) infixRight(MathematicaElementTypes.APPLY, MathematicaElementTypes.APPLY_EXPRESSION, 60); // Apply(@@) infixRight(MathematicaElementTypes.APPLY1, MathematicaElementTypes.APPLY1_EXPRESSION, 60); // Apply1(@@@) postfix(MathematicaElementTypes.EXCLAMATION_MARK, MathematicaElementTypes.FACTORIAL_POSTFIX, 58); register(MathematicaElementTypes.DERIVATIVE, MathematicaElementTypes.DERIVATIVE_EXPRESSION, new DerivativeParselet(56)); // Derivative(') infixLeft(MathematicaElementTypes.STRING_JOIN, MathematicaElementTypes.STRING_JOIN_EXPRESSION, 54); // StringJoin(<>) infixRight(MathematicaElementTypes.POWER, MathematicaElementTypes.POWER_EXPRESSION, 52); // Power(^) infixLeft(MathematicaElementTypes.NON_COMMUTATIVE_MULTIPLY, MathematicaElementTypes.NON_COMMUTATIVE_MULTIPLY_EXPRESSION, 50); // NonCommutativeMultiply(**) infixLeft(MathematicaElementTypes.POINT, MathematicaElementTypes.DOT_EXPRESSION, 48); // Dot(.) prefix(MathematicaElementTypes.MINUS, MathematicaElementTypes.UNARY_MINUS_PREFIX, 46); // UnaryMinus(-) prefix(MathematicaElementTypes.PLUS, MathematicaElementTypes.UNARY_PLUS_PREFIX, 46); // UnaryPlus(+) infixLeft(MathematicaElementTypes.DIVIDE, MathematicaElementTypes.DIVIDE_EXPRESSION, 44); // Divide(/) infixLeft(MathematicaElementTypes.TIMES, MathematicaElementTypes.TIMES_EXPRESSION, 42); // Times(*) infixLeft(MathematicaElementTypes.PLUS, MathematicaElementTypes.PLUS_EXPRESSION, 40); // Plus(+) infixLeft(MathematicaElementTypes.MINUS, MathematicaElementTypes.MINUS_EXPRESSION, 40); // Minus(-) register(MathematicaElementTypes.SPAN, MathematicaElementTypes.SPAN_EXPRESSION, new SpanParselet(38)); // Span(;;) registerPrefixExplicitly(MathematicaElementTypes.SPAN, MathematicaElementTypes.SPAN_EXPRESSION, new PrefixSpanParselet(38)); // Span(;;) infixLeft(MathematicaElementTypes.EQUAL, MathematicaElementTypes.EQUAL_EXPRESSION, 36); // Equal(==) infixLeft(MathematicaElementTypes.UNEQUAL, MathematicaElementTypes.UNEQUAL_EXPRESSION, 36); // Unequal(!=) infixLeft(MathematicaElementTypes.GREATER, MathematicaElementTypes.GREATER_EXPRESSION, 36); // Greater(>) infixLeft(MathematicaElementTypes.GREATER_EQUAL, MathematicaElementTypes.GREATER_EQUAL_EXPRESSION, 36); // GreaterEqual(>=) infixLeft(MathematicaElementTypes.LESS, MathematicaElementTypes.LESS_EXPRESSION, 36); // Less(<) infixLeft(MathematicaElementTypes.LESS_EQUAL, MathematicaElementTypes.LESS_EQUAL_EXPRESSION, 36); // LessEqual(<=) infixLeft(MathematicaElementTypes.SAME_Q, MathematicaElementTypes.SAME_Q_EXPRESSION, 34); // SameQ(===) infixLeft(MathematicaElementTypes.UNSAME_Q, MathematicaElementTypes.UNSAME_Q_EXPRESSION, 34); // UnsameQ(=!=) prefix(MathematicaElementTypes.EXCLAMATION_MARK, MathematicaElementTypes.NOT_PREFIX, 32); // Not(!) infixLeft(MathematicaElementTypes.AND, MathematicaElementTypes.AND_EXPRESSION, 30); // And(&&) infixLeft(MathematicaElementTypes.OR, MathematicaElementTypes.OR_EXPRESSION, 28); // Or(||) postfix(MathematicaElementTypes.REPEATED, MathematicaElementTypes.REPEATED_POSTFIX, 26); postfix(MathematicaElementTypes.REPEATED_NULL, MathematicaElementTypes.REPEATED_NULL_POSTFIX, 26); infixLeft(MathematicaElementTypes.ALTERNATIVE, MathematicaElementTypes.ALTERNATIVE_EXPRESSION, 24); // Alternative(|) infixLeft(MathematicaElementTypes.COLON, MathematicaElementTypes.PATTERN_EXPRESSION, 22); // Optional(:) and Patter (:) register(MathematicaElementTypes.COLON, MathematicaElementTypes.PATTERN_EXPRESSION, new PatternParselet(22)); // MessageName(::) infixLeft(MathematicaElementTypes.STRING_EXPRESSION, MathematicaElementTypes.STRING_EXPRESSION_EXPRESSION, 20); // StringExpression(~~) infixLeft(MathematicaElementTypes.CONDITION, MathematicaElementTypes.CONDITION_EXPRESSION, 18); // Condition(/;) infixRight(MathematicaElementTypes.RULE, MathematicaElementTypes.RULE_EXPRESSION, 16); // Rule(->) infixRight(MathematicaElementTypes.RULE_DELAYED, MathematicaElementTypes.RULE_DELAYED_EXPRESSION, 16); // RuleDelayed(:>) infixLeft(MathematicaElementTypes.REPLACE_ALL, MathematicaElementTypes.REPLACE_ALL_EXPRESSION, 14); // ReplaceAll(/.) infixLeft(MathematicaElementTypes.REPLACE_REPEATED, MathematicaElementTypes.REPLACE_REPEATED_EXPRESSION, 14); // ReplaceRepeated(//.) infixRight(MathematicaElementTypes.ADD_TO, MathematicaElementTypes.ADD_TO_EXPRESSION, 12); // AddTo(+=) infixRight(MathematicaElementTypes.SUBTRACT_FROM, MathematicaElementTypes.SUBTRACT_FROM_EXPRESSION, 12); // SubtractFrom(-=) infixRight(MathematicaElementTypes.TIMES_BY, MathematicaElementTypes.TIMES_BY_EXPRESSION, 12); // TimesBy(*=) infixRight(MathematicaElementTypes.DIVIDE_BY, MathematicaElementTypes.DIVIDE_BY_EXPRESSION, 12); // DivideBy(/=) postfix(MathematicaElementTypes.FUNCTION, MathematicaElementTypes.FUNCTION_POSTFIX, 10); infixLeft(MathematicaElementTypes.POSTFIX, MathematicaElementTypes.POSTFIX_EXPRESSION, 8); // Postfix(//) infixRight(MathematicaElementTypes.SET, MathematicaElementTypes.SET_EXPRESSION, 6); // Set(=) infixRight(MathematicaElementTypes.SET_DELAYED, MathematicaElementTypes.SET_DELAYED_EXPRESSION, 6); // SetDelayed(:=) infixRight(MathematicaElementTypes.UP_SET, MathematicaElementTypes.UP_SET_EXPRESSION, 6); // UpSet(^=) infixRight(MathematicaElementTypes.UP_SET_DELAYED, MathematicaElementTypes.UP_SET_DELAYED_EXPRESSION, 6); // UpSetDelayed(^:=) register(MathematicaElementTypes.TAG_SET, MathematicaElementTypes.TAG_SET_EXPRESSION, new TagSetParselet(6)); // TagSet(/:) postfix(MathematicaElementTypes.UNSET, MathematicaElementTypes.UNSET_EXPRESSION, 6); // Unset(=.) register(MathematicaElementTypes.PUT, MathematicaElementTypes.PUT_EXPRESSION, new PutParselet(4)); // Put(>>) register(MathematicaElementTypes.PUT_APPEND, MathematicaElementTypes.PUT_APPEND_EXPRESSION, new PutParselet(4)); // PutAppend(>>>) register(MathematicaElementTypes.SEMICOLON, MathematicaElementTypes.COMPOUND_EXPRESSION_EXPRESSION, new CompoundExpressionParselet(2)); // CompoundExpression(;) } private ParseletProvider() { } /** * Provides the prefix-parselet which is connected to the specified token. * * @param token * The token for which the parselet is wanted * @return The {@link PrefixParselet} if available for this token and {@code null} otherwise. */ public static PrefixParselet getPrefixParselet(IElementType token) { return IELEMENT_TO_PREFIX.get(token); } /** * Provides the infix-parselet which is connected to the specified token. * * @param token * The token for which the parselet is wanted * @return The {@link InfixParselet} if available for this token and {@code null} otherwise. */ public static InfixParselet getInfixParselet(IElementType token) { return IELEMENT_TO_INFIX.get(token); } /** * Extracts the precedence of an infix operator connected to the specified token * * @param token * Token for which the precedence is required * @return The precedence of the specified token or 0 whether the precedence is not available. */ public static int getPrecedence(IElementType token) { InfixParselet parselet = IELEMENT_TO_INFIX.get(token); if (parselet != null) { return parselet.getMyPrecedence(); } return 0; } /** * Extracts the precedence of an infix operator connected to the first token in the token stream of builder. * * @param builder * Builder from which the first token is extracted to find the required precedence * @return The precedence of the specified token or 0 whether the precedence is not available. */ public static int getPrecedence(PsiBuilder builder) { IElementType token = builder.getTokenType(); if (token == null) { return 0; } InfixParselet parselet = IELEMENT_TO_INFIX.get(token); if (parselet != null) { return parselet.getMyPrecedence(); } return 0; } /** * Provides the parselet with the element type of the node for the AST. When an expression was parsed with a specific * {@link InfixParselet} the node in the AST is then the {@link IElementType} which is returned by this method. E.g. * When a PLUS token arises in the lexer token stream first the infix-parselet of the PLUS token is extracted with * {@link #getInfixParselet(IElementType)} which parses the left and right operand. Afterwards it marks the whole * expression a+b in the AST tree as being a node of type returned by this method. * * @param parselet * The parselet for which the node type is wanted * @return The node type. */ public static IElementType getInfixPsiElement(InfixParselet parselet) { IElementType elm = INFIX_TO_IELEMENT.get(parselet); if (elm == null) { return MathematicaElementTypes.FAILBACK; } return elm; } /** * Please see {@link #getInfixPsiElement(InfixParselet)} * * @param parselet * The parselet for which the type is wanted * @return The element of the node in the AST tree */ public static IElementType getPrefixPsiElement(PrefixParselet parselet) { IElementType elm = PREFIX_TO_IELEMENT.get(parselet); if (elm == null) { return MathematicaElementTypes.FAILBACK; } return elm; } private static void register(IElementType token, IElementType expressionToken, PrefixParselet parselet) { IELEMENT_TO_PREFIX.put(token, parselet); PREFIX_TO_IELEMENT.put(parselet, expressionToken); } private static void register(IElementType token, IElementType expressionToken, InfixParselet parselet) { IELEMENT_TO_INFIX.put(token, parselet); INFIX_TO_IELEMENT.put(parselet, expressionToken); } private static void registerPrefixExplicitly(IElementType token, IElementType expressionToken, PrefixParselet parselet) { IELEMENT_TO_PREFIX.put(token, parselet); PREFIX_TO_IELEMENT.put(parselet, expressionToken); } private static void postfix(IElementType token, IElementType expressionToken, int precedence) { register(token, expressionToken, new PostfixOperatorParselet(precedence)); } private static void prefix(IElementType token, IElementType expressionToken, int precedence) { register(token, expressionToken, new PrefixOperatorParselet(precedence)); } private static void infixLeft(IElementType token, IElementType expressionToken, int precedence) { register(token, expressionToken, new InfixOperatorParselet(precedence, false)); } // THIS SECTION IS AUTOMATICALLY CREATED WITH MATHEMATICA private static void infixRight(IElementType token, IElementType expressionToken, int precedence) { register(token, expressionToken, new InfixOperatorParselet(precedence, true)); } }