940 lines
46 KiB
Python
Vendored
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)
|