From f0648285752e66648f17ad056d2da35a75fc672b Mon Sep 17 00:00:00 2001 From: Tomaka17 Date: Sun, 13 Jul 2014 12:38:58 +0200 Subject: [PATCH] Cleanup rust-hl-lua-modules --- .../src/rust-hl-lua-modules.rs | 168 ++++++++++-------- 1 file changed, 97 insertions(+), 71 deletions(-) diff --git a/rust-hl-lua-modules/src/rust-hl-lua-modules.rs b/rust-hl-lua-modules/src/rust-hl-lua-modules.rs index fb5eb57..aef789a 100644 --- a/rust-hl-lua-modules/src/rust-hl-lua-modules.rs +++ b/rust-hl-lua-modules/src/rust-hl-lua-modules.rs @@ -1,4 +1,5 @@ #![feature(plugin_registrar)] +#![feature(quote)] extern crate rustc; extern crate syntax; @@ -6,6 +7,7 @@ extern crate syntax; use std::gc::{GC, Gc}; use syntax::parse::token; use syntax::ast; +use syntax::ext::build::AstBuilder; use syntax::ext::base; use syntax::ext::quote::rt::ToSource; use syntax::codemap; @@ -20,124 +22,148 @@ pub fn plugin_registrar(reg: &mut ::rustc::plugin::Registry) { pub fn expand_lua_module(ecx: &mut base::ExtCtxt, span: codemap::Span, _: Gc, input_item: Gc) -> Gc { + let ecx: &base::ExtCtxt = &*ecx; + // checking that the input item is a module let module = match input_item.node { ast::ItemMod(ref module) => module, _ => { - ecx.span_err(input_item.span, "`export_lua_module` extension is only allowed on modules"); + ecx.span_err(input_item.span, + "`export_lua_module` extension is only allowed on modules"); return input_item } }; // creating the new item that will be returned by the function // it is just a clone of the input with more elements added to it - let mut newItem = input_item.deref().clone(); - newItem.vis = ast::Public; + let mut new_item = input_item.deref().clone(); + new_item.vis = ast::Public; if input_item.vis != ast::Public { - ecx.span_warn(input_item.span, "`export_lua_module` will turn the module into a public module"); + ecx.span_warn(input_item.span, + "`export_lua_module` will turn the module into a public module"); } - // creating an array of the lines of code to add to the main Lua entry point - let moduleHandlerBody: Vec = { - let mut moduleHandlerBody = Vec::new(); + // creating an array of the statements to add to the main Lua entry point + let module_handler_body: Vec> = { + let mut module_handler_body = Vec::new(); for moditem in module.items.iter() { let moditem_name = moditem.ident.to_source(); match moditem.node { - ast::ItemFn(..) | ast::ItemStatic(..) => - moduleHandlerBody.push(format!(r#" - table.set("{0}".to_string(), {0}); - "#, moditem_name)), + ast::ItemFn(..) | ast::ItemStatic(..) => { + let moditem_name_slice = moditem_name.as_slice(); + let moditem_name_item = ecx.ident_of(moditem_name_slice); + module_handler_body.push( + quote_stmt!(&*ecx, + table.set($moditem_name_slice.to_string(), $moditem_name_item); + ) + ) + }, _ => { ecx.span_warn(moditem.span, - format!("item `{}` is neiter a function nor a static and will thus be ignored by `export_lua_module`", + format!("item `{}` is neiter a function nor a static + and will thus be ignored by `export_lua_module`", moditem_name).as_slice()); continue } }; } - moduleHandlerBody + module_handler_body }; // adding extern crate declarations { - let generatedCodeContent = format!(r#" - mod x {{ + let view_items = quote_item!(ecx, + mod x { extern crate lua = "rust-hl-lua"; extern crate libc; - }} - "#); - - // creating a new Rust parser from this - let mut parser = ::syntax::parse::new_parser_from_source_str(ecx.parse_sess(), ecx.cfg(), "".to_string(), generatedCodeContent); - - // getting all the items defined inside "generateCodeContent" - match parser.parse_item_with_outer_attributes() { - None => (), - Some(m) => { - let m = match m.node { - ast::ItemMod(ref m) => m, - _ => { ecx.span_err(span, "internal error in the library"); return input_item; } - }; - - let ref mut mutNewItem = match &mut newItem.node { - &ast::ItemMod(ref mut m) => m, - _ => { ecx.span_err(span, "internal error in the library"); return input_item; } - }; - - for i in m.view_items.iter() { - mutNewItem.view_items.unshift(i.clone()) - } } - } + ); - if !parser.eat(&token::EOF) { - ecx.span_err(input_item.span, "internal error in the library"); - return input_item; + let view_items = match view_items { + Some(a) => a, + None => { + ecx.span_err(input_item.span, + "internal error in the library (could not parse view items)"); + return input_item; + } + }; + + // getting all the items + let view_items = match view_items.node { + ast::ItemMod(ref m) => m, + _ => { ecx.span_err(span, "internal error in the library"); return input_item; } + }; + + let ref mut mut_new_item = match &mut new_item.node { + &ast::ItemMod(ref mut m) => m, + _ => { ecx.span_err(span, "internal error in the library"); return input_item; } + }; + + for i in view_items.view_items.iter() { + mut_new_item.view_items.unshift(i.clone()) } } - // generating the source code that we will add inside the module + // generating the function that we will add inside the module { - let generatedCodeContent = format!(r#" + let function_body = { + let mut function_body = Vec::new(); + + function_body.push(quote_stmt!(ecx, + let mut lua = self::lua::Lua::from_existing_state(lua, false); + )); + + function_body.push(quote_stmt!(ecx, + let mut table = lua.load_new_table(); + )); + + function_body.push_all_move(module_handler_body); + + function_body.push(quote_stmt!(ecx, + ::std::mem::forget(table); + )); + + ecx.block(span.clone(), function_body, Some( + quote_expr!(ecx, 1) + )) + }; + + // identifier for "luaopen_mylib" + let luaopen_id = ecx.ident_of(format!("luaopen_{}", input_item.ident.to_source()) + .as_slice()); + + // building the function itself + let function = quote_item!(ecx, #[no_mangle] - pub extern "C" fn luaopen_{0}(lua: *mut self::libc::c_void) -> self::libc::c_int {{ + pub extern "C" fn $luaopen_id(lua: *mut self::libc::c_void) -> self::libc::c_int {{ unsafe {{ - let mut lua = self::lua::Lua::from_existing_state(lua, false); - let mut table = lua.load_new_table(); - - {1} - - ::std::mem::forget(table); - 1 + $function_body }} }} - "#, input_item.ident.to_source(), moduleHandlerBody.connect("\n")); + ); - // creating a new Rust parser from this - let mut parser = ::syntax::parse::new_parser_from_source_str(ecx.parse_sess(), ecx.cfg(), "".to_string(), generatedCodeContent); - - // getting all the items defined inside "generateCodeContent" - loop { - match parser.parse_item_with_outer_attributes() { - None => break, - Some(i) => match &mut newItem.node { - // moving them into "newItem" - &ast::ItemMod(ref mut m) => m.items.push(i), - _ => { ecx.span_err(span, "internal error in the library"); return input_item; } - } + let function = match function { + Some(f) => f, + None => { + ecx.span_err(input_item.span, + "internal error in the library (could not parse function body)"); + return input_item; } - } + }; - if !parser.eat(&token::EOF) { - ecx.span_err(input_item.span, "internal error in the library"); - return input_item; - } + // adding the function to the module + match &mut new_item.node { + &ast::ItemMod(ref mut m) => { + m.items.push(function) + }, + _ => { ecx.span_err(span, "internal error in the library"); return input_item; } + }; } // returning - box(GC) newItem + box(GC) new_item }