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))
+}