view src/ast_type.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 94ff501bf336
children
line wrap: on
line source

use python_ast::{Module, Statement, Expr, BinOp};

use std::collections::HashMap;

#[derive(Clone, Debug, PartialEq, Eq)]
enum Type {
    Top(usize),
    Unit,
    Bool,
    Int,
    Str,
    List(Box<Type>),
    Function(Vec<Type>, Vec<Type>),
    Bottom
}

struct TypeVariable {
    id: usize,
    instance: Box<TypeVariable>,
}

trait Visitor<T> {
    fn visit_module(&mut self, module: Module) -> T;
    fn visit_statement(&mut self, statement: Statement) -> T;
    fn visit_expr(&mut self, expr: Expr) -> T;
}

struct Typing {
    environment: Vec<HashMap<String, Type>>,
    next_id: usize,
}

impl Visitor<Type> for Typing {
    fn visit_module(&mut self, module: Module) -> Type {
        println!("{:?}", self.environment);
        for statement in module.statements {
            self.visit_statement(statement);
        }
        println!("{:?}", self.environment);
        Type::Bottom
    }

    fn visit_statement(&mut self, statement: Statement) -> Type {
        match statement {
            Statement::ClassDef(name, classes, body) => {
                Type::Bottom
            },
            Statement::FunctionDef(name, arguments, body) => {
                let mut env = self.environment.pop().unwrap();
                self.environment.push(env.clone());

                let nb_args = arguments.len();
                for expr in arguments {
                    let type_ = self.visit_expr(expr.clone());
                    let name = match expr {
                        Expr::Name(name) => name,
                        _ => panic!()
                    };
                    env.insert(name.clone(), type_.clone());
                }
                self.environment.push(env);

                for statement in body {
                    self.visit_statement(statement);
                }
                self.environment.pop();

                let mut types = Vec::with_capacity(nb_args);
                for _ in 0..nb_args {
                    self.next_id += 1;
                    types.push(Type::Top(self.next_id));
                }
                Type::Bottom
            },
            Statement::Global(_) => {
                Type::Bottom
            },
            Statement::If(test, body, orelse) => {
                self.visit_expr(test);
                for statement in body {
                    self.visit_statement(statement);
                }
                for statement in orelse {
                    self.visit_statement(statement);
                }
                Type::Bottom
            },
            Statement::While(test, body, orelse) => {
                self.visit_expr(test);
                for statement in body {
                    self.visit_statement(statement);
                }
                for statement in orelse {
                    self.visit_statement(statement);
                }
                Type::Bottom
            },
            Statement::For(target, iter, body, orelse) => {
                self.visit_expr(target);
                self.visit_expr(iter);
                for statement in body {
                    self.visit_statement(statement);
                }
                for statement in orelse {
                    self.visit_statement(statement);
                }
                Type::Bottom
            },
            Statement::Assign(targets, value) => {
                let type_ = self.visit_expr(value);
                if targets.len() != 1 {
                    panic!();
                }
                println!("{:?}", self.environment.clone());
                let mut env = self.environment.pop().unwrap();
                for target in targets {
                    let name = match target {
                        Expr::Name(name) => name,
                        _ => panic!()
                    };
                    println!("{} => {:?}", name, type_);
                    env.insert(name, type_.clone());
                }
                self.environment.push(env);
                println!("{:?}", self.environment.clone());
                Type::Bottom
            },
            Statement::AugAssign(target, op, value) => {
                let value = self.visit_expr(value);
                let target = self.visit_expr(target);
                Type::Bottom
            },
            Statement::Return(expr) => {
                self.visit_expr(expr)
            },
            Statement::ImportFrom(module, names) => {
                for alias in names {
                    self.visit_expr(alias);
                }
                Type::Bottom
            },
            Statement::Expr(expr) => {
                self.visit_expr(expr)
            },
            Statement::Break => {
                Type::Bottom
            },
            Statement::Error => {
                println!("Statement::Error");
                panic!()
            },
        }
    }

    fn visit_expr(&mut self, expr: Expr) -> Type {
        let expr_str = format!("{:?}", expr);
        let type_ = match expr {
            Expr::UnaryOp(op, operand) => {
                let type_operand = self.visit_expr(*operand);
                type_operand
            },
            Expr::BinOp(left, op, right) => {
                let type_left = self.visit_expr(*left);
                let type_right = self.visit_expr(*right);

                if op == BinOp::BinMult && type_left == Type::Str && type_right == Type::Int {
                    return Type::Str;
                }

                if type_left != type_right {
                    return Type::Bottom;
                }
                if op == BinOp::BinAdd || op == BinOp::BinMult {
                    if type_left == Type::Int {
                        Type::Int
                    } else if type_left == Type::Str {
                        Type::Str
                    } else {
                        Type::Bottom
                    }
                } else if op == BinOp::BinEq || op == BinOp::BinLt {
                    Type::Bool
                } else {
                    Type::Bottom
                }
            },
            Expr::Compare(_, _, _) => Type::Bool,
            Expr::Call(func, args) => {
                let func = *func;
                let func = match func {
                    Expr::Name(arg) => arg,
                    _ => panic!()
                };
                let mut types = vec!();
                for expr in args {
                    let type_ = self.visit_expr(expr);
                    types.push(type_);
                }
                println!("types: {:?}", types);
                let env = match self.environment.pop() {
                    Some(env) => env,
                    None => return Type::Bottom
                };
                if env.contains_key(&func) {
                    let value = env.get(&func).unwrap().clone();
                    self.environment.push(env);
                    value
                } else {
                    self.environment.push(env);
                    Type::Bottom
                }
            },
            Expr::Alias(_, _) => Type::Bottom,
            Expr::Attribute(lhs, rhs) => {
                let type_left = self.visit_expr(*lhs);
                println!("coucou {:?}", type_left);
                Type::Bottom
            },
            Expr::Name(id) => {
                let env = match self.environment.pop() {
                    Some(env) => env,
                    None => return Type::Bottom
                };
                if env.contains_key(&id) {
                    let value = env.get(&id).unwrap().clone();
                    self.environment.push(env);
                    value
                } else {
                    self.environment.push(env);
                    self.next_id += 1;
                    Type::Top(self.next_id)
                }
            },
            Expr::NameConstant(value) => {
                if value == "True" || value == "False" {
                    Type::Bool
                } else if value == "None" {
                    Type::Unit
                } else {
                    Type::Bottom
                }
            },
            Expr::Str(_) => Type::Str,
            Expr::Num(_) => Type::Int,
            Expr::List(_) => Type::List(Box::new(Type::Bottom)),
            Expr::Error => {
                println!("Expr::Error");
                panic!()
            }
        };
        println!("{} => {:?}", expr_str, type_);
        type_
    }
}

#[allow(dead_code)]
pub fn type_ast(ast: Module) {
    let mut environment = HashMap::new();
    environment.insert("int".to_string(), Type::Int);
    environment.insert("__name__".to_string(), Type::Str);
    environment.insert("print".to_string(), Type::Unit);
    let mut typing = Typing{environment: vec!(environment), next_id: 0};
    typing.visit_module(ast);
}