mirror of
https://gitee.com/zlgopen/awtk.git
synced 2024-11-30 11:08:34 +08:00
e53e74db80
This reverts commit 47b555896d
.
584 lines
15 KiB
JavaScript
584 lines
15 KiB
JavaScript
const fs = require('fs')
|
||
const path = require('path')
|
||
const fse = require('fs-extra')
|
||
|
||
class CodeGen {
|
||
genPropDecls(json) {
|
||
let result = '';
|
||
if (!json.props || !json.props.length) {
|
||
return result;
|
||
}
|
||
|
||
result = json.props.map(iter => {
|
||
let propDecl = `
|
||
/**
|
||
* @property {${iter.type}} ${iter.name}
|
||
* @annotation ["readable"]
|
||
* ${iter.desc}
|
||
*/
|
||
${iter.type} ${iter.name};
|
||
`
|
||
return propDecl;
|
||
}).join('');
|
||
|
||
return result;
|
||
}
|
||
|
||
genPropSetterDecls(json) {
|
||
let result = '';
|
||
if (!json.props || !json.props.length) {
|
||
return result;
|
||
}
|
||
|
||
const className = json.name;
|
||
result = json.props.map(iter => {
|
||
return `
|
||
/**
|
||
* @method ${className}_set_${iter.name}
|
||
* 设置 ${iter.desc}
|
||
* @param {${className}_t*} ${className} ${className}对象。
|
||
* @param {${this.mapType(iter.type)}} ${iter.name} ${iter.desc}
|
||
*
|
||
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
|
||
*/
|
||
ret_t ${className}_set_${iter.name}(${className}_t* ${className}, ${this.genParamDecl(iter.type, iter.name)});
|
||
`
|
||
}).join('');
|
||
|
||
return result;
|
||
}
|
||
|
||
genPropDefines(json) {
|
||
let result = '';
|
||
if (!json.props || !json.props.length) {
|
||
return result;
|
||
}
|
||
|
||
const uclassName = json.name.toUpperCase();
|
||
|
||
result = json.props.map(iter => {
|
||
const uPropName = iter.name.toUpperCase();
|
||
return `#define ${uclassName}_PROP_${uPropName} "${iter.name}"`
|
||
}).join('\n');
|
||
|
||
return result;
|
||
}
|
||
|
||
genAssignValue(type, name, value) {
|
||
if (type.indexOf("char*") >= 0) {
|
||
return `${name} = tk_str_copy(${name}, ${value});`;
|
||
} else {
|
||
return `${name} = ${value};`;
|
||
}
|
||
}
|
||
|
||
mapType(type) {
|
||
if (type.indexOf("char*") >= 0) {
|
||
return `const char*`;
|
||
} else {
|
||
return type;
|
||
}
|
||
}
|
||
|
||
genParamDecl(type, name) {
|
||
return `${this.mapType(type)} ${name}`;
|
||
}
|
||
|
||
genPropSetterImpls(json) {
|
||
let result = '';
|
||
if (!json.props || !json.props.length) {
|
||
return result;
|
||
}
|
||
|
||
const className = json.name;
|
||
const uclassName = className.toUpperCase();
|
||
result = json.props.map(iter => {
|
||
let type = `${iter.type}`;
|
||
const paramDecl = this.genParamDecl(iter.type, iter.name);
|
||
const assignValue = this.genAssignValue(iter.type, `${className}->${iter.name}`, iter.name);
|
||
|
||
let propSetter = `
|
||
ret_t ${className}_set_${iter.name}(${className}_t* ${className}, ${paramDecl}) {
|
||
return_value_if_fail(${className} != NULL, RET_BAD_PARAMS);
|
||
|
||
${assignValue}
|
||
|
||
return RET_OK;
|
||
}
|
||
`
|
||
return propSetter;
|
||
}).join('');
|
||
|
||
return result;
|
||
}
|
||
|
||
genPropList(json) {
|
||
let result = '';
|
||
if (!json.props || !json.props.length) {
|
||
return result;
|
||
}
|
||
|
||
const uclassName = json.name.toUpperCase();
|
||
|
||
result = json.props.map(iter => {
|
||
const uPropName = iter.name.toUpperCase();
|
||
return ` ${uclassName}_PROP_${uPropName}`
|
||
}).join(',\n');
|
||
|
||
return result;
|
||
}
|
||
|
||
genToValue(clsName, type, name) {
|
||
switch (type) {
|
||
case 'int8_t':
|
||
case 'int16_t':
|
||
case 'int32_t':
|
||
case 'int64_t':
|
||
case 'uint8_t':
|
||
case 'uint16_t':
|
||
case 'uint32_t':
|
||
case 'uint64_t':
|
||
case 'bool_t':
|
||
case 'float_t':
|
||
case 'float':
|
||
case 'double': {
|
||
let typeName = type.replace(/_t$/, '');
|
||
return `value_set_${typeName}(v, ${clsName}->${name});`;
|
||
}
|
||
case 'char*': {
|
||
return `value_set_str(v, ${clsName}->${name});`;
|
||
}
|
||
case 'void*': {
|
||
return `value_set_pointer(v, ${clsName}->${name});`;
|
||
}
|
||
case 'color_t': {
|
||
return `value_set_uint32(v, ${clsName}->${name}.color);`;
|
||
}
|
||
default: {
|
||
console.log(`not supported ${type} for ${name}`);
|
||
process.exit(0);
|
||
}
|
||
}
|
||
}
|
||
|
||
genFromValue(clsName, type, name) {
|
||
let typeName = '';
|
||
switch (type) {
|
||
case 'int8_t':
|
||
case 'int16_t':
|
||
case 'int32_t':
|
||
case 'int64_t':
|
||
case 'uint8_t':
|
||
case 'uint16_t':
|
||
case 'uint32_t':
|
||
case 'uint64_t':
|
||
case 'bool_t':
|
||
case 'float_t':
|
||
case 'float':
|
||
case 'double': {
|
||
typeName = type.replace(/_t$/, '');
|
||
break;
|
||
}
|
||
case 'color_t': {
|
||
return `${clsName}_set_${name}(${clsName}, color_parse(value_str(v)));`;
|
||
break;
|
||
}
|
||
case 'char*': {
|
||
typeName = 'str';
|
||
break;
|
||
}
|
||
case 'void*': {
|
||
typeName = 'pointer';
|
||
break;
|
||
}
|
||
default: {
|
||
console.log(`not supported ${type} for ${name}`);
|
||
process.exit(0);
|
||
}
|
||
}
|
||
return `${clsName}_set_${name}(${clsName}, value_${typeName}(v));`;
|
||
}
|
||
|
||
genSetPropDispatch(json) {
|
||
let result = '';
|
||
if (!json.props || !json.props.length) {
|
||
return result;
|
||
}
|
||
|
||
const className = json.name;
|
||
const uclassName = className.toUpperCase();
|
||
|
||
result = json.props.map((iter, index) => {
|
||
const uPropName = iter.name.toUpperCase();
|
||
const propMacro = `${uclassName}_PROP_${uPropName}`
|
||
let setProp = '';
|
||
if (index) {
|
||
setProp = `\n } else if (tk_str_eq(${propMacro}, name)) {\n`
|
||
} else {
|
||
setProp = ` if (tk_str_eq(${propMacro}, name)) {\n`
|
||
}
|
||
setProp += ` ${this.genFromValue(className, iter.type, iter.name)}\n`;
|
||
setProp += ' return RET_OK;';
|
||
return setProp;
|
||
}).join('');
|
||
|
||
result += '\n }';
|
||
|
||
return result;
|
||
}
|
||
|
||
genPropInits(json) {
|
||
let result = '';
|
||
if (!json.props || !json.props.length) {
|
||
return result;
|
||
}
|
||
|
||
const className = json.name;
|
||
result = json.props.map((iter) => {
|
||
if (iter.init_value) {
|
||
if (iter.type === 'char*' && iter.init_value != 'NULL') {
|
||
return ` ${className}->${iter.name} = tk_strdup("${iter.init_value}");\n`;
|
||
} else {
|
||
return ` ${className}->${iter.name} = ${iter.init_value};\n`;
|
||
}
|
||
}
|
||
}).join('');
|
||
|
||
return result;
|
||
}
|
||
|
||
genFreeProps(json) {
|
||
let result = '';
|
||
const className = json.name;
|
||
if (!json.props || !json.props.length) {
|
||
return result;
|
||
}
|
||
|
||
result = json.props.map((iter, index) => {
|
||
if (iter.type.indexOf('char*') >= 0) {
|
||
return ` TKMEM_FREE(${className}->${iter.name});\n`;
|
||
} else {
|
||
return '';
|
||
}
|
||
}).join('');
|
||
|
||
return result;
|
||
}
|
||
|
||
genGetPropDispatch(json) {
|
||
let result = '';
|
||
if (!json.props || !json.props.length) {
|
||
return result;
|
||
}
|
||
|
||
const className = json.name;
|
||
const uclassName = className.toUpperCase();
|
||
|
||
result = json.props.map((iter, index) => {
|
||
const uPropName = iter.name.toUpperCase();
|
||
const propMacro = `${uclassName}_PROP_${uPropName}`
|
||
let setProp = '';
|
||
if (index) {
|
||
setProp = `\n } else if (tk_str_eq(${propMacro}, name)) {\n`
|
||
} else {
|
||
setProp = ` if (tk_str_eq(${propMacro}, name)) {\n`
|
||
}
|
||
setProp += ` ${this.genToValue(className, iter.type, iter.name)}\n`;
|
||
setProp += ' return RET_OK;';
|
||
return setProp;
|
||
}).join('');
|
||
|
||
result += '\n }';
|
||
|
||
return result;
|
||
}
|
||
|
||
genH(json) {
|
||
let parent = "";
|
||
let includes = '#include "tkc/object.h"\n';
|
||
let parentAnnotation = "";
|
||
const className = json.name;
|
||
const uclassName = json.name.toUpperCase();
|
||
|
||
if (json.parent) {
|
||
parent = `${json.parent}_t ${json.parent};`
|
||
parentAnnotation = `@parent ${json.parent}`
|
||
if (json.parent != 'object') {
|
||
includes = `#include "${json.parent}.h"\n`
|
||
}
|
||
}
|
||
|
||
if (json.includes) {
|
||
json.includes.forEach(iter => {
|
||
includes += `#include "${iter}"\n`
|
||
});
|
||
}
|
||
return `
|
||
/**
|
||
* File: ${className}.h
|
||
* Author: AWTK Develop Team
|
||
* Brief: ${json.desc}
|
||
*
|
||
* Copyright (c) ${json.copyright}
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* License file for more details.
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* History:
|
||
* ================================================================
|
||
* ${json.date} ${json.author} created
|
||
*
|
||
*/
|
||
#ifndef TK_${uclassName}_H
|
||
#define TK_${uclassName}_H
|
||
|
||
${includes}
|
||
|
||
BEGIN_C_DECLS
|
||
|
||
/**
|
||
* @class ${className}_t
|
||
* ${parentAnnotation}
|
||
* ${json.desc}
|
||
*/
|
||
typedef struct _${className}_t {
|
||
${parent}
|
||
${this.genPropDecls(json)}
|
||
} ${className}_t;
|
||
|
||
${this.genPropSetterDecls(json)}
|
||
|
||
${this.genPropDefines(json)}
|
||
|
||
/*public for subclass*/
|
||
/**
|
||
* @method ${className}_deinit
|
||
* ~初始化对象。
|
||
* @param {${className}_t*} ${className} ${className}对象。
|
||
*
|
||
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
|
||
*/
|
||
ret_t ${className}_deinit(${className}_t* ${className});
|
||
|
||
/**
|
||
* @method ${className}_init
|
||
* 初始化对象。
|
||
* @param {${className}_t*} ${className} ${className}对象。
|
||
*
|
||
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
|
||
*/
|
||
${className}_t* ${className}_init(${className}_t* ${className});
|
||
|
||
/**
|
||
* @method ${className}_set_prop
|
||
* 设置属性。
|
||
* @param {${className}_t*} ${className} ${className}对象。
|
||
* @param {const char*} name 属性名。
|
||
* @param {const value_t*} v 属性值。
|
||
*
|
||
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
|
||
*/
|
||
ret_t ${className}_set_prop(${className}_t* ${className}, const char* name, const value_t* v);
|
||
|
||
/**
|
||
* @method ${className}_get_prop
|
||
* 获取属性。
|
||
* @param {${className}_t*} ${className} ${className}对象。
|
||
* @param {const char*} name 属性名。
|
||
* @param {value_t*} v 属性值。
|
||
*
|
||
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
|
||
*/
|
||
ret_t ${className}_get_prop(${className}_t* ${className}, const char* name, value_t* v);
|
||
|
||
/**
|
||
* @method ${className}_cast
|
||
* 类型转换。
|
||
* @param {${className}_t*} ${className} ${className}对象。
|
||
*
|
||
* @return {${className}_t*} 返回非NULL表示成功,否则表示失败。
|
||
*/
|
||
${className}_t* ${className}_cast(object_t* obj);
|
||
|
||
/**
|
||
* @method ${className}_create
|
||
* 创建对象。
|
||
* @return {${className}_t*} 返回非NULL表示成功,否则表示失败。
|
||
*/
|
||
${className}_t* ${className}_create(void);
|
||
|
||
#define ${uclassName}(obj) ${className}_cast(OBJECT(obj))
|
||
|
||
END_C_DECLS
|
||
|
||
#endif/*TK_${uclassName}_H*/
|
||
`
|
||
}
|
||
|
||
genC(json) {
|
||
let parent = "";
|
||
let parentUpper = "";
|
||
let parentSetProp = "";
|
||
let parentGetProp = "";
|
||
let parentInit = "";
|
||
let parentDeinit = "";
|
||
const className = json.name;
|
||
const uclassName = json.name.toUpperCase();
|
||
|
||
if (json.parent) {
|
||
parent = json.parent;
|
||
parentUpper = parent.toUpperCase();
|
||
|
||
if(parent !== 'object') {
|
||
parentSetProp = `
|
||
if(${parent}_set_prop(${parentUpper}(${className}), name, v) == RET_OK) {
|
||
return RET_OK;
|
||
}`
|
||
parentGetProp = `
|
||
if(${parent}_get_prop(${parentUpper}(${className}), name, v) == RET_OK) {
|
||
return RET_OK;
|
||
}`
|
||
parentInit = ` ${parent}_init(${parentUpper}(${className}));`;
|
||
parentDeinit = ` ${parent}_deinit(${parentUpper}(${className}));`;
|
||
}
|
||
}
|
||
return `
|
||
/**
|
||
* File: ${className}.c
|
||
* Author: AWTK Develop Team
|
||
* Brief: ${json.desc}
|
||
*
|
||
* Copyright (c) ${json.copyright}
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* License file for more details.
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* History:
|
||
* ================================================================
|
||
* ${json.date} ${json.author} created
|
||
*
|
||
*/
|
||
|
||
#include "tkc/mem.h"
|
||
#include "tkc/str.h"
|
||
#include "tkc/utils.h"
|
||
#include "${className}.h"
|
||
|
||
${this.genPropSetterImpls(json)}
|
||
|
||
ret_t ${className}_set_prop(${className}_t* ${className}, const char* name, const value_t* v) {
|
||
return_value_if_fail(${className} != NULL && name != NULL && v != NULL , RET_BAD_PARAMS);
|
||
${parentSetProp}
|
||
${this.genSetPropDispatch(json)}
|
||
|
||
return RET_NOT_FOUND;
|
||
}
|
||
|
||
static ret_t ${className}_set_prop_obj(object_t* obj, const char* name, const value_t* v) {
|
||
${className}_t* ${className} = ${uclassName}(obj);
|
||
return_value_if_fail(${className} != NULL && name != NULL && v != NULL , RET_BAD_PARAMS);
|
||
|
||
return ${className}_set_prop(${className}, name, v);
|
||
}
|
||
|
||
ret_t ${className}_get_prop(${className}_t* ${className}, const char* name, value_t* v) {
|
||
return_value_if_fail(${className} != NULL && name != NULL && v != NULL , RET_BAD_PARAMS);
|
||
|
||
${parentGetProp}
|
||
${this.genGetPropDispatch(json)}
|
||
|
||
return RET_NOT_FOUND;
|
||
}
|
||
|
||
static ret_t ${className}_get_prop_obj(object_t* obj, const char* name, value_t* v) {
|
||
${className}_t* ${className} = ${uclassName}(obj);
|
||
return_value_if_fail(${className} != NULL && name != NULL && v != NULL , RET_BAD_PARAMS);
|
||
|
||
return ${className}_get_prop(${className}, name, v);
|
||
}
|
||
|
||
ret_t ${className}_deinit(${className}_t* ${className}) {
|
||
return_value_if_fail(${className} != NULL, RET_BAD_PARAMS);
|
||
${this.genFreeProps(json)}
|
||
${parentDeinit}
|
||
|
||
return RET_OK;
|
||
}
|
||
|
||
static ret_t ${className}_on_destroy(object_t* obj) {
|
||
return ${className}_deinit(${uclassName}(obj));
|
||
}
|
||
|
||
static const object_vtable_t s_${className}_vtable = {.type = "${className}",
|
||
.desc = "${className}",
|
||
.size = sizeof(${className}_t),
|
||
.is_collection = FALSE,
|
||
.on_destroy = ${className}_on_destroy,
|
||
.get_prop = ${className}_get_prop_obj,
|
||
.set_prop = ${className}_set_prop_obj};
|
||
|
||
${className}_t* ${className}_init(${className}_t* ${className}) {
|
||
return_value_if_fail(${className} != NULL, NULL);
|
||
|
||
${parentInit}
|
||
${this.genPropInits(json)}
|
||
|
||
return ${className};
|
||
}
|
||
|
||
${className}_t* ${className}_create(void) {
|
||
object_t* o = object_create(&s_${className}_vtable);
|
||
return_value_if_fail(o != NULL, NULL);
|
||
|
||
return ${className}_init(${uclassName}(o));
|
||
}
|
||
|
||
${className}_t* ${className}_cast(object_t* obj) {
|
||
return_value_if_fail(obj != NULL && obj->vt == &s_${className}_vtable, NULL);
|
||
|
||
return (${className}_t*)(obj);
|
||
}
|
||
`
|
||
}
|
||
|
||
genJson(json) {
|
||
const header = this.genH(json);
|
||
const content = this.genC(json);
|
||
const headerFileName = `${json.name}.h`
|
||
const contentFileName = `${json.name}.c`
|
||
|
||
fs.writeFileSync(headerFileName, '\ufeff' + header);
|
||
fs.writeFileSync(contentFileName, '\ufeff' + content);
|
||
|
||
console.log(`output to ${headerFileName} and ${contentFileName}`);
|
||
|
||
}
|
||
|
||
genFile(filename) {
|
||
this.genJson(JSON.parse(fs.readFileSync(filename).toString()));
|
||
}
|
||
|
||
static run(sourceIDL) {
|
||
const gen = new CodeGen();
|
||
gen.genFile(sourceIDL);
|
||
}
|
||
}
|
||
|
||
if (process.argv.length < 3) {
|
||
console.log(`Usage: node index.js foo.json`);
|
||
process.exit(0);
|
||
}
|
||
|
||
CodeGen.run(process.argv[2], process.argv[3], process.argv[4]);
|
||
|