美文网首页自制前端框架Web前端之路让前端飞
自制前端框架 Day.7 解析布尔值和null

自制前端框架 Day.7 解析布尔值和null

作者: 蚊子爸爸 | 来源:发表于2017-05-15 11:32 被阅读27次

    先写个parse函数和parser类把现有代码包装一下

    今天打算先把之前的代码整理一下,写一个parser类,包装一下Lexer,ASTBuilder,Compiler类。

    function Parser(){
      var lexer = new Lexer();
      var astbilder = new ASTBuilder(lexer);
      this.compiler = new Compiler(astbilder);
    }
    Parser.prototype.parse = function(expression){
      return this.compiler.compile(expression);
    }
    
    function parse(expression){
      var parser = new Parser();
      return parser.parse(expression);
    }
    

    这样以后调用就方便了,写个测试案例试试:

    describe('用parse函数编译',function(){
      it('编译整数',function() {
        var fn = parse('233')
        expect(fn()).toBe(233);
      })
    })
    

    思路

    如果遇到的字符串不是数字也不是引号,而是一个字符,就进入解析identity流程,这个identity就是说在编程中我们遇到的一些已经定义好的值,比如true,false等等,这种值都是确定的,所以叫identify(确定).
    先写一个函数判断是不是遇到了identify的值。

    Lexer.prototype.isIdent=function(char){
      return ('a'<=char && char<='z')||('A'<=char&&char<='Z')||char==="_"||char==="$";
    }
    

    如果遇到这样的字符,就进入readIdent流程:

    Lexer.prototype.lex=function(expression){
      this.tokens=[];
      this.text = expression;
      this.index = 0;
      while (this.index<this.text.length) {
        var currentChar = this.text.charAt(this.index);
        if(this.isNumber(currentChar)){
          this.readNumber();
        }else if (currentChar==="'"||currentChar==="\"") {
          this.readString(currentChar);
        }else if (this.isIdent(currentChar)) {
          this.readIdent()
        } else{
          throw "现在只支持数字,不支持别的字符"
        }
      }
      return this.tokens;
    }
    

    readIdent流程和其他的没什么不同,区别就是生成的token不一样,ident这种token没有值,因为值是已经被JS定义好的,只有text属性:

    Lexer.prototype.readIdent = function () {
      var ident="";
      while(this.index<this.text.length){
        var currentChar = this.text.charAt(this.index);
        if(this.isIdent(currentChar)||this.isNumber(currentChar)){
          ident+=currentChar;
          this.index++;
        }
      }
      this.tokens.push({
        text:ident
      })
    };
    

    现在虽然有了一个token,但是在构建语法树的时候还是不行,因为构建语法树现在的body是tokens[0].value。显然这个token是没有value的。所以可以完善一下构建语法树的部分了:program的body属性现在是直接调用constant方法,完善一下,program调用一个新方法,primary方法。这个方法的意图是,所有节点的主处理方法。就是说处理其他节点都会通过这个方法过一次。
    代码写好:

    ASTBuilder.constants={
      'true':true,
      'false':false,
      'null':null
    }
    ASTBuilder.prototype.ast=function(expression){
      this.tokens = this.lexer.lex(expression);
      return this.program();
    }
    ASTBuilder.prototype.program=function(){
      return {
        type:ASTBuilder.Program,
        body:this.primary()
      }
    }
    ASTBuilder.prototype.primary=function(){
      if(ASTBuilder.constants.hasOwnProperty(this.tokens[0].text)){
        return {type:ASTBuilder.Literal,value:ASTBuilder.constants[this.tokens[0].text]}
      }else{
        return this.constant();
      }
    }
    

    先写个测试案例跑一下试试:

      it('编译true',function() {
        var fn = parse('true')
        expect(fn()).toBe(true);
      })
      it('编译false',function() {
        var fn = parse('false')
        expect(fn()).toBe(false);
      })
    it('编译null',function() {
        var fn = parse('null')
        expect(fn()).toBe(null);
      })
    
    编译null报错

    编译null的时候出错了,跟一下看看怎么回事:

    因为null就是啥都没有 image.png

    这下明白了,因为现在生成的函数是这样:

    function(){
      return ;
    }
    ``
    所以其实是什么都没返回,测试案例期待的null就不行。我应该让生成的函数是这样:
    

    function(){
    return null ;
    }

    这样只要修改一下escape方法就行了:
    

    Compiler.prototype.escape=function(value){
    if(webframe.isString(value)){
    return "'"+
    value.replace(this.stringEscapeReg,this.changeToUnicode)
    +"'";
    }else if (value===null) {
    return 'null';
    } else{
    return value;
    }
    }

    这就编译成功了:
    
    ![image.png](https://img.haomeiwen.com/i839173/03ff761e4480264c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    今天已经开始写了这个东西第七天了,感觉进度还行,稳扎稳打,之前定的七个月,没准六个月就能完成呢。哈哈。
    
    

    相关文章

      网友评论

        本文标题:自制前端框架 Day.7 解析布尔值和null

        本文链接:https://www.haomeiwen.com/subject/ddgcxxtx.html