use oak_idl::ast::{IdlItem, IdlRoot};
use std::fmt::Write;
fn map_webidl_type(webidl_type: &str) -> String {
let webidl_type = webidl_type.trim();
match webidl_type {
"DOMString" | "ByteString" | "USVString" | "string" => String::from("string"),
"boolean" => String::from("boolean"),
"byte"
| "octet"
| "short"
| "unsigned short"
| "long"
| "unsigned long"
| "long long"
| "unsigned long long"
| "float"
| "unrestricted float"
| "double"
| "unrestricted double"
| "integer"
| "unsigned integer" => String::from("number"),
"any" => String::from("any"),
"undefined" => String::from("undefined"),
"null" => String::from("null"),
"void" => String::from("void"),
_ => {
if webidl_type.starts_with("sequence<") && webidl_type.ends_with(">") {
let inner_type = &webidl_type[9..webidl_type.len() - 1];
let mut result = String::with_capacity(10 + inner_type.len());
result.push_str("Array<");
result.push_str(&map_webidl_type(inner_type));
result.push('>');
return result;
}
if webidl_type.contains(" or ") {
let types: Vec<&str> = webidl_type.split(" or ").collect();
let mut result = String::with_capacity(webidl_type.len());
let mut first = true;
for t in types {
if !first {
result.push_str(" | ");
}
result.push_str(&map_webidl_type(t.trim()));
first = false;
}
return result;
}
if webidl_type.ends_with("?") {
let base_type = &webidl_type[..webidl_type.len() - 1];
let mut result = String::with_capacity(base_type.len() + 10);
result.push_str(&map_webidl_type(base_type));
result.push_str(" | undefined");
return result;
}
if webidl_type.starts_with("Promise<") && webidl_type.ends_with(">") {
let inner_type = &webidl_type[8..webidl_type.len() - 1];
let mut result = String::with_capacity(12 + inner_type.len());
result.push_str("Promise<");
result.push_str(&map_webidl_type(inner_type));
result.push('>');
return result;
}
if webidl_type.starts_with("record<") && webidl_type.ends_with(">") {
let inner = &webidl_type[7..webidl_type.len() - 1];
if let Some(comma_idx) = inner.find(",") {
let key_type = &inner[..comma_idx].trim();
let value_type = &inner[comma_idx + 1..].trim();
let mut result = String::with_capacity(20 + key_type.len() + value_type.len());
result.push_str("{ [key: ");
result.push_str(&map_webidl_type(key_type));
result.push_str("]: ");
result.push_str(&map_webidl_type(value_type));
result.push('}');
return result;
}
}
if webidl_type.ends_with("[]") {
let base_type = &webidl_type[..webidl_type.len() - 2];
let mut result = String::with_capacity(8 + base_type.len());
result.push_str("Array<");
result.push_str(&map_webidl_type(base_type));
result.push('>');
return result;
}
if webidl_type.contains(".") {
return String::from(webidl_type);
}
if webidl_type.contains("<") && webidl_type.contains(">") {
let parts: Vec<&str> = webidl_type.split("<").collect();
if parts.len() == 2 {
let name = parts[0].trim();
let generic = &parts[1][..parts[1].len() - 1].trim();
let mut result = String::with_capacity(name.len() + 2 + generic.len());
result.push_str(name);
result.push('<');
result.push_str(&map_webidl_type(generic));
result.push('>');
return result;
}
}
String::from(webidl_type)
}
}
}
pub fn convert(root: &IdlRoot) -> String {
let estimated_size = root.items.len() * 300; let mut result = String::with_capacity(estimated_size);
println!("Items count: {}", root.items.len());
for (i, item) in root.items.iter().enumerate() {
println!("Item {}: {:?}", i, item);
}
for item in root.items.iter() {
match item {
IdlItem::Interface(interface) => {
println!("处理接口: {}", interface.name);
convert_interface(interface, &mut result);
result.push_str("\n");
}
IdlItem::Struct(struct_) => {
println!("处理结构体: {}", struct_.name);
convert_struct(struct_, &mut result);
result.push_str("\n");
}
IdlItem::Enum(enum_) => {
println!("处理枚举: {}", enum_.name);
convert_enum(enum_, &mut result);
result.push_str("\n");
}
IdlItem::Typedef(typedef) => {
println!("处理类型别名: {}", typedef.name);
convert_typedef(typedef, &mut result);
result.push_str("\n");
}
IdlItem::Const(const_) => {
println!("处理常量: {}", const_.name);
convert_const(const_, &mut result);
result.push_str("\n");
}
IdlItem::Module(module) => {
println!("处理模块: {}", module.name);
convert_module(module, &mut result);
result.push_str("\n");
}
_ => {
println!("未知类型: {:?}", item);
}
}
}
result.shrink_to_fit();
println!("转换结果长度: {}", result.len());
result
}
fn convert_module(module: &oak_idl::ast::Module, result: &mut String) {
write!(result, "namespace {} {{\n", module.name).unwrap();
for item in &module.items {
match item {
IdlItem::Interface(interface) => {
convert_interface(interface, result);
result.push_str("\n");
}
IdlItem::Struct(struct_) => {
convert_struct(struct_, result);
result.push_str("\n");
}
IdlItem::Enum(enum_) => {
convert_enum(enum_, result);
result.push_str("\n");
}
IdlItem::Typedef(typedef) => {
convert_typedef(typedef, result);
result.push_str("\n");
}
IdlItem::Const(const_) => {
convert_const(const_, result);
result.push_str("\n");
}
IdlItem::Module(submodule) => {
convert_module(submodule, result);
result.push_str("\n");
}
}
}
write!(result, "}}").unwrap();
}
fn convert_interface(interface: &oak_idl::ast::Interface, result: &mut String) {
write!(result, "interface {} {{\n", interface.name).unwrap();
for member in &interface.members {
match member {
oak_idl::ast::IdlMember::Attribute(attr) => {
let mapped_type = map_webidl_type(&attr.type_name);
if attr.readonly {
write!(result, " readonly {}: {};\n", attr.name, mapped_type).unwrap();
}
else {
write!(result, " {}: {};\n", attr.name, mapped_type).unwrap();
}
}
oak_idl::ast::IdlMember::Operation(op) => {
write!(result, " {}(", op.name).unwrap();
let mut first = true;
for arg in &op.params {
if !first {
write!(result, ", ").unwrap();
}
let mapped_type = map_webidl_type(&arg.type_name);
write!(result, "{}: {}", arg.name, mapped_type).unwrap();
first = false;
}
let mapped_return_type = map_webidl_type(&op.return_type);
write!(result, "): {};\n", mapped_return_type).unwrap();
}
}
}
write!(result, "}}",).unwrap();
}
fn convert_struct(struct_: &oak_idl::ast::Struct, result: &mut String) {
write!(result, "interface {} {{\n", struct_.name).unwrap();
for field in &struct_.fields {
let mut field_type = field.type_name.clone();
let mut optional = false;
if field_type.ends_with('?') {
optional = true;
field_type = field_type.trim_end_matches('?').to_string();
}
let mut has_default = false;
let mut default_value = String::new();
if let Some(index) = field_type.find(" = ") {
has_default = true;
default_value = field_type[index + 3..].to_string();
field_type = field_type[..index].to_string();
}
let mapped_type = map_webidl_type(&field_type);
if optional {
write!(result, " {}?: {};\n", field.name, mapped_type).unwrap();
}
else if has_default {
write!(result, " {}: {} = {};\n", field.name, mapped_type, default_value).unwrap();
}
else {
write!(result, " {}: {};\n", field.name, mapped_type).unwrap();
}
}
write!(result, "}}",).unwrap();
}
fn convert_enum(enum_: &oak_idl::ast::Enum, result: &mut String) {
write!(result, "enum {} {{\n", enum_.name).unwrap();
for (i, variant) in enum_.variants.iter().enumerate() {
if i > 0 {
write!(result, ",\n").unwrap();
}
write!(result, " {}", variant).unwrap();
}
write!(result, "\n}}",).unwrap();
}
fn convert_typedef(typedef: &oak_idl::ast::Typedef, result: &mut String) {
let mapped_type = map_webidl_type(&typedef.type_name);
write!(result, "type {} = {};", typedef.name, mapped_type).unwrap();
}
fn convert_const(const_: &oak_idl::ast::Const, result: &mut String) {
let mapped_type = map_webidl_type(&const_.type_name);
write!(result, "const {}: {} = {};", const_.name, mapped_type, const_.value).unwrap();
}