initial commit
This commit is contained in:
commit
27b3274027
25 changed files with 1696 additions and 0 deletions
192
typegen/src/resolver.rs
Normal file
192
typegen/src/resolver.rs
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{outform::{self, Flag, PropertyType}, typespec::{FnParam, Function, Property, TypeSpec}};
|
||||
|
||||
pub fn resolve_types(module: &str, typespec: TypeSpec) -> anyhow::Result<HashMap<String, outform::TypeInfo>> {
|
||||
let mut outtypes = HashMap::new();
|
||||
|
||||
let types = typespec.typemap.iter()
|
||||
.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);
|
||||
|
||||
for mapping in types {
|
||||
let Some(class) = typespec.classes.iter().find(|class| class.name == mapping.cname) else {
|
||||
continue
|
||||
};
|
||||
|
||||
let mut properties = Vec::<&Property>::new();
|
||||
let mut functions = Vec::<&Function>::new();
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
let superctype = typespec.classes.iter().find(|class| &class.name == superclass);
|
||||
|
||||
match superctype {
|
||||
Some(superctype) => {
|
||||
properties.extend(superctype.properties.iter());
|
||||
functions.extend(superctype.functions.iter());
|
||||
superclass = &superctype.superclass;
|
||||
},
|
||||
None => break outform::Type::unknown(),
|
||||
}
|
||||
};
|
||||
|
||||
fn qmlparamtype(ctype: &str, typespec: &TypeSpec) -> outform::Type {
|
||||
let qtype = typespec.typemap
|
||||
.iter()
|
||||
.find(|type_| &type_.cname == ctype)
|
||||
.map(|type_| (&type_.module, &type_.name))
|
||||
.or_else(|| {
|
||||
typespec.enums
|
||||
.iter()
|
||||
.find(|type_| type_.cname.as_ref().map(|v| v as &str) == Some(ctype))
|
||||
.map(|type_| (&type_.module, &type_.name))
|
||||
});
|
||||
|
||||
match qtype {
|
||||
Some((module, name)) => outform::Type::resolve(module.as_ref().map(|v| v as &str), &name),
|
||||
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
|
||||
};
|
||||
|
||||
let gadget = typespec.gadgets.iter()
|
||||
.find(|gadget| gadget.cname == ctype);
|
||||
|
||||
match gadget {
|
||||
Some(gadget) => outform::Property {
|
||||
type_: PropertyType::Gadget(
|
||||
gadget.properties.iter()
|
||||
.map(|prop| (prop.name.clone(), solveprop(prop, typespec).type_))
|
||||
.collect()
|
||||
),
|
||||
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];
|
||||
list = true;
|
||||
}
|
||||
|
||||
if ctype.ends_with('*') {
|
||||
ctype = &ctype[..ctype.len() - 1];
|
||||
}
|
||||
|
||||
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(),
|
||||
details: func.details.clone(),
|
||||
params: func.params.iter().map(|FnParam { type_, name }| (name.clone(), qmlparamtype(type_, typespec))).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
let properties = properties.iter().map(|prop| (
|
||||
prop.name.clone(),
|
||||
solveprop(prop, &typespec)
|
||||
)).collect::<HashMap<_, _>>();
|
||||
|
||||
let functions = functions.iter().map(|func| (
|
||||
func.name.clone(),
|
||||
solvefunc(func, &typespec)
|
||||
)).collect::<HashMap<_, _>>();
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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) {
|
||||
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(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(outtypes)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue