Cleanup rust-hl-lua-modules

This commit is contained in:
Tomaka17 2014-07-13 12:38:58 +02:00
parent 912cd1442d
commit f064828575

View File

@ -1,4 +1,5 @@
#![feature(plugin_registrar)] #![feature(plugin_registrar)]
#![feature(quote)]
extern crate rustc; extern crate rustc;
extern crate syntax; extern crate syntax;
@ -6,6 +7,7 @@ extern crate syntax;
use std::gc::{GC, Gc}; use std::gc::{GC, Gc};
use syntax::parse::token; use syntax::parse::token;
use syntax::ast; use syntax::ast;
use syntax::ext::build::AstBuilder;
use syntax::ext::base; use syntax::ext::base;
use syntax::ext::quote::rt::ToSource; use syntax::ext::quote::rt::ToSource;
use syntax::codemap; 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<ast::MetaItem>, input_item: Gc<ast::Item>) pub fn expand_lua_module(ecx: &mut base::ExtCtxt, span: codemap::Span, _: Gc<ast::MetaItem>, input_item: Gc<ast::Item>)
-> Gc<ast::Item> -> Gc<ast::Item>
{ {
let ecx: &base::ExtCtxt = &*ecx;
// checking that the input item is a module // checking that the input item is a module
let module = match input_item.node { let module = match input_item.node {
ast::ItemMod(ref module) => module, 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 return input_item
} }
}; };
// creating the new item that will be returned by the function // 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 // it is just a clone of the input with more elements added to it
let mut newItem = input_item.deref().clone(); let mut new_item = input_item.deref().clone();
newItem.vis = ast::Public; new_item.vis = ast::Public;
if input_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 // creating an array of the statements to add to the main Lua entry point
let moduleHandlerBody: Vec<String> = { let module_handler_body: Vec<Gc<ast::Stmt>> = {
let mut moduleHandlerBody = Vec::new(); let mut module_handler_body = Vec::new();
for moditem in module.items.iter() { for moditem in module.items.iter() {
let moditem_name = moditem.ident.to_source(); let moditem_name = moditem.ident.to_source();
match moditem.node { match moditem.node {
ast::ItemFn(..) | ast::ItemStatic(..) => ast::ItemFn(..) | ast::ItemStatic(..) => {
moduleHandlerBody.push(format!(r#" let moditem_name_slice = moditem_name.as_slice();
table.set("{0}".to_string(), {0}); let moditem_name_item = ecx.ident_of(moditem_name_slice);
"#, moditem_name)), module_handler_body.push(
quote_stmt!(&*ecx,
table.set($moditem_name_slice.to_string(), $moditem_name_item);
)
)
},
_ => { _ => {
ecx.span_warn(moditem.span, 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()); moditem_name).as_slice());
continue continue
} }
}; };
} }
moduleHandlerBody module_handler_body
}; };
// adding extern crate declarations // adding extern crate declarations
{ {
let generatedCodeContent = format!(r#" let view_items = quote_item!(ecx,
mod x {{ mod x {
extern crate lua = "rust-hl-lua"; extern crate lua = "rust-hl-lua";
extern crate libc; 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) { let view_items = match view_items {
ecx.span_err(input_item.span, "internal error in the library"); Some(a) => a,
return input_item; 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] #[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 {{ unsafe {{
let mut lua = self::lua::Lua::from_existing_state(lua, false); $function_body
let mut table = lua.load_new_table();
{1}
::std::mem::forget(table);
1
}} }}
}} }}
"#, input_item.ident.to_source(), moduleHandlerBody.connect("\n")); );
// creating a new Rust parser from this let function = match function {
let mut parser = ::syntax::parse::new_parser_from_source_str(ecx.parse_sess(), ecx.cfg(), "".to_string(), generatedCodeContent); Some(f) => f,
None => {
// getting all the items defined inside "generateCodeContent" ecx.span_err(input_item.span,
loop { "internal error in the library (could not parse function body)");
match parser.parse_item_with_outer_attributes() { return input_item;
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; }
}
} }
} };
if !parser.eat(&token::EOF) { // adding the function to the module
ecx.span_err(input_item.span, "internal error in the library"); match &mut new_item.node {
return input_item; &ast::ItemMod(ref mut m) => {
} m.items.push(function)
},
_ => { ecx.span_err(span, "internal error in the library"); return input_item; }
};
} }
// returning // returning
box(GC) newItem box(GC) new_item
} }