Package net.paoding.rose.jade.statement.expression.impl

Source Code of net.paoding.rose.jade.statement.expression.impl.ExqlCompiler

package net.paoding.rose.jade.statement.expression.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.paoding.rose.jade.statement.expression.ExqlContext;
import net.paoding.rose.jade.statement.expression.ExqlPattern;
import net.paoding.rose.jade.statement.expression.ExqlUnit;

/**
* 实现语句编译器。
*
* @author han.liao
*/
public class ExqlCompiler {

    // 编译的常量
    private static final char BRACE_LEFT = '(';

    private static final char BRACE_RIGHT = ')';

    private static final char BLOCK_LEFT = '{';

    private static final char BLOCK_RIGHT = '}';

    private static final String SHARP = "#";

    private static final String JOIN = "!";

    private static final String KEYWORD_IF = "if";

    private static final String KEYWORD_FOR = "for";

    private static final String SHARP_ELSE = "#else";

    // 正则表达式
    private static final Pattern PATTERN_KEYWORD = Pattern.compile( // NL
            "\\:\\:|([\\:\\$]{1}[a-zA-Z0-9_\\.]+)|\\{([^\\{\\}]+)\\}\\?|#(#|!|if|for)?");

    private static final Pattern PATTERN_IN = Pattern.compile(// NL
            "([a-zA-Z0-9_]*)\\s+in\\s+(.+)");

    // 待编译的语句
    private final String pattern;

    private final int length;

    // 编译位置
    private int position = 0;

    /**
     * 创建语句编译器。
     *
     * @param pattern - 待编译的语句
     */
    public ExqlCompiler(String pattern) {
        this.pattern = pattern;
        this.length = pattern.length();
    }

    /**
     * 执行编译动作。
     *
     * @return ExqlPattern 对象
     */
    public ExqlPattern compile() {

        // 从语句编译出: ExqlPattern 对象
        return new ExqlPatternImpl(pattern, compileUnit());
    }

    /**
     * 从语句编译出: ExqlUnit 对象。
     *
     *
     * @return ExqlUnit 对象
     */
    protected ExqlUnit compileUnit() {

        // 在输入中查找  PREFIX 字符
        Matcher matcher = PATTERN_KEYWORD.matcher(pattern);

        // 输出的单元列表
        ArrayList<ExqlUnit> units = new ArrayList<ExqlUnit>();

        // 组装位置
        int fromIndex = 0;

        while ((position < length) && matcher.find(position)) {

            // 修改当前位置
            position = matcher.end();

            // 检查  :expr | $expr 形式的子句
            String expr = matcher.group(1);
            if (expr != null) {

                // 创建文本子句
                if (matcher.start() > fromIndex) {
                    units.add(new TextUnit(pattern.substring(fromIndex, matcher.start())));
                }

                // 创建  :expr | $expr 形式的子句
                if (expr.charAt(0) == '$') {

                    // 创建  $expr 形式的子句, 作为拼接处理
                    units.add(new JoinExprUnit(expr));
                } else {

                    // 创建  :expr 形式的子句
                    units.add(new ExprUnit(expr));
                }

                fromIndex = position;

                continue;
            }

            // 检查  {...}? 的语法
            String group = matcher.group(2);
            if (group != null) {

                // 创建文本子句
                if (matcher.start() > fromIndex) {
                    units.add(new TextUnit(pattern.substring(fromIndex, matcher.start())));
                }

                // 编译  {...} 内部的子句
                ExqlCompiler compiler = new ExqlCompiler(group);
                ExqlUnit unit = compiler.compileUnit();

                // 创建   {...}? 形式的子句
                units.add(new OptionUnit(unit));

                fromIndex = position;

                continue;
            }

            // 检查  # 后面的关键字
            String keyword = matcher.group(3);

            // 处理  #(:expr) 形式的子句
            if (keyword == null) {

                // 获取括号内的内容
                expr = findBrace(BRACE_LEFT, BRACE_RIGHT);
                if (expr != null) {

                    // 创建文本子句
                    if (matcher.start() > fromIndex) {
                        units.add(new TextUnit(pattern.substring(fromIndex, matcher.start())));
                    }

                    // 创建  #(:expr) 形式的表达式
                    units.add(new ExprUnit(expr));

                    fromIndex = position;
                }
            }
            // 处理  ##(:expr) 形式的子句
            else if (keyword.equals(SHARP) || keyword.equals(JOIN)) {

                // 获取括号内的内容
                expr = findBrace(BRACE_LEFT, BRACE_RIGHT);
                if (expr != null) {

                    // 创建文本子句
                    if (matcher.start() > fromIndex) {
                        units.add(new TextUnit(pattern.substring(fromIndex, matcher.start())));
                    }

                    // 创建  ##(:expr) 形式的表达式
                    units.add(new JoinExprUnit(expr));

                    fromIndex = position;
                }
            }
            // 处理  #if(:expr) {...} #else {...} 形式的子句
            else if (keyword.equals(KEYWORD_IF)) {

                // 获取括号内的内容
                expr = findBrace(BRACE_LEFT, BRACE_RIGHT);
                if (expr != null) {

                    // 编译  {...} 单元
                    ExqlUnit unitIfTrue = compileBlock();
                    if (unitIfTrue != null) {

                        // 创建文本子句
                        if (matcher.start() > fromIndex) {
                            units.add(new TextUnit(pattern.substring(fromIndex, matcher.start())));
                        }

                        ExqlUnit unitIfFalse = null;

                        // 匹配  #else {...} 子句
                        if (match(SHARP_ELSE, position)) {

                            // 编译  {...} 单元
                            unitIfFalse = compileBlock();
                        }

                        // 创建  #if(:expr) {...} #else {...} 形式的子句
                        units.add(new ChoiceUnit(expr, unitIfTrue, unitIfFalse));

                        fromIndex = position;
                    }
                }
            }
            // 处理  #for(variant in :expr) {...} 形式的子句
            else if (keyword.equals(KEYWORD_FOR)) {

                // 获取括号内的内容
                expr = findBrace(BRACE_LEFT, BRACE_RIGHT);
                if (expr != null) {

                    // 编译  {...} 单元
                    ExqlUnit unit = compileBlock();
                    if (unit != null) {

                        // 创建文本子句
                        if (matcher.start() > fromIndex) {
                            units.add(new TextUnit(pattern.substring(fromIndex, matcher.start())));
                        }

                        // 循环变量名
                        String variant = null;

                        // 解析  variant in :expr 表达式
                        Matcher matcherIn = PATTERN_IN.matcher(expr);
                        if (matcherIn.matches()) {
                            variant = matcherIn.group(1);
                            expr = matcherIn.group(2);
                        }

                        // 创建  #for(variant in :expr) {...} 形式的子句
                        units.add(new ForEachUnit(expr, variant, unit));

                        fromIndex = position;
                    }
                }
            }
        }

        if (fromIndex < length) {
            // 写入 PREFIX 字符后的内容。
            units.add(new TextUnit(pattern.substring(fromIndex)));
        }

        if (units.size() > 1) {

            // 返回集合对象
            return new BunchUnit(units);

        } else if (!units.isEmpty()) {

            // 返回单个对象
            return units.get(0);

        } else {

            // 返回空对象
            return new EmptyUnit();
        }
    }

    /**
     * 查找匹配的左括号, 忽略之前的空白字符。
     *
     * 如果未找到匹配的左括号,函数返回 -1.
     *
     * @param chLeft - 匹配的左括号
     * @param fromIndex - 查找的起始位置
     *
     * @return 左括号的位置, 如果未找到匹配的左括号,函数返回 -1.
     */
    private int findLeftBrace(char chLeft, int fromIndex) {

        // 查找出现的左括号。
        for (int index = fromIndex; index < length; index++) {

            char ch = pattern.charAt(index);

            // 如果出现左括号,返回。
            if (ch == chLeft) {
                return index;
            }
            // 如果出现非空白字符,返回 - 1.
            else if (!Character.isWhitespace(ch)) {
                return -1;
            }
        }

        // 没有找到匹配的括号。
        return -1;
    }

    /**
     * 查找匹配的右括号, 可以用于匹配 '{}', '[]', '()' 括号对。
     *
     * 如果未找到匹配的右括号,函数返回 -1.
     *
     * @param string - 查找的字符串
     * @param chLeft - 匹配的左括号
     * @param chRight - 匹配的右括号
     * @param fromIndex - 查找的起始位置
     *
     * @return 右括号的位置, 如果未找到匹配的右括号,函数返回 -1.
     */
    private int findRightBrace(char chLeft, char chRight, int fromIndex) {

        int level = 0; // 记录括号重叠级别。

        // 查找匹配的右括号。
        for (int index = fromIndex; index < length; index++) {

            char ch = pattern.charAt(index);

            // 如果出现左括号,重叠级别增加。
            if (ch == chLeft) {
                level++;
            }
            // 如果出现右括号,重叠级别降低。
            else if (ch == chRight) {

                if (level == 0) {
                    // 找到右括号。
                    return index;
                }

                level--;
            }
        }

        // 没有找到匹配的括号。
        return -1;
    }

    /**
     * 从当前位置查找匹配的一对括号, 并返回内容。
     *
     * 如果有匹配的括号, 返回后的当前位置指向匹配的右括号后一个字符。
     *
     * @param chLeft - 匹配的左括号
     * @param chRight - 匹配的右括号
     *
     * @return 返回括号内容, 如果没有括号匹配, 返回 <code>null</code>.
     */
    private String findBrace(char chLeft, char chRight) {

        // 从当前位置查找查找匹配的  (...)
        int left = findLeftBrace(chLeft, position);
        if (left >= position) {

            int start = left + 1;
            int end = findRightBrace(chLeft, chRight, start);
            if (end >= start) {

                // 当前位置指向匹配的右括号后一个字符
                position = end + 1;

                // 返回匹配的括号内容
                return pattern.substring(start, end);
            }
        }

        return null; // 没有  (...) 匹配
    }

    /**
     * 从当前位置查找匹配的: {...} 并编译出: ExqlUnit 对象。
     *
     * 如果有匹配的: {...}, 编译后, 当前位置指向匹配的右括号后一个字符。
     *
     * @return ExqlUnit, 如果没有: {...} 匹配, 返回 <code>null</code>.
     */
    private ExqlUnit compileBlock() {

        // 查找匹配的  {...}
        String group = findBrace(BLOCK_LEFT, BLOCK_RIGHT);
        if (group != null) {

            // 编译  {...} 内部的子句
            ExqlCompiler compiler = new ExqlCompiler(group);
            return compiler.compileUnit();
        }

        return null; // 没有  {...} 匹配
    }

    /**
     * 匹配指定的关键字。
     *
     * 如果匹配成功, 当前位置是关键字最后一个字符之后。
     *
     * @param keyword - 匹配的关键字
     * @param fromIndex - 查找的起始位置
     *
     * @return true / false
     */
    private boolean match(String keyword, int fromIndex) {

        int match = 0;

        // 查找非空白字符。
        for (int index = fromIndex; index < length; index++) {

            char ch = pattern.charAt(index);

            if (!Character.isWhitespace(ch)) {
                match = index;
                break;
            }
        }

        // 匹配关键字内容。
        for (int index = 0; index < keyword.length(); index++) {

            char ch = pattern.charAt(match);

            if (ch != keyword.charAt(index)) {
                // 与关键字不匹配
                return false;
            }

            match++;
        }

        // 修改当前位置
        position = match;

        return true;
    }

    // 进行简单测试
    public static void main(String... args) throws Exception {

        String string = "SELECT :expr1, #($expr2.class),"
                + " WHERE #if(:expr3) {e = $expr3} #else {e IS NULL}"
                + "#for(variant in $expr4.bytes) { AND c = :variant}" // NL
                + " {AND d = :expr5}? {AND f = $expr6}?" // NL
                + " BY #!(:expr7) ASC";

        // 在输入中查找  PREFIX 字符
        Matcher matcher = PATTERN_KEYWORD.matcher(string);

        int position = 0;

        while (matcher.find(position)) {

            System.out.println("===============================");
            System.out.println("group 0: " + matcher.group(0));
            System.out.println("group 1: " + matcher.group(1));
            System.out.println("group 2: " + matcher.group(2));
            System.out.println("group 3: " + matcher.group(3));

            position = matcher.end();
        }

        // 在循环表达式中查找
        matcher = PATTERN_IN.matcher("variant in :expr5");

        if (matcher.matches()) {

            System.out.println("===============================");
            System.out.println("group 0: " + matcher.group(0));
            System.out.println("group 1: " + matcher.group(1));
            System.out.println("group 2: " + matcher.group(2));
        }

        // 编译下列语句
        ExqlPattern pattern = new ExqlCompiler(string).compile();

        ExqlContext context = new ExqlContextImpl(string.length());

        HashMap<String, Object> map = new HashMap<String, Object>();

        map.put("expr1", "expr1");
        map.put("expr2", "expr2");
        map.put("expr3", "expr3");
        map.put("expr4", "expr4");
        map.put("expr5", "expr5");
        // map.put("expr6", "expr6");
        map.put("expr7", "expr7");

        System.out.println(pattern.execute(context, map, map));
        System.out.println(Arrays.toString(context.getParams()));
    }
}
TOP

Related Classes of net.paoding.rose.jade.statement.expression.impl.ExqlCompiler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.