自制前端框架 Day5.编译普通字符串

今天打算完成编译字符串的功能。
目标效果(测试案例):

    var expression = " 'hello' ";
    var lexer = new Lexer();
    var astbuilder = new ASTBuilder(lexer);
    var compiler = new Compiler(astbuilder);
    var FnA = compiler.compile(expression);
    expect(FnA()).toBe('hello');

基本思路是,测法分析阶段,如果检测到单引号或者双引号,则进入readString流程,就像readNumber流程一样。

Lexer.prototype.lex=function(expression){
  this.tokens=[];
  this.text = expression;
  this.index = 0;
  while (this.index

在这里面,调用readString方法的时候传入当前的字符,也就是单引号或者双引号。原因是这样的:
如果是双引号开始的字符串,一定要用双引号封闭;单引号也是同理。所以readString方法是这样的:

Lexer.prototype.readString=function(quote){
  var string='';
  this.index++;
  while(this.index

在这里我写代码的时候有个小问题,注意readString方法里面的循环,循环体中,进入if(char==quote)分支之后,把一个token推入tokens数组,然后this.index++这里没问题,问题是下面的那个return,我之前写的是break然后就每次都会抛出异常字符串解析流程出错。原因是:

break语句是跳出当前循环,所以跳出循环以后接着往下走,遇到了throw语句。
return 语句是跳出当前函数/方法。直接跳出了readString流程,回到lex方法。

虽然这是一个很常识性的错误,可是这再次提醒我:写程序要注意逻辑思维,想好了再写!
试着想一下现在运行测试案例会出现什么问题?假设我们编译的是123这个数字,编译后生成的函数会是这样:

function (){
    return 123 ;
}

那么我们编译'hello'这个字符串呢?生成的函数会是这样:

function (){
    return hello ;
}

这个函数运行的时候肯定会报错说hello is undefined
所以我们想要的编译出来的函数应该是这样的:

function (){
    return 'hello' ;//hello被引号包裹着
}

想做出这个改动表面复杂,其实很简单,因为String产生的token其实也是Literal类型,换句话说,Literal类型的token也就是数字和字符两种东西。说的不清楚,还是写个代码。
数字产生的token和string产生的token分别是这样的:

{
    text:'123',
    value:123
}
{
    text:'hello',
    value:'hello'
}

ASTBuilder根据token的类型给他们加上type属性,然后插入AST中。接着Compiler根据AST树的type来执行相应的流程。那么思路就是,在Compiler阶段,遇到type是Literal的节点,有可能是数字也有可能是字符串,要做一下更妥善的处理,之前只是处理的数字没有处理字符串,现在给加上:

Compiler.prototype.recurse=function(ast){
  switch (ast.type) {
    case ASTBuilder.Program:
      this.state.body.push('return ',this.recurse(ast.body),' ;');
      break;
    case ASTBuilder.Literal:
      if(webframe.isString(ast.value)){
        return "\'"+ast.value+"\'";
      }else{
        return ast.value;
      }
      break;
  }
}

在这里面调用了一个webframe.isString方法来判断一个变量是不是字符串,这个方法是自己手写的,也是一个很简单的方法:

webframe.isString=function(userinput){
  return String(userinput)===userinput;
}

现在测试案例就可以跑通了:

image.png

感觉怎么这么简单?果然我忘了,还有转义字符串的功能没写。我想想怎么写,明天再弄。

你可能感兴趣的:(自制前端框架 Day5.编译普通字符串)