<commit_before>use std::cell::{Cell, Ref, RefCell, RefMut};
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;

use super::super::super::frontend::Module as FrontendModule;
use super::super::super::type_ast::{self as ast};
use super::super::path_to_name::path_to_name;
use super::super::vecs_equal::vecs_equal;
use super::typ::{RealType, TupleType, Type};
use super::typer::Typer;
use super::value::{AbstractValue, FuncValue, LocalValue, StaticValue, Value, ValueId};
use super::{Container, Func, Module, Root};

pub struct BasicBlockManager {
    next_value_id: Cell<usize>,
    current_index: Cell<Option<usize>>,
    pub basic_blocks: RefCell<Vec<BasicBlock>>,
}

// Pointer to a basic block.
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct BasicBlockIndex(usize);

impl BasicBlockManager {
    pub fn new() -> Self {
        Self {
            next_value_id: Cell::new(0),
            current_index: Cell::new(None),
            basic_blocks: RefCell::new(vec![]),
        }
    }

    fn append_basic_block(&self, name: Option<&str>) -> BasicBlockIndex {
        let name = name.unwrap_or("block");
        let index = self.basic_blocks.borrow().len();
        let name = format!("{}{}", name, index);
        let mut basic_blocks = self.basic_blocks.borrow_mut();
        basic_blocks.push(BasicBlock {
            index,
            name,
            instructions: vec![],
        });
        self.current_index.set(Some(index));
        BasicBlockIndex(index)
    }

    fn current_index(&self) -> BasicBlockIndex {
        BasicBlockIndex(self.current_index.get().unwrap())
    }

    fn position_at_end(&self, index: BasicBlockIndex) {
        let index = index.0;
        self.current_index.set(Some(index));
    }

    fn push_instruction(&self, instruction: Instruction) {
        let index = self.current_index.get().expect("No basic blocks");
        let mut basic_block = RefMut::map(self.basic_blocks.borrow_mut(), |basic_blocks| {
            &mut basic_blocks[index]
        });
        basic_block.instructions.push(instruction);
    }

    fn get_next_value_id(&self) -> ValueId {
        let current = self.next_value_id.take();
        self.next_value_id.set(current + 1);
        ValueId::new(current)
    }
}

pub fn compile_modules<'m, M: Iterator<Item = &'m FrontendModule>>(
    frontend_modules: M,
    entry_frontend_module: &FrontendModule,
) -> Root {
    let typer = Typer::new(None);
    let root = Root::new(typer.clone());

    // TODO: Build a root `TypeScope` will all the builtins.

    for frontend_module in frontend_modules {
        define_module(frontend_module, root.clone());
    }

    // Find and compile the main func.
    let entry = root.find_module_by_id(entry_frontend_module.id()).unwrap();
    let main_func = entry
        .find_func_by_name("main")
        .expect("Missing 'main' func");

    if !is_immediately_specializable(&main_func) {
        panic!("Main func cannot be specialized");
    }
    let ast_func = &main_func.0.ast_func;
    let parameters = ast_func
        .arguments
        .iter()
        .map(|argument| typer.build_type(&argument.typ))
        .collect::<Vec<_>>();
    let retrn = typer.build_type(&ast_func.typ.unwrap_func().retrn.borrow());
    let func_value = compile_func_specialization(main_func, parameters, retrn);
    // Mark is as the main func for the target compiler.
    func_value.set_main(true);

    root
}

fn compile_func_specialization(func: Func, parameters: Vec<Type>, retrn: Type) -> FuncValue {
    // Ensure all the parameters are real types.
    let parameters = parameters
        .into_iter()
        .map(|parameter| parameter.into_real())
        .collect::<Vec<_>>();
    let retrn = retrn.into_real();

    let func_value = func.get_or_insert_specialization(parameters, retrn);

    // `create_basic_blocks` returns a `Some` if it just created the basic
    // block manager (indicating this specialization hasn't been compiled).
    if let Some(basic_blocks) = func_value.create_basic_blocks() {
        let builder = Builder {
            buildable: Box::new(func_value.clone()),
            basic_blocks,
        };
        compile_func_body(&builder, func_value.clone(), &func.0.ast_func.body);
    }

    func_value
}

// Abstraction so that we can compile both funcs and closures with the
// same functions.
pub trait Buildable: Container {
    /// Search for a func defined within this scope (including the
    /// current func).
    fn find_func(&self, name: &str) -> Option<Func>;

    fn find_local(&self, name: &str) -> Option<(usize, RealType)>;

    fn build_type(&self, ast_type: &ast::Type) -> Type {
        self.get_typer().build_type(ast_type)
    }
}

struct Builder<'a> {
    buildable: Box<dyn Buildable>,
    basic_blocks: Ref<'a, BasicBlockManager>,
}

impl<'a> Builder<'a> {
    fn define_func(&self, ast_func: ast::Func) -> Func {
        self.buildable.define_func(ast_func)
    }

    fn find_func(&self, name: &str) -> Option<Func> {
        self.buildable.find_func(name)
    }

    fn find_local(&self, name: &str) -> Option<(usize, RealType)> {
        self.buildable.find_local(name)
    }

    fn build_type(&self, ast_type: &ast::Type) -> Type {
        self.buildable.get_typer().build_type(ast_type)
    }

    fn build_value(&self, typ: Type) -> Value {
        match typ {
            Type::Real(real_type) => match real_type {
                RealType::FuncPtr(func_ptr_type) => {
                    Value::Local(LocalValue::FuncPtr(self.get_next_value_id(), func_ptr_type))
                }
                RealType::Int64 => Value::Local(LocalValue::Int64(self.get_next_value_id(), None)),
                RealType::Tuple(tuple_type) => {
                    Value::Local(LocalValue::Tuple(self.get_next_value_id(), tuple_type))
                }
            },
            _ => unreachable!("Cannot build an SSA Value for an Abstract type"),
        }
    }

    fn append_basic_block(&self, name: Option<&str>) -> BasicBlockIndex {
        self.basic_blocks.append_basic_block(name)
    }

    fn get_next_value_id(&self) -> ValueId {
        self.basic_blocks.get_next_value_id()
    }

    fn push_instruction(&self, instruction: Instruction) {
        self.basic_blocks.push_instruction(instruction);
    }

    fn const_unit(&self) -> Value {
        let id = self.get_next_value_id();
        Value::Local(LocalValue::Tuple(id, TupleType::unit()))
    }

    fn const_int64(&self, const_value: u64) -> Value {
        let id = self.get_next_value_id();
        Value::Local(LocalValue::Int64(id, Some(const_value)))
    }

    fn build_call_func(
        &self,
        retrn: RealType,
        func_value: FuncValue,
        arguments: Vec<Value>,
    ) -> Value {
        let retrn = self.build_value(Type::Real(retrn));
        self.push_instruction(Instruction::CallFunc(retrn.clone(), func_value, arguments));
        retrn
    }

    fn build_call_func_ptr(
        &self,
        retrn: RealType,
        value: LocalValue,
        arguments: Vec<Value>,
    ) -> Value {
        let retrn = self.build_value(Type::Real(retrn));
        self.push_instruction(Instruction::CallFuncPtr(retrn.clone(), value, arguments));
        retrn
    }

    fn build_get_local(&self, index: usize, real_type: RealType) -> Value {
        let value = self.build_value(Type::Real(real_type));
        self.push_instruction(Instruction::GetLocal(value.clone(), index));
        value
    }

    fn build_return(&self, value: Value) {
        self.push_instruction(Instruction::Return(value));
    }
}

fn compile_func_body(builder: &Builder, func_value: FuncValue, body: &ast::FuncBody) {
    builder.append_basic_block(Some("entry"));
    let implicit_retrn = match body {
        ast::FuncBody::Block(block) => compile_block(builder, block),
    };
    builder.build_return(implicit_retrn);
}

fn compile_block(builder: &Builder, block: &ast::Block) -> Value {
    // Implicit return is the unit tuple or the value produced by the
    // last statement.
    let mut implicit_value = builder.const_unit();
    if !block.statements.is_empty() {
        let last_index = block.statements.len() - 1;
        for (index, statement) in block.statements.iter().enumerate() {
            let value = match statement {
                ast::BlockStatement::Expression(expression) => {
                    compile_expression(builder, expression)
                }
                ast::BlockStatement::Func(func) => {
                    let func = builder.define_func(func.clone());
                    Value::Abstract(AbstractValue::UnspecializedFunc(func))
                }
                other @ _ => unreachable!("Cannot compile BlockStatement: {:?}", other),
            };
            if index == last_index {
                implicit_value = value
            }
        }
    }

    implicit_value
}

fn compile_expression(builder: &Builder, expression: &ast::Expression) -> Value {
    match expression {
        ast::Expression::Identifier(identifier) => compile_identifier(builder, identifier),
        ast::Expression::LiteralInt(literal) => builder.const_int64(literal.value as u64),
        ast::Expression::PostfixCall(call) => compile_postfix_call(builder, call),
        other @ _ => unreachable!("Cannot compile Expression: {:?}", other),
    }
}

fn compile_identifier(builder: &Builder, identifier: &ast::Identifier) -> Value {
    let resolution = &identifier.resolution;
    match resolution {
        ast::ScopeResolution::Local(name, ast_typ) => {
            // First search for funcs defined in this func.
            if let Some(func) = builder.find_func(name) {
                // Use the type expected by the AST to preemptively specialize
                // if possible.
                if !ast_typ.contains_generics() {
                    // Using `unwrap` since this type better be callable,
                    // otherwise we have a huge problem in typing.
                    let (ast_parameters, ast_retrn) = ast_typ.maybe_callable().unwrap();
                    let parameters = ast_parameters
                        .iter()
                        .map(|ast_parameter| builder.build_type(ast_parameter))
                        .collect::<Vec<_>>();
                    let retrn = builder.build_type(&ast_retrn);
                    let func_value = compile_func_specialization(func, parameters, retrn);
                    return Value::Static(StaticValue::Func(func_value));
                }
                return Value::Abstract(AbstractValue::UnspecializedFunc(func));
            }
            // Then search for a slot in the stack frame.
            if let Some((index, typ)) = builder.find_local(name) {
                return builder.build_get_local(index, typ);
            }
            panic!("Local not found: {}", name)
        }
        other @ _ => unreachable!(
            "Cannot compile Identifier with ScopeResolution: {:?}",
            other
        ),
    }
}

fn compile_postfix_call(builder: &Builder, call: &ast::PostfixCall) -> Value {
    let target = compile_expression(builder, &call.target);
    let arguments = call
        .arguments
        .iter()
        .map(|argument| compile_expression(builder, argument))
        .collect::<Vec<_>>();
    // TODO: Sanity-check that the types of the values match the types
    //   built from the AST.
    let retrn_type = builder.build_type(&call.typ);
    match target {
        Value::Abstract(abstract_value) => match abstract_value {
            AbstractValue::UnspecializedFunc(func) => {
                let arguments_types = arguments
                    .iter()
                    .map(|argument| argument.typ())
                    .collect::<Vec<_>>();
                return compile_unspecialized_call(
                    builder,
                    func,
                    arguments,
                    arguments_types,
                    retrn_type,
                );
            }
        },
        Value::Static(static_value) => match static_value {
            StaticValue::Func(func_value) => {
                let retrn = func_value.get_retrn();
                return builder.build_call_func(retrn, func_value, arguments);
            }
        },
        Value::Local(local_value) => match &local_value {
            LocalValue::FuncPtr(value, func_ptr_type) => {
                // Converting these to real types because func pointers must
                // be callable with real (non-generic) types.
                let parameters = arguments
                    .iter()
                    .map(|argument| argument.typ().into_real())
                    .collect::<Vec<_>>();
                let retrn = retrn_type.into_real();

                let parameters_match =
                    vecs_equal(&parameters, &func_ptr_type.parameters, RealType::is_equal);
                if !parameters_match {
                    panic!("Tried calling function pointer but parameter types don't match\nexpected: {:?}\ngot: {:?}",
                        func_ptr_type.parameters,
                        parameters,
                    );
                }
                if !retrn.is_equal(&func_ptr_type.retrn) {
                    panic!("Tried calling function pointer but return types don't match\nexpected: {:?}\ngot: {:?}",
                        func_ptr_type.retrn,
                        parameters,
                    );
                }

                return builder.build_call_func_ptr(retrn, local_value, arguments);
            }
            _ => (),
        },
    }
    unreachable!("Cannot compile Call")
}

fn compile_unspecialized_call(
    builder: &Builder,
    func: Func,
    arguments: Vec<Value>,
    arguments_types: Vec<Type>,
    retrn_type: Type,
) -> Value {
    let func_value = compile_func_specialization(func, arguments_types, retrn_type);
    let retrn = func_value.get_retrn();
    builder.build_call_func(retrn, func_value, arguments)
}

fn define_module(frontend_module: &FrontendModule, root: Root) -> Module {
    let qualified_name = path_to_name(frontend_module.path());
    let module = root.add_module(frontend_module.id(), qualified_name);
    // Walk the AST to forward-define all of the funcs.
    let ast_module = frontend_module.unwrap_ast();
    for statement in ast_module.statements.iter() {
        match statement {
            ast::ModuleStatement::Func(ast_func) => {
                module.define_func(ast_func.clone());
            }
        }
    }
    module
}

fn is_immediately_specializable(func: &Func) -> bool {
    let ast_typ = &func.0.ast_func.typ;
    ast_typ.unwrap_func(); // Assert that it's a func type.
    !ast_typ.contains_generics()
}

pub struct BasicBlock {
    index: usize,
    pub name: String,
    pub instructions: Vec<Instruction>,
}

impl BasicBlock {
    pub fn get_index(&self) -> BasicBlockIndex {
        BasicBlockIndex(self.index)
    }
}

pub enum Instruction {
    // $1 = $2($3...)
    CallFunc(Value, FuncValue, Vec<Value>),
    // $1 = $2($3...)
    CallFuncPtr(Value, LocalValue, Vec<Value>),
    // $1 = GetLocal($2)
    GetLocal(Value, usize),
    // Return($1)
    Return(Value),
}
<commit_msg>Remove completed TODO<commit_after>use std::cell::{Cell, Ref, RefCell, RefMut};
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;

use super::super::super::frontend::Module as FrontendModule;
use super::super::super::type_ast::{self as ast};
use super::super::path_to_name::path_to_name;
use super::super::vecs_equal::vecs_equal;
use super::typ::{RealType, TupleType, Type};
use super::typer::Typer;
use super::value::{AbstractValue, FuncValue, LocalValue, StaticValue, Value, ValueId};
use super::{Container, Func, Module, Root};

pub struct BasicBlockManager {
    next_value_id: Cell<usize>,
    current_index: Cell<Option<usize>>,
    pub basic_blocks: RefCell<Vec<BasicBlock>>,
}

// Pointer to a basic block.
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct BasicBlockIndex(usize);

impl BasicBlockManager {
    pub fn new() -> Self {
        Self {
            next_value_id: Cell::new(0),
            current_index: Cell::new(None),
            basic_blocks: RefCell::new(vec![]),
        }
    }

    fn append_basic_block(&self, name: Option<&str>) -> BasicBlockIndex {
        let name = name.unwrap_or("block");
        let index = self.basic_blocks.borrow().len();
        let name = format!("{}{}", name, index);
        let mut basic_blocks = self.basic_blocks.borrow_mut();
        basic_blocks.push(BasicBlock {
            index,
            name,
            instructions: vec![],
        });
        self.current_index.set(Some(index));
        BasicBlockIndex(index)
    }

    fn current_index(&self) -> BasicBlockIndex {
        BasicBlockIndex(self.current_index.get().unwrap())
    }

    fn position_at_end(&self, index: BasicBlockIndex) {
        let index = index.0;
        self.current_index.set(Some(index));
    }

    fn push_instruction(&self, instruction: Instruction) {
        let index = self.current_index.get().expect("No basic blocks");
        let mut basic_block = RefMut::map(self.basic_blocks.borrow_mut(), |basic_blocks| {
            &mut basic_blocks[index]
        });
        basic_block.instructions.push(instruction);
    }

    fn get_next_value_id(&self) -> ValueId {
        let current = self.next_value_id.take();
        self.next_value_id.set(current + 1);
        ValueId::new(current)
    }
}

pub fn compile_modules<'m, M: Iterator<Item = &'m FrontendModule>>(
    frontend_modules: M,
    entry_frontend_module: &FrontendModule,
) -> Root {
    let typer = Typer::new(None);
    let root = Root::new(typer.clone());

    for frontend_module in frontend_modules {
        define_module(frontend_module, root.clone());
    }

    // Find and compile the main func.
    let entry = root.find_module_by_id(entry_frontend_module.id()).unwrap();
    let main_func = entry
        .find_func_by_name("main")
        .expect("Missing 'main' func");

    if !is_immediately_specializable(&main_func) {
        panic!("Main func cannot be specialized");
    }
    let ast_func = &main_func.0.ast_func;
    let parameters = ast_func
        .arguments
        .iter()
        .map(|argument| typer.build_type(&argument.typ))
        .collect::<Vec<_>>();
    let retrn = typer.build_type(&ast_func.typ.unwrap_func().retrn.borrow());
    let func_value = compile_func_specialization(main_func, parameters, retrn);
    // Mark is as the main func for the target compiler.
    func_value.set_main(true);

    root
}

fn compile_func_specialization(func: Func, parameters: Vec<Type>, retrn: Type) -> FuncValue {
    // Ensure all the parameters are real types.
    let parameters = parameters
        .into_iter()
        .map(|parameter| parameter.into_real())
        .collect::<Vec<_>>();
    let retrn = retrn.into_real();

    let func_value = func.get_or_insert_specialization(parameters, retrn);

    // `create_basic_blocks` returns a `Some` if it just created the basic
    // block manager (indicating this specialization hasn't been compiled).
    if let Some(basic_blocks) = func_value.create_basic_blocks() {
        let builder = Builder {
            buildable: Box::new(func_value.clone()),
            basic_blocks,
        };
        compile_func_body(&builder, func_value.clone(), &func.0.ast_func.body);
    }

    func_value
}

// Abstraction so that we can compile both funcs and closures with the
// same functions.
pub trait Buildable: Container {
    /// Search for a func defined within this scope (including the
    /// current func).
    fn find_func(&self, name: &str) -> Option<Func>;

    fn find_local(&self, name: &str) -> Option<(usize, RealType)>;

    fn build_type(&self, ast_type: &ast::Type) -> Type {
        self.get_typer().build_type(ast_type)
    }
}

struct Builder<'a> {
    buildable: Box<dyn Buildable>,
    basic_blocks: Ref<'a, BasicBlockManager>,
}

impl<'a> Builder<'a> {
    fn define_func(&self, ast_func: ast::Func) -> Func {
        self.buildable.define_func(ast_func)
    }

    fn find_func(&self, name: &str) -> Option<Func> {
        self.buildable.find_func(name)
    }

    fn find_local(&self, name: &str) -> Option<(usize, RealType)> {
        self.buildable.find_local(name)
    }

    fn build_type(&self, ast_type: &ast::Type) -> Type {
        self.buildable.get_typer().build_type(ast_type)
    }

    fn build_value(&self, typ: Type) -> Value {
        match typ {
            Type::Real(real_type) => match real_type {
                RealType::FuncPtr(func_ptr_type) => {
                    Value::Local(LocalValue::FuncPtr(self.get_next_value_id(), func_ptr_type))
                }
                RealType::Int64 => Value::Local(LocalValue::Int64(self.get_next_value_id(), None)),
                RealType::Tuple(tuple_type) => {
                    Value::Local(LocalValue::Tuple(self.get_next_value_id(), tuple_type))
                }
            },
            _ => unreachable!("Cannot build an SSA Value for an Abstract type"),
        }
    }

    fn append_basic_block(&self, name: Option<&str>) -> BasicBlockIndex {
        self.basic_blocks.append_basic_block(name)
    }

    fn get_next_value_id(&self) -> ValueId {
        self.basic_blocks.get_next_value_id()
    }

    fn push_instruction(&self, instruction: Instruction) {
        self.basic_blocks.push_instruction(instruction);
    }

    fn const_unit(&self) -> Value {
        let id = self.get_next_value_id();
        Value::Local(LocalValue::Tuple(id, TupleType::unit()))
    }

    fn const_int64(&self, const_value: u64) -> Value {
        let id = self.get_next_value_id();
        Value::Local(LocalValue::Int64(id, Some(const_value)))
    }

    fn build_call_func(
        &self,
        retrn: RealType,
        func_value: FuncValue,
        arguments: Vec<Value>,
    ) -> Value {
        let retrn = self.build_value(Type::Real(retrn));
        self.push_instruction(Instruction::CallFunc(retrn.clone(), func_value, arguments));
        retrn
    }

    fn build_call_func_ptr(
        &self,
        retrn: RealType,
        value: LocalValue,
        arguments: Vec<Value>,
    ) -> Value {
        let retrn = self.build_value(Type::Real(retrn));
        self.push_instruction(Instruction::CallFuncPtr(retrn.clone(), value, arguments));
        retrn
    }

    fn build_get_local(&self, index: usize, real_type: RealType) -> Value {
        let value = self.build_value(Type::Real(real_type));
        self.push_instruction(Instruction::GetLocal(value.clone(), index));
        value
    }

    fn build_return(&self, value: Value) {
        self.push_instruction(Instruction::Return(value));
    }
}

fn compile_func_body(builder: &Builder, func_value: FuncValue, body: &ast::FuncBody) {
    builder.append_basic_block(Some("entry"));
    let implicit_retrn = match body {
        ast::FuncBody::Block(block) => compile_block(builder, block),
    };
    builder.build_return(implicit_retrn);
}

fn compile_block(builder: &Builder, block: &ast::Block) -> Value {
    // Implicit return is the unit tuple or the value produced by the
    // last statement.
    let mut implicit_value = builder.const_unit();
    if !block.statements.is_empty() {
        let last_index = block.statements.len() - 1;
        for (index, statement) in block.statements.iter().enumerate() {
            let value = match statement {
                ast::BlockStatement::Expression(expression) => {
                    compile_expression(builder, expression)
                }
                ast::BlockStatement::Func(func) => {
                    let func = builder.define_func(func.clone());
                    Value::Abstract(AbstractValue::UnspecializedFunc(func))
                }
                other @ _ => unreachable!("Cannot compile BlockStatement: {:?}", other),
            };
            if index == last_index {
                implicit_value = value
            }
        }
    }

    implicit_value
}

fn compile_expression(builder: &Builder, expression: &ast::Expression) -> Value {
    match expression {
        ast::Expression::Identifier(identifier) => compile_identifier(builder, identifier),
        ast::Expression::LiteralInt(literal) => builder.const_int64(literal.value as u64),
        ast::Expression::PostfixCall(call) => compile_postfix_call(builder, call),
        other @ _ => unreachable!("Cannot compile Expression: {:?}", other),
    }
}

fn compile_identifier(builder: &Builder, identifier: &ast::Identifier) -> Value {
    let resolution = &identifier.resolution;
    match resolution {
        ast::ScopeResolution::Local(name, ast_typ) => {
            // First search for funcs defined in this func.
            if let Some(func) = builder.find_func(name) {
                // Use the type expected by the AST to preemptively specialize
                // if possible.
                if !ast_typ.contains_generics() {
                    // Using `unwrap` since this type better be callable,
                    // otherwise we have a huge problem in typing.
                    let (ast_parameters, ast_retrn) = ast_typ.maybe_callable().unwrap();
                    let parameters = ast_parameters
                        .iter()
                        .map(|ast_parameter| builder.build_type(ast_parameter))
                        .collect::<Vec<_>>();
                    let retrn = builder.build_type(&ast_retrn);
                    let func_value = compile_func_specialization(func, parameters, retrn);
                    return Value::Static(StaticValue::Func(func_value));
                }
                return Value::Abstract(AbstractValue::UnspecializedFunc(func));
            }
            // Then search for a slot in the stack frame.
            if let Some((index, typ)) = builder.find_local(name) {
                return builder.build_get_local(index, typ);
            }
            panic!("Local not found: {}", name)
        }
        other @ _ => unreachable!(
            "Cannot compile Identifier with ScopeResolution: {:?}",
            other
        ),
    }
}

fn compile_postfix_call(builder: &Builder, call: &ast::PostfixCall) -> Value {
    let target = compile_expression(builder, &call.target);
    let arguments = call
        .arguments
        .iter()
        .map(|argument| compile_expression(builder, argument))
        .collect::<Vec<_>>();
    // TODO: Sanity-check that the types of the values match the types
    //   built from the AST.
    let retrn_type = builder.build_type(&call.typ);
    match target {
        Value::Abstract(abstract_value) => match abstract_value {
            AbstractValue::UnspecializedFunc(func) => {
                let arguments_types = arguments
                    .iter()
                    .map(|argument| argument.typ())
                    .collect::<Vec<_>>();
                return compile_unspecialized_call(
                    builder,
                    func,
                    arguments,
                    arguments_types,
                    retrn_type,
                );
            }
        },
        Value::Static(static_value) => match static_value {
            StaticValue::Func(func_value) => {
                let retrn = func_value.get_retrn();
                return builder.build_call_func(retrn, func_value, arguments);
            }
        },
        Value::Local(local_value) => match &local_value {
            LocalValue::FuncPtr(value, func_ptr_type) => {
                // Converting these to real types because func pointers must
                // be callable with real (non-generic) types.
                let parameters = arguments
                    .iter()
                    .map(|argument| argument.typ().into_real())
                    .collect::<Vec<_>>();
                let retrn = retrn_type.into_real();

                let parameters_match =
                    vecs_equal(&parameters, &func_ptr_type.parameters, RealType::is_equal);
                if !parameters_match {
                    panic!("Tried calling function pointer but parameter types don't match\nexpected: {:?}\ngot: {:?}",
                        func_ptr_type.parameters,
                        parameters,
                    );
                }
                if !retrn.is_equal(&func_ptr_type.retrn) {
                    panic!("Tried calling function pointer but return types don't match\nexpected: {:?}\ngot: {:?}",
                        func_ptr_type.retrn,
                        parameters,
                    );
                }

                return builder.build_call_func_ptr(retrn, local_value, arguments);
            }
            _ => (),
        },
    }
    unreachable!("Cannot compile Call")
}

fn compile_unspecialized_call(
    builder: &Builder,
    func: Func,
    arguments: Vec<Value>,
    arguments_types: Vec<Type>,
    retrn_type: Type,
) -> Value {
    let func_value = compile_func_specialization(func, arguments_types, retrn_type);
    let retrn = func_value.get_retrn();
    builder.build_call_func(retrn, func_value, arguments)
}

fn define_module(frontend_module: &FrontendModule, root: Root) -> Module {
    let qualified_name = path_to_name(frontend_module.path());
    let module = root.add_module(frontend_module.id(), qualified_name);
    // Walk the AST to forward-define all of the funcs.
    let ast_module = frontend_module.unwrap_ast();
    for statement in ast_module.statements.iter() {
        match statement {
            ast::ModuleStatement::Func(ast_func) => {
                module.define_func(ast_func.clone());
            }
        }
    }
    module
}

fn is_immediately_specializable(func: &Func) -> bool {
    let ast_typ = &func.0.ast_func.typ;
    ast_typ.unwrap_func(); // Assert that it's a func type.
    !ast_typ.contains_generics()
}

pub struct BasicBlock {
    index: usize,
    pub name: String,
    pub instructions: Vec<Instruction>,
}

impl BasicBlock {
    pub fn get_index(&self) -> BasicBlockIndex {
        BasicBlockIndex(self.index)
    }
}

pub enum Instruction {
    // $1 = $2($3...)
    CallFunc(Value, FuncValue, Vec<Value>),
    // $1 = $2($3...)
    CallFuncPtr(Value, LocalValue, Vec<Value>),
    // $1 = GetLocal($2)
    GetLocal(Value, usize),
    // Return($1)
    Return(Value),
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! internal class to handle OpenAl context and device.
//!
//! Work as a Singleton, check_al_context must be called before each OpenAl object
//! to be sure that the context is created.

#![macro_use]
#![allow(raw_pointer_derive)]

use std::ffi::CString;
use std::cell::RefCell;
use std::ptr;
use openal::ffi;
use record_context;
use record_context::RecordContext;

thread_local!(static AL_CONTEXT: RefCell<Box<OpenAlData>> = RefCell::new(Box::new(OpenAlData::default())));

#[derive(Clone)]
pub struct OpenAlData {
    pub al_context: ffi::ALCcontextPtr,
    pub al_device: ffi::ALCdevicePtr,
    pub al_capt_device: ffi::ALCdevicePtr
}

impl OpenAlData {
    /// Create a new OpenAlData struct
    ///
    /// Private method.
    fn new() -> Result<OpenAlData, String> {
        let device = unsafe { ffi::alcOpenDevice(ptr::null_mut()) };
        if device == 0 {
            return Err("internal error: cannot open the default device.".to_string());
        }
        let context = unsafe { ffi::alcCreateContext(device, ptr::null_mut()) };
        if context == 0 {
            return Err("internal error: cannot create the OpenAL context.".to_string());
        }
        if unsafe { ffi::alcMakeContextCurrent(context) } == ffi::ALC_FALSE {
            return Err("internal error: cannot make the OpenAL context current.".to_string());
        }

        Ok(
            OpenAlData {
                al_context: context,
                al_device: device,
                al_capt_device: 0
            }
        )
    }

    fn default() -> OpenAlData {
        OpenAlData {
            al_context: 0,
            al_device: 0,
            al_capt_device: 0
        }
    }

    fn is_default(&self) -> bool {
        if self.al_context == 0 &&
           self.al_device == 0 &&
           self.al_capt_device == 0 {
            false
        } else {
            true
        }
    }

    /// Check if the context is created.
    ///
    /// This function check is the OpenAl context is already created.
    /// If context doesn't exist, create it, and store it in a local_data,
    /// else get it from the local data and return it.
    ///
    /// # Return
    /// A result containing nothing if the OpenAlData struct exist,
    /// otherwise an error message.
    pub fn check_al_context() -> Result<(), String> {
        if unsafe { ffi::alcGetCurrentContext() != 0 } {
            return Ok(())
        }
        AL_CONTEXT.with(|f| {
            let is_def = f.borrow_mut().is_default();
            if is_def {
                match OpenAlData::new() {
                    Ok(al_data) => {
                        *f.borrow_mut() = Box::new(al_data); Ok(())
                    },
                    Err(err) => Err(err)
                }
            } else {
                Ok(())
            }
        })
    }

    fn is_input_context_init() -> Result<RecordContext, String> {
        // let is_some = AL_CONTEXT.get().is_some();
        AL_CONTEXT.with(|f| {
            let is_def = f.borrow_mut().is_default();
            if !is_def {
                let mut new_context = f.borrow_mut();
                if !new_context.al_capt_device == 0 {
                    Ok(record_context::new(new_context.al_capt_device))
                } else {
					let c_str = CString::new("ALC_EXT_CAPTURE").unwrap();
                    if unsafe {
                        ffi::alcIsExtensionPresent(new_context.al_device, c_str.as_ptr()) } == ffi::ALC_FALSE {
                        return Err("Error: no input device available on your system.".to_string())
                    } else {
                        new_context.al_capt_device = unsafe {
                        ffi::alcCaptureOpenDevice(ptr::null_mut(),
                                                  44100,
                                                  ffi::AL_FORMAT_MONO16,
                                                  44100) };
                        if new_context.al_capt_device == 0 {
                            return Err("internal error: cannot open the default capture device.".to_string())
                        } else {
                           let cap_device = new_context.al_capt_device;
                           return Ok(record_context::new(cap_device))
                        }
                    }
                    Err("Error: you must request the input context, \
                        in the task where you initialize ears.".to_string())
                }
            } else {
                Err("Error: you must request the input context, \
                    in the task where you initialize ears.".to_string())
            }
        })
    }

    /// Check if the input context is created.
    ///
    /// This function check if the input OpenAl context is already created.
    /// The input openAL context need the normal AL context + its own extension.
    /// So check if the context exist first, then load the input extension.
    ///
    /// # Return
    /// A result containing nothing if the OpenAlData struct exist,
    /// otherwise an error message.
    pub fn check_al_input_context() -> Result<RecordContext, String> {
        if unsafe { !ffi::alcGetCurrentContext() == 0 } {
            OpenAlData::is_input_context_init()
        } else {
            match OpenAlData::check_al_context() {
                Ok(_)    => OpenAlData::is_input_context_init(),
                Err(err) => Err(err)
            }
        }
    }
}

impl Drop for OpenAlData {
    fn drop(&mut self) {
        unsafe {
            ffi::alcDestroyContext(self.al_context);
            if !self.al_capt_device == 0 {
                ffi::alcCaptureCloseDevice(self.al_capt_device);
            }
            ffi::alcCloseDevice(self.al_device);
        }
    }
}

macro_rules! check_openal_context(
    ($def_ret:expr) => (
            match OpenAlData::check_al_context() {
                Ok(_)    => {},
                Err(err) => { println!("{}", err); return $def_ret; }
            }
        );
);
<commit_msg>fix OpenALData::is_default() probably logical error<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! internal class to handle OpenAl context and device.
//!
//! Work as a Singleton, check_al_context must be called before each OpenAl object
//! to be sure that the context is created.

#![macro_use]
#![allow(raw_pointer_derive)]

use std::ffi::CString;
use std::cell::RefCell;
use std::ptr;
use openal::ffi;
use record_context;
use record_context::RecordContext;

thread_local!(static AL_CONTEXT: RefCell<Box<OpenAlData>> = RefCell::new(Box::new(OpenAlData::default())));

#[derive(Clone)]
pub struct OpenAlData {
    pub al_context: ffi::ALCcontextPtr,
    pub al_device: ffi::ALCdevicePtr,
    pub al_capt_device: ffi::ALCdevicePtr
}

impl OpenAlData {
    /// Create a new OpenAlData struct
    ///
    /// Private method.
    fn new() -> Result<OpenAlData, String> {
        let device = unsafe { ffi::alcOpenDevice(ptr::null_mut()) };
        if device == 0 {
            return Err("internal error: cannot open the default device.".to_string());
        }
        let context = unsafe { ffi::alcCreateContext(device, ptr::null_mut()) };
        if context == 0 {
            return Err("internal error: cannot create the OpenAL context.".to_string());
        }
        if unsafe { ffi::alcMakeContextCurrent(context) } == ffi::ALC_FALSE {
            return Err("internal error: cannot make the OpenAL context current.".to_string());
        }

        Ok(
            OpenAlData {
                al_context: context,
                al_device: device,
                al_capt_device: 0
            }
        )
    }

    fn default() -> OpenAlData {
        OpenAlData {
            al_context: 0,
            al_device: 0,
            al_capt_device: 0
        }
    }

    fn is_default(&self) -> bool {
        if self.al_context == 0 &&
           self.al_device == 0 &&
           self.al_capt_device == 0 {
            true
        } else {
            false
        }
    }

    /// Check if the context is created.
    ///
    /// This function check is the OpenAl context is already created.
    /// If context doesn't exist, create it, and store it in a local_data,
    /// else get it from the local data and return it.
    ///
    /// # Return
    /// A result containing nothing if the OpenAlData struct exist,
    /// otherwise an error message.
    pub fn check_al_context() -> Result<(), String> {
        if unsafe { ffi::alcGetCurrentContext() != 0 } {
            return Ok(())
        }
        AL_CONTEXT.with(|f| {
            let is_def = f.borrow_mut().is_default();
            if is_def {
                match OpenAlData::new() {
                    Ok(al_data) => {
                        *f.borrow_mut() = Box::new(al_data); Ok(())
                    },
                    Err(err) => Err(err)
                }
            } else {
                Ok(())
            }
        })
    }

    fn is_input_context_init() -> Result<RecordContext, String> {
        // let is_some = AL_CONTEXT.get().is_some();
        AL_CONTEXT.with(|f| {
            let is_def = f.borrow_mut().is_default();
            if !is_def {
                let mut new_context = f.borrow_mut();
                if !new_context.al_capt_device == 0 {
                    Ok(record_context::new(new_context.al_capt_device))
                } else {
					let c_str = CString::new("ALC_EXT_CAPTURE").unwrap();
                    if unsafe {
                        ffi::alcIsExtensionPresent(new_context.al_device, c_str.as_ptr()) } == ffi::ALC_FALSE {
                        return Err("Error: no input device available on your system.".to_string())
                    } else {
                        new_context.al_capt_device = unsafe {
                        ffi::alcCaptureOpenDevice(ptr::null_mut(),
                                                  44100,
                                                  ffi::AL_FORMAT_MONO16,
                                                  44100) };
                        if new_context.al_capt_device == 0 {
                            return Err("internal error: cannot open the default capture device.".to_string())
                        } else {
                           let cap_device = new_context.al_capt_device;
                           return Ok(record_context::new(cap_device))
                        }
                    }
                    Err("Error: you must request the input context, \
                        in the task where you initialize ears.".to_string())
                }
            } else {
                Err("Error: you must request the input context, \
                    in the task where you initialize ears.".to_string())
            }
        })
    }

    /// Check if the input context is created.
    ///
    /// This function check if the input OpenAl context is already created.
    /// The input openAL context need the normal AL context + its own extension.
    /// So check if the context exist first, then load the input extension.
    ///
    /// # Return
    /// A result containing nothing if the OpenAlData struct exist,
    /// otherwise an error message.
    pub fn check_al_input_context() -> Result<RecordContext, String> {
        if unsafe { !ffi::alcGetCurrentContext() == 0 } {
            OpenAlData::is_input_context_init()
        } else {
            match OpenAlData::check_al_context() {
                Ok(_)    => OpenAlData::is_input_context_init(),
                Err(err) => Err(err)
            }
        }
    }
}

impl Drop for OpenAlData {
    fn drop(&mut self) {
        unsafe {
            ffi::alcDestroyContext(self.al_context);
            if !self.al_capt_device == 0 {
                ffi::alcCaptureCloseDevice(self.al_capt_device);
            }
            ffi::alcCloseDevice(self.al_device);
        }
    }
}

macro_rules! check_openal_context(
    ($def_ret:expr) => (
            match OpenAlData::check_al_context() {
                Ok(_)    => {},
                Err(err) => { println!("{}", err); return $def_ret; }
            }
        );
);
<|endoftext|>


<commit_before>use std::env;
use std::os::unix::process::CommandExt;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::time::Instant;

use crate::cmdline::Opt;
use crate::core::*;
use crate::utils::is_dev_machine;

const TMUX: &str = "tmux";

pub struct Tmux {
    nmk_home: PathBuf,
    tmux_dir: PathBuf,
    config: PathBuf,
    pub bin: PathBuf,
    pub version: String,
}

fn find_config(tmux_dir: &PathBuf, version: &str) -> PathBuf {
    let config = tmux_dir.join(format!("{}.conf", version));
    assert!(config.exists(), "unsupported tmux version: {}", version);
    config
}

fn find_version() -> String {
    if let Ok(output) = Command::new(TMUX).arg("-V").output() {
        if !output.status.success() {
            let code = output.status.code().expect("tmux is terminated by signal");
            panic!("tmux exit with status: {}", code);
        }
        let version_output =
            String::from_utf8(output.stdout).expect("tmux version output contain non utf-8");
        version_output
            .trim()
            .split(" ")
            .nth(1)
            .unwrap_or_else(|| panic!("bad output: {}", version_output))
            .to_string()
    } else {
        panic!("{} not found", TMUX);
    }
}

fn is_server_running(socket: &str) -> bool {
    let running = Command::new(TMUX)
        .arg("-L")
        .arg(socket)
        .arg("list-sessions")
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
        .map(|status| status.success())
        .unwrap_or(false);
    log::debug!("server {} running", if running { "is" } else { "is not" });
    running
}

impl Tmux {
    pub fn new(nmk_home: &Path) -> Tmux {
        let tmux_dir = nmk_home.join("tmux");
        assert!(
            tmux_dir.is_dir(),
            "{} is not directory",
            tmux_dir.to_string_lossy()
        );
        let bin = which::which(TMUX).expect("Cannot find tmux binary");
        let version = find_version();
        let config = find_config(&tmux_dir, &version);
        Tmux {
            nmk_home: nmk_home.to_owned(),
            tmux_dir,
            bin,
            version,
            config,
        }
    }

    pub fn setup_environment(&self, arg: &Opt, is_color_term: bool) {
        set_env(
            "NMK_TMUX_DEFAULT_SHELL",
            which::which("zsh").expect("zsh not found"),
        );
        set_env("NMK_TMUX_DETACH_ON_DESTROY", on_off!(arg.detach_on_destroy));
        set_env("NMK_TMUX_HISTORY", self.tmux_dir.join(".tmux_history"));
        set_env("NMK_TMUX_VERSION", &self.version);
        let default_term = if is_color_term {
            "screen-256color"
        } else {
            "screen"
        };
        set_env("NMK_TMUX_DEFAULT_TERMINAL", default_term);
        set_env("NMK_TMUX_256_COLOR", one_hot!(is_color_term));
    }

    fn print_usage_time(&self, arg: &Opt, start: &Instant) {
        let before_exec = start.elapsed().as_millis();
        if arg.usage {
            println!("{}", before_exec);
        } else {
            log::debug!("usage time: {}ms", before_exec);
        }
    }

    pub fn login_shell(&self, arg: &Opt, start: &Instant, is_color_term: bool) -> ! {
        let mut cmd = Command::new(&self.bin);
        cmd.args(&["-L", &arg.socket]);
        if is_color_term {
            cmd.arg("-2");
        }
        if arg.unicode {
            cmd.arg("-u");
        }
        cmd.arg("-f");
        cmd.arg(&self.config);
        cmd.args(&["-c", "exec zsh --login"]);
        log::debug!("login command: {:?}", cmd);
        self.print_usage_time(&arg, &start);
        let err = cmd.exec();
        panic!("exec fail with {:?}", err);
    }

    pub fn exec(&self, arg: &Opt, start: &Instant, is_color_term: bool) -> ! {
        let mut cmd = Command::new(&self.bin);
        cmd.args(&["-L", &arg.socket]);
        if is_color_term {
            cmd.arg("-2");
        }
        if arg.unicode {
            cmd.arg("-u");
        }
        if is_server_running(&arg.socket) {
            if !arg.tmux_args.is_empty() {
                cmd.args(arg.tmux_args.iter());
            } else {
                if env::var_os("TMUX").is_some() && !arg.inception {
                    panic!("add --inception to allow nested tmux sessions");
                }
                cmd.arg("attach");
            }
        } else {
            cmd.arg("-f");
            cmd.arg(&self.config);
            cmd.args(arg.tmux_args.iter());
        }
        log::debug!("exec command: {:?}", cmd);
        self.print_usage_time(&arg, &start);
        if self.is_vendored_tmux() && is_dev_machine() {
            log::warn!("Using vendored tmux on development machine")
        }
        let err = cmd.exec();
        panic!("exec fail with {:?}", err);
    }

    pub fn is_vendored_tmux(&self) -> bool {
        self.bin.starts_with(&self.nmk_home)
    }
}
<commit_msg>Use str::from_utf8<commit_after>use std::env;
use std::os::unix::process::CommandExt;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::time::Instant;

use crate::cmdline::Opt;
use crate::core::*;
use crate::utils::is_dev_machine;

const TMUX: &str = "tmux";

pub struct Tmux {
    nmk_home: PathBuf,
    tmux_dir: PathBuf,
    config: PathBuf,
    pub bin: PathBuf,
    pub version: String,
}

fn find_config(tmux_dir: &PathBuf, version: &str) -> PathBuf {
    let config = tmux_dir.join(format!("{}.conf", version));
    assert!(config.exists(), "unsupported tmux version: {}", version);
    config
}

fn find_version() -> String {
    let output = Command::new(TMUX)
        .arg("-V")
        .output()
        .expect("tmux not found");
    if !output.status.success() {
        let code = output.status.code().expect("tmux is terminated by signal");
        panic!("tmux exit with status: {}", code);
    }
    let unparsed_version =
        std::str::from_utf8(&output.stdout).expect("tmux version output contain non utf-8");
    unparsed_version
        .trim()
        .split(" ")
        .nth(1)
        .unwrap_or_else(|| panic!("bad output: {}", unparsed_version))
        .to_string()
}

fn is_server_running(socket: &str) -> bool {
    let running = Command::new(TMUX)
        .arg("-L")
        .arg(socket)
        .arg("list-sessions")
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
        .map(|status| status.success())
        .unwrap_or(false);
    log::debug!("server {} running", if running { "is" } else { "is not" });
    running
}

impl Tmux {
    pub fn new(nmk_home: &Path) -> Tmux {
        let tmux_dir = nmk_home.join("tmux");
        assert!(
            tmux_dir.is_dir(),
            "{} is not directory",
            tmux_dir.to_string_lossy()
        );
        let bin = which::which(TMUX).expect("Cannot find tmux binary");
        let version = find_version();
        let config = find_config(&tmux_dir, &version);
        Tmux {
            nmk_home: nmk_home.to_owned(),
            tmux_dir,
            bin,
            version,
            config,
        }
    }

    pub fn setup_environment(&self, arg: &Opt, is_color_term: bool) {
        set_env(
            "NMK_TMUX_DEFAULT_SHELL",
            which::which("zsh").expect("zsh not found"),
        );
        set_env("NMK_TMUX_DETACH_ON_DESTROY", on_off!(arg.detach_on_destroy));
        set_env("NMK_TMUX_HISTORY", self.tmux_dir.join(".tmux_history"));
        set_env("NMK_TMUX_VERSION", &self.version);
        let default_term = if is_color_term {
            "screen-256color"
        } else {
            "screen"
        };
        set_env("NMK_TMUX_DEFAULT_TERMINAL", default_term);
        set_env("NMK_TMUX_256_COLOR", one_hot!(is_color_term));
    }

    fn print_usage_time(&self, arg: &Opt, start: &Instant) {
        let before_exec = start.elapsed().as_millis();
        if arg.usage {
            println!("{}", before_exec);
        } else {
            log::debug!("usage time: {}ms", before_exec);
        }
    }

    pub fn login_shell(&self, arg: &Opt, start: &Instant, is_color_term: bool) -> ! {
        let mut cmd = Command::new(&self.bin);
        cmd.args(&["-L", &arg.socket]);
        if is_color_term {
            cmd.arg("-2");
        }
        if arg.unicode {
            cmd.arg("-u");
        }
        cmd.arg("-f");
        cmd.arg(&self.config);
        cmd.args(&["-c", "exec zsh --login"]);
        log::debug!("login command: {:?}", cmd);
        self.print_usage_time(&arg, &start);
        let err = cmd.exec();
        panic!("exec fail with {:?}", err);
    }

    pub fn exec(&self, arg: &Opt, start: &Instant, is_color_term: bool) -> ! {
        let mut cmd = Command::new(&self.bin);
        cmd.args(&["-L", &arg.socket]);
        if is_color_term {
            cmd.arg("-2");
        }
        if arg.unicode {
            cmd.arg("-u");
        }
        if is_server_running(&arg.socket) {
            if !arg.tmux_args.is_empty() {
                cmd.args(arg.tmux_args.iter());
            } else {
                if env::var_os("TMUX").is_some() && !arg.inception {
                    panic!("add --inception to allow nested tmux sessions");
                }
                cmd.arg("attach");
            }
        } else {
            cmd.arg("-f");
            cmd.arg(&self.config);
            cmd.args(arg.tmux_args.iter());
        }
        log::debug!("exec command: {:?}", cmd);
        self.print_usage_time(&arg, &start);
        if self.is_vendored_tmux() && is_dev_machine() {
            log::warn!("Using vendored tmux on development machine")
        }
        let err = cmd.exec();
        panic!("exec fail with {:?}", err);
    }

    pub fn is_vendored_tmux(&self) -> bool {
        self.bin.starts_with(&self.nmk_home)
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::{env, fs};
use std::vec::Vec;

fn main() {
    if let Some(git_sha) = read_git_sha() {
        println!("cargo:rustc-env={}={}", "BUILD_SHA", git_sha);
    }

    if wasm_files_present() {
        println!("cargo:rustc-cfg={}", "TREE_SITTER_EMBED_WASM_BINDING");
    }

    println!(
        "cargo:rustc-env=BUILD_TARGET={}",
        std::env::var("TARGET").unwrap()
    );
}

#[cfg(unix)]
fn required_files() -> Vec<&'static Path> {
    return vec![
        Path::new("../cli/src/web_ui.html"),
        Path::new("../docs/assets/js/playground.js"),
        Path::new("../lib/binding_web/tree-sitter.js"),
        Path::new("../lib/binding_web/tree-sitter.wasm")
        ];
}

#[cfg(windows)]
fn required_files() -> Vec<&'static Path> {
    return vec![
        Path::new("../cli/src/web_ui.html"),
        Path::new("../docs/assets/js/playground.js"),
        ];
}

fn wasm_files_present() -> bool {
    for path in required_files() {
        if path.exists() {
            return false
        }
    }
    return true
}

fn read_git_sha() -> Option<String> {
    let mut repo_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());

    let mut git_path;
    loop {
        git_path = repo_path.join(".git");
        if git_path.exists() {
            break;
        } else if !repo_path.pop() {
            return None;
        }
    }

    let git_dir_path;
    if git_path.is_dir() {
        git_dir_path = git_path;
    } else if let Ok(git_path_content) = fs::read_to_string(&git_path) {
        git_dir_path = repo_path.join(git_path_content.get("gitdir: ".len()..).unwrap().trim_end());
    } else {
        return None;
    }
    let git_head_path = git_dir_path.join("HEAD");
    if let Some(path) = git_head_path.to_str() {
        println!("cargo:rerun-if-changed={}", path);
    }
    if let Ok(mut head_content) = fs::read_to_string(&git_head_path) {
        if head_content.ends_with("\n") {
            head_content.pop();
        }

        // If we're on a branch, read the SHA from the ref file.
        if head_content.starts_with("ref: ") {
            head_content.replace_range(0.."ref: ".len(), "");
            let ref_filename = git_dir_path.join(&head_content);
            if let Some(path) = ref_filename.to_str() {
                println!("cargo:rerun-if-changed={}", path);
            }
            return fs::read_to_string(&ref_filename).ok();
        }
        // If we're on a detached commit, then the `HEAD` file itself contains the sha.
        else if head_content.len() == 40 {
            return Some(head_content);
        }
    }

    None
}
<commit_msg>web_ui and playground.js are always there.<commit_after>use std::path::{Path, PathBuf};
use std::{env, fs};
use std::vec::Vec;

fn main() {
    if let Some(git_sha) = read_git_sha() {
        println!("cargo:rustc-env={}={}", "BUILD_SHA", git_sha);
    }

    if wasm_files_present() {
        println!("cargo:rustc-cfg={}", "TREE_SITTER_EMBED_WASM_BINDING");
    }

    println!(
        "cargo:rustc-env=BUILD_TARGET={}",
        std::env::var("TARGET").unwrap()
    );
}

#[cfg(unix)]
fn required_files() -> Vec<&'static Path> {
    return vec![
        Path::new("../lib/binding_web/tree-sitter.js"),
        Path::new("../lib/binding_web/tree-sitter.wasm")
        ];
}

#[cfg(windows)]
fn required_files() -> Vec<&'static Path> {
    return vec![
        ];
}

fn wasm_files_present() -> bool {
    for path in required_files() {
        if path.exists() {
            return false
        }
    }
    return true
}

fn read_git_sha() -> Option<String> {
    let mut repo_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());

    let mut git_path;
    loop {
        git_path = repo_path.join(".git");
        if git_path.exists() {
            break;
        } else if !repo_path.pop() {
            return None;
        }
    }

    let git_dir_path;
    if git_path.is_dir() {
        git_dir_path = git_path;
    } else if let Ok(git_path_content) = fs::read_to_string(&git_path) {
        git_dir_path = repo_path.join(git_path_content.get("gitdir: ".len()..).unwrap().trim_end());
    } else {
        return None;
    }
    let git_head_path = git_dir_path.join("HEAD");
    if let Some(path) = git_head_path.to_str() {
        println!("cargo:rerun-if-changed={}", path);
    }
    if let Ok(mut head_content) = fs::read_to_string(&git_head_path) {
        if head_content.ends_with("\n") {
            head_content.pop();
        }

        // If we're on a branch, read the SHA from the ref file.
        if head_content.starts_with("ref: ") {
            head_content.replace_range(0.."ref: ".len(), "");
            let ref_filename = git_dir_path.join(&head_content);
            if let Some(path) = ref_filename.to_str() {
                println!("cargo:rerun-if-changed={}", path);
            }
            return fs::read_to_string(&ref_filename).ok();
        }
        // If we're on a detached commit, then the `HEAD` file itself contains the sha.
        else if head_content.len() == 40 {
            return Some(head_content);
        }
    }

    None
}
<|endoftext|>


<commit_before>use ast::*;
use ast::Expr::*;
use cpu::{Reg, REG_RESULT, REG_TMP1, REG_PARAMS};
use cpu::emit;
use cpu::Reg::*;
use ctxt::*;
use dseg::DSeg;
use jit::buffer::*;
use jit::codegen::JumpCond;
use sym::BuiltinType;

pub struct ExprGen<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>,
    fct: &'ast Function,
    buf: &'a mut Buffer,
    dseg: &'a mut DSeg,
    tempsize: i32,
    localsize: i32,
}

impl<'a, 'ast> ExprGen<'a, 'ast> where 'ast: 'a {
    pub fn new(
        ctxt: &'a Context<'a, 'ast>,
        fct: &'ast Function,
        buf: &'a mut Buffer,
        dseg: &'a mut DSeg,
        localsize: i32,
    ) -> ExprGen<'a, 'ast> {
        ExprGen {
            ctxt: ctxt,
            fct: fct,
            buf: buf,
            dseg: dseg,
            tempsize: 0,
            localsize: localsize,
        }
    }

    pub fn generate(mut self, e: &'ast Expr) -> Reg {
        self.emit_expr(e, REG_RESULT)
    }

    fn emit_expr(&mut self, e: &'ast Expr, dest: Reg) -> Reg {
        match *e {
            ExprLitInt(ref expr) => self.emit_lit_int(expr, dest),
            ExprLitBool(ref expr) => self.emit_lit_bool(expr, dest),
            ExprUn(ref expr) => self.emit_un(expr, dest),
            ExprIdent(ref expr) => self.emit_ident(expr, dest),
            ExprAssign(ref expr) => self.emit_assign(expr, dest),
            ExprBin(ref expr) => self.emit_bin(expr, dest),
            ExprCall(ref expr) => self.emit_call(expr, dest),
            _ => unreachable!(),
        }

        dest
    }

    fn emit_lit_int(&mut self, lit: &'ast ExprLitIntType, dest: Reg) {
        emit::movl_imm_reg(self.buf, lit.value as u32, dest);
    }

    fn emit_lit_bool(&mut self, lit: &'ast ExprLitBoolType, dest: Reg) {
        let value : u32 = if lit.value { 1 } else { 0 };
        emit::movl_imm_reg(self.buf, value, dest);
    }

    fn emit_ident(&mut self, e: &'ast ExprIdentType, dest: Reg) {
        let defs = self.ctxt.defs.borrow();
        let varid = *defs.get(&e.id).unwrap();

        emit::var_load(self.buf, self.ctxt, varid, dest);
    }

    fn emit_un(&mut self, e: &'ast ExprUnType, dest: Reg) {
        self.emit_expr(&e.opnd, dest);

        match e.op {
            UnOp::Plus => {},
            UnOp::Neg => emit::negl_reg(self.buf, dest),
            UnOp::BitNot => emit::notl_reg(self.buf, dest),
            UnOp::Not => emit::bool_not_reg(self.buf, dest)
        }
    }

    fn emit_assign(&mut self, e: &'ast ExprAssignType, dest: Reg) {
        self.emit_expr(&e.rhs, dest);

        let defs = self.ctxt.defs.borrow();
        let varid = *defs.get(&e.lhs.id()).unwrap();

        emit::var_store(&mut self.buf, self.ctxt, dest, varid);
    }

    fn emit_bin(&mut self, e: &'ast ExprBinType, dest: Reg) {
        // assert!(e.rhs.is_leaf());

        match e.op {
            BinOp::Add => self.emit_bin_add(e, dest),
            BinOp::Sub => self.emit_bin_sub(e, dest),
            BinOp::Mul => self.emit_bin_mul(e, dest),
            BinOp::Div => self.emit_bin_div(e, dest),
            BinOp::Mod => self.emit_bin_mod(e, dest),
            BinOp::Cmp(op) => self.emit_bin_cmp(e, dest, op),
            BinOp::BitOr => self.emit_bin_bit_or(e, dest),
            BinOp::BitAnd => self.emit_bin_bit_and(e, dest),
            BinOp::BitXor => self.emit_bin_bit_xor(e, dest),
            BinOp::Or => self.emit_bin_or(e, dest),
            BinOp::And => self.emit_bin_and(e, dest),
        }
    }

    fn emit_bin_or(&mut self, e: &'ast ExprBinType, dest: Reg) {
        let lbl_true = self.buf.create_label();
        let lbl_false = self.buf.create_label();
        let lbl_end = self.buf.create_label();

        self.emit_expr(&e.lhs, REG_RESULT);
        emit::jump_if(self.buf, JumpCond::NonZero, REG_RESULT, lbl_true);

        self.emit_expr(&e.rhs, REG_RESULT);
        emit::jump_if(self.buf, JumpCond::Zero, REG_RESULT, lbl_false);

        self.buf.define_label(lbl_true);
        emit::movl_imm_reg(self.buf, 1, dest);
        emit::jump(self.buf, lbl_end);

        self.buf.define_label(lbl_false);
        emit::movl_imm_reg(self.buf, 0, dest);

        self.buf.define_label(lbl_end);
    }

    fn emit_bin_and(&mut self, e: &'ast ExprBinType, dest: Reg) {
        let lbl_true = self.buf.create_label();
        let lbl_false = self.buf.create_label();
        let lbl_end = self.buf.create_label();

        self.emit_expr(&e.lhs, REG_RESULT);
        emit::jump_if(self.buf, JumpCond::Zero, REG_RESULT, lbl_false);

        self.emit_expr(&e.rhs, REG_RESULT);
        emit::jump_if(self.buf, JumpCond::Zero, REG_RESULT, lbl_false);

        self.buf.define_label(lbl_true);
        emit::movl_imm_reg(self.buf, 1, dest);
        emit::jump(self.buf, lbl_end);

        self.buf.define_label(lbl_false);
        emit::movl_imm_reg(self.buf, 0, dest);

        self.buf.define_label(lbl_end);
    }

    fn emit_bin_cmp(&mut self, e: &'ast ExprBinType, dest: Reg, op: CmpOp) {
        self.emit_binop(e, dest, None, |eg, lhs, rhs, dest| {
            emit::cmpl_setl(eg.buf, lhs, op, rhs, dest);

            dest
        });
    }

    fn emit_bin_div(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, Some(RAX), |eg, lhs, rhs, dest| {
            emit::divl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_mod(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, Some(RAX), |eg, lhs, rhs, dest| {
            emit::modl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_mul(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, None, |eg, lhs, rhs, dest| {
            emit::mull(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_add(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, None, |eg, lhs, rhs, dest| {
            emit::addl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_sub(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, None, |eg, lhs, rhs, dest| {
            emit::subl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_bit_or(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, None, |eg, lhs, rhs, dest| {
            emit::orl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_bit_and(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, None, |eg, lhs, rhs, dest| {
            emit::andl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_bit_xor(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, None, |eg, lhs, rhs, dest| {
            emit::xorl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_binop<F>(&mut self, e: &'ast ExprBinType,
            dest_reg: Reg, lhs_reg: Option<Reg>, emit_action: F)
            where F: FnOnce(&mut ExprGen, Reg, Reg, Reg) -> Reg {
        let lhs_reg = lhs_reg.unwrap_or(REG_RESULT);
        let rhs_reg = REG_TMP1;

        let not_leaf = !is_leaf(&e.rhs);
        let mut temp_offset : i32 = 0;

        if not_leaf {
            temp_offset = self.add_temp_var(BuiltinType::Int);
        }

        self.emit_expr(&e.lhs, lhs_reg);
        if not_leaf { emit::movl_reg_local(self.buf, lhs_reg, temp_offset); }

        self.emit_expr(&e.rhs, rhs_reg);
        if not_leaf { emit::movl_local_reg(self.buf, temp_offset, lhs_reg); }

        let reg = emit_action(self, lhs_reg, rhs_reg, dest_reg);
        if reg != dest_reg { emit::movl_reg_reg(self.buf, reg, dest_reg); }
    }

    fn add_temp_var(&mut self, ty: BuiltinType) -> i32 {
        self.tempsize += ty.size();

        -(self.tempsize + self.localsize)
    }

    fn emit_call(&mut self, e: &'ast ExprCallType, dest: Reg) {
        let calls = self.ctxt.calls.borrow();
        let fid = *calls.get(&e.id).unwrap();

        self.ctxt.fct_info_for_id(fid, |fct_info| {
            assert!(fct_info.compiled_fct.is_some());

            for (ind, arg) in e.args.iter().enumerate().rev() {
                if REG_PARAMS.len() > ind {
                    let dest = REG_PARAMS[ind];
                    self.emit_expr(arg, dest);
                } else {
                    self.emit_expr(arg, REG_RESULT);
                    emit::push_param(self.buf, REG_RESULT);
                }
            }

            let disp = self.dseg.add_addr(fct_info.compiled_fct.unwrap());
            let pos = self.buf.pos() as i32;

            emit::call(self.buf, disp + pos);

            // TODO: move REG_RESULT into dest
            assert_eq!(REG_RESULT, dest);
        })
    }
}

/// Returns `true` if the given expression `expr` is either literal or
/// variable usage.
pub fn is_leaf(expr: &Expr) -> bool {
    match *expr {
        ExprUn(_) => false,
        ExprBin(ref val) => false,
        ExprLitInt(ref val) => true,
        ExprLitStr(ref val) => true,
        ExprLitBool(ref val) => true,
        ExprIdent(ref val) => true,
        ExprAssign(ref val) => false,
        ExprCall(ref val) => false,
    }
}
<commit_msg>codegen: removed all specific register usages<commit_after>use ast::*;
use ast::Expr::*;
use cpu::{Reg, REG_RESULT, REG_TMP1, REG_PARAMS};
use cpu::emit;
use ctxt::*;
use dseg::DSeg;
use jit::buffer::*;
use jit::codegen::JumpCond;
use sym::BuiltinType;

pub struct ExprGen<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>,
    fct: &'ast Function,
    buf: &'a mut Buffer,
    dseg: &'a mut DSeg,
    tempsize: i32,
    localsize: i32,
}

impl<'a, 'ast> ExprGen<'a, 'ast> where 'ast: 'a {
    pub fn new(
        ctxt: &'a Context<'a, 'ast>,
        fct: &'ast Function,
        buf: &'a mut Buffer,
        dseg: &'a mut DSeg,
        localsize: i32,
    ) -> ExprGen<'a, 'ast> {
        ExprGen {
            ctxt: ctxt,
            fct: fct,
            buf: buf,
            dseg: dseg,
            tempsize: 0,
            localsize: localsize,
        }
    }

    pub fn generate(mut self, e: &'ast Expr) -> Reg {
        self.emit_expr(e, REG_RESULT)
    }

    fn emit_expr(&mut self, e: &'ast Expr, dest: Reg) -> Reg {
        match *e {
            ExprLitInt(ref expr) => self.emit_lit_int(expr, dest),
            ExprLitBool(ref expr) => self.emit_lit_bool(expr, dest),
            ExprUn(ref expr) => self.emit_un(expr, dest),
            ExprIdent(ref expr) => self.emit_ident(expr, dest),
            ExprAssign(ref expr) => self.emit_assign(expr, dest),
            ExprBin(ref expr) => self.emit_bin(expr, dest),
            ExprCall(ref expr) => self.emit_call(expr, dest),
            _ => unreachable!(),
        }

        dest
    }

    fn emit_lit_int(&mut self, lit: &'ast ExprLitIntType, dest: Reg) {
        emit::movl_imm_reg(self.buf, lit.value as u32, dest);
    }

    fn emit_lit_bool(&mut self, lit: &'ast ExprLitBoolType, dest: Reg) {
        let value : u32 = if lit.value { 1 } else { 0 };
        emit::movl_imm_reg(self.buf, value, dest);
    }

    fn emit_ident(&mut self, e: &'ast ExprIdentType, dest: Reg) {
        let defs = self.ctxt.defs.borrow();
        let varid = *defs.get(&e.id).unwrap();

        emit::var_load(self.buf, self.ctxt, varid, dest);
    }

    fn emit_un(&mut self, e: &'ast ExprUnType, dest: Reg) {
        self.emit_expr(&e.opnd, dest);

        match e.op {
            UnOp::Plus => {},
            UnOp::Neg => emit::negl_reg(self.buf, dest),
            UnOp::BitNot => emit::notl_reg(self.buf, dest),
            UnOp::Not => emit::bool_not_reg(self.buf, dest)
        }
    }

    fn emit_assign(&mut self, e: &'ast ExprAssignType, dest: Reg) {
        self.emit_expr(&e.rhs, dest);

        let defs = self.ctxt.defs.borrow();
        let varid = *defs.get(&e.lhs.id()).unwrap();

        emit::var_store(&mut self.buf, self.ctxt, dest, varid);
    }

    fn emit_bin(&mut self, e: &'ast ExprBinType, dest: Reg) {
        // assert!(e.rhs.is_leaf());

        match e.op {
            BinOp::Add => self.emit_bin_add(e, dest),
            BinOp::Sub => self.emit_bin_sub(e, dest),
            BinOp::Mul => self.emit_bin_mul(e, dest),
            BinOp::Div => self.emit_bin_div(e, dest),
            BinOp::Mod => self.emit_bin_mod(e, dest),
            BinOp::Cmp(op) => self.emit_bin_cmp(e, dest, op),
            BinOp::BitOr => self.emit_bin_bit_or(e, dest),
            BinOp::BitAnd => self.emit_bin_bit_and(e, dest),
            BinOp::BitXor => self.emit_bin_bit_xor(e, dest),
            BinOp::Or => self.emit_bin_or(e, dest),
            BinOp::And => self.emit_bin_and(e, dest),
        }
    }

    fn emit_bin_or(&mut self, e: &'ast ExprBinType, dest: Reg) {
        let lbl_true = self.buf.create_label();
        let lbl_false = self.buf.create_label();
        let lbl_end = self.buf.create_label();

        self.emit_expr(&e.lhs, REG_RESULT);
        emit::jump_if(self.buf, JumpCond::NonZero, REG_RESULT, lbl_true);

        self.emit_expr(&e.rhs, REG_RESULT);
        emit::jump_if(self.buf, JumpCond::Zero, REG_RESULT, lbl_false);

        self.buf.define_label(lbl_true);
        emit::movl_imm_reg(self.buf, 1, dest);
        emit::jump(self.buf, lbl_end);

        self.buf.define_label(lbl_false);
        emit::movl_imm_reg(self.buf, 0, dest);

        self.buf.define_label(lbl_end);
    }

    fn emit_bin_and(&mut self, e: &'ast ExprBinType, dest: Reg) {
        let lbl_true = self.buf.create_label();
        let lbl_false = self.buf.create_label();
        let lbl_end = self.buf.create_label();

        self.emit_expr(&e.lhs, REG_RESULT);
        emit::jump_if(self.buf, JumpCond::Zero, REG_RESULT, lbl_false);

        self.emit_expr(&e.rhs, REG_RESULT);
        emit::jump_if(self.buf, JumpCond::Zero, REG_RESULT, lbl_false);

        self.buf.define_label(lbl_true);
        emit::movl_imm_reg(self.buf, 1, dest);
        emit::jump(self.buf, lbl_end);

        self.buf.define_label(lbl_false);
        emit::movl_imm_reg(self.buf, 0, dest);

        self.buf.define_label(lbl_end);
    }

    fn emit_bin_cmp(&mut self, e: &'ast ExprBinType, dest: Reg, op: CmpOp) {
        self.emit_binop(e, dest, |eg, lhs, rhs, dest| {
            emit::cmpl_setl(eg.buf, lhs, op, rhs, dest);

            dest
        });
    }

    fn emit_bin_div(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, |eg, lhs, rhs, dest| {
            emit::divl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_mod(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, |eg, lhs, rhs, dest| {
            emit::modl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_mul(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, |eg, lhs, rhs, dest| {
            emit::mull(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_add(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, |eg, lhs, rhs, dest| {
            emit::addl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_sub(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, |eg, lhs, rhs, dest| {
            emit::subl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_bit_or(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, |eg, lhs, rhs, dest| {
            emit::orl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_bit_and(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, |eg, lhs, rhs, dest| {
            emit::andl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_bin_bit_xor(&mut self, e: &'ast ExprBinType, dest: Reg) {
        self.emit_binop(e, dest, |eg, lhs, rhs, dest| {
            emit::xorl(eg.buf, lhs, rhs, dest)
        });
    }

    fn emit_binop<F>(&mut self, e: &'ast ExprBinType, dest_reg: Reg, emit_action: F)
            where F: FnOnce(&mut ExprGen, Reg, Reg, Reg) -> Reg {
        let lhs_reg = REG_RESULT;
        let rhs_reg = REG_TMP1;

        let not_leaf = !is_leaf(&e.rhs);
        let mut temp_offset : i32 = 0;

        if not_leaf {
            temp_offset = self.add_temp_var(BuiltinType::Int);
        }

        self.emit_expr(&e.lhs, lhs_reg);
        if not_leaf { emit::movl_reg_local(self.buf, lhs_reg, temp_offset); }

        self.emit_expr(&e.rhs, rhs_reg);
        if not_leaf { emit::movl_local_reg(self.buf, temp_offset, lhs_reg); }

        let reg = emit_action(self, lhs_reg, rhs_reg, dest_reg);
        if reg != dest_reg { emit::movl_reg_reg(self.buf, reg, dest_reg); }
    }

    fn add_temp_var(&mut self, ty: BuiltinType) -> i32 {
        self.tempsize += ty.size();

        -(self.tempsize + self.localsize)
    }

    fn emit_call(&mut self, e: &'ast ExprCallType, dest: Reg) {
        let calls = self.ctxt.calls.borrow();
        let fid = *calls.get(&e.id).unwrap();

        self.ctxt.fct_info_for_id(fid, |fct_info| {
            assert!(fct_info.compiled_fct.is_some());

            for (ind, arg) in e.args.iter().enumerate().rev() {
                if REG_PARAMS.len() > ind {
                    let dest = REG_PARAMS[ind];
                    self.emit_expr(arg, dest);
                } else {
                    self.emit_expr(arg, REG_RESULT);
                    emit::push_param(self.buf, REG_RESULT);
                }
            }

            let disp = self.dseg.add_addr(fct_info.compiled_fct.unwrap());
            let pos = self.buf.pos() as i32;

            emit::call(self.buf, disp + pos);

            // TODO: move REG_RESULT into dest
            assert_eq!(REG_RESULT, dest);
        })
    }
}

/// Returns `true` if the given expression `expr` is either literal or
/// variable usage.
pub fn is_leaf(expr: &Expr) -> bool {
    match *expr {
        ExprUn(_) => false,
        ExprBin(ref val) => false,
        ExprLitInt(ref val) => true,
        ExprLitStr(ref val) => true,
        ExprLitBool(ref val) => true,
        ExprIdent(ref val) => true,
        ExprAssign(ref val) => false,
        ExprCall(ref val) => false,
    }
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    log:        ~[~str],
}

impl Shell {

    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            log: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt); // prints 'gash >'
            io::stdio::flush();

            let line = stdin.read_line().unwrap(); // reads whats on the line
            let cmd_line = line.trim().to_owned();  // removes leading and trailing whitespace
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");  // get command

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                "history" => {
                    self.log.push(cmd_line.to_owned());
                    self.run_history();
                }
                "cd" => {
                    self.log.push(cmd_line.to_owned());
                    self.run_cd(cmd_line);
                }
                _       =>  {
                    self.log.push(cmd_line.to_owned());
                    self.run_cmdline(cmd_line);
                }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

	let length = argv.len()-1;

    	if argv[length] == ~"&" {
	    argv.remove(length);
            let program: ~str = argv.remove(0);
	    let argv2 = argv.clone();
	    if self.cmd_exists(program){

		spawn(proc() {run::process_status(program, argv2);});

	    }
            else {
		println!("{:s}: command not found", program);
            }
	}
	else{
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
	}
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    fn run_history(&mut self){
        for i in range(0, self.log.len()) {
            println!("{}", self.log[i]);
        }
    }

    fn run_cd(&mut self, cmd_line: &str) {
         let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {

            if argv.len() == 1 {
                self.go_to_home_dir();
                return ;
            }

            let string: ~str = argv.remove(1);
            if string == ~"$home" || string == ~"$home"{
                self.go_to_home_dir();
                return ;
            }
            let path = ~Path::new(string);
            if (path.exists()){
                let success = std::os::change_dir(path);
                if !success {
                    println("Invalid path");
                }
            }
        }
        else {
            println("Invalid input");
        }
    }

    fn go_to_home_dir(&mut self){
        match std::os::homedir() {
            Some(path) => {
                    std::os::change_dir(~path);
               }
             None => {
                    println("$HOME is not set");
               }
         }
    }

}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>working on pipes<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    log:        ~[~str],
}

impl Shell {

    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            log: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt); // prints 'gash >'
            io::stdio::flush();

            let line = stdin.read_line().unwrap(); // reads whats on the line
            let cmd_line = line.trim().to_owned();  // removes leading and trailing whitespace
            let user_input: ~[&str] = cmd_line.split(' ').collect();
            let mut index: uint = 0;

            for &string in user_input.iter(){
                let mut prog : ~str;    // saves command
                let mut input : ~str;
                let mut index1 : uint;
                let mut index2 : uint;
                let mut index3 : uint;
                let mut index4 : uint;

                match string {
                    "<" => {
                        let file  = user_input[index+1].to_owned(); // get file name
                        println(file);
                    }
                    ">" => {

                    }
                    "|" => {

                    }
                    _ => {

                    }
                }
                index += 1;
            }

            let result = self.find_prog(cmd_line);
            match result {
                ~"return" => {return}
                ~"continue" => {continue;}
                _          => {continue;}
            }

        }
    }

    fn find_prog(&mut self, cmd_line : &str) -> ~str{
         let program = cmd_line.splitn(' ', 1).nth(0).expect("no program"); // get command

         match program {
                ""      =>  { return ~"continue"; }
                "exit"  =>  { return ~"return"; }
                "history" => {
                    self.log.push(cmd_line.to_owned());
                    self.run_history();
                }
                "cd" => {
                    self.log.push(cmd_line.to_owned());
                    self.run_cd(cmd_line);
                }
                _       =>  {
                    self.log.push(cmd_line.to_owned());
                    self.run_cmdline(cmd_line);
                }
            }
        ~"fine"
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

	let length = argv.len()-1;

    	if argv[length] == ~"&" {
	    argv.remove(length);
            let program: ~str = argv.remove(0);
	    let argv2 = argv.clone();
	    if self.cmd_exists(program){

		spawn(proc() {run::process_status(program, argv2);});

	    }
            else {
		println!("{:s}: command not found", program);
            }
	}
	else{
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
	}
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    fn run_history(&mut self){
        for i in range(0, self.log.len()) {
            println!("{}", self.log[i]);
        }
    }

    fn run_cd(&mut self, cmd_line: &str) {
         let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {

            if argv.len() == 1 {
                self.go_to_home_dir();
                return ;
            }

            let string: ~str = argv.remove(1);
            if string == ~"$HOME" || string == ~"$home"{
                self.go_to_home_dir();
                return ;
            }
            let path = ~Path::new(string);
            if (path.exists()){
                let success = std::os::change_dir(path);
                if !success {
                    println("Invalid path");
                }
            }
        }
        else {
            println("Invalid input");
        }
    }

    fn go_to_home_dir(&mut self){
        match std::os::homedir() {
            Some(path) => {
                    std::os::change_dir(~path);
               }
             None => {
                    println("$HOME is not set");
               }
         }
    }

}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>#![cfg(test)]

extern crate protobuf;

#[cfg(feature = "with-bytes")]
extern crate bytes;

mod v2;

// `cfg(proto3)` is emitted by `build.rs`

#[cfg(proto3)]
mod v3;

#[cfg(proto3)]
mod google;

mod test;
<commit_msg>Include common tests<commit_after>#![cfg(test)]

extern crate protobuf;

#[cfg(feature = "with-bytes")]
extern crate bytes;

mod v2;

// `cfg(proto3)` is emitted by `build.rs`

#[cfg(proto3)]
mod v3;

mod common;

#[cfg(proto3)]
mod google;

mod test;
<|endoftext|>


<commit_before>use getopts::{Options,Matches};
use std::net::{TcpListener,TcpStream};
use std::io::{Read,BufStream,BufRead};
use std::old_io::{LineBufferedWriter,stdio};

pub fn listen(matches: &Matches) {
    // append port to localhost IP address
    let mut s = String::from_str("127.0.0.1:");
    s.push_str(matches.free[0].as_slice());
    let listener = TcpListener::bind(s.as_slice()).unwrap();
    // block until we get connection
    match listener.accept() {
        Ok((stream, socket_addr)) => {
            // nc doesn't handle multiple connections, so no need to do `handle_client`
            // in thread.
            handle_client(stream);
        },
        Err(f) => {
            panic!(f.to_string());
        }
    }
}

fn handle_client(stream: TcpStream) {
    let mut buf_stream = BufStream::new(stream);
    let mut read_buf = [0; 4096];
    let mut writer = LineBufferedWriter::new(stdio::stdout());
    loop {
        match(buf_stream.read(&mut read_buf)) {
            Ok(n) => {
                if n > 0 {
                    writer.write_all(&read_buf);
                }
                else {
                    return;
                }
            }
            Err(f) => {
                panic!(f.to_string());
            }
        }
    }
}
<commit_msg>Pass writer to `handle_client`.<commit_after>use getopts::{Options,Matches};
use std::net::{TcpListener,TcpStream};
use std::io::{Read,BufStream,BufRead};
use std::old_io::{LineBufferedWriter,stdio};

pub fn listen(matches: &Matches) {
    // append port to localhost IP address
    let mut s = String::from_str("127.0.0.1:");
    s.push_str(matches.free[0].as_slice());
    let listener = TcpListener::bind(s.as_slice()).unwrap();
    // block until we get connection
    let mut writer = LineBufferedWriter::new(stdio::stdout());
    match listener.accept() {
        Ok((stream, socket_addr)) => {
            // nc doesn't handle multiple connections, so no need to do `handle_client`
            // in thread.
            handle_client(stream, &mut writer);
        },
        Err(f) => {
            panic!(f.to_string());
        }
    }
}

fn handle_client(stream: TcpStream, writer: &mut Writer) {
    let mut buf_stream = BufStream::new(stream);
    let mut read_buf = [0; 4096];
    loop {
        match(buf_stream.read(&mut read_buf)) {
            Ok(n) => {
                if n > 0 {
                    writer.write_all(&read_buf.slice_to(n)).unwrap();
                }
                else {
                    return;
                }
            }
            Err(f) => {
                panic!(f.to_string());
            }
        }
    }
}
<|endoftext|>