grammerValue()

in src/langs/cpp/combinator.js [1448:1944]


  grammerValue(emitter, gram, layer = 0) {
    if (is.annotation(gram)) {
      this.emitAnnotation(emitter, gram);
      return;
    }
    if (gram.type === 'map' || gram.type === 'model_construct_params') {
      if (gram.type === 'model_construct_params' && this.emitType(gram.dataType) !== 'map<string, boost::any>') {
        gram.dataType = new TypeMap(
          new TypeString(), new TypeGeneric()
        );
      }
      this.emitMap(emitter, gram, layer);
    } else if (gram.type === 'string') {
      emitter.emit(`"${gram.value}"`);
    } else if (gram.type === 'null') {
      emitter.emit('nullptr');
    } else if (gram.type === 'behavior' || gram.type === 'call'
      || gram.type === 'var' || gram.type === 'instance') {
      this.grammer(emitter, gram.value, false, false);
    } else if (gram.type === 'number' || gram.type === 'param' || gram.type === 'bool') {
      emitter.emit(gram.value);
    } else if (gram.type === 'expr') {
      if (Array.isArray(gram.value)) {
        gram.value.forEach(gramItem => {
          this.grammer(emitter, gramItem, false, false);
        });
      } else {
        this.grammer(emitter, gram.value, false, false);
      }
    } else if (gram.type === 'array') {
      let itemType = this.emitType(gram.dataType.itemType);
      if (gram.value.length) {
        emitter.emitln(`vector<${itemType}>({`);
        this.levelUp();
        gram.value.forEach((item, i) => {
          if (item instanceof AnnotationItem) {
            this.emitAnnotation(emitter, item);
            return;
          }
          emitter.emit('', this.level);
          this.grammerValue(emitter, item, false, false);
          if (i < gram.value.length - 1) {
            emitter.emitln(',');
          } else {
            emitter.emitln();
          }
        });
        this.levelDown();
        emitter.emit('})', this.level);
      } else {
        emitter.emit(`vector<${itemType}>()`);
      }
    } else if (gram.type === 'not') {
      emitter.emit(_symbol(Symbol.reverse()));
      this.grammerValue(emitter, gram.value);
    } else {
      debug.stack(gram);
    }
  }

  grammerCall(emitter, gram) {
    if (gram.type === 'sys_func' || gram.type === 'method') {
      const resolve_method = _resolveGrammerCall(gram, this.dependencies);
      if (resolve_method !== null) {
        if (!modules[resolve_method]) {
          debug.stack(`Unsupported method : ${resolve_method}`);
        }
        modules[resolve_method].call(this, emitter, gram);
        return;
      }
      let params = gram.params.length > 0 ? this.resolveParams(gram) : '';
      emitter.emit(this.resolveCallPath(gram.path, params, gram));
    } else if (gram.type === 'prop') {
      emitter.emit(this.resolveCallPath(gram.path, '', gram));
    } else if (gram.type === 'key') {
      emitter.emit(this.resolveCallPath(gram.path, '', gram));
    } else {
      debug.stack(gram);
    }
  }

  grammerExpr(emitter, gram) {
    if (gram.opt === Symbol.concat()) {
      // implement by behaviorTamplateString
      debug.stack(gram);
    }
    this.exprIsAssignToPtr = this.isPointerVar(gram.left);
    if (!gram.left && !gram.right) {
      // only emit symbol
      emitter.emit(` ${_symbol(gram.opt)} `);
      this.exprIsAssignToPtr = null;
      return;
    }
    // emit left of expr
    if (gram.opt !== Symbol.assign() && this.exprIsAssignToPtr) {
      emitter.emit('*');
    }
    this.grammer(emitter, gram.left, false, false);

    if (gram.right.type === 'null') {
      // not emit symbol&right if right of expr is null
      this.exprIsAssignToPtr = null;
      if (gram.left instanceof GrammerVar) { return; }
    }

    // emit right of expr
    if (gram.opt === Symbol.assign()) {
      let isNewObject = false;
      let right = null;
      if (gram.right instanceof GrammerValue && gram.right.type === 'instance' && gram.right.value instanceof GrammerNewObject) {
        isNewObject = true;
        right = gram.right.value;
      } else if (gram.right instanceof GrammerNewObject) {
        isNewObject = true;
        right = gram.right;
      }
      if (isNewObject) {
        this.exprIsAssignToPtr = this.isPointerVar(gram.left);
        // is new object
        if (this.isPointerVar(gram.left)) {
          // new object to ptr property
          emitter.emit(` ${_symbol(gram.opt)} `); // emit symbol of expr
          this.grammerNewObject(emitter, right, true, true);
          this.exprIsAssignToPtr = null;
          return;
        }
        this.grammerNewObject(emitter, right, false);
        this.exprIsAssignToPtr = null;
        return;
      }
      emitter.emit(` ${_symbol(gram.opt)} `); // emit symbol of expr
      let toStream = false;
      let leftIsPointer;
      let leftDataType = this.resolveDataType(gram.left);
      if (leftDataType !== 'Darabonba::Stream' && gram.left instanceof GrammerValue && gram.left.type === 'call' && gram.left.value.path[1].name === 'body') {
        const k = gram.left.value.path.map(item => item.name).join('.');
        toStream = k === '__request.body' && is.string(gram.right.dataType);
        leftIsPointer = true;
      } else {
        toStream = leftDataType === 'Darabonba::Stream';
        leftIsPointer = this.isPointerVar(gram.left);
      }
      let rightIsPointer = this.isPointerVar(gram.right);
      if (toStream) {
        emitter.emit(`${this.config.tea.converter.name}::toStream(`);
      }
      let dataType = this.resolveDataType(gram.right);
      if (dataType === null) {
        dataType = this.resolveDataType(gram.left);
      }
      if (leftIsPointer && rightIsPointer) {
        if (toStream) {
          emitter.emit('*');
        }
        this.exprIsAssignToPtr = true;
        this.grammer(emitter, gram.right, false, false);
      } else if (leftIsPointer && !rightIsPointer) {
        this.exprIsAssignToPtr = true;
        if (toStream) {
          this.grammer(emitter, gram.right, false, false);
        } else {
          emitter.emit(this.emitMakeShared(dataType, gram.right));
        }
      } else if (!leftIsPointer && rightIsPointer) {
        emitter.emit('*');
        this.grammer(emitter, gram.right, false, false);
      } else {
        this.grammer(emitter, gram.right, false, false);
      }
      if (toStream) {
        emitter.emit(')');
      }
      this.exprIsAssignToPtr = null;
      return;
    }
    emitter.emit(` ${_symbol(gram.opt)} `); // emit symbol of expr
    this.grammer(emitter, gram.right, false, false);
    this.exprIsAssignToPtr = null;
  }

  grammerLoop(emitter, gram) {
    this.pushInclude('algorithm');
    if (gram.type === 'foreach') {
      emitter.emit('for(auto ');
      this.grammerVar(emitter, gram.item, false, false);
      emitter.emit(' : ');
      if (this.isPointerVar(gram.source)) {
        emitter.emit('*');
      }
      this.grammer(emitter, gram.source, false, false);
      emitter.emitln(') {');
    }
    this.levelUp();
    gram.body.forEach(node => {
      this.grammer(emitter, node);
    });
    this.levelDown();
    emitter.emitln('}', this.level);
  }

  grammerBreak(emitter, gram) {
    emitter.emit('break');
  }

  grammerCondition(emitter, gram) {
    if (gram.type === 'elseif') {
      emitter.emit('else if');
    } else {
      emitter.emit(`${gram.type}`);
    }
    if (gram.type !== 'else') {
      emitter.emit(' (');
      let emit = new Emitter(this.config);
      gram.conditionBody.forEach(condition => {
        this.grammer(emitter, condition, false, false);
      });
      emitter.emit(`${emit.output})`);
    }

    emitter.emitln(' {');
    this.levelUp();
    gram.body.forEach(node => {
      this.grammer(emitter, node);
    });
    this.levelDown();
    emitter.emitln('}', this.level);
    if (gram.elseItem.length && gram.elseItem.length > 0) {
      gram.elseItem.forEach(e => {
        this.grammer(emitter, e);
      });
    }
  }

  grammerTryCatch(emitter, gram) {
    emitter.emitln('try {');
    this.levelUp();
    gram.body.forEach(node => {
      this.grammer(emitter, node);
    });
    this.levelDown();
    emitter.emitln('}', this.level);
    gram.catchBody.forEach(node => {
      assert.strictEqual(true, node instanceof GrammerCatch);
      this.grammerCatch(emitter, node);
    });
    if (gram.finallyBody) {
      this.grammerFinally(emitter, gram.finallyBody);
    }
  }

  grammerCatch(emitter, gram) {
    let emitterVar = new Emitter(this.config);
    this.grammerVar(emitterVar, gram.exceptions.exceptionVar, false);
    let varName = emitterVar.output;
    emitter.emit(`catch (${this.emitType(gram.exceptions.type)} &`, this.level);
    this.addStatement(varName, gram.exceptions.type, false);
    emitter.emit(varName);
    emitter.emitln(') {');
    this.levelUp();
    gram.body.forEach(childGram => {
      this.grammer(emitter, childGram);
    });
    this.levelDown();
    emitter.emitln('}', this.level);
  }

  grammerFinally(emitter, gram) {
    emitter.emitln('catch(std::exception &e) {', this.level);
    this.levelUp();
    gram.body.forEach(childGram => {
      this.grammer(emitter, childGram);
    });
    this.levelDown();
    emitter.emitln('}', this.level);
  }

  grammerContinue(emitter, gram) {
    emitter.emit('continue');
  }

  grammerThrows(emitter, gram) {
    this.pushInclude('throw_exception');
    emitter.emit('BOOST_THROW_EXCEPTION(');
    // emit exception_begin
    if (gram.exception) {
      let isException = is.object(gram.exception) && gram.exception.objectName === '$Exception';
      if (isException) {
        emitter.emit('std::runtime_error(');
      } else {
        emitter.emit(`${this.emitType(gram.exception)}(`);
      }
    }

    // emit exception_body
    if (!gram.params.length) {
      let msg = gram.message ? `"${gram.message}"` : '';
      emitter.emit(msg);
    } else if (gram.params.length === 1) {
      let isError = is.object(gram.exception) && gram.exception.objectName === '$Error';
      if (isError) {
        let dataType = this.resolveDataType(gram.params[0]);
        emitter.emit(`${dataType}(`);
        this.grammerValue(emitter, gram.params[0]);
        emitter.emit(')');
      } else {
        this.grammerValue(emitter, gram.params[0]);
      }
    } else {
      let tmp = [];
      gram.params.forEach(p => {
        let emit = new Emitter(this.config);
        this.grammerValue(emit, p);
        tmp.push(emit.output);
      });
      emitter.emit(tmp.join(', '));
    }

    // emit exception_end
    if (gram.exception) {
      emitter.emit(')');
    }

    emitter.emit(')'); // close BOOST_THROW_EXCEPTION
  }

  grammerNewObject(emitter, gram, isAssign = true, isPtrParam = false) {
    let objectName = gram.name;
    if (!this.exprIsAssignToPtr && isAssign) {
      emitter.emit(`${this.resolveName(objectName)}(`);
    } else if (isAssign) {
      emitter.emit(`make_shared<${this.resolveName(objectName)}>(`);
    }
    let tmp = [];
    let params;
    if (Array.isArray(gram.params)) {
      params = gram.params;
    } else {
      params = [gram.params];
    }
    if (params.length) {
      params.forEach(p => {
        if (p instanceof GrammerValue && p.type === 'model_construct_params' && !p.value.length) {
          return;
        } else if (p instanceof GrammerValue && p.type === 'model_construct_params') {
          isPtrParam = false;
        }
        let emit = new Emitter(this.config);
        if (isPtrParam && !this.isPointerVar(p)) {
          emit.emit(this.emitMakeShared(p.dataType ? p.dataType : p.type, p));
        } else {
          this.grammerValue(emit, p, false, false);
        }
        tmp.push(emit.output);
      });
      // emitter.emit(tmp.join(', '));
    }
    if (isAssign) {
      emitter.emit(tmp.join(', '));
      emitter.emit(')');
    } else if (tmp.length) {
      emitter.emit('(');
      emitter.emit(tmp.join(', '));
      emitter.emit(')');
    }
  }

  grammerReturn(emitter, gram) {
    if (is.void(this.funcReturnType)) {
      emitter.emit('return');
      return;
    }
    emitter.emit('return ');
    if (gram.type === 'null') {
      this.grammerValue(emitter, new GrammerValue('null'), false, false);
    } else if (gram.type === 'grammer') {
      let returnPointer = this.isPointerType(this.funcReturnType);
      if (this.isPointerVar(gram.expr) && !returnPointer) {
        emitter.emit('*');
      }
      this.grammer(emitter, gram.expr, false, false);
    } else if (gram.type === 'string') {
      emitter.emit('string("")');
    } else {
      this.grammer(emitter, gram.expr, false, false);
    }
  }

  /**************************************** behavior ****************************************/
  behaviorTimeNow(emitter, behavior) {
    emitter.emit('0');
  }

  behaviorDoAction(emitter, behavior) {
    emitter.emit('', this.level);
    this.grammerVar(emitter, behavior.var);
    emitter.emit(` = make_shared<${this.addInclude('$Response')}>(${this.addInclude('$Core')}::${this.config.tea.core.doAction}(`);
    let params = [];
    behavior.params.forEach(p => {
      let emit = new Emitter(this.config);
      if (this.isPointerVar(p)) {
        emit.emit('*');
      }
      this.grammerValue(emit, p);
      params.push(emit.output);
    });
    emitter.emit(params.join(', '));
    emitter.emitln('));');
    behavior.body.forEach(node => {
      this.grammer(emitter, node);
    });
  }

  behaviorToMap(emitter, behavior) {
    const grammer = behavior.grammer;
    if (grammer instanceof GrammerCall) {
      grammer.path.push({
        type: 'call',
        name: 'toMap'
      });
      this.grammerCall(emitter, grammer);
    } else if (grammer instanceof GrammerVar) {
      const grammerCall = new GrammerCall('method');
      grammerCall.path.push({
        type: 'object',
        name: grammer.name
      });
      grammerCall.path.push({
        type: 'call',
        name: 'toMap'
      });
      this.grammerCall(emitter, grammerCall);
    } else {
      debug.stack(grammer);
    }
  }

  behaviorToModel(emitter, behavior) {
    emitter.emit(`${behavior.expected}(`);
    let type = this.resolveDataType(behavior.grammer);
    if (type === 'map<string, string>') {
      emitter.emit(`${this.config.tea.converter.name}::toGenericMap(`);
      this.grammer(emitter, behavior.grammer, false, false);
      emitter.emit(')');
    } else {
      behavior.grammer.type = 'model_construct_params';
      this.grammer(emitter, behavior.grammer, false, false);
    }
    emitter.emit(')');
  }

  behaviorSetMapItem(emitter, behavior) {
    let emit = new Emitter(this.config);
    this.grammerCall(emit, behavior.call);
    this.pushInclude('map');
    let paths = behavior.call.path;
    let key = super.resolveName(behavior.key);
    if (this.isPointerPath(paths.length - 1, paths)) {
      emitter.emit(`${emit.output}->insert(pair<string, ${this.emitType(behavior.value.dataType)}>("${key}", `, this.level);
    } else {
      emitter.emit(`${emit.output}.insert(pair<string, ${this.emitType(behavior.value.dataType)}>("${key}", `, this.level);
    }
    if (this.isPointerVar(behavior.value)) {
      emitter.emit('*');
    }
    this.grammerValue(emitter, behavior.value);
    emitter.emitln('));');
  }

  behaviorRetry(emitter, behavior) {
    emitter.emitln(`throw ${this.addInclude('$Error')}(${this.config.request}, ${this.config.response});`, this.level);
  }

  behaviorTamplateString(emitter, behavior) {
    let tmp = [];
    behavior.items.forEach(item => {
      let emit = new Emitter(this.config);
      if (this.isPointerVar(item) && !is.any(item.dataType)) {
        emit.emit('*');
      }
      if (is.string(item.dataType)) {
        this.grammer(emit, item, false, false);
      } else if (is.any(item.dataType)) {
        this.pushInclude('darabonba_core');
        emit.emit(`${this.config.tea.converter.name}::toString(`);
        this.grammer(emit, item, false, false);
        emit.emit(')');
      } else {
        this.pushInclude('cast');
        emit.emit('boost::lexical_cast<string>(');
        this.grammer(emit, item, false, false);
        emit.emit(')');
      }
      tmp.push(emit.output);
    });
    emitter.emit(`${tmp.filter(s => s !== '""').map(s => `string(${s})`).join(' + ')}`);
  }
}