自己动手实现解释型语言

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:   好久没写博客了,依然是按照我喜欢的风格,写一篇自己实现解释型语言。看过我之前的博客应该知道,我写的东西大多只是起到一个抛砖引玉的功能,实际上自己要实现一个框架,语言啥的,都有太多需要考虑的东西,能力有限,精力有限,只能实现一个最基本的框框出来,有兴趣的朋友自己去扩展。

  好久没写博客了,依然是按照我喜欢的风格,写一篇自己实现解释型语言。看过我之前的博客应该知道,我写的东西大多只是起到一个抛砖引玉的功能,实际上自己要实现一个框架,语言啥的,都有太多需要考虑的东西,能力有限,精力有限,只能实现一个最基本的框框出来,有兴趣的朋友自己去扩展。
  刚学开发语言的时候,那些大牛们就说一个语言最基本的执行流程就三种:顺序,条件分支,循环。只要支持三种执行流程,任意嵌套下,理论上可以实现任意复杂的逻辑。后面学到mybatis的时候对里面动态语言很感兴趣,里面其实已经包含了一个解释型语言,最基本的三种执行流程。好多次想要彻底研究它的实现,找了一遍又一遍,每次看不懂里面的封装,大概比较牛B的代码都是封装到让别人看不懂吧。15年的时候我自己尝试着实现了一版以xml作为格式的解析语言,后面自己写着都觉得恶心,就改成了现在的格式。我觉得要实现一个解析型语言,最主要的事情就是实现一个可解析的格式。其次要对一个语言的解析执行有清晰的认识(顺序就不用说了,条件分支无非就是计算一下条件true or false然后决定是否执行条件语句的内容,循环无非就是先初始化一个变量(可选),然后判断是否符合循环的条件,然后决定是否执行循环体的内容,如果不满足循环条件,直接执行下一个,如果满足循环条件,继续执行当前循环语句,重复判断,这里只需要在一个地方保存好循环产生的变量如:每个循环的标志,每个循环是否结束等)。笔者只是一个草根,没有研究过太多算法,和大部分开发者差不多,基本只会解析xml和json,xml写起来太恶心,json写起来也好不到哪里去。所以笔者尝试用最简单的办法将json格式改变了一下,然后通过转换函数转成json格式去解释执行。本语言使用java编写,用到的外部jar包主要是json-lib和ognl,尽量不依赖太多外部包。json-lib主要用来解析json格式,ognl主要是用来计算表达式,如if里的条件表达式。
  语言最终的格式例子如下 

service(
        name:'test',do [
            set(name:'a',value:1);
            set(name:'b',value:0);
            def(name:'c',value:0);
            if(condition:'a==0',do[
                set(name:'b',value:1);
                test(desc:'b1');
            ]) 
            else(condition:'a==2',do [
                    set(name:'b',value:2);
                    test(desc:'b2');
            ]) 
            else( do [
                set(name:'b',value:3);
                set(name:'c',value:3);
                def(name:'d',value:3);
                test(desc:'b3');
                if(condition:'b==2',do [
                        set(name:'e',value:1);
                        test(desc:'e1');
                ])
                else(do [
                        set(name:'e',value:2);
                        test(desc:'e2');
                ])
            ]);
            test(desc:'d4')
    ])

  转换成json之后格式如下

{
        service: {
            name: 'test',
            do: [
                {set: {name: 'a',value: 1}},
                {set: {name: 'b',value: 0}},
                {def: {name: 'c',value: 0}},
                {if: {condition: 'a==0',
                    do: [
                        {set: {name: 'b',value: 1}},
                        {test: {desc: 'b1'}}
                    ]}
                },
                {else: { condition: 'a==2',
                    do: [
                        {set: {name: 'b',value: 2}},
                        {test: {desc: 'b2'}}
                    ]}
                },
                {else: {
                    do: [
                        {set: {name: 'b',value: 3}},
                        {set: {name: 'c',value: 3}},
                        {def: {name: 'd',value: 3}},
                        {test: {desc: 'b3'}},
                        {if: { condition: 'b==2',
                                do: [
                                    {set: {name: 'e',value: 1}},
                                    {test: {desc: 'e1'}}
                                ]}
                        },
                        {else: {
                                do: [
                                    {set: {name: 'e',value: 2}},
                                    {test: {desc: 'e2'}}
                                ]}
                            }
                        ]
                    }
                },
                {test: {desc: 'd4'}}
            ]
        }
    }

     转换函数如下

public static JSONObject transferJson(String str) {
        //去掉多行注释
        str = str.replaceAll(Regex.MULTILINE_COMMENT,"");
        //转换do[成do:[
        str = str.replaceAll(Regex.DO, "do:[");
        //转换)else成);else
        str = str.replaceAll(Regex.ELSE, ");else(");
        str = "{"+str+"}";
        str = str.replaceAll(";\\s*]","]");
        str = str.replace("(", ":{");
        str = str.replace(")","}");
        str = str.replace(";","},{");
        str = str.replace("[", "<-{");
        str = str.replace("]", "}->");
        str = str.replace("<-", "[");
        str = str.replace("->", "]");
        System.out.println(str);
        return JSONObject.fromObject(str);
}

  如上,用了最笨的办法,玩了一个花样,主要是让语言写起来更顺眼一点。其实还可以变得更加简单,有兴趣的朋友再研究下。不知道这种思路
对那些也想写写自己的语言的朋友有没有一点帮助呢。假设是数据库应用,还可以在保存这份格式的时候先转换成json后保存数据库的另外一个字段。
拿出来解析执行的时候就拿那份json的。呵呵,不知道像不像预编译呢?(要不要来个666呢?开个玩笑,其实编译是指编译成机器语言,这里不沾边,顶多算个预处理)
  为了支持多种格式解析,这里使用最简单的策略模式。抽象解析类如下

public interface Parser {
    
        //这里暂时只提供一种解析器
        public static Parser getParser(String format) {
            return new JSonParser();
        }
        
        //正式解析执行
        public Result parser(String str,Map<String,Object> params);
        
        //测试解析执行
        public Result testParser(String str,Map<String,Object> params);
        
}

/**

  
service( name:"test", do:[ // 也可以直接写成do[ def(name:'name',value:'"zhangsan"'); test(desc:'def'); def(name:'age',value:'11'); test(desc:'def'); set(name:'age',value:'age+11'); test(desc:'set'); set(name:'name',value:'"lisi"'); test(desc:'set'); if(condition:'name=="lisi1111"',do:[ test(desc:'if'); set(name:'age',value:'12'); test(desc:'set') ]); set(name:'lisi',value:'{11,21,31}'); set(name:'map',value:'#{"name1":"zhangsan","age1":56}'); while(index:'i',collection:'map',var:'item',do:[ test(desc:'while'); set(name:'i',value:'i+1') ]); set(name:'xx',value:'2'); test(desc:'set'); result(name:'result',value:'map') ] ) service( name:"test", do:[ def(name:'name',value:'\"zhangsan\"'); def(name:'age',value:12); choose( do:[ when(condition:'name == \"zhangsan\"' do:[ set(name:'age',value:22); test(desc:'when'); ]); when(condition:'name == \"lisi\"' do:[ set(name:'age',value:23) ]); other(do:[ set(name:'age',value:24) ]); ]); test(desc:'choose'); print(name:'age') ] ) service( name:'test', do:[ def(name:'map',value:'#{}'); select(id:'test1',name:'test1'); set(name:'name',value:'currentUser.username',target:'map'); set(name:'test1',value:'test1',target:'map'); result(value:'map') ] ) */ public class JSonParser implements Parser{ public JSonParser() { } /** * 将变种格式替换成json格式 * @param str * @return */ public static JSONObject transferJson(String str) { //去掉多行注释 str = str.replaceAll(Regex.MULTILINE_COMMENT,""); //转换do[成do:[ str = str.replaceAll(Regex.DO, "do:["); //转换)else成);else str = str.replaceAll(Regex.ELSE, ");else("); str = "{"+str+"}"; str = str.replaceAll(";\\s*]","]"); str = str.replace("(", ":{"); str = str.replace(")","}"); str = str.replace(";","},{"); str = str.replace("[", "<-{"); str = str.replace("]", "}->"); str = str.replace("<-", "["); str = str.replace("->", "]"); System.out.println(str); return JSONObject.fromObject(str); } /** 以如下原始语言格式为 service( name:'test',do[ set(name:'a',value:1); set(name:'b',value:0); def(name:'c',value:0); if(condition:'a==0',do[ set(name:'b',value:1); test(desc:'b1'); ]) else(condition:'a==2',do [ set(name:'b',value:2); test(desc:'b2'); ]) else( do [ set(name:'b',value:3); set(name:'c',value:3); def(name:'d',value:3); test(desc:'b3'); if(condition:'b==2',do [ set(name:'e',value:1); test(desc:'e1'); ]) else(do [ set(name:'e',value:2); test(desc:'e2'); ]) ]); test(desc:'d4') ]) 转成json格式之后如下 { service: { name: 'test', do: [ {set: {name: 'a',value: 1}}, {set: {name: 'b',value: 0}}, {def: {name: 'c',value: 0}}, {if: {condition: 'a==0', do: [ {set: {name: 'b',value: 1}}, {test: {desc: 'b1'}} ]} }, {else: { condition: 'a==2', do: [ {set: {name: 'b',value: 2}}, {test: {desc: 'b2'}} ]} }, {else: { do: [ {set: {name: 'b',value: 3}}, {set: {name: 'c',value: 3}}, {def: {name: 'd',value: 3}}, {test: {desc: 'b3'}}, {if: { condition: 'b==2', do: [ {set: {name: 'e',value: 1}}, {test: {desc: 'e1'}} ]} }, {else: { do: [ {set: {name: 'e',value: 2}}, {test: {desc: 'e2'}} ]} } ] } }, {test: {desc: 'd4'}} ] } } */ public static void main(String[] args) throws Exception { String str = "service(\n" + " name:'test',do[\n" + " set(name:'a',value:1);\n" + " set(name:'b',value:0);\n" + " def(name:'c',value:0);\n" + " if(condition:'a==0',do[\n" + " set(name:'b',value:1);\n" + " test(desc:'b1');\n" + " ]) \n" + " else(condition:'a==2',do [\n" + " set(name:'b',value:2);\n" + " test(desc:'b2');\n" + " ]) \n" + " else( do [\n" + " set(name:'b',value:3);\n" + " set(name:'c',value:3);\n" + " def(name:'d',value:3);\n" + " test(desc:'b3');\n" + " if(condition:'b==2',do [\n" + " set(name:'e',value:1);\n" + " test(desc:'e1');\n" + " ])\n" + " else(do [\n" + " set(name:'e',value:2);\n" + " test(desc:'e2');\n" + " ])\n" + " ]);\n" + " test(desc:'d4')\n" + " ])"; str = transferJson(str).toString(); new JSonParser().parser(str, new HashMap<String,Object>()); } //测试解析执行 @Override public Result testParser(String json,Map<String,Object> params){ params.put(Attrs.ROLLBACK_FLAG, true); return parser(json, params); } //正式解析执行 @Override public Result parser(String json,Map<String,Object> params){ String errorMsg = ""; List<Object> consoles = null; Object data = null; try { JSONObject root = JSONObject.fromObject(json); Map<String,Object> currParams = new HashMap<String,Object>(); parserElement(root, currParams,params); data = params.get(Attrs.RESULT_FLAG); consoles = (List<Object>)params.get(Attrs.CONSOLE_VAR); //销毁各种过程变量 destroy(params); } catch (Exception e) { e.printStackTrace(); errorMsg = e.getMessage(); } if(consoles == null) { consoles = new ArrayList<Object>(); } if(StringUtils.isNotEmpty(errorMsg)) { consoles.add("error: "+errorMsg); } return new Result(data, consoles); } @Override public Result parser(String str, Map<String, Object> scope, Map<String, Object> params) { // TODO Auto-generated method stub return null; } //销毁各种过程变量 public void destroy(Map<String,Object> params) { params.remove(Attrs.TRANSACTIONAL); params.remove(Attrs.RETURN_FLAG); params.remove(Attrs.TASK_EXECUTOR); } //解析json元素 private void parserElement(JSONObject ele1,Map<String,Object> currParams,Map<String,Object> globalParams)
                                                        throws Exception {
       //当解析到return标志直接退出递归解析运行
            boolean return_flag = MapUtils.getBoolean(globalParams, Attrs.RETURN_FLAG,false);
            if(return_flag) {
                return;
            }
            //解析一个节点,如{if:{condition:'b==2',do:[{set:{name:'e',value:1}},{test:{desc:'e1'}}]}}
            TempVal val = parserOneElement(currParams,globalParams, ele1);
            //得到处理节点类如IfNode
            BaseNode node = val.getNode();
            //得到当前节点的内容,如{condition:'b==2',do:[{set:{name:'e',value:1}},{test:{desc:'e1'}}]}
            JSONObject obj = val.getObj();
            boolean flag = val.isContinue();
            //得到当前节点的子节点do属性里的节点集合,如[{set:{name:'e',value:1}},{test:{desc:'e1'}}]
            JSONArray eles = obj.optJSONArray(Attrs.DO);
            //判断是否需要继续处理当前节点的do属性的内容
            if(flag && eles != null && !eles.isEmpty()) {
                //处理当前节点内容,之前做点什么
                node.pre(currParams, globalParams, obj);
                //创建本节点下的局部参数
                Map<String,Object> params = new HashMap<String,Object>();
                /**
                 将处理当前节点产生的局部变量全部放入局部参数,如当前节点为if节点,里面就有过程变量,如果是否应该进入if对应的else的标志等
                 这里重新创建一个map,将局部参数全部加入这个map的目的是模拟嵌套标签处理时,子节点的局部变量应该包含父节点里的局部变量的情况,
                 也实现了参数的就近原则,如使用如下例子模拟
                {
                        do [
                                i = 1;
                                do [
                                    i = 2;
                                ]
                                i = 3;
                        ]
                }
                当处理第一个do节点时currParams里产生了局部变量i = 1,当处理第二个do节点时新产生一个map将父节点产生的局部变量放入其中
                这时候map作为内层do节点里的局部变量容器,当内层do执行完后,直接清空内层局部变量容器map,执行到i = 3时使用的局部变量容器
                currParams。任意多层嵌套,都是这个规则递归下去
                */
                params.putAll(currParams);
                for(int i = 0; i< eles.size();) {
                    JSONObject ele = eles.optJSONObject(i);
                    //递归解析json子元素
                    parserElement(ele, params, globalParams);
                    //如果循环标志不会true则解析下一个标签
                    //这里表示需要重复解析这个循环标签,则i不变,反之继续处理下一个元素
                    String index = getEleAttr(Attrs.INDEX, ele);
                    /**
                    * 如果当前局部变量中有循环标记,或者循环变量没有结束,则i不自增,重复解析执行当前标签,知道处理后,循环标记清除后,i自增,
             继续处理下一个标签
*/ if(!"true".equals(params.get(Attrs.WHILE_FLAG)) || !"while".equals(getEleName(ele))
                    || index == null || !index.equals(params.get(Attrs.WHILE_INDEX))) { i++; } } node.after(currParams, globalParams, obj); //回收当前作用域参数 params.clear(); params = null; } } //获取指定json块的指定key的值 private String getEleAttr(String key,JSONObject ele) { JSONObject target = ele.optJSONObject(getEleName(ele)); if(target != null) { return target.optString(key); } return null; } /** 获取当前json块对应的标签名,如{if:{condition:'b==2',do:[{set:{name:'e',value:1}},{test:{desc:'e1'}}]}} 这个json块标签名就是if,一般都是取json块第一个key */ private String getEleName(JSONObject ele) { Set<String> names = ele.keySet(); String eleName = null; if(names != null && !names.isEmpty()) { eleName = names.toArray(new String[names.size()])[0]; } return eleName; } //解析一个json元素 private TempVal parserOneElement(Map<String, Object> currParams,Map<String,Object> globalParams, JSONObject ele)
                                                          throws Exception{
         //获取该json块对应的标签名,如{if:{condition:'b==2',do:[{set:{name:'e',value:1}},{test:{desc:'e1'}}]}}的标签名就是if,
            String eleName = getEleName(ele);
            boolean isContinue = false;
            BaseNode node = null;
            if(StringUtils.isNotEmpty(eleName)) {
                /**
                * 获取标签名对应内容json块,如{if:{condition:'b==2',do:[{set:{name:'e',value:1}},{test:{desc:'e1'}}]}}
                * 标签名对应的内容json块就是{condition:'b==2',do:[{set:{name:'e',value:1}},{test:{desc:'e1'}}]}
                */
                ele = ele.optJSONObject(eleName);
                //根据标签名在工厂中得到对应标签名的处理节点
                node = NodeFactory.create(eleName);
                /**
                * 使用处理节点处理后返回是否需要继续处理标签对应内容里的子标签,一般的标签直接返回true,有些情况
                * 如{if:{condition:'b==2',do:[{set:{name:'e',value:1}},{test:{desc:'e1'}}]}}
                * 这里当condition里表达式不为true时,do里的内容不应该被处理,这时就需要返回false
                */
                isContinue = node.parse(currParams, globalParams, ele);
            }
            //将是否继续处理结果,当前json块,对应的处理节点包装成临时对象返回
            return new TempVal(isContinue,ele,node);
            
        } 
        
        
        
        final static class TempVal{
            
            private boolean isContinue;
            
            private JSONObject obj;
            
            private BaseNode node;

            public TempVal(boolean isContinue, JSONObject obj,BaseNode node) {
                this.isContinue = isContinue;
                this.obj = obj;
                this.node = node;
            }

            public boolean isContinue() {
                return isContinue;
            }

            public void setContinue(boolean isContinue) {
                this.isContinue = isContinue;
            }

            public JSONObject getObj() {
                return obj;
            }

            public void setObj(JSONObject obj) {
                this.obj = obj;
            }

            public BaseNode getNode() {
                return node;
            }

            public void setNode(BaseNode node) {
                this.node = node;
            }
            
        }

    }

  如上述,是解释执行的核心类,可以通过增加实现类的方式来扩充解释器兼容的格式。可以看到实际上本语言主要用来编写一个业务方法。在我们实际工作过程,大部分东西都是重复劳动,变动的只是业务。
  为了让语言支持的语句具有扩展性,这里使用最简单的工厂模式,部分代码如下

public abstract class BaseNode {
    
        public abstract boolean parse(Map<String, Object> currParams,Map<String, Object> globalParams,JSONObject obj) 
                    throws Exception;
        
        public void pre(Map<String, Object> currParams,Map<String, Object> globalParams,JSONObject obj) throws Exception {
            
        }
        
        public void after(Map<String, Object> currParams,Map<String, Object> globalParams,JSONObject obj) throws Exception {
            
        }
        
        protected Map<String, Object> getAllParams(Map<String, Object> currParams,
                Map<String, Object> globalParams) {
            Map<String,Object> allParams = new HashMap<String,Object>();
            allParams.putAll(globalParams);
            allParams.putAll(currParams);
            return allParams;
        }

    }
/**
    set赋值操作
    set标签有必填属性name,value,非必填属性if,else,if表示当满足条件才赋值,如果if里面表达式是true
    那么就拿value里面的值赋值,如果是false就拿else里面的值赋值,如果else属性没有name就相当于是赋值null
    赋值时先看局部变量里面有么有这个变量,如果有直接将参数放入局部变量,
    */
    public class SetNode extends BaseNode {

        @Override
        public boolean parse(Map<String, Object> currParams,
                Map<String, Object> globalParams, JSONObject obj) throws Exception {
        
            String name = obj.optString(Attrs.NAME);
            String target = obj.optString(Attrs.TARGET);
    //        String type = obj.optString(Attrs.TYPE);
    //        String format = obj.optString(Attrs.FORMAT);
            Map<String, Object> allParams = getAllParams(currParams,globalParams);
            String valueStr = obj.optString(Attrs.VALUE);
            Object value = null;
            if(StringUtils.isNotEmpty(valueStr)) {
                valueStr = TypeUtil.replaceArray(valueStr);
                value = Ognl.getValue(valueStr,allParams);
            }
            if(value == null) {
                throw new Exception("set操作的变量("+name+")的值不存在");
            }
            String ifStr = obj.optString(Attrs.IF);
            boolean iif = true;
            if (StringUtils.isNotEmpty(ifStr)) {
                ifStr = TypeUtil.replaceArray(ifStr);
                iif = (Boolean) Ognl.getValue(ifStr, allParams);
                if (!iif) {
                    String elseStr = obj.optString(Attrs.ELSE);
                    if (StringUtils.isNotEmpty(elseStr)) {
                        Object value1 = Ognl.getValue(elseStr, allParams);
                        value = value1;
                    }
                }
            }
            // 如果局部变量存在则更新局部变量(如果全局变量中也存在,那么全局变量被局部变量遮蔽了),反之更新全局变量
            try {
                //如果target没有值就直接关注顶层变量
                if(StringUtils.isEmpty(target)) {
                    if (currParams.containsKey(name)) {
                        currParams.put(name, value);
                    } else {
                        globalParams.put(name, value);
                    }
                } else { //如果target有值,则关注顶层变量中的target代表的变量
                    Object obj1 = new HashMap<String,Object>();
                    if (currParams.containsKey(target)) {
                        obj1 = currParams.get(target);
                    } else if(globalParams.containsKey(target)){
                        obj1 = globalParams.get(target);
                    }
                    if(obj1 instanceof Map) {
                        Map map = (Map)obj1;
                        map.put(name, value);
                    } else {
                        throw new Exception("add指令的"+target+"参数不是对象不能设置值");
                    }
                }
                
            } catch (Exception e) {
                String msg = "";
                if(target != null) {
                    msg = "往"+target+"变量中设置参数("+name+")出错"+e.getMessage();
                } else {
                    msg = "设置参数("+name+")出错"+e.getMessage();
                }
                throw new Exception(msg);
            }
            
            return true;
            
        }
    }
/**
    判断操作
    属性如下
    condition 判断条件支持ognl表达式
    */
    public class IfNode extends BaseNode {

        @Override
        public boolean parse(Map<String, Object> currParams,Map<String, Object> globalParams, JSONObject obj) 
                throws Exception {
            
            //解析if时先清空过程变量
            currParams.remove(Attrs.PROCESS_VAR);
            
            String testStr = obj.optString(Attrs.CONDITION);
            
            boolean test = false;
            try {
                if(StringUtils.isNotEmpty(testStr)) {
                    Map<String, Object> allParams = getAllParams(currParams,globalParams);
                    test = (Boolean)Ognl.getValue(testStr,allParams);
                }
            } catch (Exception e) {
                throw new Exception("判断操作参数"+testStr+"不合法");
            }
            JSONArray array = obj.optJSONArray(Attrs.DO);
            if(array != null && array.size() == 0) {
                test = true;
            }
            //如果没有进入if节点的处理体do中,则传入过程变量到下一个else节点,其实就是条件取非
            if(!test) {
                currParams.put(Attrs.PROCESS_VAR, "!("+testStr+")");
            }
            return test;
        }

    }
/**
    else判断操作
    属性如下
    condition 判断条件支持ognl表达式
    */
    public class ElseNode extends BaseNode {

        @Override
        public boolean parse(Map<String, Object> currParams,Map<String, Object> globalParams, JSONObject obj) 
                    throws Exception {
            
            //解析if时先清空过程变量
            String process_var = MapUtils.getString(currParams,Attrs.PROCESS_VAR);
            
            //如果else节点没有if传递过来的过程变量,直接返回false,不能进入else的处理体do中去
            if(StringUtils.isEmpty(process_var)) {
                return false;
            }

            String testStr = obj.optString(Attrs.CONDITION);
            
            boolean test = false;
            try {
                if(StringUtils.isNotEmpty(testStr)) {
                    testStr = process_var + "&&" + testStr;
                    Map<String, Object> allParams = getAllParams(currParams,globalParams);
                    test = (Boolean)Ognl.getValue(testStr,allParams);
                } else { //如果又有前面传递过来的过程变量。而且又没有condition,那么说明直接进入else里了
                    //先清空过程变量
                    currParams.remove(Attrs.PROCESS_VAR);
                    return true;
                }
            } catch (Exception e) {
                throw new Exception("判断操作参数"+testStr+"不合法");
            }
            JSONArray array = obj.optJSONArray(Attrs.DO);
            if(array != null && array.size() == 0) {
                test = true;
            }
            //如果没有进入else节点的处理体do中,则传入过程变量到下一个else节点
            if(!test) {
                currParams.put(Attrs.PROCESS_VAR, "!("+testStr+")");
            }
            return test;
        }

    }
/**

        循环操作
        属性如下
        collection 遍历的集合或map,可不填单纯依靠condition做简单循环
        condition 遍历条件,可不填,单纯遍历collection
        break 循环退出条件支持ognl
        continue 循环跳过条件,支持ognl
        index 循环变量可以是集合下标,也可以是map的key
        var 循环中获取集合或者map中的值保存在这个对应的变量中
    */
    public class WhileNode extends BaseNode {

        @Override
        public boolean parse(Map<String, Object> currParams,Map<String, Object> globalParams, JSONObject obj) 
                        throws Exception {
            String conditionStr = obj.optString(Attrs.CONDITION);
            String breakStr = obj.optString(Attrs.BREAK);
            String continueStr = obj.optString(Attrs.CONTINUE);
            String index = obj.optString(Attrs.INDEX);
            String varStr = obj.optString(Attrs.VAR);
            String collectionStr = obj.optString(Attrs.COLLECTION);
            if(index != null) {
                if(currParams.get(index) != null) {
                    currParams.put(index+"_", (Integer)currParams.get(index+"_") + 1);
                } else {
                    currParams.put(index+"_", 0);
                }
                currParams.put(index, (Integer)currParams.get(index+"_"));
            }
            boolean condition = true;
            boolean break_ = false;
            boolean continue_ = false;
            Map<String, Object> allParams = getAllParams(currParams,globalParams);
            Object collection = null;
            if(StringUtils.isNotEmpty(collectionStr)) {
                collection = Ognl.getValue(collectionStr,allParams);
                //如果集合属性不为空,但是条件为null则默认加上一个边界条件
                if(StringUtils.isEmpty(conditionStr)) {
                    if(collection instanceof List) {
                        conditionStr = index+"_<"+collectionStr+".size()";
                    } else if(collection instanceof Map){
                        Map map = (Map)collection;
                        Set set = map.entrySet();
                        List list = new ArrayList(set);
                        allParams.put("_list_", list);
                        conditionStr = index+"_<_list_"+".size()";
                    }
                }
            }
            if(StringUtils.isNotEmpty(conditionStr)) {
                conditionStr = TypeUtil.replaceArray(conditionStr);
                condition = (Boolean)Ognl.getValue(conditionStr,allParams);
            }
            if(StringUtils.isNotEmpty(breakStr)) {
                breakStr = TypeUtil.replaceArray(breakStr);
                break_ = (Boolean)Ognl.getValue(breakStr,allParams);
            }
            if(StringUtils.isNotEmpty(continueStr)) {
                continueStr = TypeUtil.replaceArray(continueStr);
                continue_ = (Boolean)Ognl.getValue(continueStr,allParams);
            }
            boolean flag = true;
            currParams.put(Attrs.WHILE_INDEX, index);
            currParams.put(Attrs.WHILE_FLAG, "true");
            if(continue_) {
                flag = false;
            } else if(break_) {
                flag = false;
                destroyVars(currParams, index, varStr);
            } else if(condition) {
                try {
                    if(StringUtils.isNotEmpty(varStr) && StringUtils.isNotEmpty(collectionStr)) {
                        Object value = null;
                        int idx = Integer.parseInt(currParams.get(index+"_").toString());
                        if(collection instanceof List) {
                            value = ((List)collection).get(idx);
                            currParams.put(varStr, value);
                        } else if(collection instanceof Map){
                            Map map = (Map)collection;
                            Set<Entry<String,Object>> set = map.entrySet();
                            List<Entry<String,Object>> list = new ArrayList(set);
                            currParams.put(varStr, list.get(idx).getValue());
                            currParams.put(index, list.get(idx).getKey());
                        }
                    
                    }
                } catch (Exception e) {
                    throw new Exception("从集合或者映射取值"+currParams.get(index)+"错误"+e.getMessage());
                }
                
            } else {
                flag = false;
                destroyVars(currParams, index, varStr);
            }
        
            return flag;
            
        }

        //释放临时变量
        private void destroyVars(Map<String, Object> currParams, String index,
                String varStr) {
            currParams.remove(Attrs.WHILE_INDEX);
            currParams.remove(Attrs.WHILE_FLAG);
            currParams.remove(varStr);
            currParams.remove(index);
            currParams.remove(index+"_");
        }

    }
 /**
    测试节点
    */
    public class TestNode extends BaseNode {

        @Override
        public boolean parse(Map<String, Object> currParams,Map<String, Object> globalParams, JSONObject obj) 
                        throws Exception {
            String desc = obj.optString(Attrs.DESC);
            System.out.println(desc+"局部变量为"+currParams.toString());
            System.out.println(desc+"全局变量为"+globalParams.toString());
            System.out.println("----------------------------------------");
            return true;
        }

    }
    执行JSonParser类的主函数,结果如下
    b3局部变量为{d=3, c=3}
    b3全局变量为{a=1, b=3}
    ----------------------------------------
    e2局部变量为{d=3, c=3}
    e2全局变量为{a=1, b=3, e=2}
    ----------------------------------------
    d4局部变量为{c=0}
    d4全局变量为{a=1, b=3, e=2}
    ----------------------------------------

  如上代码在需要的地方,在代码里都加上了详细的说明。其余代码就不一一贴出来了,详细请见https://gitee.com/rongdi/mylanguage

  最后声明:本语言的实现,纯属为了好玩,如果真的要使用解释型语言写业务代码,直接用js写就好了,如java的jdk8中就有很高效的解析器nashorn

 

目录
相关文章
|
4月前
|
存储 算法 程序员
神秘代码世界惊现高效秘籍!究竟是什么让汇编语言编程如此强大?快来一探究竟!
【8月更文挑战第31天】《代码之美:探索高效汇编语言编程的最佳实践》介绍了汇编语言在系统内核、嵌入式系统及高性能应用中的不可替代作用。书中强调了深入理解处理器架构、提升代码可读性、优化算法与数据结构及有效利用寄存器等最佳实践的重要性。通过具体示例,如在 x86 架构下实现高效的加法函数,展示了如何运用这些技巧编写出既高效又可靠的汇编代码,充分展现了汇编语言的独特魅力及其在现代软件开发中的价值。
52 0
|
4月前
|
算法 Java 开发者
探索代码世界:我的编程之旅
在数字时代的浪潮中,编程已成为一门艺术和科学的结合体。本文将带领读者穿梭于代码的迷宫,分享个人的技术感悟,从初识编程的迷茫到深入其境的喜悦,探讨如何通过编程解决实际问题,以及编程带来的思维转变和生活影响。文章旨在为编程初学者提供一盏指路灯,同时也为资深开发者带来共鸣。
|
4月前
|
算法 数据处理 数据库
探索代码世界的魔法:我的编程之旅
【8月更文挑战第31天】 在编程的世界里,每一行代码都像是施法的咒语,拥有改变数字世界的力量。本文将带你走进一个初学者眼中的编程世界,一起感受从零开始构建项目的兴奋与挑战。通过分享个人的学习经历和心得,我们将探讨编程基础、项目实践以及持续学习的重要性,同时提供实用的代码示例,旨在激励和指导编程新手开启自己的技术探索之旅。
|
4月前
|
人工智能 算法 安全
代码之诗:我的编程之旅
在数字世界的无限画布上,每一行代码都是一笔精细的勾勒,每一个算法都是深邃的思考。本文是一次个人技术感悟的分享,从初识编程的困惑与好奇到深入掌握后的创造与热情,再到对技术趋势的洞察与适应,我试图将编程比作一首诗,通过个人经历展现编程艺术的魅力和挑战,并探讨如何持续学习以适应不断变化的技术环境。
|
4月前
|
算法 程序员
代码间的诗篇:我的编程之旅
【8月更文挑战第5天】 在数字世界中,编程不仅仅是一项技术活动,它更像是一种艺术。本文将通过个人经历探索编程的美学,从初识编程的困惑到逐渐掌握后的成就感,再到深刻理解代码背后的逻辑美。我们将一起走进编程的世界,感受它在解决问题、创造新事物中的魅力,以及它如何影响我们的生活和思维方式。
41 0
|
算法 程序员 人机交互
什么?这样自学C语言能事半功倍?
什么?这样自学C语言能事半功倍?
115 0
|
人工智能 前端开发 搜索推荐
程序初学者推荐学习的三种热门编程语言
在当前的社会需求中,市场上运用最多的、最为广泛的、最热门的、最常用的编程语言可以大致分为一下三种:C语言、JAVA语言、Python语言。
|
Rust Java C语言
【RUST学习日记】第17课 流程控制
【RUST学习日记】第17课 流程控制
|
自然语言处理 C语言
【C语言进阶】—— 程序环境和预处理 ( 坚持总会有收获!!!)(中)
【C语言进阶】—— 程序环境和预处理 ( 坚持总会有收获!!!)(中)
125 0
【C语言进阶】—— 程序环境和预处理 ( 坚持总会有收获!!!)(中)
|
存储 自然语言处理 Linux
【C语言进阶】—— 程序环境和预处理 ( 坚持总会有收获!!!)(上)
【C语言进阶】—— 程序环境和预处理 ( 坚持总会有收获!!!)(上)
156 0
【C语言进阶】—— 程序环境和预处理 ( 坚持总会有收获!!!)(上)