add tool to generate object code

This commit is contained in:
lixianjing 2021-06-28 16:01:57 +08:00
parent 6babba15fc
commit a2a54d40b4
4 changed files with 660 additions and 0 deletions

View File

@ -2,6 +2,7 @@
2021/06/28
* 增加函数matrix\_transform\_pointf。
* 增加一个生成object的框架代码的小工具。
* 完善编辑脚本APP支持输出到不同目录(感谢[ufbycd](https://github.com/ufbycd)提供补丁)。
2021/06/27

View File

@ -0,0 +1,52 @@
# object 代码生成器
用来生成 object 的框架代码的小工具。
## 1.编写描述文件
```json
{
"name":"foobar",
"date":"2021-06-15",
"team":"AWTK Develop Team",
"author":"Li XianJing <xianjimli@hotmail.com>",
"desc":"foobar",
"copyright":"Guangzhou ZHIYUAN Electronics Co.,Ltd.",
"parent": "object",
"includes":[],
"props": [
{
"name":"type",
"desc":"a int value",
"init_value":0,
"type":"uint32_t"
},
{
"name":"name",
"desc":"a string value",
"init_value":"NULL",
"type":"char*"
}
]
}
```
属性的类型目前支持:
* int8\_t
* int16\_t
* int32\_t
* int64\_t
* uint8\_t
* uint16\_t
* uint32\_t
* uint64\_t
* float
* double
* char*
## 2.生成代码
```
node gen_object.js samples/foobar.json
```

View File

@ -0,0 +1,583 @@
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]);

View File

@ -0,0 +1,24 @@
{
"name":"foobar",
"date":"2021-06-15",
"team":"AWTK Develop Team",
"author":"Li XianJing <xianjimli@hotmail.com>",
"desc":"foobar",
"copyright":"Guangzhou ZHIYUAN Electronics Co.,Ltd.",
"parent": "object",
"includes":[],
"props": [
{
"name":"type",
"desc":"a int value",
"init_value":0,
"type":"uint32_t"
},
{
"name":"name",
"desc":"a string value",
"init_value":"NULL",
"type":"char*"
}
]
}