in lib/generator.js [1113:1715]
visitRuntimeBefore(ast, level, env) {
assert.equal(ast.type, 'object');
this.emit('_runtime := dara.NewRuntimeObject(', level);
this.visitObject(ast, level, env, 'map[string]interface{}');
this.emit(')\n\n');
this.emit('var retryPolicyContext *dara.RetryPolicyContext\n', level);
this.emit('var request_ *dara.Request\n', level);
this.emit('var response_ *dara.Response\n', level);
this.emit('var _resultErr error\n', level);
this.emit('retriesAttempted := int(0)\n', level);
this.emit('retryPolicyContext = &dara.RetryPolicyContext{\n', level);
this.emit('RetriesAttempted: retriesAttempted,\n', level + 1);
this.emit('}\n\n', level);
if (_name(env.returnType) && _name(env.returnType) !== 'void') {
this.emit(`_result = ${_initValue(_name(env.returnType))}\n`, level);
} else if (env.returnType.path) {
this.emit(`_result = new(`, level);
for (let i = 0; i < env.returnType.path.length; i++) {
const path = env.returnType.path[i];
if (i === 0) {
this.emit(_name(path).toLowerCase());
} else {
this.emit(`.${_name(path)}`);
}
}
this.emit(`)\n`);
} else if (env.returnType.type === 'map') {
this.emit(`_result = make(`, level);
this.visitPointerType(env.returnType, level);
this.emit(`)\n`);
}
this.emit(`for dara.ShouldRetry(_runtime.RetryOptions, retryPolicyContext) {\n`, level);
this.emit(`_resultErr = nil\n`, level + 1);
this.emit(`_backoffDelayTime := dara.GetBackoffDelay(_runtime.RetryOptions, retryPolicyContext)\n`, level + 1);
this.emit(`dara.Sleep(_backoffDelayTime)\n`, level + 1);
this.emit(`\n`);
}
visitStmt(ast, level, env) {
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
this.visitComments(comments, level);
if (ast.type === 'return') {
this.visitReturn(ast, level, env);
} else if (ast.type === 'yield') {
this.visitYield(ast, level, env);
} else if (ast.type === 'if') {
this.visitIf(ast, level, env);
} else if (ast.type === 'throw') {
this.visitThrow(ast, level, env);
} else if (ast.type === 'assign') {
this.visitAssign(ast, level, env);
} else if (ast.type === 'retry') {
this.visitRetry(ast, level);
} else if (ast.type === 'declare') {
this.visitDeclare(ast, level, env);
} else if (ast.type === 'while') {
this.visitWhile(ast, level, env);
} else if (ast.type === 'for') {
this.visitFor(ast, level, env);
} else if (ast.type === 'try') {
this.visitTry(ast, level, env);
} else if (ast.type === 'break') {
this.emit(`break\n`, level);
} else {
if (ast.type === 'call' && ast.hasThrow) {
if (ast.inferred && _name(ast.inferred) !== 'void') {
this.emit(`_, _err ${env.yieldFunc ? ':' : ''}= `, level);
} else {
this.emit(`_err ${env.yieldFunc ? ':' : ''}= `, level);
}
this.visitExpr(ast, level, env, { pointer: false });
this.emit(`\n`);
if(env.runtimeBody){
this.visitAPIErrCatch(level, env);
} else if(env.try) {
const tryStmt = env.try;
env.try = null;
this.visitCatch(tryStmt, level, env);
} else {
this.emit(`if _err != nil {\n`, level);
if (env.returnType && _name(env.returnType) !== 'void') {
this.emit(`return _result, _err\n`, level + 1);
} else if(env.yieldFunc){
this.emit(`_yieldErr <- _err\n`, level + 1);
this.emit(`return\n`, level + 1);
} else {
this.emit(`return _err\n`, level + 1);
}
this.emit(`}\n`, level);
}
} else {
this.emit(``, level);
this.visitExpr(ast, level, env, { pointer: false });
this.emit(`\n`);
}
}
}
getReturnType(stmts, env) {
for (var i = 0; i < stmts.length; i++) {
const ast = stmts[i];
if (ast.type === 'return') {
return env.returnType || { lexeme: 'void' };
}
}
return { lexeme: 'void' };
}
visitCatch(ast, level, env) {
if(ast.finallyBlock) {
env.finallyBlock = true;
this.visitStmts(ast.finallyBlock, level, env);
env.finallyBlock = false;
}
this.emit(`if _err != nil {\n`, level);
if (ast.catchBlocks && ast.catchBlocks.length > 0) {
ast.catchBlocks.forEach(catchBlock => {
if (!catchBlock.id) {
return;
}
if (!catchBlock.id.type) {
this.emit(`if _t, ok := _err.(*dara.SDKError); ok {\n`, level + 1);
} else {
this.emit(`if _t, ok := _err.(`, level + 1);
this.visitType(catchBlock.id.type);
this.emit('); ok {\n');
}
if(catchBlock.catchStmts && catchBlock.catchStmts.stmts.length > 0){
this.emit(`${_name(catchBlock.id)} := _t;\n`, level + 2);
this.visitStmts(catchBlock.catchStmts, level + 2, env);
}
this.emit('}\n', level + 1);
});
} else if (ast.catchBlock && ast.catchBlock.stmts.length > 0) {
this.emit(`if _t, ok := _err.(*dara.SDKError); ok {\n`, level + 1);
this.emit(`${_name(ast.catchId)} := _t\n`, level + 2);
this.emit(`}\n`, level + 1);
this.visitStmts(ast.catchBlock, level + 1, env);
}
this.emit(`}\n`, level);
}
visitTry(ast, level, env) {
assert.equal(ast.type, 'try');
env = env || {
local: new Map(),
};
const tryBlock = ast.tryBlock;
const errCounts = this.stmtsErrCount(tryBlock.stmts);
if(errCounts > 1) {
const funcName = `${_lowerFirst(env.funcName)}_opTryFunc`;
const args = this.getStmtsVars(tryBlock.stmts);
const returnType = this.getReturnType(tryBlock.stmts, env);
this.tryFunc.push({
args,
functionBody: tryBlock,
returnType,
name: funcName,
pointerParams: env.pointerParams,
});
if (returnType !== 'void') {
this.emit(`_result, _err = ${funcName}`, level);
} else {
this.emit(`_err = ${funcName}`, level);
}
this.visitTryArgs(args, level, env);
this.emit('\n');
this.visitCatch(ast, level, env);
env.hasReturn = true;
return;
}
env.try = ast;
this.visitStmts(tryBlock, level, env);
}
visitWhile(ast, level, env) {
assert.equal(ast.type, 'while');
let argHasThrowFunc;
if (ast.condition.type === 'not' && ast.condition.expr && ast.condition.expr.type === 'call') {
argHasThrowFunc = this.visitFunctionNested(ast.condition.expr, level, env);
} else if (ast.condition.type === 'call') {
argHasThrowFunc = this.visitFunctionNested(ast.condition, level, env);
}
this.emit('for ', level);
let setFunc;
if(ast.condition && ast.condition.type === 'call') {
let dealFunc = this.getVarDealFunc(ast.condition, true);
setFunc = dealFunc && dealFunc(_name(ast.condition.inferred));
}
if(setFunc) {
this.emit(`${setFunc}`);
}
this.visitExpr(ast.condition, level + 1, env, false, argHasThrowFunc);
if(setFunc) {
this.emit(')');
}
this.emit(' {\n');
this.visitStmts(ast.stmts, level + 1, env);
this.emit('}\n', level);
}
visitFor(ast, level, env) {
assert.equal(ast.type, 'for');
if(ast.list.inferred && _isIterator(ast.list.inferred)) {
this.emit(`for ${_name(ast.id)} := range `, level);
} else {
this.emit(`for _, ${_name(ast.id)} := range `, level);
}
this.visitExpr(ast.list, level + 1, env, { pointer: true });
this.emit(' {\n');
this.visitStmts(ast.stmts, level + 1, env);
this.emit('}\n', level);
}
visitFieldValue(ast, structName, level) {
if (ast.type === 'fieldType') {
if (ast.fieldType === 'array') {
if (ast.fieldItemType.type === 'modelBody') {
this.emit('{\n');
this.visitModelBody(ast.fieldItemType, ast.fieldItemType.nodes, structName, level);
}
return;
}
}
if (ast.type === 'modelBody') {
this.emit('{\n');
this.visitModelBody(ast, ast.nodes, structName, level);
return;
}
throw new Error('unimpelemented');
}
visitType(ast, level) {
if (ast.type === 'moduleModel') {
const [ mainId, ...rest ] = ast.path;
let moduleName = _importFilter(_name(ast.path[0]).toLowerCase());
let modelName = rest.map(node => {
return _upperFirst(_name(node));
}).join('');
const externEx = this.usedExternException.get(_name(mainId));
if (externEx && externEx.has(modelName)) {
modelName += 'Error';
}
this.emit(`*${moduleName}.${_format(modelName)}`);
} else if (ast.type === 'moduleTypedef') {
this.emit(`*`);
for (let i = 1; i < ast.path.length; i++) {
this.emit(`${this.typeRelover(ast.path[i], ast.path[0])}`);
}
} else if (ast.type === 'subModel') {
this.emit(`*${_format(_name(ast.path[0]))}`);
for (let i = 1; i < ast.path.length; i++) {
this.emit(`${_format(_name(ast.path[i]))}`);
}
} else if ((ast.type === 'map' || ast.fieldType === 'map') && _name(ast.keyType)) {
this.emit(`map[${this.getType(_name(ast.keyType), false)}]`);
this.visitPointerType(ast.valueType, level);
} else if (ast.fieldType === 'array' || ast.type === 'array') {
this.emit(`[]`);
this.visitPointerType(ast.subType || ast.itemType, level);
} else if (ast.idType === 'module' || this.clientName[_name(ast)]) {
this.emit(`${this.clientName[_name(ast)]}`);
} else if (this.typeRelover(ast)) {
this.emit(this.getType(this.typeRelover(ast), false));
} else if (ast.fieldType && DSL.util.isBasicType(ast.fieldType)) {
this.emit(this.getType(ast.fieldType, false));
} else if (ast.fieldType && this.typeRelover(ast.fieldType)) {
this.emit(this.getType(this.typeRelover(ast.fieldType), false));
} else {
this.emit(this.getType(ast, false));
}
}
visitModuleName(aliasId) {
const moduleName = _importFilter(_format(_name(aliasId)).toLowerCase());
this.emit(`${moduleName}`);
const { pkgName } = this.module.importPackages[_name(aliasId)];
this.imports.push({
aliasId: _name(aliasId),
pkgName,
});
}
visitPointerType(ast, level) {
if (ast.type === 'moduleModel') {
this.emit('*');
this.visitModuleName(ast.path[0]);
for (let i = 1; i < ast.path.length; i++) {
if (i === 1) {
this.emit(`.`);
}
this.emit(`${_format(_name(ast.path[i]))}`);
}
} else if (ast.type === 'moduleTypedef') {
this.emit(`*`);
for (let i = 1; i < ast.path.length; i++) {
this.emit(`${this.typeRelover(ast.path[i], ast.path[0])}`);
}
} else if (ast.type === 'subModel') {
this.emit(`*${_format(_name(ast.path[0]))}`);
for (let i = 1; i < ast.path.length; i++) {
this.emit(`${_format(_name(ast.path[i]))}`);
}
} else if ((ast.type === 'map' || ast.fieldType === 'map') && _name(ast.keyType)) {
this.emit(`map[${this.getType(_name(ast.keyType), false)}]`);
this.visitPointerType(ast.valueType, level);
} else if (ast.type === 'asyncIterator' || ast.type === 'iterator') {
this.visitPointerType(ast.valueType, level);
}else if (ast.fieldType === 'array' || ast.type === 'array') {
this.emit(`[]`);
this.visitPointerType(ast.subType || ast.itemType, level);
} else if (ast.idType === 'module' || this.clientName[_name(ast)]) {
this.emit(`${this.clientName[_name(ast)]}`);
} else if (ast.idType === 'builtin_model') {
this.emit(`${this.getType(_name(ast), false)}`);
} else if (ast.type === 'model') {
this.emit(`*`);
if (ast.moduleName) {
this.emit(`${ast.moduleName.replace(/-/g, '_').toLowerCase()}.`);
}
let strs = _format(_name(ast)).split('.');
strs.forEach(str => {
this.emit(`${_modelName(_format(str))}`);
});
} else if (_name(ast)) {
this.emit(this.getType(this.typeRelover(ast)));
} else if (ast.fieldType && DSL.util.isBasicType(ast.fieldType)) {
this.emit(this.getType(ast.fieldType));
} else if (ast.fieldType && this.typeRelover(ast.fieldTyp)) {
this.emit(this.getType(this.typeRelover(ast.fieldType)));
} else {
this.emit(this.getType(ast));
}
}
visitModelField(ast, structName, level) {
//assert.equal(ast.fieldValue.type, 'fieldType');
this.emit(`type ${structName} struct `);
this.visitFieldValue(ast, structName, level);
}
visitFieldType(node, structName, fields, structMap, level) {
let type = '', omitemptyEnable = true;
if (node.fieldValue.fieldType === 'array') {
type = `type:"Repeated"`;
if (this.config.go && this.config.go.mapAndSliceWithoutOmitempty === true) {
omitemptyEnable = false;
}
if (_name(node.fieldValue.fieldItemType)) {
this.emit(`[]${this.getType(_name(node.fieldValue.fieldItemType))} `);
} else if (node.fieldValue.fieldItemType.type === 'map') {
this.emit(`[]`);
this.visitType(node.fieldValue.fieldItemType);
this.emit(` `);
} else if (node.fieldValue.fieldItemType.type === 'modelBody') {
structMap.push(structName);
this.emit(`[]*${structName} `);
fields.push(node.fieldValue);
} else if (node.fieldValue.fieldItemType.fieldType === 'array') {
this.emit(`[][]`);
this.emitModelArray(node.fieldValue.fieldItemType, structMap, fields, structName);
}
} else if (node.fieldValue.type === 'modelBody') {
this.emit(`*${structName} `);
structMap.push(structName);
fields.push(node.fieldValue);
type = `type:"Struct"`;
} else {
const fieldType = node.fieldValue.fieldType;
if (!_name(fieldType) && (fieldType === 'map' || fieldType === 'object')) {
if (this.config.go && this.config.go.mapAndSliceWithoutOmitempty === true) {
omitemptyEnable = false;
}
this.visitPointerType(node.fieldValue, level);
this.emit(` `);
} else {
this.visitPointerType(fieldType, level);
this.emit(` `);
}
}
return { type, omitemptyEnable };
}
visitModelBody(ast, nodes, lastName, level) {
assert.equal(ast.type, 'modelBody');
var fields = [];
const structMap = [];
let node;
for (let i = 0; i < nodes.length; i++) {
node = nodes[i];
let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
this.visitComments(comments, level);
var fieldName = _name(node.fieldName);
const structName = lastName + _format(fieldName);
const description = getAttr(node, 'description');
const example = getAttr(node, 'example');
const checkBlank = getAttr(node, 'checkBlank');
const nullable = getAttr(node, 'nullable');
const sensitive = getAttr(node, 'sensitive');
const deprecated = getAttr(node, 'deprecated');
let hasNextSection = false;
if (deprecated === 'true') {
this.emit(`// Deprecated\n`, level);
hasNextSection = true;
}
if (description || example || typeof checkBlank !== 'undefined' || typeof nullable !== 'undefined' || typeof sensitive !== 'undefined') {
if (description) {
if (hasNextSection) {
this.emit(`// \n`, level);
}
const descriptions = _escape(description).split('\n');
for (let j = 0; j < descriptions.length; j++) {
if (descriptions[j] === '') {
this.emit(`// \n`, level);
}
else {
this.emit(`// ${descriptions[j]}\n`, level);
if (j < descriptions.length - 1 && descriptions[j + 1] !== '') {
this.emit(`// \n`, level);
}
}
}
hasNextSection = true;
}
if (typeof checkBlank !== 'undefined') {
if (hasNextSection) {
this.emit(`// \n`, level);
}
this.emit('// check if is blank:\n', level);
this.emit(`// ${checkBlank}\n`, level);
hasNextSection = true;
}
if (typeof nullable !== 'undefined') {
if (hasNextSection) {
this.emit(`// \n`, level);
}
this.emit('// if can be null:\n', level);
this.emit(`// ${nullable}\n`, level);
hasNextSection = true;
}
if (typeof sensitive !== 'undefined') {
if (hasNextSection) {
this.emit(`// \n`, level);
}
this.emit('// if sensitive:\n', level);
this.emit(`// ${sensitive}\n`, level);
hasNextSection = true;
}
if (example) {
if (hasNextSection) {
this.emit(`// \n`, level);
}
const examples = _escape(example).split('\n');
this.emit('// example:\n', level);
this.emit(`// \n`, level);
for (let j = 0; j < examples.length; j++) {
if (examples[j] === '') {
this.emit(`// \n`, level);
} else {
this.emit(`// ${examples[j]}\n`, level);
if (j < examples.length - 1 && examples[j + 1] !== '') {
this.emit(`// \n`, level);
}
}
}
}
}
this.emit(`${_format(fieldName)} `, level);
let { type, omitemptyEnable } = this.visitFieldType(node, structName, fields, structMap, level);
var realName = _getAttr(node, 'name');
if (!realName) {
realName = fieldName;
}
var tag = `json:"${realName}${omitemptyEnable ? ',omitempty' : ''}" xml:"${realName}${omitemptyEnable ? ',omitempty' : ''}"`;
const anno = this.parseAnnotation(node, {
'signed': 'string', 'encode': 'string'
, 'pattern': 'string', 'maxLength': 'value', 'minLength': 'value',
'maximum': 'value', 'minimum': 'value'
});
if (node.required) {
tag = tag + ` require:"true"`;
}
if (anno !== '') {
tag = tag + anno;
}
if (type !== '') {
tag = tag + ` ${type}`;
}
this.emit(`\`${tag}\``);
this.emit(`\n`);
}
if (node) {
//find the last node's back comment
let comments = DSL.comment.getBetweenComments(this.comments, node.tokenRange[0], ast.tokenRange[1]);
this.visitComments(comments, level);
}
if (ast.nodes.length === 0) {
//empty block's comment
let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
this.visitComments(comments, level);
}
this.emit(`}\n`);
this.emit(`\n`);
this.eachGetFunc(nodes, lastName, 'model');
this.eachSetFunc(nodes, lastName);
this.visitValidate(nodes, lastName);
for (let i = 0; i < fields.length; i++) {
this.visitModelField(fields[i], structMap[i], level);
}
}
emitModelArray(node, structMap, fields, structName) {
if (node.fieldItemType.fieldType === 'array') {
this.emit(`[]`);
this.emitModelArray(node, structMap, fields, structName);
} else if (node.fieldItemType.type === 'modelBody') {
structMap.push(structName);
this.emit(`*${structName} `);
fields.push(node);
} else {
this.visitPointerType(node.fieldItemType);
this.emit(` `);
}
}
checkAnnotation(node, attrName) {
for (let i = 0; i < node.attrs.length; i++) {
if (attrName === _name(node.attrs[i].attrName)) {
return true;
}
}
return false;
}
parseAnnotation(node, annos) {
var tag = '';
for (let i = 0; i < node.attrs.length; i++) {
const attrValueType = annos[_name(node.attrs[i].attrName)];
if (attrValueType) {
var attrName = _name(node.attrs[i].attrName);
attrName = attrName.split('-').join('');
tag = tag + ` ${attrName}:"${node.attrs[i].attrValue[attrValueType]}"`;
}
}
return tag;
}
emitFuncArray(node, structName) {
if (node.fieldItemType.fieldType === 'array') {
this.emit(`[]`);
this.emitFuncArray(node, structName);
} else if (node.fieldItemType.type === 'modelBody') {
this.emit(`*${structName}`);
} else {
this.visitPointerType(node.fieldItemType);
}
}
eachGetFunc(nodes, structName, type = 'model', level = 0) {
if(type === 'model') {
this.emit(`func (s ${structName}) String() string {\n`, level);
this.emit(`return dara.Prettify(s)\n`, level + 1);
this.emit(`}\n`, level);
this.emit(`\n`, level);
this.emit(`func (s ${structName}) GoString() string {\n`, level);
this.emit(`return s.String()\n`, level + 1);
this.emit(`}\n`, level);
this.emit(`\n`, level);
} else {
this.builtinModule.push({
path: 'fmt'
});
this.emit(`func (err ${structName}Error) Error() string {\n`, level);
this.emit('if err.Message == nil {\n', level + 1);
this.emit(`str := fmt.Sprintf("${structName}Error:\\n Name: %s\\n Code: %s\\n",\n`, level + 2);
this.emit('dara.StringValue(err.Name), dara.StringValue(err.Code))\n', level + 3);
this.emit('err.Message = dara.String(str)\n', level + 2);
this.emit(`}\n`, level + 1);
this.emit(`return dara.StringValue(err.Message)\n`, level + 1);
this.emit(`}\n\n`, level);
}
// for (let i = 0; i < ast.extendFileds.length; i++) {
// const node = ast.extendFileds[i];
// this.visitGetFunc(node, structName, level);
// }
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
this.visitGetFunc(node, structName, type, level);
}
}