Files
dl/document/generate_dl_api.py
T
2026-09-16 14:07:40 +08:00

940 lines
46 KiB
Python
Vendored

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
根据dl_lua_register.cpp文件生成Lua智能提示文件
"""
import re
import sys
import os
def parse_header_file(header_path):
"""
解析头文件,提取Doxygen风格注释和函数类型信息
"""
try:
# Python 2 兼容的文件读取方式
with open(header_path, 'r') as f:
content = f.read()
except Exception as e:
return {}
# 提取注释块
comment_blocks = []
# 匹配 /** ... */ 风格的注释
pattern = re.compile(r'/\*\*[\s\S]*?\*/', re.MULTILINE)
for match in pattern.finditer(content):
comment = match.group(0)
# 清理注释格式
comment = comment.replace('/**', '').replace('*/', '').strip()
# 提取函数声明或类定义
# 查找注释后面的函数或类
start_pos = match.end()
# 跳过空白字符
while start_pos < len(content) and content[start_pos].isspace():
start_pos += 1
# 提取函数或类定义的开始部分
end_pos = start_pos
while end_pos < len(content) and content[end_pos] != ';' and content[end_pos] != '{':
end_pos += 1
if end_pos > start_pos:
declaration = content[start_pos:end_pos].strip()
# 输出调试信息
if 'CreateText' in declaration:
print('注释块:', comment)
print('声明:', declaration)
comment_blocks.append((declaration, comment))
# 构建注释字典
comments = {}
for declaration, comment in comment_blocks:
# 提取函数名
func_match = re.search(r'\b\w+\s+([\w:]+)\s*\(', declaration)
if func_match:
func_name = func_match.group(1)
# 提取参数类型和名称
params = []
# 提取参数注释
param_comments = {}
# 匹配 @param 注释(更灵活的模式,支持星号前缀和制表符)
param_pattern = re.compile(r'\*?\s*@param\s*(?:\[(in|out|inout)\]\s*)?(\w+)\s+(.+)', re.MULTILINE)
for param_match in param_pattern.finditer(comment):
param_name = param_match.group(2)
param_comment = param_match.group(3).strip()
param_comments[param_name] = param_comment
# 输出调试信息
if 'CreateText' in func_name:
print('函数名:', func_name)
print('参数注释:', param_comments)
# 匹配括号内的参数列表
params_match = re.search(r'\(([^)]+)\)', declaration)
if params_match:
params_str = params_match.group(1)
# 分割参数
param_list = re.split(r',\s*', params_str)
# 用于存储已经处理过的参数名称,避免重复
processed_params = set()
for param in param_list:
# 处理默认参数值
param = param.split('=')[0].strip()
param_parts = param.strip().split()
if param_parts:
# 类型是除了最后一个部分之外的所有部分
param_type = ' '.join(param_parts[:-1])
param_name = param_parts[-1]
# 过滤掉不合法的参数名称(如常量)
if not param_name.isdigit() and param_name not in ['true', 'false', 'null', 'nil'] and '::' not in param_name:
# 检查参数是否已经处理过
if param_name not in processed_params:
# 移除引用符号
param_type = param_type.replace('&', '').replace('*', '')
# 简化类型名称
param_type = param_type.split('::')[-1]
# 映射到 Lua 类型
lua_type = map_cpp_type_to_lua(param_type)
# 获取参数注释
param_comment = param_comments.get(param_name, '')
params.append((param_name, lua_type, param_comment))
processed_params.add(param_name)
elif '::' in param_name:
# 如果参数名称是常量,使用更有意义的参数名称
# 移除引用符号
param_type = param_type.replace('&', '').replace('*', '')
# 简化类型名称
param_type = param_type.split('::')[-1]
# 映射到 Lua 类型
lua_type = map_cpp_type_to_lua(param_type)
# 使用类型名称作为参数名称
param_name = param_type.lower()
# 检查参数是否已经处理过
if param_name not in processed_params:
# 获取参数注释
param_comment = param_comments.get(param_name, '')
params.append((param_name, lua_type, param_comment))
processed_params.add(param_name)
# 提取返回值类型
return_type = ''
return_match = re.search(r'^\s*([^\(]+)\s+[\w:]+\s*\(', declaration)
if return_match:
return_type = return_match.group(1).strip()
# 移除引用符号
return_type = return_type.replace('&', '').replace('*', '')
# 简化类型名称
return_type = return_type.split('::')[-1]
# 映射到 Lua 类型
return_type = map_cpp_type_to_lua(return_type)
# 处理命名空间
if '::' in func_name:
# 提取命名空间和函数名
parts = func_name.split('::')
if len(parts) > 1:
ns = parts[-2]
name = parts[-1]
if ns not in comments:
comments[ns] = {}
comments[ns][name] = {
'comment': comment,
'params': params,
'return_type': return_type
}
else:
comments[func_name] = {
'comment': comment,
'params': params,
'return_type': return_type
}
# 提取类名
class_match = re.search(r'class\s+(\w+)', declaration)
if class_match:
class_name = class_match.group(1)
comments[class_name] = comment
# 提取 constexpr 变量
constexpr_match = re.search(r'constexpr\s+[\w:]+\s+(\w+)\s*=\s*"(.+?)"', declaration)
if constexpr_match:
var_name = constexpr_match.group(1)
var_value = constexpr_match.group(2)
print('提取到 constexpr 变量:', var_name, '=', var_value)
comments[var_name] = {
'comment': '',
'params': [],
'return_type': 'string',
'value': var_value
}
return comments
def map_cpp_type_to_lua(cpp_type):
"""
将 C++ 类型映射到 Lua 类型
"""
# 基本类型映射
type_map = {
'void': 'nil',
'bool': 'boolean',
'char': 'string',
'int': 'number',
'float': 'number',
'double': 'number',
'std::string': 'string',
'string': 'string',
'std::string_view': 'string',
'string_view': 'string',
'std::vector': 'table',
'std::map': 'table',
'std::unordered_map': 'table',
'std::list': 'table',
'std::set': 'table',
'std::unordered_set': 'table',
'Position2': 'Position2',
'Size': 'Size',
'Color': 'Color',
'Image': 'Image',
'Graphics': 'Graphics',
'System': 'System',
'Panel': 'UIPanel',
'Text': 'UIText',
'Manager': 'UIManager',
'ParamWindow': 'ParamWindow',
'gcText': 'gcText',
'std::ifstream': 'userdata',
'std::ofstream': 'userdata',
'FILE': 'userdata',
'Buffer': 'userdata',
'BufferView': 'userdata',
'SearchRule': 'table',
'NTree': 'table',
'std::chrono::system_clock::time_point': 'userdata',
'time_t': 'number',
'uint8_t': 'number',
'uint16_t': 'number',
'uint32_t': 'number',
'uint64_t': 'number',
'int8_t': 'number',
'int16_t': 'number',
'int32_t': 'number',
'int64_t': 'number',
'size_t': 'number',
'std::nullptr_t': 'nil',
'std::unique_ptr': 'userdata',
'std::shared_ptr': 'userdata',
'std::weak_ptr': 'userdata',
'std::optional': 'any',
'std::variant': 'any',
'std::tuple': 'table',
'std::pair': 'table',
'std::function': 'function',
'std::regex': 'userdata',
'std::smatch': 'userdata',
'std::istream': 'userdata',
'std::ostream': 'userdata',
'std::iostream': 'userdata',
'std::fstream': 'userdata',
'std::stringstream': 'userdata',
'std::istringstream': 'userdata',
'std::ostringstream': 'userdata',
'std::vector<bool>': 'table',
'std::vector<char>': 'string',
'std::vector<unsigned char>': 'string',
'std::array': 'table',
'std::deque': 'table',
'std::forward_list': 'table',
'std::queue': 'table',
'std::priority_queue': 'table',
'std::stack': 'table',
'std::unordered_multimap': 'table',
'std::unordered_multiset': 'table',
'std::multimap': 'table',
'std::multiset': 'table',
'std::bitset': 'userdata',
'std::complex': 'table',
'std::valarray': 'table',
'std::span': 'table',
'std::initializer_list': 'table',
'std::type_index': 'userdata',
'std::type_info': 'userdata',
'std::exception': 'userdata',
'std::error_code': 'userdata',
'std::error_condition': 'userdata',
'std::chrono::duration': 'number',
'std::chrono::time_point': 'userdata',
'std::filesystem::path': 'string',
'std::filesystem::directory_entry': 'table',
'std::filesystem::directory_iterator': 'userdata',
'std::filesystem::recursive_directory_iterator': 'userdata',
'std::filesystem::file_status': 'userdata',
'std::filesystem::permissions': 'number',
'std::filesystem::file_type': 'number',
'std::filesystem::space_info': 'table',
'unsigned': 'number',
'unsigned int': 'number',
'unsigned short': 'number',
'unsigned long': 'number',
'signed': 'number',
'short': 'number',
'long': 'number',
'long long': 'number',
'unsigned long long': 'number',
'long double': 'number'
}
# 查找映射
# 优先匹配完整类型
if cpp_type in type_map:
return type_map[cpp_type]
# 然后匹配部分类型
for key, value in type_map.items():
if key in cpp_type:
return value
# 特殊处理:如果是指针或引用类型,返回指向的类型
if '*' in cpp_type or '&' in cpp_type:
# 提取指向的类型
base_type = cpp_type.replace('*', '').replace('&', '').strip()
# 简化类型名称
base_type = base_type.split('::')[-1]
# 检查是否在映射表中
for key, value in type_map.items():
if key in base_type:
return value
# 如果是 gcText 类型,返回 gcText
if 'gcText' in base_type:
return 'gcText'
# 如果是 UI::Text 类型,返回 UIText
if 'UI::Text' in cpp_type:
return 'UIText'
# 默认返回 userdata
return 'userdata'
# 特殊处理:如果是枚举类型,返回 number
if 'enum' in cpp_type:
return 'number'
# 特殊处理:如果是类模板实例,返回 table
if '<' in cpp_type and '>' in cpp_type:
return 'table'
# 默认返回 any
return 'any'
def collect_header_comments(base_path):
"""
收集所有头文件中的注释
"""
all_comments = {}
for root, dirs, files in os.walk(base_path):
for file in files:
if file.endswith('.h'):
header_path = os.path.join(root, file)
print('处理头文件:', header_path)
comments = parse_header_file(header_path)
# 合并注释
for key, value in comments.items():
if key not in all_comments:
all_comments[key] = value
elif isinstance(value, dict):
# 如果是命名空间,合并其内部函数注释
if isinstance(all_comments[key], dict):
all_comments[key].update(value)
# 提取 constexpr 变量(没有注释块的)
try:
with open(header_path, 'r') as f:
content = f.read()
# 匹配 constexpr 变量定义
constexpr_pattern = re.compile(r'constexpr\s+[\w:]+\s+(\w+)\s*=\s*"(.+?)"', re.MULTILINE)
for match in constexpr_pattern.finditer(content):
var_name = match.group(1)
var_value = match.group(2)
print('提取到 constexpr 变量:', var_name, '=', var_value)
if var_name not in all_comments:
all_comments[var_name] = {
'comment': '',
'params': [],
'return_type': 'string',
'value': var_value
}
except Exception as e:
print('提取 constexpr 变量失败:', e)
return all_comments
def parse_lua_register_file(file_path):
"""
解析dl_lua_register.cpp文件,提取Lua绑定信息
"""
with open(file_path, 'r') as f:
content = f.read()
# 提取基本函数
base_functions = []
base_match = re.search(r'lua_register_base\(sol::state& l\)\s*\{([\s\S]*?)\}', content)
if base_match:
base_code = base_match.group(1)
# 提取基本函数注册
function_matches = re.findall(r'l\["([^"]+)"\]\s*=\s*([^;]+);', base_code)
for func_name, func_value in function_matches:
if 'lua_' in func_value or '::' in func_value:
base_functions.append(func_name)
# 提取命名空间
namespaces = {}
namespace_vars = {}
# 提取命名空间注册
namespace_pattern = re.compile(r'sol::table ll = l\["([^"]+)"\]\.get_or_create<sol::table>\(\);([\s\S]*?)\s*\}', re.MULTILINE)
namespace_matches = namespace_pattern.findall(content)
for namespace_name, namespace_code in namespace_matches:
if namespace_name not in namespaces:
namespaces[namespace_name] = []
namespace_vars[namespace_name] = []
# 提取函数注册(包括重载)
func_matches = re.findall(r'll\["([^"]+)"\]\s*=\s*([^;]+);', namespace_code)
for func_name, func_value in func_matches:
if '::' in func_value or 'overload' in func_value or 'lua_' in func_value:
if func_name not in namespaces[namespace_name]:
namespaces[namespace_name].append(func_name)
# 提取变量注册(确保不是函数)
var_matches = re.findall(r'll\["([^"]+)"\]\s*=\s*([^;]+);', namespace_code)
for var_name, var_value in var_matches:
if '::' in var_value and '(' not in var_value and 'overload' not in var_value and 'lua_' not in var_value:
if var_name not in namespace_vars[namespace_name]:
namespace_vars[namespace_name].append(var_name)
# 提取类
classes = {}
# 提取类注册
class_pattern = re.compile(r'l\.new_usertype<([^>]+)>\("([^"]+)"\s*(?:,\s*sol::no_constructor)?\s*,([\s\S]*?)\s*\);', re.MULTILINE)
class_matches = class_pattern.findall(content)
for class_type, class_name, class_code in class_matches:
methods = []
# 提取方法注册
method_matches = re.findall(r'"([^"]+)"\s*,\s*&([^,]+)', class_code)
for method_name, method_value in method_matches:
methods.append(method_name)
# 提取重载方法注册
overload_matches = re.findall(r'"([^"]+)"\s*,\s*sol::overload\s*\(([\s\S]*?)\)', class_code)
for method_name, overload_value in overload_matches:
methods.append(method_name)
classes[class_name] = {
'type': class_type,
'methods': methods
}
# 提取全局变量
globals = []
global_matches = re.findall(r'l\["([^"]+)"\]\s*=\s*g_\w+;', content)
globals.extend(global_matches)
return {
'base_functions': base_functions,
'namespaces': namespaces,
'namespace_vars': namespace_vars,
'classes': classes,
'globals': globals
}
def generate_lua_intellisense(data, output_path, comments):
"""
根据提取的信息生成Lua智能提示文件
"""
lines = []
lines.append('---@meta')
lines.append('')
# 生成基础函数
if data['base_functions']:
lines.append('--- 基础函数')
for func in data['base_functions']:
# 添加函数注释
params = []
if func in comments:
if isinstance(comments[func], dict):
# 新格式,包含注释和参数
for line in comments[func]['comment'].split('\n'):
# 处理 Doxygen 格式的注释
# 过滤掉所有格式的 @param 注释
if '@param' not in line:
# 处理 Doxygen 格式的注释
stripped_line = line.strip()
if stripped_line.startswith('@brief'):
content = stripped_line[len('@brief'):].strip()
if content:
lines.append('---' + line.replace('@brief', '').strip())
elif stripped_line.startswith('* @brief'):
content = stripped_line[len('* @brief'):].strip()
if content:
lines.append('---' + line.replace('* @brief', '*').strip())
elif stripped_line.startswith('@note'):
content = stripped_line[len('@note'):].strip()
if content:
lines.append('---' + line.replace('@note', '').strip())
elif stripped_line.startswith('* @note'):
content = stripped_line[len('* @note'):].strip()
if content:
lines.append('---' + line.replace('* @note', '*').strip())
elif stripped_line.startswith('@retval'):
content = stripped_line[len('@retval'):].strip()
if content:
return_type = comments[func].get('return_type', 'any')
lines.append('---@return {} {}'.format(return_type, content))
elif stripped_line.startswith('* @retval'):
content = stripped_line[len('* @retval'):].strip()
if content:
return_type = comments[func].get('return_type', 'any')
lines.append('---@return {} {}'.format(return_type, content))
else:
lines.append('---' + line)
# 添加参数类型注解和注释
for param_name, param_type, param_comment in comments[func]['params']:
if param_comment:
lines.append('---@param {} {} {}'.format(param_name, param_type, param_comment))
else:
lines.append('---@param {} {}'.format(param_name, param_type))
params.append(param_name)
# 如果没有返回值注释,添加默认的返回值类型
return_type = comments[func].get('return_type', 'any')
has_return_comment = False
for line in comments[func]['comment'].split('\n'):
stripped_line = line.strip()
if stripped_line.startswith('@retval') or stripped_line.startswith('* @retval'):
has_return_comment = True
break
if not has_return_comment:
lines.append('---@return {}'.format(return_type))
else:
# 旧格式,只有注释
for line in comments[func].split('\n'):
lines.append('---' + line)
lines.append('---@param ... any')
else:
lines.append('---@param ... any')
# 生成函数定义
if params:
lines.append('function {}({})'.format(func, ', '.join(params)))
else:
lines.append('function {}(...)'.format(func))
lines.append('end')
lines.append('')
# 生成命名空间
for namespace, functions in data['namespaces'].items():
# 添加命名空间注释
if namespace in comments:
if isinstance(comments[namespace], dict):
# 如果是命名空间字典,可能没有直接注释
lines.append('--- {}命名空间'.format(namespace))
else:
for line in comments[namespace].split('\n'):
lines.append('---' + line)
else:
lines.append('--- {}命名空间'.format(namespace))
lines.append('{} = {{}}'.format(namespace))
# 存储已经生成的函数名,避免重复生成变量
generated_functions = set()
for func in functions:
# 添加函数名到集合
generated_functions.add(func)
# 特殊处理 GetPathFileAll 函数的重载
if namespace == 'File' and func == 'GetPathFileAll':
# 生成多个重载版本
# 第一个重载版本:只有 search_rule 参数
lines.append('---* 获取文件夹所有文件(重载版本1)')
lines.append('---@return nil 返回相对路径')
lines.append('---@param search_rule table 搜索规则')
lines.append('function File.GetPathFileAll(search_rule)')
lines.append('end')
lines.append('')
# 第二个重载版本:path 和 search_rule 参数
lines.append('---* 获取文件夹所有文件(重载版本2)')
lines.append('---@return nil 返回相对路径')
lines.append('---@param path string 搜索路径')
lines.append('---@param search_rule table 搜索规则')
lines.append('function File.GetPathFileAll(path, search_rule)')
lines.append('end')
lines.append('')
# 第三个重载版本:path、search_rule 和 max_count 参数
lines.append('---* 获取文件夹所有文件(重载版本3)')
lines.append('---@return nil 返回相对路径')
lines.append('---@param path string 搜索路径')
lines.append('---@param search_rule table 搜索规则')
lines.append('---@param max_count number 最大搜索数量')
lines.append('function File.GetPathFileAll(path, search_rule, max_count)')
lines.append('end')
lines.append('')
else:
# 处理普通函数
# 添加函数注释
params = []
# 尝试直接在comments中查找函数名
if func in comments:
if isinstance(comments[func], dict):
# 新格式,包含注释和参数
for line in comments[func]['comment'].split('\n'):
# 处理 Doxygen 格式的注释
# 过滤掉所有格式的 @param 注释
if '@param' not in line:
# 处理 Doxygen 格式的注释
stripped_line = line.strip()
if stripped_line.startswith('@brief'):
content = stripped_line[len('@brief'):].strip()
if content:
lines.append('---' + line.replace('@brief', '').strip())
elif stripped_line.startswith('* @brief'):
content = stripped_line[len('* @brief'):].strip()
if content:
lines.append('---' + line.replace('* @brief', '*').strip())
elif stripped_line.startswith('@note'):
content = stripped_line[len('@note'):].strip()
if content:
lines.append('---' + line.replace('@note', '').strip())
elif stripped_line.startswith('* @note'):
content = stripped_line[len('* @note'):].strip()
if content:
lines.append('---' + line.replace('* @note', '*').strip())
elif stripped_line.startswith('@retval'):
content = stripped_line[len('@retval'):].strip()
if content:
return_type = comments[func].get('return_type', 'any')
lines.append('---@return {} {}'.format(return_type, content))
elif stripped_line.startswith('* @retval'):
content = stripped_line[len('* @retval'):].strip()
if content:
return_type = comments[func].get('return_type', 'any')
lines.append('---@return {} {}'.format(return_type, content))
else:
lines.append('---' + line)
# 添加参数类型注解和注释
for param_name, param_type, param_comment in comments[func]['params']:
if param_comment:
lines.append('---@param {} {} {}'.format(param_name, param_type, param_comment))
else:
lines.append('---@param {} {}'.format(param_name, param_type))
params.append(param_name)
# 如果没有返回值注释,添加默认的返回值类型
return_type = comments[func].get('return_type', 'any')
has_return_comment = False
for line in comments[func]['comment'].split('\n'):
stripped_line = line.strip()
if stripped_line.startswith('@retval') or stripped_line.startswith('* @retval'):
has_return_comment = True
break
if not has_return_comment:
lines.append('---@return {}'.format(return_type))
else:
# 旧格式,只有注释
for line in comments[func].split('\n'):
lines.append('---' + line)
lines.append('---@param ... any')
# 尝试在命名空间中查找函数名
elif namespace in comments and isinstance(comments[namespace], dict) and func in comments[namespace]:
if isinstance(comments[namespace][func], dict):
# 新格式,包含注释和参数
# 提取返回值类型
return_type = comments[namespace][func].get('return_type', 'any')
for line in comments[namespace][func]['comment'].split('\n'):
# 过滤掉所有格式的 @param 注释,避免重复
if '@param' not in line:
# 处理 Doxygen 格式的注释
stripped_line = line.strip()
if stripped_line.startswith('@retval'):
content = stripped_line[len('@retval'):].strip()
if content:
lines.append('---@return {} {}'.format(return_type, content))
elif stripped_line.startswith('* @retval'):
content = stripped_line[len('* @retval'):].strip()
if content:
lines.append('---@return {} {}'.format(return_type, content))
else:
lines.append('---' + line)
# 添加参数类型注解和注释
for param_name, param_type, param_comment in comments[namespace][func]['params']:
if param_comment:
lines.append('---@param {} {} {}'.format(param_name, param_type, param_comment))
else:
lines.append('---@param {} {}'.format(param_name, param_type))
params.append(param_name)
# 如果没有返回值注释,添加默认的返回值类型
return_type = comments[namespace][func].get('return_type', 'any')
has_return_comment = False
for line in comments[namespace][func]['comment'].split('\n'):
stripped_line = line.strip()
if stripped_line.startswith('@retval') or stripped_line.startswith('* @retval'):
has_return_comment = True
break
if not has_return_comment:
lines.append('---@return {}'.format(return_type))
else:
# 旧格式,只有注释
for line in comments[namespace][func].split('\n'):
lines.append('---' + line)
lines.append('---@param ... any')
else:
lines.append('---@param ... any')
# 生成函数定义
if params:
lines.append('function {}.{}({})'.format(namespace, func, ', '.join(params)))
else:
lines.append('function {}.{}('.format(namespace, func) + '...)')
lines.append('end')
# 生成命名空间变量
if namespace in data.get('namespace_vars', {}):
for var in data['namespace_vars'][namespace]:
# 检查变量是否已经作为函数生成过
if var not in generated_functions:
# 检查变量是否有值
if var in comments and isinstance(comments[var], dict) and 'value' in comments[var]:
var_value = comments[var]['value']
var_type = comments[var].get('return_type', 'any')
lines.append('---')
lines.append('---@type {}'.format(var_type))
# 不要给已经是字符串形式的值再加上双引号
if var_value.startswith('"') and var_value.endswith('"'):
lines.append('{}.{} = {}'.format(namespace, var, var_value))
else:
lines.append('{}.{} = "{}"'.format(namespace, var, var_value))
else:
# 如果找不到变量值,不生成变量定义,避免重复
pass
# 特殊处理 Img 命名空间的 REGEX_FORMAT 变量
if namespace == 'Img':
# 检查 REGEX_FORMAT 是否在 comments 中
if 'REGEX_FORMAT' in comments and isinstance(comments['REGEX_FORMAT'], dict) and 'value' in comments['REGEX_FORMAT']:
var_value = comments['REGEX_FORMAT']['value']
var_type = comments['REGEX_FORMAT'].get('return_type', 'string')
# 检查 REGEX_FORMAT 是否已作为函数生成过
if 'REGEX_FORMAT' not in generated_functions:
lines.append('---')
lines.append('---@type {}'.format(var_type))
# 不要给已经是字符串形式的值再加上双引号
if var_value.startswith('"') and var_value.endswith('"'):
lines.append('{}.{} = {}'.format(namespace, 'REGEX_FORMAT', var_value))
else:
lines.append('{}.{} = "{}"'.format(namespace, 'REGEX_FORMAT', var_value))
lines.append('')
# 生成类
for class_name, class_info in data['classes'].items():
# 添加类注释
if class_name in comments:
for line in comments[class_name].split('\n'):
lines.append('---' + line)
else:
lines.append('--- {}类'.format(class_name))
lines.append('---@class {}'.format(class_name))
lines.append('{} = {{}}'.format(class_name))
for method in class_info['methods']:
# 添加方法注释
params = []
if method in comments:
if isinstance(comments[method], dict):
# 新格式,包含注释和参数
for line in comments[method]['comment'].split('\n'):
# 过滤掉所有格式的 @param 注释,避免重复
if '@param' not in line:
lines.append('---' + line)
# 添加参数类型注解和注释
for param_name, param_type, param_comment in comments[method]['params']:
if param_comment:
lines.append('---@param {} {} {}'.format(param_name, param_type, param_comment))
else:
lines.append('---@param {} {}'.format(param_name, param_type))
params.append(param_name)
else:
# 旧格式,只有注释
for line in comments[method].split('\n'):
lines.append('---' + line)
lines.append('---@param ... any')
elif class_name in comments and isinstance(comments[class_name], dict) and method in comments[class_name]:
if isinstance(comments[class_name][method], dict):
# 新格式,包含注释和参数
# 提取返回值类型
return_type = comments[class_name][method].get('return_type', 'any')
for line in comments[class_name][method]['comment'].split('\n'):
# 过滤掉所有格式的 @param 注释,避免重复
if '@param' not in line:
# 处理 Doxygen 格式的注释
stripped_line = line.strip()
if stripped_line.startswith('@retval'):
content = stripped_line[len('@retval'):].strip()
if content:
lines.append('---@return {} {}'.format(return_type, content))
elif stripped_line.startswith('* @retval'):
content = stripped_line[len('* @retval'):].strip()
if content:
lines.append('---@return {} {}'.format(return_type, content))
else:
lines.append('---' + line)
# 添加参数类型注解和注释
for param_name, param_type, param_comment in comments[class_name][method]['params']:
if param_comment:
lines.append('---@param {} {} {}'.format(param_name, param_type, param_comment))
else:
lines.append('---@param {} {}'.format(param_name, param_type))
params.append(param_name)
# 如果没有返回值注释,添加默认的返回值类型
return_type = comments[class_name][method].get('return_type', 'any')
has_return_comment = False
for line in comments[class_name][method]['comment'].split('\n'):
stripped_line = line.strip()
if stripped_line.startswith('@retval') or stripped_line.startswith('* @retval'):
has_return_comment = True
break
if not has_return_comment:
lines.append('---@return {}'.format(return_type))
else:
# 旧格式,只有注释
for line in comments[class_name][method].split('\n'):
lines.append('---' + line)
lines.append('---@param ... any')
else:
lines.append('---@param ... any')
# 生成函数定义
if params:
lines.append('function {}:{}({})'.format(class_name, method, ', '.join(params)))
else:
lines.append('function {}:{}('.format(class_name, method) + '...)')
lines.append('end')
lines.append('')
# 生成全局变量
global_type_map = {
'g_system': 'System',
'g_gfx': 'Graphics',
'g_ui': 'UIManager',
'g_factory': 'Factory'
}
for global_var in data['globals']:
var_type = global_type_map.get(global_var, 'any')
lines.append('--- 全局{}实例'.format(global_var))
lines.append('{} = nil --[[@type {}]]'.format(global_var, var_type))
# 为全局变量添加类的方法
if var_type in data['classes']:
class_info = data['classes'][var_type]
for method in class_info['methods']:
# 添加方法注释
params = []
if method in comments:
if isinstance(comments[method], dict):
# 新格式,包含注释和参数
for line in comments[method]['comment'].split('\n'):
# 过滤掉所有格式的 @param 注释,避免重复
if '@param' not in line:
# 处理 Doxygen 格式的注释
stripped_line = line.strip()
if stripped_line.startswith('@brief'):
content = stripped_line[len('@brief'):].strip()
if content:
lines.append('---' + line.replace('@brief', '').strip())
elif stripped_line.startswith('* @brief'):
content = stripped_line[len('* @brief'):].strip()
if content:
lines.append('---' + line.replace('* @brief', '*').strip())
elif stripped_line.startswith('@note'):
content = stripped_line[len('@note'):].strip()
if content:
lines.append('---' + line.replace('@note', '').strip())
elif stripped_line.startswith('* @note'):
content = stripped_line[len('* @note'):].strip()
if content:
lines.append('---' + line.replace('* @note', '*').strip())
elif stripped_line.startswith('@retval'):
content = stripped_line[len('@retval'):].strip()
if content:
return_type = comments[method].get('return_type', 'any')
lines.append('---@return {} {}'.format(return_type, content))
elif stripped_line.startswith('* @retval'):
content = stripped_line[len('* @retval'):].strip()
if content:
return_type = comments[method].get('return_type', 'any')
lines.append('---@return {} {}'.format(return_type, content))
else:
lines.append('---' + line)
# 添加参数类型注解和注释
for param_name, param_type, param_comment in comments[method]['params']:
if param_comment:
lines.append('---@param {} {} {}'.format(param_name, param_type, param_comment))
else:
lines.append('---@param {} {}'.format(param_name, param_type))
params.append(param_name)
else:
# 旧格式,只有注释
for line in comments[method].split('\n'):
lines.append('---' + line)
lines.append('---@param ... any')
elif var_type in comments and isinstance(comments[var_type], dict) and method in comments[var_type]:
if isinstance(comments[var_type][method], dict):
# 新格式,包含注释和参数
for line in comments[var_type][method]['comment'].split('\n'):
# 过滤掉所有格式的 @param 注释,避免重复
if '@param' not in line:
lines.append('---' + line)
# 添加参数类型注解和注释
for param_name, param_type, param_comment in comments[var_type][method]['params']:
if param_comment:
lines.append('---@param {} {} {}'.format(param_name, param_type, param_comment))
else:
lines.append('---@param {} {}'.format(param_name, param_type))
params.append(param_name)
else:
# 旧格式,只有注释
for line in comments[var_type][method].split('\n'):
lines.append('---' + line)
lines.append('---@param ... any')
else:
lines.append('---@param ... any')
# 生成函数定义
if params:
lines.append('function {}.{}({})'.format(global_var, method, ', '.join(params)))
else:
lines.append('function {}.{}('.format(global_var, method) + '...)')
lines.append('end')
lines.append('')
# 生成辅助类型定义
lines.append('--- 辅助类型定义')
lines.append('')
lines.append('---@class Position2')
lines.append('---@field x number X坐标')
lines.append('---@field y number Y坐标')
lines.append('')
lines.append('---@class Size')
lines.append('---@field w number 宽度')
lines.append('---@field h number 高度')
lines.append('')
lines.append('---@class Color')
lines.append('---@field r number 红色通道 (0-1)')
lines.append('---@field g number 绿色通道 (0-1)')
lines.append('---@field b number 蓝色通道 (0-1)')
lines.append('---@field a number 透明度 (0-1)')
# 写入文件
with open(output_path, 'wb') as f:
content = '\n'.join(lines)
if isinstance(content, unicode):
f.write(content.encode('utf-8'))
else:
f.write(content)
print('生成完成:{}'.format(output_path))
if __name__ == '__main__':
input_file = '../dl/script/dl_lua_register.cpp'
output_file = './dl_api.lua'
# 收集头文件注释
header_comments = collect_header_comments('../dl')
data = parse_lua_register_file(input_file)
generate_lua_intellisense(data, output_file, header_comments)