renderGrammerValue()

in src/resolver/client.js [480:820]


  renderGrammerValue(valGrammer, object, expectedType = null, canCast = false) {
    if (!valGrammer) {
      valGrammer = new GrammerValue();
    }
    if (!valGrammer.value && object.type === 'object') {
      valGrammer.value = [];
    }
    if (object.type === 'variable') {
      if (object.needCast) {
        let grammerVar = new GrammerVar(object.id.lexeme, this.resolveTypeItem(object.inferred));
        valGrammer.type = 'behavior';
        grammerVar.belong = valGrammer.index;
        const behaviorToMap = new BehaviorToMap(grammerVar, object.inferred);
        behaviorToMap.belong = valGrammer.index;
        valGrammer.value = behaviorToMap;
      } else {
        valGrammer.type = 'var';
        let grammerVar;
        if (object.id.type === 'model') {
          const name = `#${object.id.lexeme}`;
          const type = this.resolveTypeItem(object.inferred);
          type.objectName = name;
          grammerVar = new GrammerVar(object.id.lexeme, type);
          grammerVar.varType = 'static_class';
          grammerVar.name = name;
        } else if (object.type === 'variable') {
          grammerVar = new GrammerVar(object.id.lexeme, this.resolveTypeItem(object.inferred));
          grammerVar.varType = 'var';
          grammerVar.needCast = canCast;
          grammerVar.expected = expectedType ? this.resolveTypeItem(expectedType) : null;
        }
        valGrammer.value = grammerVar;
      }
    } else if (object.type === 'object') {
      object.fields.forEach(field => {
        var val = null;
        var type = field.expr.type;
        if (field.expr.type === 'object') {
          val = [];
          type = 'map';
        }
        var exprChild = new GrammerValue(type, val);
        if (field.type === 'expandField') {
          exprChild.isExpand = true;
        }
        if (field.fieldName && (field.fieldName.lexeme || field.fieldName.string)) {
          exprChild.key = field.fieldName.lexeme || _string(field.fieldName);
        }
        this.renderGrammerValue(exprChild, field.expr, expectedType, true);
        this.findComments(valGrammer, field);
        valGrammer.value.push(exprChild);
        this.findComments(valGrammer, field.expr, 'back');
      });
      valGrammer.type = 'map';
      valGrammer.dataType = this.resolveTypeItem(object.inferred);
      valGrammer.expected = expectedType ? this.resolveTypeItem(expectedType) : null;
    } else if (object.type === 'string') {
      valGrammer.type = 'string';
      valGrammer.value = object.value.string;
    } else if (object.type === 'property_access') {
      let last_path_type = this.resolveTypeItem(object.id.inferred || object.inferred);
      let call = new GrammerCall('prop', [], [], last_path_type);
      var model = false;
      if (object.id.lexeme !== '__request' && object.id.lexeme !== '__response') {
        model = canCast;
      }
      call.addPath({ type: 'object', name: object.id.lexeme, dataType: last_path_type, needCast: model });
      object.propertyPath.forEach((item, i) => {
        var path_name = item.lexeme;
        let path_type = this.resolveTypeItem(object.propertyPathTypes[i]);
        let call_type = 'prop';
        if (is.array(last_path_type)) {
          call_type = 'list';
        } else if (is.map(last_path_type)) {
          call_type = 'map';
        } else if (is.object(last_path_type)) {
          call_type = 'prop';
        } else {
          debug.stack(last_path_type);
        }
        var resolve = false;
        if (i !== (object.propertyPath.length - 1) && object.id.lexeme !== '__request' && object.id.lexeme !== '__response') {
          resolve = true;
        }
        call.addPath({ type: call_type, name: path_name, dataType: path_type, needCast: resolve });
        last_path_type = path_type;
      });

      valGrammer.type = 'call';
      valGrammer.value = call;
      if (object.needCast) {
        valGrammer.type = 'behavior';
        valGrammer.value = new BehaviorToMap(valGrammer.value, object.inferred);
      }
      valGrammer.needCast = model;
    } else if (object.type === 'number') {
      valGrammer.type = 'number';
      valGrammer.value = object.value.value;
      valGrammer.dataType = this.resolveTypeItem(object.inferred);
    } else if (object.type === 'virtualVariable') {
      valGrammer.type = 'call';
      let call = new GrammerCall('prop', [
        { type: 'parent', name: '' },
        { type: 'prop', name: object.vid.lexeme },
      ]);
      // call.isOptional = true;
      valGrammer.needCast = canCast;
      valGrammer.value = call;
    } else if (object.type === 'template_string') {
      valGrammer.type = 'behavior';
      let behaviorTamplateString = new BehaviorTamplateString();
      object.elements.forEach(ele => {
        if (ele.type !== 'element') {
          behaviorTamplateString.addItem(this.renderGrammerValue(null, ele.expr, null, true));
        } else {
          behaviorTamplateString.addItem(new GrammerValue('string', ele.value.string, new TypeString()));
        }
      });
      valGrammer.value = behaviorTamplateString;
    } else if (object.type === 'null') {
      valGrammer.type = 'null';
      valGrammer.value = null;
    } else if (object.type === 'construct_model') {
      let objectName = object.aliasId.lexeme ? object.aliasId.lexeme : '';
      if (object.propertyPath && object.propertyPath.length > 0) {
        if (object.propertyPath.length > 0 && objectName !== '') {
          objectName = objectName + '.';
        }
        object.propertyPath.forEach((p, i) => {
          objectName += p.lexeme;
          if (i !== object.propertyPath.length - 1) {
            objectName += '.';
          }
        });
      }
      objectName = `#${objectName}`;

      valGrammer.type = 'instance';
      let params = [];
      if (object.object) {
        params = this.renderGrammerValue(null, object.object);
        if (params.value.length === 0) {
          this.findComments(params, object.object, 'between');
        }
        if (object.object.inferred.type === 'map') {
          params.type = 'model_construct_params';
        }
      }
      valGrammer.value = new GrammerNewObject(objectName, params);
    } else if (object.type === 'call') {
      let call_type = 'method';
      valGrammer.type = 'call';
      if (object.left && object.left.id && object.left.id.type === 'module') {
        if (systemPackage.indexOf(object.left.id.lexeme) > -1) {
          call_type = 'sys_func';
        }
      } else {
        valGrammer.type = 'call';
        call_type = 'method';
      }
      let call = new GrammerCall(call_type, undefined, undefined, undefined, object.hasThrow, object.isAsync, object.isStatic, object.isOptional);
      if (object.left) {
        let isStatic = object.isStatic ? true : false;
        let callType = isStatic ? '_static' : '';
        if (object.left.type === 'method_call') {
          if (isStatic) {
            call.addPath({ type: 'class', name: '' });
          }
          call.addPath({ type: 'call' + callType, name: object.left.id.lexeme });
        } else if (object.left.type === 'instance_call') {
          if (object.left && object.left.id && object.left.id.lexeme) {
            if (object.left.id.type === 'variable') {
              call.addPath({ type: 'object' + callType, name: object.left.id.lexeme });
            } else if (typeof object.left.id.type === 'undefined' && object.left.id.lexeme.indexOf('@') > -1) {
              call.addPath({ type: 'parent', name: '' });
              call.addPath({ type: 'prop', name: object.left.id.lexeme, needCast: true });
            } else {
              debug.stack('Unsupported object.left.id.type : ' + object.left.id.type, object);
            }
          }
        } else if (object.left.type === 'static_call') {
          if (object.left.id.type === 'module') {
            call.addPath({ type: 'object_static', name: `^${object.left.id.lexeme}` });
            isStatic = true;
          } else {
            // call.addPath({ type: 'call_static', name: object.left.id.lexeme });
            debug.stack(object);
          }
        } else {
          debug.stack(object.left);
        }

        if (object.left.propertyPath) {
          object.left.propertyPath.forEach(p => {
            call.addPath({
              type: 'call' + callType,
              name: p.lexeme
            });
          });
        }
      }
      if (object.args) {
        object.args.forEach(arg => {
          const grammerValue = this.renderGrammerValue(null, arg, null, true);
          grammerValue.belong = call.index;
          call.addParams(grammerValue);
        });
      }
      call.returnType = this.resolveTypeItem(object.inferred);
      valGrammer.value = call;
    } else if (object.type === 'construct') {
      valGrammer.type = 'instance';
      const objectName = `^${object.aliasId.lexeme}`;
      valGrammer.value = new GrammerNewObject(objectName);
      object.args.forEach(item => {
        valGrammer.value.addParam(this.renderGrammerValue(null, item));
      });
    } else if (object.type === 'boolean') {
      valGrammer.type = 'bool';
      valGrammer.value = object.value;
    } else if (object.type === 'not') {
      valGrammer.type = 'not';
      valGrammer.value = this.renderGrammerValue(null, object.expr);
    } else if (object.type === 'array') {
      valGrammer.type = 'array';
      valGrammer.value = [];
      if (object.items.length > 0) {
        object.items.forEach(field => {
          this.findComments(valGrammer, field);
          var exprChild = this.renderGrammerValue(null, field, expectedType);
          valGrammer.value.push(exprChild);
          this.findComments(valGrammer, field, 'back');
        });
      } else {
        this.findComments(valGrammer, object, 'between');
      }
      valGrammer.type = 'array';
      valGrammer.expected = expectedType ? this.resolveTypeItem(expectedType) : null;
    } else if (object.type === 'property') {
      object.type = 'property_access';
      this.renderGrammerValue(valGrammer, object, null, canCast);
    } else if (object.type === 'super') {
      valGrammer.type = 'call';
      let call = new GrammerCall('super', undefined, undefined, undefined, object.hasThrow, object.isAsync);
      object.args.forEach(arg => {
        call.addParams(this.renderGrammerValue(null, arg));
      });
      valGrammer.value = call;
    } else if (object.type === 'map_access') {
      valGrammer.type = 'call';
      let accessKey;
      if (object.accessKey.inferred) {
        accessKey = this.renderGrammerValue(null, object.accessKey, null, true);
      } else if (object.accessKey.type === 'variable') {
        accessKey = object.accessKey.id.lexeme;
      } else if (object.accessKey.type === 'string') {
        accessKey = object.accessKey.value.string;
      } else if (object.accessKey.value && object.accessKey.value.lexeme) {
        accessKey = object.accessKey.value.lexeme;
      } else {
        debug.stack(object);
      }
      let current = object.id.inferred;
      let call = new GrammerCall('key');
      call.addPath({ type: 'object', name: object.id.lexeme });
      if (object.propertyPathTypes) {
        for (let i = 0; i < object.propertyPath.length; i++) {
          if (current.type === 'model') {
            call.type = 'prop';
            call.addPath({ type: 'prop', name: object.propertyPath[i].lexeme, needCast: canCast });
          } else if (current.type === 'array') {
            call.addPath({ type: 'list', name: object.propertyPath[i].lexeme, needCast: canCast });
          } else {
            call.addPath({ type: 'map', name: object.propertyPath[i].lexeme, needCast: canCast });
          }
          current = object.propertyPathTypes[i];
        }
      }
      call.addPath({ type: 'map', name: accessKey });
      if (object.inferred) {
        let inferred = object.inferred;
        if (object.propertyPathTypes && object.propertyPathTypes.length) {
          if (object.propertyPathTypes[object.propertyPathTypes.length - 1].type === 'map') {
            inferred = object.propertyPathTypes[object.propertyPathTypes.length - 1].keyType;
          }
        }
        call.returnType = this.resolveTypeItem(inferred);
      }
      valGrammer.value = call;
      valGrammer.needCast = canCast;
    } else if (object.type === 'array_access') {
      valGrammer.type = 'call';
      let accessKey;
      if (object.accessKey.inferred) {
        accessKey = this.renderGrammerValue(null, object.accessKey);
      } else if (object.accessKey.type === 'number') {
        accessKey = object.accessKey.value.value;
      } else if (object.accessKey.type === 'variable') {
        accessKey = object.accessKey.id.lexeme;
      } else {
        debug.stack(object);
      }
      let current = object.id.inferred;
      let call = new GrammerCall('key');
      call.addPath({ type: 'object', name: object.id.lexeme });
      if (object.propertyPathTypes) {
        for (let i = 0; i < object.propertyPath.length; i++) {
          if (current.type === 'model') {
            call.type = 'prop';
            call.addPath({ type: 'prop', name: object.propertyPath[i].lexeme });
          } else if (current.type === 'array') {
            call.addPath({ type: 'list', name: object.propertyPath[i].lexeme });
          } else {
            call.addPath({ type: 'map', name: object.propertyPath[i].lexeme });
          }
          current = object.propertyPathTypes[i];
        }
      }
      call.addPath({ type: 'list', name: accessKey, isVar: object.accessKey.type === 'variable' });
      if (object.inferred) {
        call.returnType = this.resolveTypeItem(object.inferred);
      }
      valGrammer.value = call;
    } else if (['and', 'or', 'not'].indexOf(object.type) > -1) {
      valGrammer.type = 'expr';
      valGrammer.value = this.visitIfConfition(object);
    } else {
      debug.stack('unimpelemented : ' + object.type, object);
    }
    if (object.inferred) {
      valGrammer.dataType = this.resolveTypeItem(object.inferred);
    }
    if (object.needToReadable) {
      valGrammer.needToReadable = true;
    }
    if (!valGrammer.dataType) {
      debug.stack('Invalid GrammerValue.dataType', valGrammer, object);
    }

    return valGrammer;
  }