visitStmt()

in src/resolver/client.js [822:1044]


  visitStmt(obj, stmt, belong) {
    let node;
    let renderByGrammerValueTypes = [
      'construct_model',
      'property_access',
      'map_access',
      'boolean',
      'super',
      'not',
    ];
    if (renderByGrammerValueTypes.indexOf(stmt.type) > -1) {
      node = this.renderGrammerValue(null, stmt);
    } else if (stmt.type === 'declare') {
      let type = null;
      if (stmt.expr && stmt.expr.inferred) {
        let inferred = stmt.expr.inferred;
        if (stmt.expr.propertyPathTypes && stmt.expr.propertyPathTypes.length) {
          if (stmt.expr.propertyPathTypes[stmt.expr.propertyPathTypes.length - 1].type === 'map') {
            inferred = stmt.expr.propertyPathTypes[stmt.expr.propertyPathTypes.length - 1].keyType;
          }
        }
        type = this.resolveTypeItem(inferred);
      } else if (stmt.expectedType) {
        type = this.resolveTypeItem(stmt.expectedType);
      } else {
        debug.stack(stmt);
      }
      let expectedType = stmt.expectedType ? stmt.expectedType : null;
      assert.strictEqual(true, type instanceof TypeItem);
      let variate = new GrammerVar(stmt.id.lexeme, type);
      if (stmt.expr.type === 'null') {
        variate.isOptional = true;
      }
      let value = this.renderGrammerValue(null, stmt.expr, expectedType, true);
      node = new GrammerExpr(variate, Symbol.assign(), value);
    } else if (stmt.type === 'requestAssign') {
      let variate = new GrammerCall('prop', [
        { type: 'object', name: this.config.request },
        { type: 'prop', name: stmt.left.id.lexeme }
      ]);
      let value = this.renderGrammerValue(null, stmt.expr);
      if (stmt.left.type === 'request_property_assign') {
        let key = '';
        stmt.left.propertyPath.forEach((p, i) => {
          if (i === stmt.left.propertyPath.length - 1) {
            key = p.lexeme;
          } else {
            variate.addPath({ type: 'map', name: p.lexeme });
          }
        });
        node = new BehaviorSetMapItem(variate, key, value);
      } else {
        node = new GrammerExpr(variate, Symbol.assign(), value);
      }
    } else if (stmt.type === 'ifRequestAssign' || stmt.type === 'if') {
      node = this.visitIfElse(stmt, 'if');
    } else if (stmt.type === 'elseIfRequestAssign') {
      node = this.visitIfElse(stmt, 'elseif');
    } else if (stmt.type === 'return') {
      node = new GrammerReturn();
      if (typeof stmt.expr === 'undefined') {
        node.type = 'null';
      } else if (stmt.expr.type === 'null') {
        node.type = 'null';
      } else if (stmt.expr.type === 'call') {
        let val = this.renderGrammerValue(null, stmt.expr, null, true);
        node.expr = val;
        node.type = 'grammer';
      } else if (_isBasicType(stmt.expr.type)) {
        node.type = stmt.expr.type;
        node.expr = this.renderGrammerValue(null, stmt.expr);
      } else {
        node.expr = this.renderGrammerValue(null, stmt.expr, null, true);
        node.type = 'grammer';
      }
      if (stmt.expectedType && stmt.expectedType.type === 'model') {
        let expected = '';
        if (stmt.expectedType.moduleName) {
          expected += `${stmt.expectedType.moduleName}.`;
        }
        expected += stmt.expectedType.name;
        node.expr = new BehaviorToModel(node.expr, expected);
      }
    } else if (stmt.type === 'throw') {
      this.currThrows['$Error'] = errorType;
      node = new GrammerThrows(errorType);
      if (Array.isArray(stmt.expr)) {
        stmt.expr.forEach(e => {
          node.addParam(this.renderGrammerValue(null, e));
        });
      } else {
        node.addParam(this.renderGrammerValue(null, stmt.expr));
      }
    } else if (stmt.type === 'virtualCall') {
      let val = this.renderGrammerValue(null, stmt);
      node = val.value;
    } else if (stmt.type === 'while') {
      node = new GrammerCondition('while');
      if (Array.isArray(stmt.condition)) {
        stmt.condition.forEach(c => {
          node.addCondition(this.renderGrammerValue(null, c));
        });
      } else {
        node.addCondition(this.renderGrammerValue(null, stmt.condition));
      }
      if (stmt.stmts) {
        stmt.stmts.stmts.forEach(s => {
          this.visitStmt(node, s, node.index);
        });
      }
    } else if (stmt.type === 'for') {
      node = new GrammerLoop('foreach');
      node.item = new GrammerVar(stmt.id.lexeme, this.resolveTypeItem(stmt.list.inferred.itemType));
      node.source = this.renderGrammerValue(null, stmt.list);
      if (stmt.stmts) {
        stmt.stmts.stmts.forEach(s => {
          this.visitStmt(node, s, node.index);
        });
      }
    } else if (stmt.type === 'assign') {
      let hasMapAccess = false;
      let expectedType = stmt.expectedType ? stmt.expectedType : stmt.left.inferred ? stmt.left.inferred.name || stmt.left.inferred : null;
      let needCast = true;
      if (stmt.left.type === 'virtualVariable' || stmt.left.type === 'property') {
        needCast = false;
        if (stmt.left.id && (stmt.left.id.lexeme === '__request' || stmt.left.id.lexeme === '__response')) {
          needCast = true;
        }
      }
      const right = this.renderGrammerValue(null, stmt.expr, expectedType, needCast);
      if (stmt.left.type === 'property') {
        hasMapAccess = stmt.left.propertyPathTypes.some(item => item.type === 'map');
        if (hasMapAccess) {
          const grammerValue = this.renderGrammerValue(null, stmt.left);
          const call = grammerValue.value;
          let lastIndex = 0;
          for (let i = 0; i < stmt.left.propertyPathTypes.length; i++) {
            const propertyPathType = stmt.left.propertyPathTypes[i];
            if (propertyPathType.type === 'map') {
              lastIndex = i;
              break;
            }
          }
          if (lastIndex + 1 < stmt.left.propertyPathTypes.length) {
            call.type = 'prop';
            call.path = call.path.splice(0, lastIndex + 2);
            const key = stmt.left.propertyPath[lastIndex + 1].lexeme;
            node = new BehaviorSetMapItem(call, key, right);
          } else {
            hasMapAccess = false;
          }
        }
      } else if (stmt.left.type === 'map_access') {
        hasMapAccess = true;
        const grammerValue = this.renderGrammerValue(null, stmt.left);
        const call = grammerValue.value;
        call.type = 'prop';
        call.path = call.path.splice(0, call.path.length - 1);
        node = new BehaviorSetMapItem(call, stmt.left.accessKey.value.string, right);
      }

      if (!hasMapAccess) {
        const left = this.renderGrammerValue(null, stmt.left);
        let isBehavior = false;
        if (left.type === 'call' && left.value instanceof GrammerCall && left.value.type === 'key') {
          const keyPath = left.value.path[left.value.path.length - 1];
          if (keyPath.type === 'map') {
            left.value.path = left.value.path.slice(0, left.value.path.length - 1);
            node = new BehaviorSetMapItem(left.value, keyPath.name, right);
            isBehavior = true;
          }
        }
        if (!isBehavior) {
          node = new GrammerExpr(
            left,
            Symbol.assign(),
            right
          );
        }
      }
    } else if (stmt.type === 'call') {
      node = this.renderGrammerValue(null, stmt).value;
    } else if (stmt.type === 'break') {
      node = new GrammerBreak();
    } else if (stmt.type === 'retry') {
      node = new BehaviorRetry();
    } else if (stmt.type === 'try') {
      const tryGram = new GrammerTryCatch();
      stmt.tryBlock.stmts.forEach(item => {
        this.visitStmt(tryGram, item, tryGram.index);
      });
      if (stmt.catchId) {
        const exceptionGram = new GrammerException(
          exceptionType,
          new GrammerVar(stmt.catchId.lexeme, exceptionType)
        );
        const catchGram = new GrammerCatch([], exceptionGram);

        if (stmt.catchBlock) {
          stmt.catchBlock.stmts.forEach(item => {
            this.visitStmt(catchGram, item, catchGram.index);
          });
        }
        tryGram.addCatch(catchGram);
      }
      if (stmt.finallyBlock) {
        const finallyGram = new GrammerFinally();
        stmt.finallyBlock.stmts.forEach(item => {
          this.visitStmt(finallyGram, item, finallyGram.index);
        });
        tryGram.setFinally(finallyGram);
      }
      node = tryGram;
    } else {
      debug.stack(stmt);
    }
    if (belong) {
      node.belong = belong;
    }
    this.findComments(obj, stmt, belong);
    obj.addBodyNode(node);
    this.findComments(obj, stmt, belong, 'back');
  }