view src/python_symtable.rs @ 96:20c1c9d7803d default tip

Fix dump failure in strings containing backquotes and double quotes.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 28 Jun 2016 01:40:55 +0100
parents 4e62a8927dcc
children
line wrap: on
line source

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