2024-02-12 12:07:01 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
2024-02-19 01:38:55 +00:00
|
|
|
use crate::{
|
2024-03-21 09:42:57 +00:00
|
|
|
outform::{self, Flag, Parameter, PropertyType},
|
2024-02-19 01:38:55 +00:00
|
|
|
typespec::{FnParam, Function, Property, Signal, TypeSpec},
|
|
|
|
};
|
|
|
|
|
|
|
|
pub fn resolve_types(
|
|
|
|
module: &str,
|
|
|
|
typespec: TypeSpec,
|
|
|
|
) -> anyhow::Result<HashMap<String, outform::TypeInfo>> {
|
2024-02-12 12:07:01 +00:00
|
|
|
let mut outtypes = HashMap::new();
|
|
|
|
|
2024-02-19 01:38:55 +00:00
|
|
|
let types = typespec
|
|
|
|
.typemap
|
2024-02-12 12:07:01 +00:00
|
|
|
.iter()
|
2024-02-19 01:38:55 +00:00
|
|
|
.filter(|type_| type_.module.as_ref().map(|v| v as &str) == Some(module));
|
|
|
|
|
|
|
|
let findqmltype = |cname: &str| typespec.typemap.iter().find(|type_| type_.cname == cname);
|
2024-02-12 12:07:01 +00:00
|
|
|
|
|
|
|
for mapping in types {
|
2024-02-19 01:38:55 +00:00
|
|
|
let Some(class) = typespec
|
|
|
|
.classes
|
|
|
|
.iter()
|
|
|
|
.find(|class| class.name == mapping.cname)
|
|
|
|
else {
|
2024-02-12 12:07:01 +00:00
|
|
|
continue
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut properties = Vec::<&Property>::new();
|
|
|
|
let mut functions = Vec::<&Function>::new();
|
2024-02-19 01:38:55 +00:00
|
|
|
let mut signals = Vec::<&Signal>::new();
|
2024-02-12 12:07:01 +00:00
|
|
|
|
|
|
|
// the first superclass availible from QML
|
|
|
|
let mut superclass = &class.superclass;
|
|
|
|
let superclass = loop {
|
|
|
|
let type_ = findqmltype(superclass);
|
|
|
|
|
|
|
|
if let Some(type_) = type_ {
|
|
|
|
break outform::Type::resolve(type_.module.as_ref().map(|v| v as &str), &type_.name)
|
|
|
|
}
|
|
|
|
|
2024-02-19 01:38:55 +00:00
|
|
|
let superctype = typespec
|
|
|
|
.classes
|
|
|
|
.iter()
|
|
|
|
.find(|class| &class.name == superclass);
|
2024-02-12 12:07:01 +00:00
|
|
|
|
|
|
|
match superctype {
|
|
|
|
Some(superctype) => {
|
|
|
|
properties.extend(superctype.properties.iter());
|
|
|
|
functions.extend(superctype.functions.iter());
|
2024-02-19 01:38:55 +00:00
|
|
|
signals.extend(superctype.signals.iter());
|
2024-02-12 12:07:01 +00:00
|
|
|
superclass = &superctype.superclass;
|
|
|
|
},
|
|
|
|
None => break outform::Type::unknown(),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
fn qmlparamtype(ctype: &str, typespec: &TypeSpec) -> outform::Type {
|
2024-02-19 01:38:55 +00:00
|
|
|
let qtype = typespec
|
|
|
|
.typemap
|
2024-02-12 12:07:01 +00:00
|
|
|
.iter()
|
|
|
|
.find(|type_| &type_.cname == ctype)
|
|
|
|
.map(|type_| (&type_.module, &type_.name))
|
|
|
|
.or_else(|| {
|
2024-02-19 01:38:55 +00:00
|
|
|
typespec
|
|
|
|
.enums
|
2024-02-12 12:07:01 +00:00
|
|
|
.iter()
|
|
|
|
.find(|type_| type_.cname.as_ref().map(|v| v as &str) == Some(ctype))
|
|
|
|
.map(|type_| (&type_.module, &type_.name))
|
|
|
|
});
|
|
|
|
|
|
|
|
match qtype {
|
2024-02-19 01:38:55 +00:00
|
|
|
Some((module, name)) => {
|
|
|
|
outform::Type::resolve(module.as_ref().map(|v| v as &str), &name)
|
|
|
|
},
|
2024-02-12 12:07:01 +00:00
|
|
|
None => outform::Type::unknown(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn solveprop(prop: &Property, typespec: &TypeSpec) -> outform::Property {
|
|
|
|
let mut ctype = &prop.type_[..];
|
|
|
|
|
|
|
|
let flags = {
|
|
|
|
let mut flags = Vec::new();
|
|
|
|
|
|
|
|
if prop.default {
|
|
|
|
flags.push(Flag::Default);
|
|
|
|
}
|
|
|
|
|
|
|
|
if !prop.readable {
|
|
|
|
flags.push(Flag::Writeonly);
|
|
|
|
} else if !prop.writable {
|
|
|
|
flags.push(Flag::Readonly);
|
|
|
|
}
|
|
|
|
|
|
|
|
flags
|
|
|
|
};
|
|
|
|
|
2024-02-19 01:38:55 +00:00
|
|
|
let gadget = typespec.gadgets.iter().find(|gadget| gadget.cname == ctype);
|
2024-02-12 12:07:01 +00:00
|
|
|
|
|
|
|
match gadget {
|
|
|
|
Some(gadget) => outform::Property {
|
|
|
|
type_: PropertyType::Gadget(
|
2024-02-19 01:38:55 +00:00
|
|
|
gadget
|
|
|
|
.properties
|
|
|
|
.iter()
|
2024-02-12 12:07:01 +00:00
|
|
|
.map(|prop| (prop.name.clone(), solveprop(prop, typespec).type_))
|
2024-02-19 01:38:55 +00:00
|
|
|
.collect(),
|
2024-02-12 12:07:01 +00:00
|
|
|
),
|
|
|
|
details: prop.details.clone(),
|
|
|
|
flags,
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
let mut list = false;
|
|
|
|
|
|
|
|
if ctype.starts_with("QQmlListProperty<") {
|
|
|
|
ctype = &ctype[17..ctype.len() - 1];
|
|
|
|
list = true;
|
|
|
|
} else if ctype.starts_with("QList<") {
|
|
|
|
ctype = &ctype[6..ctype.len() - 1];
|
2024-05-05 11:16:17 +00:00
|
|
|
if ctype.ends_with('*') {
|
|
|
|
ctype = &ctype[0..ctype.len() - 1];
|
|
|
|
}
|
|
|
|
|
2024-02-12 12:07:01 +00:00
|
|
|
list = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut type_ = qmlparamtype(ctype, typespec);
|
|
|
|
|
|
|
|
if list {
|
|
|
|
type_ = outform::Type {
|
|
|
|
type_: outform::TypeSource::Qt,
|
|
|
|
module: "qml".to_string(),
|
|
|
|
name: "list".to_string(),
|
|
|
|
of: Some(Box::new(type_)),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
outform::Property {
|
|
|
|
type_: PropertyType::Type(type_),
|
|
|
|
details: prop.details.clone(),
|
|
|
|
flags,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn solvefunc(func: &Function, typespec: &TypeSpec) -> outform::Function {
|
|
|
|
outform::Function {
|
|
|
|
ret: qmlparamtype(&func.ret, typespec),
|
|
|
|
name: func.name.clone(),
|
2024-03-21 09:35:17 +00:00
|
|
|
id: {
|
2024-03-21 09:42:57 +00:00
|
|
|
let params = func
|
|
|
|
.params
|
2024-03-21 09:35:17 +00:00
|
|
|
.iter()
|
|
|
|
.map(|FnParam { type_, .. }| qmlparamtype(type_, typespec).name);
|
|
|
|
|
|
|
|
let mut id = func.name.clone();
|
|
|
|
id.push('(');
|
|
|
|
for param in params {
|
|
|
|
id.push_str(¶m);
|
|
|
|
id.push('_')
|
|
|
|
}
|
|
|
|
id.truncate(id.len() - 1);
|
|
|
|
id.push(')');
|
|
|
|
|
|
|
|
id
|
|
|
|
},
|
2024-02-12 12:07:01 +00:00
|
|
|
details: func.details.clone(),
|
2024-02-19 01:38:55 +00:00
|
|
|
params: func
|
|
|
|
.params
|
|
|
|
.iter()
|
2024-03-21 09:42:57 +00:00
|
|
|
.map(|FnParam { type_, name }| Parameter {
|
|
|
|
name: name.clone(),
|
|
|
|
type_: qmlparamtype(type_, typespec),
|
|
|
|
})
|
2024-02-19 01:38:55 +00:00
|
|
|
.collect(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn solvesignal(func: &Signal, typespec: &TypeSpec) -> outform::Signal {
|
|
|
|
outform::Signal {
|
|
|
|
name: func.name.clone(),
|
|
|
|
details: func.details.clone(),
|
|
|
|
params: func
|
|
|
|
.params
|
|
|
|
.iter()
|
2024-03-21 09:42:57 +00:00
|
|
|
.map(|FnParam { type_, name }| Parameter {
|
|
|
|
name: name.clone(),
|
|
|
|
type_: qmlparamtype(type_, typespec),
|
|
|
|
})
|
2024-02-19 01:38:55 +00:00
|
|
|
.collect(),
|
2024-02-12 12:07:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
properties.extend(class.properties.iter());
|
|
|
|
properties.sort_by(|a, b| Ord::cmp(&a.name, &b.name));
|
|
|
|
|
|
|
|
functions.extend(class.functions.iter());
|
|
|
|
functions.sort_by(|a, b| Ord::cmp(&a.name, &b.name));
|
|
|
|
|
2024-02-19 01:38:55 +00:00
|
|
|
signals.extend(class.signals.iter());
|
|
|
|
signals.sort_by(|a, b| Ord::cmp(&a.name, &b.name));
|
|
|
|
|
|
|
|
let properties = properties
|
|
|
|
.iter()
|
|
|
|
.map(|prop| (prop.name.clone(), solveprop(prop, &typespec)))
|
|
|
|
.collect::<HashMap<_, _>>();
|
|
|
|
|
|
|
|
let functions = functions
|
|
|
|
.iter()
|
2024-03-21 09:35:17 +00:00
|
|
|
.map(|func| solvefunc(func, &typespec))
|
|
|
|
.collect::<Vec<_>>();
|
2024-02-12 12:07:01 +00:00
|
|
|
|
2024-02-19 01:38:55 +00:00
|
|
|
let signals = signals
|
|
|
|
.iter()
|
|
|
|
.map(|signal| (signal.name.clone(), solvesignal(signal, &typespec)))
|
|
|
|
.collect::<HashMap<_, _>>();
|
2024-02-12 12:07:01 +00:00
|
|
|
|
|
|
|
let type_ = outform::ClassInfo {
|
|
|
|
superclass,
|
|
|
|
description: class.description.clone(),
|
|
|
|
details: class.details.clone(),
|
|
|
|
flags: {
|
|
|
|
let mut flags = Vec::new();
|
|
|
|
|
|
|
|
if class.singleton {
|
|
|
|
flags.push(Flag::Singleton);
|
|
|
|
} else if class.uncreatable {
|
|
|
|
flags.push(Flag::Uncreatable);
|
|
|
|
}
|
|
|
|
|
|
|
|
flags
|
|
|
|
},
|
|
|
|
properties,
|
|
|
|
functions,
|
2024-02-19 01:38:55 +00:00
|
|
|
signals,
|
2024-02-12 12:07:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
outtypes.insert(mapping.name.clone(), outform::TypeInfo::Class(type_));
|
|
|
|
}
|
|
|
|
|
|
|
|
for enum_ in typespec.enums {
|
|
|
|
if enum_.module.as_ref().map(|v| v as &str) == Some(module) {
|
2024-02-19 01:38:55 +00:00
|
|
|
outtypes.insert(
|
|
|
|
enum_.name,
|
|
|
|
outform::TypeInfo::Enum(outform::EnumInfo {
|
|
|
|
description: enum_.description,
|
|
|
|
details: enum_.details,
|
|
|
|
variants: enum_
|
|
|
|
.varaints
|
|
|
|
.into_iter()
|
|
|
|
.map(|variant| {
|
|
|
|
(variant.name, outform::Variant {
|
|
|
|
details: variant.details,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
}),
|
|
|
|
);
|
2024-02-12 12:07:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(outtypes)
|
|
|
|
}
|