Mercurial > python-compiler.rs
changeset 90:4e62a8927dcc
Add a symtable module, to obtain information about symbols.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Thu, 23 Jun 2016 03:16:59 +0100 |
parents | 898876834564 |
children | 859d44f143b8 |
files | src/main.rs src/python_symtable.rs |
diffstat | 2 files changed, 195 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod tests; mod python_tb; mod python_parse; mod python_ast; +mod python_symtable; mod ast_convert; mod ast_dump; //mod ast_scope; @@ -39,7 +40,7 @@ fn main() { code }; - let module = match python_parse::parse_ast(code) { + let module = match python_parse::parse_ast(code.clone()) { Ok(module) => module, Err(err) => { // TODO: use stderr instead. @@ -49,6 +50,17 @@ fn main() { } }; + let symtable = match python_symtable::generate_symtable(code, &filename) { + Ok(symtable) => symtable, + Err(err) => { + // TODO: use stderr instead. + println!("Error while parsing file “{}”:", filename); + python_tb::traceback(err); + std::process::exit(4); + } + }; + println!("{:#?}", symtable); + let module_ast = ast_convert::convert_ast("__main__".to_string(), &module); println!("{}", ast_dump::dump_ast(&module_ast)); //let scoped_ast = ast_scope::scope_ast(vec!(module_ast));
new file mode 100644 --- /dev/null +++ b/src/python_symtable.rs @@ -0,0 +1,182 @@ +use cpython::{Python, PyObject, PyErr, NoArgs}; +use cpython::ObjectProtocol; //for call method + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum Type { + Module, + Class, + Function +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct SymbolTable { + pub type_: Type, + pub id: usize, + pub name: String, + pub lineno: usize, + pub optimized: bool, + pub nested: bool, + pub has_exec: bool, + pub identifiers: Vec<String>, + pub symbols: Vec<Symbol>, + pub children: Vec<SymbolTable> +} + +impl SymbolTable { + fn lookup(self, name: String) -> Option<Symbol> { + for symbol in self.symbols { + if symbol.name == name { + return Some(symbol); + } + } + None + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Symbol { + pub name: String, + pub referenced: bool, + pub imported: bool, + pub parameter: bool, + pub global: bool, + pub declared_global: bool, + pub local: bool, + pub free: bool, + pub assigned: bool, + pub namespaces: Vec<SymbolTable> +} + +fn parse_symbol(py: Python, symbol: PyObject) -> Symbol { + let get_name = symbol.getattr(py, "get_name").unwrap(); + let name = get_name.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let is_referenced = symbol.getattr(py, "is_referenced").unwrap(); + let referenced = is_referenced.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let is_imported = symbol.getattr(py, "is_imported").unwrap(); + let imported = is_imported.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let is_parameter = symbol.getattr(py, "is_parameter").unwrap(); + let parameter = is_parameter.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let is_global = symbol.getattr(py, "is_global").unwrap(); + let global = is_global.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let is_declared_global = symbol.getattr(py, "is_declared_global").unwrap(); + let declared_global = is_declared_global.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let is_local = symbol.getattr(py, "is_local").unwrap(); + let local = is_local.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let is_free = symbol.getattr(py, "is_free").unwrap(); + let free = is_free.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let is_assigned = symbol.getattr(py, "is_assigned").unwrap(); + let assigned = is_assigned.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let is_namespace = symbol.getattr(py, "is_namespace").unwrap(); + let namespace = is_namespace.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let namespaces = if namespace { + let get_namespaces = symbol.getattr(py, "get_namespaces").unwrap(); + let namespaces = get_namespaces.call(py, NoArgs, None).unwrap().iter(py).unwrap(); + let mut new_namespaces = vec!(); + for namespace in namespaces { + let namespace = namespace.unwrap(); + let symtable = parse_symtable(py, namespace); + new_namespaces.push(symtable); + } + new_namespaces + } else { + vec!() + }; + + Symbol{name: name, referenced: referenced, imported: imported, parameter: parameter, global: global, declared_global: declared_global, local: local, free: free, assigned: assigned, namespaces: namespaces} +} + +fn parse_symtable(py: Python, symtable: PyObject) -> SymbolTable { + let get_type = symtable.getattr(py, "get_type").unwrap(); + let type_: String = get_type.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + let type_ = if type_ == "module" { + Type::Module + } else if type_ == "class" { + Type::Class + } else if type_ == "function" { + Type::Function + } else { + unreachable!(); + }; + + let get_id = symtable.getattr(py, "get_id").unwrap(); + let id = get_id.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let get_name = symtable.getattr(py, "get_name").unwrap(); + let name = get_name.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let get_lineno = symtable.getattr(py, "get_lineno").unwrap(); + let lineno = get_lineno.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let is_optimized = symtable.getattr(py, "is_optimized").unwrap(); + let optimized = is_optimized.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let is_nested = symtable.getattr(py, "is_nested").unwrap(); + let nested = is_nested.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let has_children = symtable.getattr(py, "has_children").unwrap(); + let has_children = has_children.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let has_exec = symtable.getattr(py, "has_exec").unwrap(); + let has_exec = has_exec.call(py, NoArgs, None).unwrap().extract(py).unwrap(); + + let identifiers = { + let get_identifiers = symtable.getattr(py, "get_identifiers").unwrap(); + let identifiers = get_identifiers.call(py, NoArgs, None).unwrap().iter(py).unwrap(); + let mut new_identifiers = vec!(); + for identifier in identifiers { + let identifier = identifier.unwrap().extract(py).unwrap(); + new_identifiers.push(identifier); + } + new_identifiers + }; + + let symbols = { + let get_symbols = symtable.getattr(py, "get_symbols").unwrap(); + let symbols = get_symbols.call(py, NoArgs, None).unwrap().iter(py).unwrap(); + let mut new_symbols = vec!(); + for symbol in symbols { + let symbol = symbol.unwrap(); + let symbol = parse_symbol(py, symbol); + new_symbols.push(symbol); + } + new_symbols + }; + + let children = if has_children { + let get_children = symtable.getattr(py, "get_children").unwrap(); + let children = get_children.call(py, NoArgs, None).unwrap().iter(py).unwrap(); + let mut new_children = vec!(); + for child in children { + let child = child.unwrap(); + let child = parse_symtable(py, child); + new_children.push(child); + } + new_children + } else { + vec!() + }; + + SymbolTable{type_: type_, id: id, name: name, lineno: lineno, optimized: optimized, nested: nested, has_exec: has_exec, identifiers: identifiers, symbols: symbols, children: children} +} + +pub fn generate_symtable(code: String, filename: &String) -> Result<SymbolTable, PyErr> { + let gil = Python::acquire_gil(); + let py = gil.python(); + + let symtable_module = py.import("symtable").unwrap(); + let symtable_symtable = symtable_module.get(py, "symtable").unwrap(); + + let symtable = try!(symtable_symtable.call(py, (code, filename, "exec"), None)); + //Ok(symtable) + Ok(parse_symtable(py, symtable)) +}