Cleanup rust-hl-lua-modules

master
Tomaka17 2014-07-13 12:38:58 +02:00
parent 912cd1442d
commit f064828575
1 changed files with 97 additions and 71 deletions

View File

@ -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<ast::MetaItem>, input_item: Gc<ast::Item>)
-> Gc<ast::Item>
{
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<String> = {
let mut moduleHandlerBody = Vec::new();
// creating an array of the statements to add to the main Lua entry point
let module_handler_body: Vec<Gc<ast::Stmt>> = {
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
}