Solo  当前访客:0 开始使用

支持迭代语句 - 一步步实现JS语言编译执行


迭代语句是我们最常用的语句了, 其中包含了while, do-while, for, for-in, 本节我们主要通过实现for语句,了解迭代语句的AST及执行过程

目标
实现while和for语句
支持break和continue

解析ast

语法树的解析逻辑和之前的语句、表达式使用的方法类似,这边简单描述

文法描述

IterationStatement :
    	  for (ExpressionNoInopt ; Expressionopt ; Expressionopt) Statement

IterationStatement :
    	  for (var VariableDeclarationListNoIn ; Expressionopt ; Expressionopt) Statement

解析代码

forStatement() {
        let node = null;
        let nextToken = this.lexerLevel.tokenPeek()
        console.log("for======0", nextToken, TokenEnum.type.FOR)
        if(nextToken && nextToken.type === TokenEnum.type.FOR) {
            this.lexerLevel.tokenRead();
            node = new ForStatementAstNode('forStatement', 'for');
            nextToken = this.lexerLevel.tokenPeek()
            console.log("for======1.1", nextToken, TokenEnum.type.FOR)
            if(nextToken && nextToken.type === TokenEnum.type.LeftParen) {
                // 分解for语句内的三个语句
                console.log("for======1", nextToken)
                this.lexerLevel.tokenRead();
                nextToken = this.lexerLevel.tokenPeek()
                let forExpCount = 1; // 用于记录数量
                while(nextToken && nextToken.type !== TokenEnum.type.RightParen) {
                    // 依次取出三个表达式
                    // 第一个表达式,可以是 var
                    let childTest = null
                    if(forExpCount == 1) {
                        childTest = this.variable()
                    }
                    if(!childTest) {
                        childTest = this.lowestExpression();
                    }
                    node[forExpCount === 1? "addInit": (forExpCount === 2? "addTest" : "addUpdate")](childTest)
                    forExpCount ++;
                    nextToken = this.lexerLevel.tokenPeek()
                    if(nextToken && nextToken.type === TokenEnum.type.SemiColon) {
                        this.lexerLevel.tokenRead();
                        nextToken = this.lexerLevel.tokenPeek()
                    }
                }
                // 简单判断语句异常
                if(forExpCount != 3 && forExpCount != 4) {
                    throw Error("expression error in forStatement")
                }
                if(nextToken && nextToken.type === TokenEnum.type.RightParen) {
                    this.lexerLevel.tokenRead();
                    // 解析函数体
                    // 进入statement
                    let child1 = this.statement();
                    if(child1) {
                        node.addBody(child1)
                    }
                }else {
                    throw Error("lost right paren in forStatement")
                }
            }

        }

        return node;
    }

计算过程

对于for语句, 执行过程如下

  1. 初始化语句存在,则先执行
  2. 循环执行:
    • 判断test语句, 如果为false, 则退出循环
    • 执行函数体, 执行结果记为stmt
    • stmt.type 是break, 则退出循环,返回(completion[normal, rst, empty])
    • stmt.type 是continue或者normal, 执行update语句

Completion type:
{
type: "normal, break, continue, return, or throw",
value: jsVal|empty,
target: identifier
}

计算逻辑

 getValue() {
        // console.log("=====if value", this.test.getValue())
        // Let exprRef be the result of evaluating ExpressionNoIn.
        // Call GetValue(exprRef). (This value is not used but the call may have side-effects.)
        let initValue = this.init ? this.init.getValue() : null;

        //
        let testVal = this.test ? !!(this.test.getValue()) : true // 转换成boolean

        while(testVal) {
            let val = this.body.getValue();

            if(val) {
                if(val.__type__ === "break") {
                    break;
                }else if(val.__type__ === "return") {
                    return val.obj
                }
            }
            // continue的操作同 普通语句

            // Let incExprRef be the result of evaluating the second Expression.
            this.update && this.update.getValue()

            // 更新test 标识
            testVal = this.test ? !!(this.test.getValue()) : true
            if(!testVal){
                return {__type__:"normal", obj: val && val.obj}
            }

        }
    }

测试

测试正常解析

// 测试正常解析
    let syntaxLevel = new SyntaxLevel2(`
      for(;;){}
   `)
    console.info("test----", syntaxLevel.astParse().showStructure())

结果:

{ type: 'Program',
  value: 'program',
  children:
   [ { type: 'forStatement',
       value: '
for',
       init: null,
       test: null,
       update: null,
       body: { type: 'Block', value: '', children: [] } } ] }

测试异常

 try{
        let syntaxLevel1 = new SyntaxLevel2(`
             for(;){}
        `)
        console.info("test----Error", syntaxLevel1
.astParse().showStructure())
    }catch(e){
        console.error("test----Error1", e)
    }

结果:

Error: expression error in forStatement

测试计算

// 测试计算
    let syntaxLevel2 = new SyntaxLevel2(`
        var a = 0;
        var b = 1;
         for(;a<3;a=a+1){
            b = b+a
         }
         b
     `)

     console.info("test-val1: 4 == ", syntaxLevel2.exe())

结果:
test-val1: 4 == 4

测试continue

 // 测试continue
    let syntaxLevel3 = new SyntaxLevel2(`
        var a = 0;
        var b = 1;
         for(;a<3;a=a+1){
            if(a == 1){
                continue;
            }
            b = b+a
         }
         b
     `)

    console.info("test-val2: 3 == ", syntaxLevel3.exe())

结果
test-val2: 3 == 3

测试break

 // 测试 break
    let syntaxLevel4 = new SyntaxLevel2(`
        var a = 0;
        var b = 1;
         for(;a<3;a=a+1){
            if(a == 1){
                break;
            }
            b = b+a
         }
         b
     `)

    // console.info("test-val2: 4 == ", syntaxLevel3.astParse().showStructure())
    console.info("test-val3: 1 == ", syntaxLevel4.exe())

结果:
test-val3: 1 == 1

测试var

// 测试 var
    let syntaxLevel5 = new SyntaxLevel2(`
        var b = 1;
         for(var a = 0;a<3;a=a+1){
          
            b = b+a
         }
         b
     `)

    // console.info("test-val2: 4 == ", syntaxLevel5.astParse().showStructure())
    console.info("test-val4: 4 == ", syntaxLevel5.exe())

结果:
test-val4: 4 == 4


标题:支持迭代语句 - 一步步实现JS语言编译执行
作者:hugh0524
地址:https://newblog.uproject.cn/articles/2020/03/19/1584599210209.html

, , , 0 0