设计模式课程 设计模式精讲 20-3 解释器模式源码解析

1    源码解析

1.1    源码解析1(jdk中的应用)

1.2    源码解析2(Spring中的应用)

1.3    源码解析为何算出666?

 

 

 

 

1    源码解析
1.1    源码解析1(jdk中的应用

java.util.regex.Pattern

(java正则表达式通过java.util.regex包下的Pattern类与Matcher类实现)

 

 

1.2    源码解析2(Spring中的应用)

测试类:(通过el表达式计算出结果)(以下代码中红色粗体为跳转顺序)

 

package com.geely.design.pattern.behavioral.interpreter;

import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;

/**
 * Created by geely
 */
public class SpringTest {
    public static void main(String[] args) {
        org.springframework.expression.ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression("100 * 2 + 400 * 1 + 66");
        int result = (Integer) expression.getValue();
        System.out.println(result);

    }
}

 

 

应用类1:

 

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.expression.common;

import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;

public abstract class TemplateAwareExpressionParser implements ExpressionParser {
    private static final ParserContext NON_TEMPLATE_PARSER_CONTEXT = new ParserContext() {
        public String getExpressionPrefix() {
            return null;
        }

        public String getExpressionSuffix() {
            return null;
        }

        public boolean isTemplate() {
            return false;
        }
    };

    public TemplateAwareExpressionParser() {
    }

    public Expression parseExpression(String expressionString) throws ParseException {
        return this.parseExpression(expressionString, NON_TEMPLATE_PARSER_CONTEXT);
    }

    public Expression parseExpression(String expressionString, ParserContext context) throws ParseException {
        if (context == null) {
            context = NON_TEMPLATE_PARSER_CONTEXT;
        }

        return context.isTemplate() ? this.parseTemplate(expressionString, context) : this.doParseExpression(expressionString, context);
    }

    private Expression parseTemplate(String expressionString, ParserContext context) throws ParseException {
        if (expressionString.length() == 0) {
            return new LiteralExpression("");
        } else {
            Expression[] expressions = this.parseExpressions(expressionString, context);
            return (Expression)(expressions.length == 1 ? expressions[0] : new CompositeStringExpression(expressionString, expressions));
        }
    }

    private Expression[] parseExpressions(String expressionString, ParserContext context) throws ParseException {
        List expressions = new LinkedList();
        String prefix = context.getExpressionPrefix();
        String suffix = context.getExpressionSuffix();
        int startIdx = 0;

        while(startIdx < expressionString.length()) {
            int prefixIndex = expressionString.indexOf(prefix, startIdx);
            if (prefixIndex >= startIdx) {
                if (prefixIndex > startIdx) {
                    expressions.add(this.createLiteralExpression(context, expressionString.substring(startIdx, prefixIndex)));
                }

                int afterPrefixIndex = prefixIndex + prefix.length();
                int suffixIndex = this.skipToCorrectEndSuffix(prefix, suffix, expressionString, afterPrefixIndex);
                if (suffixIndex == -1) {
                    throw new ParseException(expressionString, prefixIndex, "No ending suffix '" + suffix + "' for expression starting at character " + prefixIndex + ": " + expressionString.substring(prefixIndex));
                }

                if (suffixIndex == afterPrefixIndex) {
                    throw new ParseException(expressionString, prefixIndex, "No expression defined within delimiter '" + prefix + suffix + "' at character " + prefixIndex);
                }

                String expr = expressionString.substring(prefixIndex + prefix.length(), suffixIndex);
                expr = expr.trim();
                if (expr.length() == 0) {
                    throw new ParseException(expressionString, prefixIndex, "No expression defined within delimiter '" + prefix + suffix + "' at character " + prefixIndex);
                }

                expressions.add(this.doParseExpression(expr, context));
                startIdx = suffixIndex + suffix.length();
            } else {
                expressions.add(this.createLiteralExpression(context, expressionString.substring(startIdx)));
                startIdx = expressionString.length();
            }
        }

        return (Expression[])expressions.toArray(new Expression[expressions.size()]);
    }

    private Expression createLiteralExpression(ParserContext context, String text) {
        return new LiteralExpression(text);
    }

    private boolean isSuffixHere(String expressionString, int pos, String suffix) {
        int suffixPosition = 0;

        for(int i = 0; i < suffix.length() && pos < expressionString.length(); ++i) {
            if (expressionString.charAt(pos++) != suffix.charAt(suffixPosition++)) {
                return false;
            }
        }

        return suffixPosition == suffix.length();
    }

    private int skipToCorrectEndSuffix(String prefix, String suffix, String expressionString, int afterPrefixIndex) throws ParseException {
        int pos = afterPrefixIndex;
        int maxlen = expressionString.length();
        int nextSuffix = expressionString.indexOf(suffix, afterPrefixIndex);
        if (nextSuffix == -1) {
            return -1;
        } else {
            Stack stack;
            for(stack = new Stack(); pos < maxlen && (!this.isSuffixHere(expressionString, pos, suffix) || !stack.isEmpty()); ++pos) {
                char ch = expressionString.charAt(pos);
                switch(ch) {
                case '"':
                case '\'':
                    int endLiteral = expressionString.indexOf(ch, pos + 1);
                    if (endLiteral == -1) {
                        throw new ParseException(expressionString, pos, "Found non terminating string literal starting at position " + pos);
                    }

                    pos = endLiteral;
                    break;
                case '(':
                case '[':
                case '{':
                    stack.push(new TemplateAwareExpressionParser.Bracket(ch, pos));
                    break;
                case ')':
                case ']':
                case '}':
                    if (stack.isEmpty()) {
                        throw new ParseException(expressionString, pos, "Found closing '" + ch + "' at position " + pos + " without an opening '" + TemplateAwareExpressionParser.Bracket.theOpenBracketFor(ch) + "'");
                    }

                    TemplateAwareExpressionParser.Bracket p = (TemplateAwareExpressionParser.Bracket)stack.pop();
                    if (!p.compatibleWithCloseBracket(ch)) {
                        throw new ParseException(expressionString, pos, "Found closing '" + ch + "' at position " + pos + " but most recent opening is '" + p.bracket + "' at position " + p.pos);
                    }
                }
            }

            if (!stack.isEmpty()) {
                TemplateAwareExpressionParser.Bracket p = (TemplateAwareExpressionParser.Bracket)stack.pop();
                throw new ParseException(expressionString, p.pos, "Missing closing '" + TemplateAwareExpressionParser.Bracket.theCloseBracketFor(p.bracket) + "' for '" + p.bracket + "' at position " + p.pos);
            } else {
                return !this.isSuffixHere(expressionString, pos, suffix) ? -1 : pos;
            }
        }
    }

    protected abstract Expression doParseExpression(String var1, ParserContext var2) throws ParseException;

    private static class Bracket {
        char bracket;
        int pos;

        Bracket(char bracket, int pos) {
            this.bracket = bracket;
            this.pos = pos;
        }

        boolean compatibleWithCloseBracket(char closeBracket) {
            if (this.bracket == '{') {
                return closeBracket == '}';
            } else if (this.bracket == '[') {
                return closeBracket == ']';
            } else {
                return closeBracket == ')';
            }
        }

        static char theOpenBracketFor(char closeBracket) {
            if (closeBracket == '}') {
                return '{';
            } else {
                return (char)(closeBracket == ']' ? '[' : '(');
            }
        }

        static char theCloseBracketFor(char openBracket) {
            if (openBracket == '{') {
                return '}';
            } else {
                return (char)(openBracket == '[' ? ']' : ')');
            }
        }
    }
}

 

 

 

 

应用类2(继承了应用类1):

 

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.expression.spel.standard;

import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateAwareExpressionParser;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.util.Assert;

public class SpelExpressionParser extends TemplateAwareExpressionParser {
    private final SpelParserConfiguration configuration;

    public SpelExpressionParser() {
        this.configuration = new SpelParserConfiguration(false, false);
    }

    public SpelExpressionParser(SpelParserConfiguration configuration) {
        Assert.notNull(configuration, "SpelParserConfiguration must not be null");
        this.configuration = configuration;
    }

    protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {
        return (new InternalSpelExpressionParser(this.configuration)).doParseExpression(expressionString, context);
    }

    public SpelExpression parseRaw(String expressionString) throws ParseException {
        return this.doParseExpression(expressionString, (ParserContext)null);
    }
}

 

 

 

应用类3(继承了应用类1)

 

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.expression.spel.standard;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateAwareExpressionParser;
import org.springframework.expression.spel.InternalParseException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.SpelParseException;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.ast.Assign;
import org.springframework.expression.spel.ast.BeanReference;
import org.springframework.expression.spel.ast.BooleanLiteral;
import org.springframework.expression.spel.ast.CompoundExpression;
import org.springframework.expression.spel.ast.ConstructorReference;
import org.springframework.expression.spel.ast.Elvis;
import org.springframework.expression.spel.ast.FunctionReference;
import org.springframework.expression.spel.ast.Identifier;
import org.springframework.expression.spel.ast.Indexer;
import org.springframework.expression.spel.ast.InlineList;
import org.springframework.expression.spel.ast.Literal;
import org.springframework.expression.spel.ast.MethodReference;
import org.springframework.expression.spel.ast.NullLiteral;
import org.springframework.expression.spel.ast.OpAnd;
import org.springframework.expression.spel.ast.OpDec;
import org.springframework.expression.spel.ast.OpDivide;
import org.springframework.expression.spel.ast.OpEQ;
import org.springframework.expression.spel.ast.OpGE;
import org.springframework.expression.spel.ast.OpGT;
import org.springframework.expression.spel.ast.OpInc;
import org.springframework.expression.spel.ast.OpLE;
import org.springframework.expression.spel.ast.OpLT;
import org.springframework.expression.spel.ast.OpMinus;
import org.springframework.expression.spel.ast.OpModulus;
import org.springframework.expression.spel.ast.OpMultiply;
import org.springframework.expression.spel.ast.OpNE;
import org.springframework.expression.spel.ast.OpOr;
import org.springframework.expression.spel.ast.OpPlus;
import org.springframework.expression.spel.ast.OperatorBetween;
import org.springframework.expression.spel.ast.OperatorInstanceof;
import org.springframework.expression.spel.ast.OperatorMatches;
import org.springframework.expression.spel.ast.OperatorNot;
import org.springframework.expression.spel.ast.OperatorPower;
import org.springframework.expression.spel.ast.Projection;
import org.springframework.expression.spel.ast.PropertyOrFieldReference;
import org.springframework.expression.spel.ast.QualifiedIdentifier;
import org.springframework.expression.spel.ast.Selection;
import org.springframework.expression.spel.ast.SpelNodeImpl;
import org.springframework.expression.spel.ast.StringLiteral;
import org.springframework.expression.spel.ast.Ternary;
import org.springframework.expression.spel.ast.TypeReference;
import org.springframework.expression.spel.ast.VariableReference;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
    private static final Pattern VALID_QUALIFIED_ID_PATTERN = Pattern.compile("[\\p{L}\\p{N}_$]+");
    private String expressionString;
    private List tokenStream;
    private int tokenStreamLength;
    private int tokenStreamPointer;
    private final Stack constructedNodes = new Stack();
    private final SpelParserConfiguration configuration;

    public InternalSpelExpressionParser(SpelParserConfiguration configuration) {
        this.configuration = configuration;
    }

    protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {
        try {
            this.expressionString = expressionString;
            Tokenizer tokenizer = new Tokenizer(expressionString);
            tokenizer.process();
            this.tokenStream = tokenizer.getTokens();
            this.tokenStreamLength = this.tokenStream.size();
            this.tokenStreamPointer = 0;
            this.constructedNodes.clear();
            SpelNodeImpl ast = this.eatExpression();
            if (this.moreTokens()) {
                throw new SpelParseException(this.peekToken().startpos, SpelMessage.MORE_INPUT, new Object[]{this.toString(this.nextToken())});
            } else {
                Assert.isTrue(this.constructedNodes.isEmpty());
                return new SpelExpression(expressionString, ast, this.configuration);
            }
        } catch (InternalParseException var5) {
            throw var5.getCause();
        }
    }

    private SpelNodeImpl eatExpression() {
        SpelNodeImpl expr = this.eatLogicalOrExpression();
        if (this.moreTokens()) {
            Token t = this.peekToken();
            SpelNodeImpl ifTrueExprValue;
            if (t.kind == TokenKind.ASSIGN) {
                if (expr == null) {
                    expr = new NullLiteral(this.toPos(t.startpos - 1, t.endpos - 1));
                }

                this.nextToken();
                ifTrueExprValue = this.eatLogicalOrExpression();
                return new Assign(this.toPos(t), new SpelNodeImpl[]{(SpelNodeImpl)expr, ifTrueExprValue});
            }

            if (t.kind == TokenKind.ELVIS) {
                if (expr == null) {
                    expr = new NullLiteral(this.toPos(t.startpos - 1, t.endpos - 2));
                }

                this.nextToken();
                SpelNodeImpl valueIfNull = this.eatExpression();
                if (valueIfNull == null) {
                    valueIfNull = new NullLiteral(this.toPos(t.startpos + 1, t.endpos + 1));
                }

                return new Elvis(this.toPos(t), new SpelNodeImpl[]{(SpelNodeImpl)expr, (SpelNodeImpl)valueIfNull});
            }

            if (t.kind == TokenKind.QMARK) {
                if (expr == null) {
                    expr = new NullLiteral(this.toPos(t.startpos - 1, t.endpos - 1));
                }

                this.nextToken();
                ifTrueExprValue = this.eatExpression();
                this.eatToken(TokenKind.COLON);
                SpelNodeImpl ifFalseExprValue = this.eatExpression();
                return new Ternary(this.toPos(t), new SpelNodeImpl[]{(SpelNodeImpl)expr, ifTrueExprValue, ifFalseExprValue});
            }
        }

        return (SpelNodeImpl)expr;
    }

    private SpelNodeImpl eatLogicalOrExpression() {
        Object expr;
        Token t;
        SpelNodeImpl rhExpr;
        for(expr = this.eatLogicalAndExpression(); this.peekIdentifierToken("or") || this.peekToken(TokenKind.SYMBOLIC_OR); expr = new OpOr(this.toPos(t), new SpelNodeImpl[]{(SpelNodeImpl)expr, rhExpr})) {
            t = this.nextToken();
            rhExpr = this.eatLogicalAndExpression();
            this.checkOperands(t, (SpelNodeImpl)expr, rhExpr);
        }

        return (SpelNodeImpl)expr;
    }

    private SpelNodeImpl eatLogicalAndExpression() {
        Object expr;
        Token t;
        SpelNodeImpl rhExpr;
        for(expr = this.eatRelationalExpression(); this.peekIdentifierToken("and") || this.peekToken(TokenKind.SYMBOLIC_AND); expr = new OpAnd(this.toPos(t), new SpelNodeImpl[]{(SpelNodeImpl)expr, rhExpr})) {
            t = this.nextToken();
            rhExpr = this.eatRelationalExpression();
            this.checkOperands(t, (SpelNodeImpl)expr, rhExpr);
        }

        return (SpelNodeImpl)expr;
    }

    private SpelNodeImpl eatRelationalExpression() {
        SpelNodeImpl expr = this.eatSumExpression();
        Token relationalOperatorToken = this.maybeEatRelationalOperator();
        if (relationalOperatorToken != null) {
            Token t = this.nextToken();
            SpelNodeImpl rhExpr = this.eatSumExpression();
            this.checkOperands(t, expr, rhExpr);
            TokenKind tk = relationalOperatorToken.kind;
            if (relationalOperatorToken.isNumericRelationalOperator()) {
                int pos = this.toPos(t);
                if (tk == TokenKind.GT) {
                    return new OpGT(pos, new SpelNodeImpl[]{expr, rhExpr});
                } else if (tk == TokenKind.LT) {
                    return new OpLT(pos, new SpelNodeImpl[]{expr, rhExpr});
                } else if (tk == TokenKind.LE) {
                    return new OpLE(pos, new SpelNodeImpl[]{expr, rhExpr});
                } else if (tk == TokenKind.GE) {
                    return new OpGE(pos, new SpelNodeImpl[]{expr, rhExpr});
                } else if (tk == TokenKind.EQ) {
                    return new OpEQ(pos, new SpelNodeImpl[]{expr, rhExpr});
                } else {
                    Assert.isTrue(tk == TokenKind.NE);
                    return new OpNE(pos, new SpelNodeImpl[]{expr, rhExpr});
                }
            } else if (tk == TokenKind.INSTANCEOF) {
                return new OperatorInstanceof(this.toPos(t), new SpelNodeImpl[]{expr, rhExpr});
            } else if (tk == TokenKind.MATCHES) {
                return new OperatorMatches(this.toPos(t), new SpelNodeImpl[]{expr, rhExpr});
            } else {
                Assert.isTrue(tk == TokenKind.BETWEEN);
                return new OperatorBetween(this.toPos(t), new SpelNodeImpl[]{expr, rhExpr});
            }
        } else {
            return expr;
        }
    }

    private SpelNodeImpl eatSumExpression() {
        Object expr = this.eatProductExpression();

        while(this.peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.INC)) {
            Token t = this.nextToken();
            SpelNodeImpl rhExpr = this.eatProductExpression();
            this.checkRightOperand(t, rhExpr);
            if (t.kind == TokenKind.PLUS) {
                expr = new OpPlus(this.toPos(t), new SpelNodeImpl[]{(SpelNodeImpl)expr, rhExpr});
            } else if (t.kind == TokenKind.MINUS) {
                expr = new OpMinus(this.toPos(t), new SpelNodeImpl[]{(SpelNodeImpl)expr, rhExpr});
            }
        }

        return (SpelNodeImpl)expr;
    }

    private SpelNodeImpl eatProductExpression() {
        Object expr = this.eatPowerIncDecExpression();

        while(this.peekToken(TokenKind.STAR, TokenKind.DIV, TokenKind.MOD)) {
            Token t = this.nextToken();
            SpelNodeImpl rhExpr = this.eatPowerIncDecExpression();
            this.checkOperands(t, (SpelNodeImpl)expr, rhExpr);
            if (t.kind == TokenKind.STAR) {
                expr = new OpMultiply(this.toPos(t), new SpelNodeImpl[]{(SpelNodeImpl)expr, rhExpr});
            } else if (t.kind == TokenKind.DIV) {
                expr = new OpDivide(this.toPos(t), new SpelNodeImpl[]{(SpelNodeImpl)expr, rhExpr});
            } else {
                Assert.isTrue(t.kind == TokenKind.MOD);
                expr = new OpModulus(this.toPos(t), new SpelNodeImpl[]{(SpelNodeImpl)expr, rhExpr});
            }
        }

        return (SpelNodeImpl)expr;
    }

    private SpelNodeImpl eatPowerIncDecExpression() {
        SpelNodeImpl expr = this.eatUnaryExpression();
        Token t;
        if (this.peekToken(TokenKind.POWER)) {
            t = this.nextToken();
            SpelNodeImpl rhExpr = this.eatUnaryExpression();
            this.checkRightOperand(t, rhExpr);
            return new OperatorPower(this.toPos(t), new SpelNodeImpl[]{expr, rhExpr});
        } else if (expr != null && this.peekToken(TokenKind.INC, TokenKind.DEC)) {
            t = this.nextToken();
            return (SpelNodeImpl)(t.getKind() == TokenKind.INC ? new OpInc(this.toPos(t), true, new SpelNodeImpl[]{expr}) : new OpDec(this.toPos(t), true, new SpelNodeImpl[]{expr}));
        } else {
            return expr;
        }
    }

    private SpelNodeImpl eatUnaryExpression() {
        Token t;
        SpelNodeImpl expr;
        if (this.peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.NOT)) {
            t = this.nextToken();
            expr = this.eatUnaryExpression();
            if (t.kind == TokenKind.NOT) {
                return new OperatorNot(this.toPos(t), expr);
            } else if (t.kind == TokenKind.PLUS) {
                return new OpPlus(this.toPos(t), new SpelNodeImpl[]{expr});
            } else {
                Assert.isTrue(t.kind == TokenKind.MINUS);
                return new OpMinus(this.toPos(t), new SpelNodeImpl[]{expr});
            }
        } else if (this.peekToken(TokenKind.INC, TokenKind.DEC)) {
            t = this.nextToken();
            expr = this.eatUnaryExpression();
            return (SpelNodeImpl)(t.getKind() == TokenKind.INC ? new OpInc(this.toPos(t), false, new SpelNodeImpl[]{expr}) : new OpDec(this.toPos(t), false, new SpelNodeImpl[]{expr}));
        } else {
            return this.eatPrimaryExpression();
        }
    }

    private SpelNodeImpl eatPrimaryExpression() {
        List nodes = new ArrayList();
        SpelNodeImpl start = this.eatStartNode();
        nodes.add(start);

        while(this.maybeEatNode()) {
            nodes.add(this.pop());
        }

        return (SpelNodeImpl)(nodes.size() == 1 ? (SpelNodeImpl)nodes.get(0) : new CompoundExpression(this.toPos(start.getStartPosition(), ((SpelNodeImpl)nodes.get(nodes.size() - 1)).getEndPosition()), (SpelNodeImpl[])nodes.toArray(new SpelNodeImpl[nodes.size()])));
    }

    private boolean maybeEatNode() {
        SpelNodeImpl expr = null;
        if (this.peekToken(TokenKind.DOT, TokenKind.SAFE_NAVI)) {
            expr = this.eatDottedNode();
        } else {
            expr = this.maybeEatNonDottedNode();
        }

        if (expr == null) {
            return false;
        } else {
            this.push(expr);
            return true;
        }
    }

    private SpelNodeImpl maybeEatNonDottedNode() {
        return this.peekToken(TokenKind.LSQUARE) && this.maybeEatIndexer() ? this.pop() : null;
    }

    private SpelNodeImpl eatDottedNode() {
        Token t = this.nextToken();
        boolean nullSafeNavigation = t.kind == TokenKind.SAFE_NAVI;
        if (!this.maybeEatMethodOrProperty(nullSafeNavigation) && !this.maybeEatFunctionOrVar() && !this.maybeEatProjection(nullSafeNavigation) && !this.maybeEatSelection(nullSafeNavigation)) {
            if (this.peekToken() == null) {
                this.raiseInternalException(t.startpos, SpelMessage.OOD);
            } else {
                this.raiseInternalException(t.startpos, SpelMessage.UNEXPECTED_DATA_AFTER_DOT, this.toString(this.peekToken()));
            }

            return null;
        } else {
            return this.pop();
        }
    }

    private boolean maybeEatFunctionOrVar() {
        if (!this.peekToken(TokenKind.HASH)) {
            return false;
        } else {
            Token t = this.nextToken();
            Token functionOrVariableName = this.eatToken(TokenKind.IDENTIFIER);
            SpelNodeImpl[] args = this.maybeEatMethodArgs();
            if (args == null) {
                this.push(new VariableReference(functionOrVariableName.data, this.toPos(t.startpos, functionOrVariableName.endpos)));
                return true;
            } else {
                this.push(new FunctionReference(functionOrVariableName.data, this.toPos(t.startpos, functionOrVariableName.endpos), args));
                return true;
            }
        }
    }

    private SpelNodeImpl[] maybeEatMethodArgs() {
        if (!this.peekToken(TokenKind.LPAREN)) {
            return null;
        } else {
            List args = new ArrayList();
            this.consumeArguments(args);
            this.eatToken(TokenKind.RPAREN);
            return (SpelNodeImpl[])args.toArray(new SpelNodeImpl[args.size()]);
        }
    }

    private void eatConstructorArgs(List accumulatedArguments) {
        if (!this.peekToken(TokenKind.LPAREN)) {
            throw new InternalParseException(new SpelParseException(this.expressionString, this.positionOf(this.peekToken()), SpelMessage.MISSING_CONSTRUCTOR_ARGS, new Object[0]));
        } else {
            this.consumeArguments(accumulatedArguments);
            this.eatToken(TokenKind.RPAREN);
        }
    }

    private void consumeArguments(List accumulatedArguments) {
        int pos = this.peekToken().startpos;
        Token next = null;

        do {
            this.nextToken();
            Token t = this.peekToken();
            if (t == null) {
                this.raiseInternalException(pos, SpelMessage.RUN_OUT_OF_ARGUMENTS);
            }

            if (t.kind != TokenKind.RPAREN) {
                accumulatedArguments.add(this.eatExpression());
            }

            next = this.peekToken();
        } while(next != null && next.kind == TokenKind.COMMA);

        if (next == null) {
            this.raiseInternalException(pos, SpelMessage.RUN_OUT_OF_ARGUMENTS);
        }

    }

    private int positionOf(Token t) {
        return t == null ? this.expressionString.length() : t.startpos;
    }

    private SpelNodeImpl eatStartNode() {
        if (this.maybeEatLiteral()) {
            return this.pop();
        } else if (this.maybeEatParenExpression()) {
            return this.pop();
        } else if (!this.maybeEatTypeReference() && !this.maybeEatNullReference() && !this.maybeEatConstructorReference() && !this.maybeEatMethodOrProperty(false) && !this.maybeEatFunctionOrVar()) {
            if (this.maybeEatBeanReference()) {
                return this.pop();
            } else if (!this.maybeEatProjection(false) && !this.maybeEatSelection(false) && !this.maybeEatIndexer()) {
                return this.maybeEatInlineList() ? this.pop() : null;
            } else {
                return this.pop();
            }
        } else {
            return this.pop();
        }
    }

    private boolean maybeEatBeanReference() {
        if (this.peekToken(TokenKind.BEAN_REF)) {
            Token beanRefToken = this.nextToken();
            Token beanNameToken = null;
            String beanname = null;
            if (this.peekToken(TokenKind.IDENTIFIER)) {
                beanNameToken = this.eatToken(TokenKind.IDENTIFIER);
                beanname = beanNameToken.data;
            } else if (this.peekToken(TokenKind.LITERAL_STRING)) {
                beanNameToken = this.eatToken(TokenKind.LITERAL_STRING);
                beanname = beanNameToken.stringValue();
                beanname = beanname.substring(1, beanname.length() - 1);
            } else {
                this.raiseInternalException(beanRefToken.startpos, SpelMessage.INVALID_BEAN_REFERENCE);
            }

            BeanReference beanReference = new BeanReference(this.toPos(beanNameToken), beanname);
            this.constructedNodes.push(beanReference);
            return true;
        } else {
            return false;
        }
    }

    private boolean maybeEatTypeReference() {
        if (!this.peekToken(TokenKind.IDENTIFIER)) {
            return false;
        } else {
            Token typeName = this.peekToken();
            if (!typeName.stringValue().equals("T")) {
                return false;
            } else {
                this.nextToken();
                this.eatToken(TokenKind.LPAREN);
                SpelNodeImpl node = this.eatPossiblyQualifiedId();

                int dims;
                for(dims = 0; this.peekToken(TokenKind.LSQUARE, true); ++dims) {
                    this.eatToken(TokenKind.RSQUARE);
                }

                this.eatToken(TokenKind.RPAREN);
                this.constructedNodes.push(new TypeReference(this.toPos(typeName), node, dims));
                return true;
            }
        }
    }

    private boolean maybeEatNullReference() {
        if (this.peekToken(TokenKind.IDENTIFIER)) {
            Token nullToken = this.peekToken();
            if (!nullToken.stringValue().equalsIgnoreCase("null")) {
                return false;
            } else {
                this.nextToken();
                this.constructedNodes.push(new NullLiteral(this.toPos(nullToken)));
                return true;
            }
        } else {
            return false;
        }
    }

    private boolean maybeEatProjection(boolean nullSafeNavigation) {
        Token t = this.peekToken();
        if (!this.peekToken(TokenKind.PROJECT, true)) {
            return false;
        } else {
            SpelNodeImpl expr = this.eatExpression();
            this.eatToken(TokenKind.RSQUARE);
            this.constructedNodes.push(new Projection(nullSafeNavigation, this.toPos(t), expr));
            return true;
        }
    }

    private boolean maybeEatInlineList() {
        Token t = this.peekToken();
        if (!this.peekToken(TokenKind.LCURLY, true)) {
            return false;
        } else {
            SpelNodeImpl expr = null;
            Token closingCurly = this.peekToken();
            if (this.peekToken(TokenKind.RCURLY, true)) {
                expr = new InlineList(this.toPos(t.startpos, closingCurly.endpos), new SpelNodeImpl[0]);
            } else {
                ArrayList listElements = new ArrayList();

                do {
                    listElements.add(this.eatExpression());
                } while(this.peekToken(TokenKind.COMMA, true));

                closingCurly = this.eatToken(TokenKind.RCURLY);
                expr = new InlineList(this.toPos(t.startpos, closingCurly.endpos), (SpelNodeImpl[])listElements.toArray(new SpelNodeImpl[listElements.size()]));
            }

            this.constructedNodes.push(expr);
            return true;
        }
    }

    private boolean maybeEatIndexer() {
        Token t = this.peekToken();
        if (!this.peekToken(TokenKind.LSQUARE, true)) {
            return false;
        } else {
            SpelNodeImpl expr = this.eatExpression();
            this.eatToken(TokenKind.RSQUARE);
            this.constructedNodes.push(new Indexer(this.toPos(t), expr));
            return true;
        }
    }

    private boolean maybeEatSelection(boolean nullSafeNavigation) {
        Token t = this.peekToken();
        if (!this.peekSelectToken()) {
            return false;
        } else {
            this.nextToken();
            SpelNodeImpl expr = this.eatExpression();
            if (expr == null) {
                this.raiseInternalException(this.toPos(t), SpelMessage.MISSING_SELECTION_EXPRESSION);
            }

            this.eatToken(TokenKind.RSQUARE);
            if (t.kind == TokenKind.SELECT_FIRST) {
                this.constructedNodes.push(new Selection(nullSafeNavigation, 1, this.toPos(t), expr));
            } else if (t.kind == TokenKind.SELECT_LAST) {
                this.constructedNodes.push(new Selection(nullSafeNavigation, 2, this.toPos(t), expr));
            } else {
                this.constructedNodes.push(new Selection(nullSafeNavigation, 0, this.toPos(t), expr));
            }

            return true;
        }
    }

    private SpelNodeImpl eatPossiblyQualifiedId() {
        LinkedList qualifiedIdPieces = new LinkedList();

        Token node;
        for(node = this.peekToken(); this.isValidQualifiedId(node); node = this.peekToken()) {
            this.nextToken();
            if (node.kind != TokenKind.DOT) {
                qualifiedIdPieces.add(new Identifier(node.stringValue(), this.toPos(node)));
            }
        }

        if (qualifiedIdPieces.isEmpty()) {
            if (node == null) {
                this.raiseInternalException(this.expressionString.length(), SpelMessage.OOD);
            }

            this.raiseInternalException(node.startpos, SpelMessage.NOT_EXPECTED_TOKEN, "qualified ID", node.getKind().toString().toLowerCase());
        }

        int pos = this.toPos(((SpelNodeImpl)qualifiedIdPieces.getFirst()).getStartPosition(), ((SpelNodeImpl)qualifiedIdPieces.getLast()).getEndPosition());
        return new QualifiedIdentifier(pos, (SpelNodeImpl[])qualifiedIdPieces.toArray(new SpelNodeImpl[qualifiedIdPieces.size()]));
    }

    private boolean isValidQualifiedId(Token node) {
        if (node != null && node.kind != TokenKind.LITERAL_STRING) {
            if (node.kind != TokenKind.DOT && node.kind != TokenKind.IDENTIFIER) {
                String value = node.stringValue();
                return StringUtils.hasLength(value) && VALID_QUALIFIED_ID_PATTERN.matcher(value).matches();
            } else {
                return true;
            }
        } else {
            return false;
        }
    }

    private boolean maybeEatMethodOrProperty(boolean nullSafeNavigation) {
        if (this.peekToken(TokenKind.IDENTIFIER)) {
            Token methodOrPropertyName = this.nextToken();
            SpelNodeImpl[] args = this.maybeEatMethodArgs();
            if (args == null) {
                this.push(new PropertyOrFieldReference(nullSafeNavigation, methodOrPropertyName.data, this.toPos(methodOrPropertyName)));
                return true;
            } else {
                this.push(new MethodReference(nullSafeNavigation, methodOrPropertyName.data, this.toPos(methodOrPropertyName), args));
                return true;
            }
        } else {
            return false;
        }
    }

    private boolean maybeEatConstructorReference() {
        if (!this.peekIdentifierToken("new")) {
            return false;
        } else {
            Token newToken = this.nextToken();
            SpelNodeImpl possiblyQualifiedConstructorName = this.eatPossiblyQualifiedId();
            List nodes = new ArrayList();
            nodes.add(possiblyQualifiedConstructorName);
            if (this.peekToken(TokenKind.LSQUARE)) {
                ArrayList dimensions;
                for(dimensions = new ArrayList(); this.peekToken(TokenKind.LSQUARE, true); this.eatToken(TokenKind.RSQUARE)) {
                    if (!this.peekToken(TokenKind.RSQUARE)) {
                        dimensions.add(this.eatExpression());
                    } else {
                        dimensions.add((Object)null);
                    }
                }

                if (this.maybeEatInlineList()) {
                    nodes.add(this.pop());
                }

                this.push(new ConstructorReference(this.toPos(newToken), (SpelNodeImpl[])dimensions.toArray(new SpelNodeImpl[dimensions.size()]), (SpelNodeImpl[])nodes.toArray(new SpelNodeImpl[nodes.size()])));
            } else {
                this.eatConstructorArgs(nodes);
                this.push(new ConstructorReference(this.toPos(newToken), (SpelNodeImpl[])nodes.toArray(new SpelNodeImpl[nodes.size()])));
            }

            return true;
        }
    }

    private void push(SpelNodeImpl newNode) {
        this.constructedNodes.push(newNode);
    }

    private SpelNodeImpl pop() {
        return (SpelNodeImpl)this.constructedNodes.pop();
    }

    private boolean maybeEatLiteral() {
        Token t = this.peekToken();
        if (t == null) {
            return false;
        } else {
            if (t.kind == TokenKind.LITERAL_INT) {
                this.push(Literal.getIntLiteral(t.data, this.toPos(t), 10));
            } else if (t.kind == TokenKind.LITERAL_LONG) {
                this.push(Literal.getLongLiteral(t.data, this.toPos(t), 10));
            } else if (t.kind == TokenKind.LITERAL_HEXINT) {
                this.push(Literal.getIntLiteral(t.data, this.toPos(t), 16));
            } else if (t.kind == TokenKind.LITERAL_HEXLONG) {
                this.push(Literal.getLongLiteral(t.data, this.toPos(t), 16));
            } else if (t.kind == TokenKind.LITERAL_REAL) {
                this.push(Literal.getRealLiteral(t.data, this.toPos(t), false));
            } else if (t.kind == TokenKind.LITERAL_REAL_FLOAT) {
                this.push(Literal.getRealLiteral(t.data, this.toPos(t), true));
            } else if (this.peekIdentifierToken("true")) {
                this.push(new BooleanLiteral(t.data, this.toPos(t), true));
            } else if (this.peekIdentifierToken("false")) {
                this.push(new BooleanLiteral(t.data, this.toPos(t), false));
            } else {
                if (t.kind != TokenKind.LITERAL_STRING) {
                    return false;
                }

                this.push(new StringLiteral(t.data, this.toPos(t), t.data));
            }

            this.nextToken();
            return true;
        }
    }

    private boolean maybeEatParenExpression() {
        if (this.peekToken(TokenKind.LPAREN)) {
            this.nextToken();
            SpelNodeImpl expr = this.eatExpression();
            this.eatToken(TokenKind.RPAREN);
            this.push(expr);
            return true;
        } else {
            return false;
        }
    }

    private Token maybeEatRelationalOperator() {
        Token t = this.peekToken();
        if (t == null) {
            return null;
        } else if (t.isNumericRelationalOperator()) {
            return t;
        } else {
            if (t.isIdentifier()) {
                String idString = t.stringValue();
                if (idString.equalsIgnoreCase("instanceof")) {
                    return t.asInstanceOfToken();
                }

                if (idString.equalsIgnoreCase("matches")) {
                    return t.asMatchesToken();
                }

                if (idString.equalsIgnoreCase("between")) {
                    return t.asBetweenToken();
                }
            }

            return null;
        }
    }

    private Token eatToken(TokenKind expectedKind) {
        Token t = this.nextToken();
        if (t == null) {
            this.raiseInternalException(this.expressionString.length(), SpelMessage.OOD);
        }

        if (t.kind != expectedKind) {
            this.raiseInternalException(t.startpos, SpelMessage.NOT_EXPECTED_TOKEN, expectedKind.toString().toLowerCase(), t.getKind().toString().toLowerCase());
        }

        return t;
    }

    private boolean peekToken(TokenKind desiredTokenKind) {
        return this.peekToken(desiredTokenKind, false);
    }

    private boolean peekToken(TokenKind desiredTokenKind, boolean consumeIfMatched) {
        if (!this.moreTokens()) {
            return false;
        } else {
            Token t = this.peekToken();
            if (t.kind == desiredTokenKind) {
                if (consumeIfMatched) {
                    ++this.tokenStreamPointer;
                }

                return true;
            } else {
                return desiredTokenKind == TokenKind.IDENTIFIER && t.kind.ordinal() >= TokenKind.DIV.ordinal() && t.kind.ordinal() <= TokenKind.NOT.ordinal() && t.data != null;
            }
        }
    }

    private boolean peekToken(TokenKind possible1, TokenKind possible2) {
        if (!this.moreTokens()) {
            return false;
        } else {
            Token t = this.peekToken();
            return t.kind == possible1 || t.kind == possible2;
        }
    }

    private boolean peekToken(TokenKind possible1, TokenKind possible2, TokenKind possible3) {
        if (!this.moreTokens()) {
            return false;
        } else {
            Token t = this.peekToken();
            return t.kind == possible1 || t.kind == possible2 || t.kind == possible3;
        }
    }

    private boolean peekIdentifierToken(String identifierString) {
        if (!this.moreTokens()) {
            return false;
        } else {
            Token t = this.peekToken();
            return t.kind == TokenKind.IDENTIFIER && t.stringValue().equalsIgnoreCase(identifierString);
        }
    }

    private boolean peekSelectToken() {
        if (!this.moreTokens()) {
            return false;
        } else {
            Token t = this.peekToken();
            return t.kind == TokenKind.SELECT || t.kind == TokenKind.SELECT_FIRST || t.kind == TokenKind.SELECT_LAST;
        }
    }

    private boolean moreTokens() {
        return this.tokenStreamPointer < this.tokenStream.size();
    }

    private Token nextToken() {
        return this.tokenStreamPointer >= this.tokenStreamLength ? null : (Token)this.tokenStream.get(this.tokenStreamPointer++);
    }

    private Token peekToken() {
        return this.tokenStreamPointer >= this.tokenStreamLength ? null : (Token)this.tokenStream.get(this.tokenStreamPointer);
    }

    private void raiseInternalException(int pos, SpelMessage message, Object... inserts) {
        throw new InternalParseException(new SpelParseException(this.expressionString, pos, message, inserts));
    }

    public String toString(Token t) {
        return t.getKind().hasPayload() ? t.stringValue() : t.kind.toString().toLowerCase();
    }

    private void checkOperands(Token token, SpelNodeImpl left, SpelNodeImpl right) {
        this.checkLeftOperand(token, left);
        this.checkRightOperand(token, right);
    }

    private void checkLeftOperand(Token token, SpelNodeImpl operandExpression) {
        if (operandExpression == null) {
            this.raiseInternalException(token.startpos, SpelMessage.LEFT_OPERAND_PROBLEM);
        }

    }

    private void checkRightOperand(Token token, SpelNodeImpl operandExpression) {
        if (operandExpression == null) {
            this.raiseInternalException(token.startpos, SpelMessage.RIGHT_OPERAND_PROBLEM);
        }

    }

    private int toPos(Token t) {
        return (t.startpos << 16) + t.endpos;
    }

    private int toPos(int start, int end) {
        return (start << 16) + end;
    }
}

 

 

 

 

1.3    源码解析为何算出666?

https://blog.csdn.net/f641385712/article/details/90812967

 

你可能感兴趣的:(设计模式课程 设计模式精讲 20-3 解释器模式源码解析)