Last version with clang dep

This commit is contained in:
Rafael Caricio 2020-06-12 09:16:57 +02:00 committed by Rafael Carício
parent 119d44ef91
commit 311c8c6cc9
5 changed files with 125 additions and 7 deletions

View file

@ -17,10 +17,10 @@ name = "lvgl_codegen"
regex = "1.3.9" regex = "1.3.9"
quote = "1.0.7" quote = "1.0.7"
lazy_static = "1.4.0" lazy_static = "1.4.0"
clang = { path = "../../clang-rs" }
itertools = "0.9.0" itertools = "0.9.0"
proc-macro2 = "1.0.18" proc-macro2 = "1.0.18"
syn = "1.0.31" Inflector = "0.11.4"
lang-c = "0.8.1"
[build-dependencies] [build-dependencies]
cc = "1.0.50" cc = "1.0.50"

View file

@ -1,5 +1,6 @@
use cc::Build; use cc::Build;
use std::process::Command; use std::ffi::OsStr;
use std::process::{Command, Stdio};
use std::{env, fs, path::Path, path::PathBuf}; use std::{env, fs, path::Path, path::PathBuf};
static CONFIG_NAME: &str = "DEP_LV_CONFIG_PATH"; static CONFIG_NAME: &str = "DEP_LV_CONFIG_PATH";

View file

@ -1,4 +1,5 @@
use clang::{Clang, Entity, EntityKind, Index, Type}; use clang::{Clang, Entity, EntityKind, Index, Type};
use inflector::cases::pascalcase::to_pascal_case;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::format_ident; use quote::format_ident;
@ -42,6 +43,22 @@ pub struct LvWidget {
methods: Vec<LvFunc>, methods: Vec<LvFunc>,
} }
impl Rusty for LvWidget {
type Parent = ();
fn code(&self, _parent: &Self::Parent) -> WrapperResult<TokenStream> {
let widget_name = format_ident!("{}", to_pascal_case(self.name.as_str()));
let methods: Vec<TokenStream> = self.methods.iter().flat_map(|m| m.code(self)).collect();
Ok(quote! {
define_object!(#widget_name);
impl #widget_name {
#(#methods)*
}
})
}
}
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq)]
pub struct LvFunc { pub struct LvFunc {
name: String, name: String,
@ -64,6 +81,23 @@ impl Rusty for LvFunc {
let func_name = format_ident!("{}", new_name); let func_name = format_ident!("{}", new_name);
let original_func_name = format_ident!("{}", self.name.as_str()); let original_func_name = format_ident!("{}", self.name.as_str());
// generate constructor
if new_name.eq("create") {
return Ok(quote! {
pub fn new<C>(parent: &mut C) -> crate::LvResult<Self>
where
C: crate::NativeObject,
{
unsafe {
let ptr = lvgl_sys::#original_func_name(parent.raw()?.as_mut(), core::ptr::null_mut());
let raw = core::ptr::NonNull::new(ptr)?;
let core = <crate::Obj as crate::Widget>::from_raw(raw);
Ok(Self { core })
}
}
});
}
// Make sure all argumets can be generated, skip the first arg (self)! // Make sure all argumets can be generated, skip the first arg (self)!
for arg in self.args.iter().skip(1) { for arg in self.args.iter().skip(1) {
arg.code(self)?; arg.code(self)?;
@ -73,7 +107,7 @@ impl Rusty for LvFunc {
.args .args
.iter() .iter()
.enumerate() .enumerate()
.fold(quote!(), |mut args, (i, arg)| { .fold(quote!(), |args, (i, arg)| {
// if first arg is `const`, then it should be immutable // if first arg is `const`, then it should be immutable
let next_arg = if i == 0 { let next_arg = if i == 0 {
if arg.get_type().is_const() { if arg.get_type().is_const() {
@ -99,7 +133,7 @@ impl Rusty for LvFunc {
.args .args
.iter() .iter()
.enumerate() .enumerate()
.fold(quote!(), |mut args, (i, arg)| { .fold(quote!(), |args, (i, arg)| {
// if first arg is `const`, then it should be immutable // if first arg is `const`, then it should be immutable
let next_arg = if i == 0 { let next_arg = if i == 0 {
quote!(self.core.raw()?.as_mut()) quote!(self.core.raw()?.as_mut())
@ -169,7 +203,7 @@ impl LvArg {
impl Rusty for LvArg { impl Rusty for LvArg {
type Parent = LvFunc; type Parent = LvFunc;
fn code(&self, parent: &Self::Parent) -> WrapperResult<TokenStream> { fn code(&self, _parent: &Self::Parent) -> WrapperResult<TokenStream> {
let name = format_ident!("{}", self.name.as_str()); let name = format_ident!("{}", self.name.as_str());
let typ = self.typ.code(self)?; let typ = self.typ.code(self)?;
Ok(quote! { Ok(quote! {
@ -236,6 +270,10 @@ impl CodeGen {
Ok(Self { functions, widgets }) Ok(Self { functions, widgets })
} }
pub fn get_widgets(&self) -> &Vec<LvWidget> {
&self.widgets
}
fn extract_widgets(functions: &Vec<LvFunc>) -> CGResult<Vec<LvWidget>> { fn extract_widgets(functions: &Vec<LvFunc>) -> CGResult<Vec<LvWidget>> {
let widget_names = Self::get_widget_names(functions); let widget_names = Self::get_widget_names(functions);
@ -393,4 +431,65 @@ mod test {
assert_eq!(code.to_string(), expected_code.to_string()); assert_eq!(code.to_string(), expected_code.to_string());
} }
#[test]
fn generate_basic_widget_code() {
let arc_widget = LvWidget {
name: "arc".to_string(),
methods: vec![],
};
let code = arc_widget.code(&()).unwrap();
let expected_code = quote! {
define_object!(Arc);
impl Arc {
}
};
assert_eq!(code.to_string(), expected_code.to_string());
}
#[test]
fn generate_widget_with_constructor_code() {
// lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy);
let arc_create = LvFunc::new(
"lv_arc_create".to_string(),
vec![
LvArg::new("par".to_string(), LvType::new("lv_obj_t *".to_string())),
LvArg::new(
"copy".to_string(),
LvType::new("const lv_obj_t *".to_string()),
),
],
Some(LvType::new("lv_obj_t *".to_string())),
);
let arc_widget = LvWidget {
name: "arc".to_string(),
methods: vec![arc_create],
};
let code = arc_widget.code(&()).unwrap();
let expected_code = quote! {
define_object!(Arc);
impl Arc {
pub fn new<C>(parent: &mut C) -> crate::LvResult<Self>
where
C: crate::NativeObject,
{
unsafe {
let ptr = lvgl_sys::lv_arc_create(parent.raw()?.as_mut(), core::ptr::null_mut());
let raw = core::ptr::NonNull::new(ptr)?;
let core = <crate::Obj as crate::Widget>::from_raw(raw);
Ok(Self { core })
}
}
}
};
assert_eq!(code.to_string(), expected_code.to_string());
}
} }

19
lvgl-codegen/src/main.rs Normal file
View file

@ -0,0 +1,19 @@
use lvgl_codegen::{CodeGen, Rusty};
use proc_macro2::TokenStream;
use quote::quote;
fn main() {
let codegen = CodeGen::new().unwrap();
let widgets_impl: Vec<TokenStream> = codegen
.get_widgets()
.iter()
.flat_map(|w| w.code(&()))
.collect();
let code = quote! {
#(#widgets_impl)*
};
println!("{}", code.to_string());
}

View file

@ -1 +0,0 @@
define_object!(Btn, lv_btn_create);