<commit_before>//! This module contains the `InterpCx` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use crate::interpret::OpTy;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{InterpResult, Scalar};
use rustc_target::abi::LayoutOf;

use super::{InterpCx, Machine};

/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
/// same type as the result.
#[inline]
fn binop_left_homogeneous(op: mir::BinOp) -> bool {
    use rustc_middle::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Offset | Shl | Shr => true,
        Eq | Ne | Lt | Le | Gt | Ge => false,
    }
}
/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the
/// same type as the LHS.
#[inline]
fn binop_right_homogeneous(op: mir::BinOp) -> bool {
    use rustc_middle::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
        Offset | Shl | Shr => false,
    }
}

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    pub fn run(&mut self) -> InterpResult<'tcx> {
        while self.step()? {}
        Ok(())
    }

    /// Returns `true` as long as there are more things to do.
    ///
    /// This is used by [priroda](https://github.com/oli-obk/priroda)
    ///
    /// This is marked `#inline(always)` to work around adverserial codegen when `opt-level = 3`
    #[inline(always)]
    pub fn step(&mut self) -> InterpResult<'tcx, bool> {
        if self.stack().is_empty() {
            return Ok(false);
        }

        let loc = match self.frame().loc {
            Ok(loc) => loc,
            Err(_) => {
                // We are unwinding and this fn has no cleanup code.
                // Just go on unwinding.
                trace!("unwinding: skipping frame");
                self.pop_stack_frame(/* unwinding */ true)?;
                return Ok(true);
            }
        };
        let basic_block = &self.body().basic_blocks()[loc.block];

        let old_frames = self.frame_idx();

        if let Some(stmt) = basic_block.statements.get(loc.statement_index) {
            assert_eq!(old_frames, self.frame_idx());
            self.statement(stmt)?;
            return Ok(true);
        }

        M::before_terminator(self)?;

        let terminator = basic_block.terminator();
        assert_eq!(old_frames, self.frame_idx());
        self.terminator(terminator)?;
        Ok(true)
    }

    /// Runs the interpretation logic for the given `mir::Statement` at the current frame and
    /// statement counter. This also moves the statement counter forward.
    crate fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", stmt);

        use rustc_middle::mir::StatementKind::*;

        // Some statements (e.g., box) push new stack frames.
        // We have to record the stack frame number *before* executing the statement.
        let frame_idx = self.frame_idx();

        match &stmt.kind {
            Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,

            SetDiscriminant { place, variant_index } => {
                let dest = self.eval_place(**place)?;
                self.write_discriminant(*variant_index, &dest)?;
            }

            // Mark locals as alive
            StorageLive(local) => {
                self.storage_live(*local)?;
            }

            // Mark locals as dead
            StorageDead(local) => {
                self.storage_dead(*local)?;
            }

            // No dynamic semantics attached to `FakeRead`; MIR
            // interpreter is solely intended for borrowck'ed code.
            FakeRead(..) => {}

            // Stacked Borrows.
            Retag(kind, place) => {
                let dest = self.eval_place(**place)?;
                M::retag(self, *kind, &dest)?;
            }

            // Call CopyNonOverlapping
            CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
                let count = self.eval_operand(count, None)?;

                let src = self.eval_operand(src, None)?;
                let dst = self.eval_operand(dst, None)?;
                self.copy(&src, &dst, &count, /* nonoverlapping */ true)?;
            }

            // Statements we do not track.
            AscribeUserType(..) => {}

            // Currently, Miri discards Coverage statements. Coverage statements are only injected
            // via an optional compile time MIR pass and have no side effects. Since Coverage
            // statements don't exist at the source level, it is safe for Miri to ignore them, even
            // for undefined behavior (UB) checks.
            //
            // A coverage counter inside a const expression (for example, a counter injected in a
            // const function) is discarded when the const is evaluated at compile time. Whether
            // this should change, and/or how to implement a const eval counter, is a subject of the
            // following issue:
            //
            // FIXME(#73156): Handle source code coverage in const eval
            Coverage(..) => {}

            // Defined to do nothing. These are added by optimization passes, to avoid changing the
            // size of MIR constantly.
            Nop => {}

            LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
        }

        self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1;
        Ok(())
    }

    pub(crate) fn copy(
        &mut self,
        src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
        dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
        count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
        nonoverlapping: bool,
    ) -> InterpResult<'tcx> {
        let count = self.read_scalar(&count)?.to_machine_usize(self)?;
        let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
        let (size, align) = (layout.size, layout.align.abi);
        let src =
            self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;

        let dst =
            self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?;

        let size = size.checked_mul(count, self).ok_or_else(|| {
            err_ub_format!("overflow computing total size of `copy_nonoverlapping`")
        })?;

        if let (Some(src), Some(dst)) = (src, dst) {
            self.memory.copy(src, dst, size, nonoverlapping)?;
        }
        Ok(())
    }

    /// Evaluate an assignment statement.
    ///
    /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
    /// type writes its results directly into the memory specified by the place.
    pub fn eval_rvalue_into_place(
        &mut self,
        rvalue: &mir::Rvalue<'tcx>,
        place: mir::Place<'tcx>,
    ) -> InterpResult<'tcx> {
        let dest = self.eval_place(place)?;

        use rustc_middle::mir::Rvalue::*;
        match *rvalue {
            ThreadLocalRef(did) => {
                let id = M::thread_local_static_alloc_id(self, did)?;
                let val = self.global_base_pointer(id.into())?;
                self.write_scalar(val, &dest)?;
            }

            Use(ref operand) => {
                // Avoid recomputing the layout
                let op = self.eval_operand(operand, Some(dest.layout))?;
                self.copy_op(&op, &dest)?;
            }

            BinaryOp(bin_op, box (ref left, ref right)) => {
                let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
                let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
                self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
            }

            CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
                // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
                let left = self.read_immediate(&self.eval_operand(left, None)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
                self.binop_with_overflow(bin_op, &left, &right, &dest)?;
            }

            UnaryOp(un_op, ref operand) => {
                // The operand always has the same type as the result.
                let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?;
                let val = self.unary_op(un_op, &val)?;
                assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
                self.write_immediate(*val, &dest)?;
            }

            Aggregate(ref kind, ref operands) => {
                let (dest, active_field_index) = match **kind {
                    mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
                        self.write_discriminant(variant_index, &dest)?;
                        if adt_def.is_enum() {
                            (self.place_downcast(&dest, variant_index)?, active_field_index)
                        } else {
                            (dest, active_field_index)
                        }
                    }
                    _ => (dest, None),
                };

                for (i, operand) in operands.iter().enumerate() {
                    let op = self.eval_operand(operand, None)?;
                    // Ignore zero-sized fields.
                    if !op.layout.is_zst() {
                        let field_index = active_field_index.unwrap_or(i);
                        let field_dest = self.place_field(&dest, field_index)?;
                        self.copy_op(&op, &field_dest)?;
                    }
                }
            }

            Repeat(ref operand, _) => {
                let op = self.eval_operand(operand, None)?;
                let dest = self.force_allocation(&dest)?;
                let length = dest.len(self)?;

                if let Some(first_ptr) = self.check_mplace_access(&dest, None)? {
                    // Write the first.
                    let first = self.mplace_field(&dest, 0)?;
                    self.copy_op(&op, &first.into())?;

                    if length > 1 {
                        let elem_size = first.layout.size;
                        // Copy the rest. This is performance-sensitive code
                        // for big static/const arrays!
                        let rest_ptr = first_ptr.offset(elem_size, self)?;
                        self.memory.copy_repeatedly(
                            first_ptr,
                            rest_ptr,
                            elem_size,
                            length - 1,
                            /*nonoverlapping:*/ true,
                        )?;
                    }
                }
            }

            Len(place) => {
                // FIXME(CTFE): don't allow computing the length of arrays in const eval
                let src = self.eval_place(place)?;
                let mplace = self.force_allocation(&src)?;
                let len = mplace.len(self)?;
                self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?;
            }

            AddressOf(_, place) | Ref(_, _, place) => {
                let src = self.eval_place(place)?;
                let place = self.force_allocation(&src)?;
                if place.layout.size.bytes() > 0 {
                    // definitely not a ZST
                    assert!(place.ptr.is_ptr(), "non-ZST places should be normalized to `Pointer`");
                }
                self.write_immediate(place.to_ref(), &dest)?;
            }

            NullaryOp(mir::NullOp::Box, _) => {
                M::box_alloc(self, &dest)?;
            }

            NullaryOp(mir::NullOp::SizeOf, ty) => {
                let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty);
                let layout = self.layout_of(ty)?;
                if layout.is_unsized() {
                    // FIXME: This should be a span_bug (#80742)
                    self.tcx.sess.delay_span_bug(
                        self.frame().current_span(),
                        &format!("SizeOf nullary MIR operator called for unsized type {}", ty),
                    );
                    throw_inval!(SizeOfUnsizedType(ty));
                }
                self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), &dest)?;
            }

            Cast(cast_kind, ref operand, cast_ty) => {
                let src = self.eval_operand(operand, None)?;
                let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty);
                self.cast(&src, cast_kind, cast_ty, &dest)?;
            }

            Discriminant(place) => {
                let op = self.eval_place_to_op(place, None)?;
                let discr_val = self.read_discriminant(&op)?.0;
                self.write_scalar(discr_val, &dest)?;
            }
        }

        trace!("{:?}", self.dump_place(*dest));

        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", terminator.kind);

        self.eval_terminator(terminator)?;
        if !self.stack().is_empty() {
            if let Ok(loc) = self.frame().loc {
                info!("// executing {:?}", loc.block);
            }
        }
        Ok(())
    }
}
<commit_msg>fix copy_nonoverlapping<commit_after>//! This module contains the `InterpCx` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use crate::interpret::OpTy;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{InterpResult, Scalar};
use rustc_target::abi::LayoutOf;

use super::{InterpCx, Machine};

/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
/// same type as the result.
#[inline]
fn binop_left_homogeneous(op: mir::BinOp) -> bool {
    use rustc_middle::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Offset | Shl | Shr => true,
        Eq | Ne | Lt | Le | Gt | Ge => false,
    }
}
/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the
/// same type as the LHS.
#[inline]
fn binop_right_homogeneous(op: mir::BinOp) -> bool {
    use rustc_middle::mir::BinOp::*;
    match op {
        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
        Offset | Shl | Shr => false,
    }
}

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    pub fn run(&mut self) -> InterpResult<'tcx> {
        while self.step()? {}
        Ok(())
    }

    /// Returns `true` as long as there are more things to do.
    ///
    /// This is used by [priroda](https://github.com/oli-obk/priroda)
    ///
    /// This is marked `#inline(always)` to work around adverserial codegen when `opt-level = 3`
    #[inline(always)]
    pub fn step(&mut self) -> InterpResult<'tcx, bool> {
        if self.stack().is_empty() {
            return Ok(false);
        }

        let loc = match self.frame().loc {
            Ok(loc) => loc,
            Err(_) => {
                // We are unwinding and this fn has no cleanup code.
                // Just go on unwinding.
                trace!("unwinding: skipping frame");
                self.pop_stack_frame(/* unwinding */ true)?;
                return Ok(true);
            }
        };
        let basic_block = &self.body().basic_blocks()[loc.block];

        let old_frames = self.frame_idx();

        if let Some(stmt) = basic_block.statements.get(loc.statement_index) {
            assert_eq!(old_frames, self.frame_idx());
            self.statement(stmt)?;
            return Ok(true);
        }

        M::before_terminator(self)?;

        let terminator = basic_block.terminator();
        assert_eq!(old_frames, self.frame_idx());
        self.terminator(terminator)?;
        Ok(true)
    }

    /// Runs the interpretation logic for the given `mir::Statement` at the current frame and
    /// statement counter. This also moves the statement counter forward.
    crate fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", stmt);

        use rustc_middle::mir::StatementKind::*;

        // Some statements (e.g., box) push new stack frames.
        // We have to record the stack frame number *before* executing the statement.
        let frame_idx = self.frame_idx();

        match &stmt.kind {
            Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,

            SetDiscriminant { place, variant_index } => {
                let dest = self.eval_place(**place)?;
                self.write_discriminant(*variant_index, &dest)?;
            }

            // Mark locals as alive
            StorageLive(local) => {
                self.storage_live(*local)?;
            }

            // Mark locals as dead
            StorageDead(local) => {
                self.storage_dead(*local)?;
            }

            // No dynamic semantics attached to `FakeRead`; MIR
            // interpreter is solely intended for borrowck'ed code.
            FakeRead(..) => {}

            // Stacked Borrows.
            Retag(kind, place) => {
                let dest = self.eval_place(**place)?;
                M::retag(self, *kind, &dest)?;
            }

            // Call CopyNonOverlapping
            CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => {
                let src = self.eval_operand(src, None)?;
                let dst = self.eval_operand(dst, None)?;
                let count = self.eval_operand(count, None)?;
                self.copy(&src, &dst, &count, /* nonoverlapping */ true)?;
            }

            // Statements we do not track.
            AscribeUserType(..) => {}

            // Currently, Miri discards Coverage statements. Coverage statements are only injected
            // via an optional compile time MIR pass and have no side effects. Since Coverage
            // statements don't exist at the source level, it is safe for Miri to ignore them, even
            // for undefined behavior (UB) checks.
            //
            // A coverage counter inside a const expression (for example, a counter injected in a
            // const function) is discarded when the const is evaluated at compile time. Whether
            // this should change, and/or how to implement a const eval counter, is a subject of the
            // following issue:
            //
            // FIXME(#73156): Handle source code coverage in const eval
            Coverage(..) => {}

            // Defined to do nothing. These are added by optimization passes, to avoid changing the
            // size of MIR constantly.
            Nop => {}

            LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
        }

        self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1;
        Ok(())
    }

    pub(crate) fn copy(
        &mut self,
        src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
        dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
        count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
        nonoverlapping: bool,
    ) -> InterpResult<'tcx> {
        let count = self.read_scalar(&count)?.to_machine_usize(self)?;
        let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
        let (size, align) = (layout.size, layout.align.abi);
        let size = size.checked_mul(count, self).ok_or_else(|| {
            err_ub_format!("overflow computing total size of `copy_nonoverlapping`")
        })?;

        // Make sure we check both pointers for an access of the total size and aligment,
        // *even if* the total size is 0.
        let src =
            self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;

        let dst =
            self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?;

        if let (Some(src), Some(dst)) = (src, dst) {
            self.memory.copy(src, dst, size, nonoverlapping)?;
        }
        Ok(())
    }

    /// Evaluate an assignment statement.
    ///
    /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
    /// type writes its results directly into the memory specified by the place.
    pub fn eval_rvalue_into_place(
        &mut self,
        rvalue: &mir::Rvalue<'tcx>,
        place: mir::Place<'tcx>,
    ) -> InterpResult<'tcx> {
        let dest = self.eval_place(place)?;

        use rustc_middle::mir::Rvalue::*;
        match *rvalue {
            ThreadLocalRef(did) => {
                let id = M::thread_local_static_alloc_id(self, did)?;
                let val = self.global_base_pointer(id.into())?;
                self.write_scalar(val, &dest)?;
            }

            Use(ref operand) => {
                // Avoid recomputing the layout
                let op = self.eval_operand(operand, Some(dest.layout))?;
                self.copy_op(&op, &dest)?;
            }

            BinaryOp(bin_op, box (ref left, ref right)) => {
                let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
                let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
                self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
            }

            CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
                // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
                let left = self.read_immediate(&self.eval_operand(left, None)?)?;
                let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
                self.binop_with_overflow(bin_op, &left, &right, &dest)?;
            }

            UnaryOp(un_op, ref operand) => {
                // The operand always has the same type as the result.
                let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?;
                let val = self.unary_op(un_op, &val)?;
                assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
                self.write_immediate(*val, &dest)?;
            }

            Aggregate(ref kind, ref operands) => {
                let (dest, active_field_index) = match **kind {
                    mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
                        self.write_discriminant(variant_index, &dest)?;
                        if adt_def.is_enum() {
                            (self.place_downcast(&dest, variant_index)?, active_field_index)
                        } else {
                            (dest, active_field_index)
                        }
                    }
                    _ => (dest, None),
                };

                for (i, operand) in operands.iter().enumerate() {
                    let op = self.eval_operand(operand, None)?;
                    // Ignore zero-sized fields.
                    if !op.layout.is_zst() {
                        let field_index = active_field_index.unwrap_or(i);
                        let field_dest = self.place_field(&dest, field_index)?;
                        self.copy_op(&op, &field_dest)?;
                    }
                }
            }

            Repeat(ref operand, _) => {
                let op = self.eval_operand(operand, None)?;
                let dest = self.force_allocation(&dest)?;
                let length = dest.len(self)?;

                if let Some(first_ptr) = self.check_mplace_access(&dest, None)? {
                    // Write the first.
                    let first = self.mplace_field(&dest, 0)?;
                    self.copy_op(&op, &first.into())?;

                    if length > 1 {
                        let elem_size = first.layout.size;
                        // Copy the rest. This is performance-sensitive code
                        // for big static/const arrays!
                        let rest_ptr = first_ptr.offset(elem_size, self)?;
                        self.memory.copy_repeatedly(
                            first_ptr,
                            rest_ptr,
                            elem_size,
                            length - 1,
                            /*nonoverlapping:*/ true,
                        )?;
                    }
                }
            }

            Len(place) => {
                // FIXME(CTFE): don't allow computing the length of arrays in const eval
                let src = self.eval_place(place)?;
                let mplace = self.force_allocation(&src)?;
                let len = mplace.len(self)?;
                self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?;
            }

            AddressOf(_, place) | Ref(_, _, place) => {
                let src = self.eval_place(place)?;
                let place = self.force_allocation(&src)?;
                if place.layout.size.bytes() > 0 {
                    // definitely not a ZST
                    assert!(place.ptr.is_ptr(), "non-ZST places should be normalized to `Pointer`");
                }
                self.write_immediate(place.to_ref(), &dest)?;
            }

            NullaryOp(mir::NullOp::Box, _) => {
                M::box_alloc(self, &dest)?;
            }

            NullaryOp(mir::NullOp::SizeOf, ty) => {
                let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty);
                let layout = self.layout_of(ty)?;
                if layout.is_unsized() {
                    // FIXME: This should be a span_bug (#80742)
                    self.tcx.sess.delay_span_bug(
                        self.frame().current_span(),
                        &format!("SizeOf nullary MIR operator called for unsized type {}", ty),
                    );
                    throw_inval!(SizeOfUnsizedType(ty));
                }
                self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), &dest)?;
            }

            Cast(cast_kind, ref operand, cast_ty) => {
                let src = self.eval_operand(operand, None)?;
                let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty);
                self.cast(&src, cast_kind, cast_ty, &dest)?;
            }

            Discriminant(place) => {
                let op = self.eval_place_to_op(place, None)?;
                let discr_val = self.read_discriminant(&op)?.0;
                self.write_scalar(discr_val, &dest)?;
            }
        }

        trace!("{:?}", self.dump_place(*dest));

        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
        info!("{:?}", terminator.kind);

        self.eval_terminator(terminator)?;
        if !self.stack().is_empty() {
            if let Ok(loc) = self.frame().loc {
                info!("// executing {:?}", loc.block);
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use serde_json::error::Result;
use serde_json::ser::{Serializer, Formatter};
use serde::ser;
use std::io;

pub struct LatticeFormatter {
    current_indent: usize,
    has_value: bool,
    max_indent: usize,
    indent: &'static [u8],
}

impl LatticeFormatter {
    pub fn new() -> Self {
        LatticeFormatter::with_max_indent(2)
    }

    pub fn with_max_indent(max_indent: usize) -> Self {
        LatticeFormatter {
            current_indent: 0,
            has_value: false,
            max_indent: max_indent,
            indent: b"  ",
        }
    }

    #[inline]
    fn above_max_indent(&self) -> bool {
        self.current_indent > self.max_indent
    }

    #[inline]
    fn begin_colletion_item<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
    where
        W: io::Write,
    {
        match (first, self.above_max_indent()) {
            (true, false) => {
                try!(writer.write_all(b"\n"));
                indent(writer, self.current_indent, self.indent)
            },
            (false, false) => {
                try!(writer.write_all(b",\n"));
                indent(writer, self.current_indent, self.indent)
            },
            (false, true) => {
                try!(writer.write_all(b", "));
                Ok(())
            },
            (true, true) => Ok(()),
        }
    }
}

impl Default for LatticeFormatter {
    fn default() -> Self {
        LatticeFormatter::new()
    }
}

impl Formatter for LatticeFormatter {

    #[inline]
    fn begin_array<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        self.current_indent += 1;
        self.has_value = false;
        writer.write_all(b"[")
    }

    #[inline]
    fn end_array<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {

        self.current_indent -= 1;

        if !self.above_max_indent() && self.has_value {
            try!(writer.write_all(b"\n"));
            try!(indent(writer, self.current_indent, self.indent));
        }

        writer.write_all(b"]")
    }

    #[inline]
    fn begin_array_value<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
    where
        W: io::Write,
    {
        self.begin_colletion_item(writer, first)
    }

    #[inline]
    fn end_array_value<W: ?Sized>(&mut self, _writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        self.has_value = true;
        Ok(())
    }

    #[inline]
    fn begin_object<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        self.current_indent += 1;
        self.has_value = false;
        writer.write_all(b"{")
    }

    #[inline]
    fn end_object<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        if !self.above_max_indent() && self.has_value {
            try!(writer.write_all(b"\n"));
            try!(indent(writer, self.current_indent - 1, self.indent));
        }
        self.current_indent -= 1;
        writer.write_all(b"}")
    }

    #[inline]
    fn begin_object_key<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
    where
        W: io::Write,
    {
        self.begin_colletion_item(writer, first)
    }

    #[inline]
    fn begin_object_value<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        writer.write_all(b": ")
    }

    #[inline]
    fn end_object_value<W: ?Sized>(&mut self, _writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        self.has_value = true;
        Ok(())
    }
}

#[inline]
pub fn to_writer_lattice<W, T: ?Sized>(writer: W, value: &T) -> Result<()>
where
    W: io::Write,
    T: ser::Serialize,
{
    let mut ser = Serializer::with_formatter(writer, LatticeFormatter::new());
    try!(value.serialize(&mut ser));
    Ok(())
}

#[inline]
pub fn to_vec_lattice<T: ?Sized>(value: &T) -> Result<Vec<u8>>
where
    T: ser::Serialize,
{
    let mut writer = Vec::with_capacity(128);
    try!(to_writer_lattice(&mut writer, value));
    Ok(writer)
}

#[inline]
pub fn to_string_lattice<T: ?Sized>(value: &T) -> Result<String>
where
    T: ser::Serialize,
{
    let vec = try!(to_vec_lattice(value));
    let string = unsafe {
        // We do not emit invalid UTF-8.
        String::from_utf8_unchecked(vec)
    };
    Ok(string)
}

fn indent<W: ?Sized>(wr: &mut W, n: usize, s: &[u8]) -> io::Result<()>
where
    W: io::Write,
{
    for _ in 0..n {
        try!(wr.write_all(s));
    }

    Ok(())
}
<commit_msg>Give some polish<commit_after>use serde_json::error::Result;
use serde_json::ser::{Serializer, Formatter};
use serde::ser;
use std::io;

pub struct LatticeFormatter {
    current_indent: usize,
    has_value: bool,
    max_indent: usize,
    indent: &'static [u8],
}

impl LatticeFormatter {
    pub fn new() -> Self {
        LatticeFormatter::with_max_indent(2)
    }

    pub fn with_max_indent(max_indent: usize) -> Self {
        LatticeFormatter {
            current_indent: 0,
            has_value: false,
            max_indent: max_indent,
            indent: b"  ",
        }
    }

    #[inline]
    fn above_max_indent(&self) -> bool {
        self.current_indent > self.max_indent
    }

    #[inline]
    fn begin_colletion_item<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
        where W: io::Write
    {
        match (first, self.above_max_indent()) {
            (true, false) => {
                try!(writer.write_all(b"\n"));
                indent(writer, self.current_indent, self.indent)
            }
            (false, false) => {
                try!(writer.write_all(b",\n"));
                indent(writer, self.current_indent, self.indent)
            }
            (false, true) => {
                try!(writer.write_all(b", "));
                Ok(())
            }
            (true, true) => Ok(()),
        }
    }
}

impl Default for LatticeFormatter {
    fn default() -> Self {
        LatticeFormatter::new()
    }
}

impl Formatter for LatticeFormatter {
    #[inline]
    fn begin_array<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        self.current_indent += 1;
        self.has_value = false;
        writer.write_all(b"[")
    }

    #[inline]
    fn end_array<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        if !self.above_max_indent() && self.has_value {
            try!(writer.write_all(b"\n"));
            try!(indent(writer, self.current_indent - 1, self.indent));
        }
        self.current_indent -= 1;
        writer.write_all(b"]")
    }

    #[inline]
    fn begin_array_value<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
        where W: io::Write
    {
        self.begin_colletion_item(writer, first)
    }

    #[inline]
    fn end_array_value<W: ?Sized>(&mut self, _writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        self.has_value = true;
        Ok(())
    }

    #[inline]
    fn begin_object<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        self.current_indent += 1;
        self.has_value = false;
        writer.write_all(b"{")
    }

    #[inline]
    fn end_object<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        if !self.above_max_indent() && self.has_value {
            try!(writer.write_all(b"\n"));
            try!(indent(writer, self.current_indent - 1, self.indent));
        }
        self.current_indent -= 1;
        writer.write_all(b"}")
    }

    #[inline]
    fn begin_object_key<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
        where W: io::Write
    {
        self.begin_colletion_item(writer, first)
    }

    #[inline]
    fn begin_object_value<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        writer.write_all(b": ")
    }

    #[inline]
    fn end_object_value<W: ?Sized>(&mut self, _writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        self.has_value = true;
        Ok(())
    }
}

#[inline]
pub fn to_writer_lattice<W, T: ?Sized>(writer: W, value: &T) -> Result<()>
    where W: io::Write,
          T: ser::Serialize
{
    let mut ser = Serializer::with_formatter(writer, LatticeFormatter::new());
    try!(value.serialize(&mut ser));
    Ok(())
}

#[inline]
pub fn to_vec_lattice<T: ?Sized>(value: &T) -> Result<Vec<u8>>
    where T: ser::Serialize
{
    let mut writer = Vec::with_capacity(128);
    try!(to_writer_lattice(&mut writer, value));
    Ok(writer)
}

#[inline]
pub fn to_string_lattice<T: ?Sized>(value: &T) -> Result<String>
    where T: ser::Serialize
{
    let vec = try!(to_vec_lattice(value));
    let string = unsafe {
        // We do not emit invalid UTF-8.
        String::from_utf8_unchecked(vec)
    };
    Ok(string)
}

fn indent<W: ?Sized>(wr: &mut W, n: usize, s: &[u8]) -> io::Result<()>
    where W: io::Write
{
    for _ in 0..n {
        try!(wr.write_all(s));
    }

    Ok(())
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: usize = 0x3F000000;
const GPIO_BASE: usize = BCM2708_PERI_BASE + 0x200000;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = 4 * 1024;

pub struct Bcm2835Peripheral {
    pub addr_p: *const usize,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut usize
}

impl Bcm2835Peripheral {
    pub fn new() -> Bcm2835Peripheral {
        let mem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = &[
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            MapOption::MapOffset(GPIO_BASE),
            MapOption::MapFd(mem_file.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };

        Bcm2835Peripheral {
            addr_p: &GPIO_BASE,
            mem_fd: mem_file,
            addr: mmap.data() as *mut usize,  //switch order to avoid error of moved value `mmap`
            map: mmap,
        }
    }

    pub unsafe fn in_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k &= !(7 << (((y) % 10) * 3));
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn out_gpio(&self, y: isize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= 1 << (((y) % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio_alt(&self, y: isize, a: usize) {
        let mut k = volatile_load(self.addr.offset(y / 10));
        k |= match a {
            a if a <= 3 => a + 4,
            4 => 3,
            _ => 2,
        } << ((y % 10) * 3);
        volatile_store(self.addr.offset(y / 10), k)
    }

    pub unsafe fn set_gpio(&self, val: usize) {
        volatile_store(self.addr.offset(7), val);
    }
    pub unsafe fn clear_gpio(&self, val: usize) {
        volatile_store(self.addr.offset(10), val);
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<commit_msg>clean up and add read fn<commit_after>//volatile_store is the same as `*ptr = value;` (except that the optimiser won't touch it)
#![allow(dead_code)]
extern crate mmap;
extern crate core;

use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use mmap::{MemoryMap, MapOption};
use std::os::unix::prelude::AsRawFd;
use self::core::intrinsics::{volatile_load, volatile_store};

const BCM2708_PERI_BASE: usize = 0x3F000000;
const GPIO_BASE: usize = BCM2708_PERI_BASE + 0x200000;
const O_SYNC: u32 = 1052672;
const MAP_SHARED: i32 = 0x0001;
const BLOCK_SIZE: usize = 4 * 1024;

pub struct Bcm2835Peripheral {
    pub addr_p: *const usize,
    pub mem_fd: ::std::fs::File,
    pub map: ::mmap::MemoryMap,
    pub addr: *mut usize
}

impl Bcm2835Peripheral {
    pub fn new() -> Bcm2835Peripheral {
        let mem_file = OpenOptions::new()
            .read(true)
            .write(true)
            .mode(O_SYNC)
            .open("/dev/mem")
            .expect("unable to open /dev/mem, Are you root?");

        let map_opts = &[
            MapOption::MapNonStandardFlags(MAP_SHARED),
            MapOption::MapReadable,
            MapOption::MapWritable,
            MapOption::MapOffset(GPIO_BASE),
            MapOption::MapFd(mem_file.as_raw_fd())
        ];

        let mmap = match MemoryMap::new(BLOCK_SIZE, map_opts) {
            Ok(mmap) => mmap,
            Err(e) => panic!("ERR: {}", e)
        };

        Bcm2835Peripheral {
            addr_p: &GPIO_BASE,
            mem_fd: mem_file,
            addr: mmap.data() as *mut usize,  //switch order to avoid error of moved value `mmap`
            map: mmap,
        }
    }

    pub unsafe fn out(&self, y: isize) {
        let addr = self.addr.offset(y/10);
        let mut a = volatile_load(addr);
        a &= !(7 << (((y) % 10) * 3));
        a |= 1 << (((y) % 10) * 3);
        volatile_store(addr, a)
    }

    pub unsafe fn set_alt(&self, y: isize, a: usize) {
        let addr = self.addr.offset(y/10);
        let mut k = volatile_load(addr);
        k |= match a {
            a if a <= 3 => a + 4,
            4 => 3,
            _ => 2,
        } << ((y % 10) * 3);
        volatile_store(addr, k)
    }

    pub unsafe fn set(&self, val: usize) {
        volatile_store(self.addr.offset(7), val);
    }
    pub unsafe fn clear(&self, val: usize) {
        volatile_store(self.addr.offset(10), val);
    }
    pub unsafe fn read(&self, y: isize) -> usize {
        let addr = self.addr.offset(13);
        let mut k = volatile_load(addr);
        k &= 1 << y;
        volatile_store(addr, k);
        return k;
    }
}

impl Drop for Bcm2835Peripheral {
    fn drop(&mut self) {
        println!("Unmapped Peripheral {:?}", self.map.data())
    }
}
<|endoftext|>


<commit_before>//! Utilies for running in a build script.

use grammar::parse_tree as pt;
use grammar::repr as r;
use lalrpop_util::ParseError;
use lexer::intern_token;
use lr1;
use normalize;
use parser;
use rust::RustWrite;
use tok;
use self::filetext::FileText;

use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::exit;

mod filetext;

pub fn process_root() -> io::Result<()> {
    process_dir("src", false)
}

pub fn process_root_unconditionally() -> io::Result<()> {
    process_dir("src", true)
}

fn process_dir<P:AsRef<Path>>(root_dir: P, force_build: bool) -> io::Result<()> {
    let lalrpop_files = try!(lalrpop_files(root_dir));
    for lalrpop_file in lalrpop_files {
        let rs_file = lalrpop_file.with_extension("rs");
        if force_build || try!(needs_rebuild(&lalrpop_file, &rs_file)) {
            try!(remove_old_file(&rs_file));
            let grammar = try!(parse_and_normalize_grammar(lalrpop_file));
            try!(emit_recursive_ascent(&rs_file, &grammar));
            try!(make_read_only(&rs_file));
        }
    }
    Ok(())
}

fn remove_old_file(rs_file: &Path) -> io::Result<()> {
    match fs::remove_file(rs_file) {
        Ok(()) => Ok(()),
        Err(e) => {
            match e.kind() {
                io::ErrorKind::NotFound => Ok(()),
                _ => Err(e),
            }
        }
    }
}

fn needs_rebuild(lalrpop_file: &Path,
                 rs_file: &Path)
                 -> io::Result<bool>
{
    return match fs::metadata(&rs_file) {
        Ok(rs_metadata) => {
            let lalrpop_metadata = try!(fs::metadata(&lalrpop_file));
            Ok(compare_modification_times(&lalrpop_metadata, &rs_metadata))
        }
        Err(e) => {
            match e.kind() {
                io::ErrorKind::NotFound => Ok(true),
                _ => Err(e),
            }
        }
    };

    #[cfg(unix)]
    fn compare_modification_times(lalrpop_metadata: &fs::Metadata,
                                  rs_metadata: &fs::Metadata)
                                  -> bool
    {
        use std::os::unix::fs::MetadataExt;
        lalrpop_metadata.mtime() >= rs_metadata.mtime()
    }

    #[cfg(not(unix))]
    fn compare_modification_times(lalrpop_metadata: &fs::Metadata,
                                  rs_metadata: &fs::Metadata)
                                  -> bool
    {
        true
    }
}

fn make_read_only(rs_file: &Path) -> io::Result<()> {
    let rs_metadata = try!(fs::metadata(&rs_file));
    let mut rs_permissions = rs_metadata.permissions();
    rs_permissions.set_readonly(true);
    fs::set_permissions(&rs_file, rs_permissions)
}

fn lalrpop_files<P:AsRef<Path>>(root_dir: P) -> io::Result<Vec<PathBuf>> {
    let mut result = vec![];
    for entry in try!(fs::read_dir(root_dir)) {
        let entry = try!(entry);
        let file_type = try!(entry.file_type());

        let path = entry.path();

        if file_type.is_dir() {
            result.extend(try!(lalrpop_files(&path)));
        }

        if
            file_type.is_file() &&
            path.extension().is_some() &&
            path.extension().unwrap() == "lalrpop"
        {
            result.push(path);
        }
    }
    Ok(result)
}

fn parse_and_normalize_grammar(path: PathBuf) -> io::Result<r::Grammar> {
    let input = try!(FileText::from_path(path));

    let grammar = match parser::parse_grammar(input.text()) {
        Ok(grammar) => grammar,

        Err(ParseError::InvalidToken { location }) => {
            let ch = input.text()[location..].chars().next().unwrap();
            report_error(&input,
                         pt::Span(location, location),
                         &format!("invalid character `{}`", ch));
        }

        Err(ParseError::UnrecognizedToken { token: None, expected: _ }) => {
            let len = input.text().len();
            report_error(&input,
                         pt::Span(len, len),
                         &format!("unexpected end of file"));
        }

        Err(ParseError::UnrecognizedToken { token: Some((lo, _, hi)), expected }) => {
            assert!(expected.is_empty()); // didn't implement this yet :)
            let text = &input.text()[lo..hi];
            report_error(&input,
                         pt::Span(lo, hi),
                         &format!("unexpected token: `{}`", text));
        }

        Err(ParseError::ExtraToken { token: (lo, _, hi) }) => {
            let text = &input.text()[lo..hi];
            report_error(&input,
                         pt::Span(lo, hi),
                         &format!("extra token at end of input: `{}`", text));
        }

        Err(ParseError::User { error }) => {
            let string = match error.code {
                tok::ErrorCode::UnrecognizedToken =>
                    "unrecognized token",
                tok::ErrorCode::UnterminatedEscape =>
                    "unterminated escape; missing '`'?",
                tok::ErrorCode::UnterminatedStringLiteral =>
                    "unterminated string literal; missing `\"`?",
                tok::ErrorCode::ExpectedStringLiteral =>
                    "expected string literal; missing `\"`?",
                tok::ErrorCode::UnterminatedCode =>
                    "unterminated code block; perhaps a missing `;`, `)`, `]` or `}`?"
            };

            report_error(&input,
                         pt::Span(error.location, error.location + 1),
                         string)
        }
    };

    match normalize::normalize(grammar) {
        Ok(grammar) => Ok(grammar),
        Err(error) => {
            report_error(&input,
                         error.span,
                         &error.message)
        }
    }
}

fn report_error(file_text: &FileText, span: pt::Span, message: &str) -> ! {
    println!("{} error: {}", file_text.span_str(span), message);

    let out = io::stdout();
    let mut out = out.lock();
    file_text.highlight(span, &mut out).unwrap();

    exit(1);
}

fn emit_uses<W:Write>(grammar: &r::Grammar,
                      rust: &mut RustWrite<W>)
                      -> io::Result<()>
{
    rust.write_uses("", grammar)
}

fn emit_recursive_ascent(output_path: &Path, grammar: &r::Grammar) -> io::Result<()>
{
    let output_file = try!(fs::File::create(output_path));
    let mut rust = RustWrite::new(output_file);

    // We generate a module structure like this:
    //
    // ```
    // mod <output-file> {
    //     // For each public symbol:
    //     pub fn parse_XYZ();
    //     mod __XYZ { ... }
    //
    //     // For each bit of action code:
    //     <action-code>
    // }
    // ```
    //
    // Note that the action code goes in the outer module.  This is
    // intentional because it means that the foo.lalrpop file serves
    // as a module in the rust hierarchy, so if the action code
    // includes things like `super::` it will resolve in the natural
    // way.

    // often some of the uses are not used here
    rust!(rust, "#![allow(unused_imports)]");

    // we always thread the parameters through to the action code,
    // even if they are not used, and hence we need to disable the
    // unused variables lint, which otherwise gets very excited.
    if !grammar.parameters.is_empty() {
        rust!(rust, "#![allow(unused_variables)]");
    }

    try!(emit_uses(grammar, &mut rust));

    if grammar.start_nonterminals.is_empty() {
        println!("Error: no public symbols declared in grammar");
        exit(1);
    }

    for (&user_nt, &start_nt) in &grammar.start_nonterminals {
        // We generate these, so there should always be exactly 1
        // production. Otherwise the LR(1) algorithm doesn't know
        // where to stop!
        assert_eq!(grammar.productions_for(start_nt).len(), 1);

        let states = match lr1::build_states(&grammar, start_nt) {
            Ok(states) => states,
            Err(error) => {
                try!(lr1::report_error(&mut io::stdout(), &grammar, &error));
                exit(1)
            }
        };

        try!(lr1::ascent::compile(&grammar, user_nt, start_nt, &states, &mut rust));

        rust!(rust, "pub use self::{}parse{}::parse_{};",
              grammar.prefix, start_nt, user_nt);
    }

    if let Some(ref intern_token) = grammar.intern_token {
        try!(intern_token::compile(&grammar, intern_token, &mut rust));
    }

    try!(emit_action_code(grammar, &mut rust));

    try!(emit_to_triple_trait(grammar, &mut rust));

    Ok(())
}

fn emit_action_code<W:Write>(grammar: &r::Grammar,
                             rust: &mut RustWrite<W>)
                             -> io::Result<()>
{
    for (i, defn) in grammar.action_fn_defns.iter().enumerate() {
        rust!(rust, "");

        let ret_type = if defn.fallible {
            format!("Result<{},{}ParseError<{},{},{}>>",
                    defn.ret_type,
                    grammar.prefix,
                    grammar.types.terminal_loc_type(),
                    grammar.types.terminal_token_type(),
                    grammar.types.error_type())
        } else {
            format!("{}", defn.ret_type)
        };

        try!(rust.write_pub_fn_header(
            grammar,
            format!("{}action{}", grammar.prefix, i),
            vec![],
            defn.arg_patterns.iter()
                             .zip(defn.arg_types.iter())
                             .map(|(p, t)| format!("{}: {}", p, t))
                             .collect(),
            ret_type,
            vec![]));
        rust!(rust, "{{");
        rust!(rust, "{}", defn.code);
        rust!(rust, "}}");
    }
    Ok(())
}

fn emit_to_triple_trait<W:Write>(grammar: &r::Grammar,
                                 rust: &mut RustWrite<W>)
                                 -> io::Result<()>
{
    #![allow(non_snake_case)]

    let L = grammar.types.terminal_loc_type();
    let T = grammar.types.terminal_token_type();
    let E = grammar.types.error_type();

    let mut user_type_parameters = String::new();
    for type_parameter in &grammar.type_parameters {
        user_type_parameters.push_str(&format!("{}, ", type_parameter));
    }

    rust!(rust, "");
    rust!(rust, "pub trait {}ToTriple<{}> {{", grammar.prefix, user_type_parameters);
    rust!(rust, "type Error;");
    rust!(rust, "fn to_triple(value: Self) -> Result<({},{},{}),Self::Error>;", L, T, L);
    rust!(rust, "}}");

    rust!(rust, "");
    if grammar.types.opt_terminal_loc_type().is_some() {
        rust!(rust, "impl<{}> {}ToTriple<{}> for ({}, {}, {}) {{",
              user_type_parameters, grammar.prefix, user_type_parameters, L, T, L);
        rust!(rust, "type Error = {};", E);
        rust!(rust, "fn to_triple(value: Self) -> Result<({},{},{}),{}> {{", L, T, L, E);
        rust!(rust, "Ok(value)");
        rust!(rust, "}}");
        rust!(rust, "}}");

        rust!(rust, "impl<{}> {}ToTriple<{}> for Result<({}, {}, {}),{}> {{",
              user_type_parameters, grammar.prefix, user_type_parameters, L, T, L, E);
        rust!(rust, "type Error = {};", E);
        rust!(rust, "fn to_triple(value: Self) -> Result<({},{},{}),{}> {{", L, T, L, E);
        rust!(rust, "value");
        rust!(rust, "}}");
        rust!(rust, "}}");
    } else {
        rust!(rust, "impl<{}> {}ToTriple<{}> for {} {{",
              user_type_parameters, grammar.prefix, user_type_parameters, T);
        rust!(rust, "type Error = {};", E);
        rust!(rust, "fn to_triple(value: Self) -> Result<((),{},()),{}> {{", T, E);
        rust!(rust, "Ok(((), value, ()))");
        rust!(rust, "}}");
        rust!(rust, "}}");

        rust!(rust, "impl<{}> {}ToTriple<{}> for Result<({}),{}> {{",
              user_type_parameters, grammar.prefix, user_type_parameters, T, E);
        rust!(rust, "type Error = {};", E);
        rust!(rust, "fn to_triple(value: Self) -> Result<((),{},()),{}> {{", T, E);
        rust!(rust, "value.map(|v| ((), v, ()))");
        rust!(rust, "}}");
        rust!(rust, "}}");
    }

    Ok(())
}
<commit_msg>Copy brson's changes to lalrpop-snap to lalrpop and add windows timestamp check<commit_after>//! Utilies for running in a build script.

use grammar::parse_tree as pt;
use grammar::repr as r;
use lalrpop_util::ParseError;
use lexer::intern_token;
use lr1;
use normalize;
use parser;
use rust::RustWrite;
use tok;
use self::filetext::FileText;

use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::exit;

mod filetext;

pub fn process_root() -> io::Result<()> {
    process_dir("src", false)
}

pub fn process_root_unconditionally() -> io::Result<()> {
    process_dir("src", true)
}

fn process_dir<P:AsRef<Path>>(root_dir: P, force_build: bool) -> io::Result<()> {
    let lalrpop_files = try!(lalrpop_files(root_dir));
    for lalrpop_file in lalrpop_files {
        let rs_file = lalrpop_file.with_extension("rs");
        if force_build || try!(needs_rebuild(&lalrpop_file, &rs_file)) {
            try!(remove_old_file(&rs_file));
            let grammar = try!(parse_and_normalize_grammar(lalrpop_file));
            try!(emit_recursive_ascent(&rs_file, &grammar));
            try!(make_read_only(&rs_file));
        }
    }
    Ok(())
}

fn remove_old_file(rs_file: &Path) -> io::Result<()> {
    match fs::remove_file(rs_file) {
        Ok(()) => Ok(()),
        Err(e) => {
            // Unix reports NotFound, Windows PermissionDenied!
            match e.kind() {
                io::ErrorKind::NotFound | io::ErrorKind::PermissionDenied=> Ok(()),
                _ => Err(e),
            }
        }
    }
}

fn needs_rebuild(lalrpop_file: &Path,
                 rs_file: &Path)
                 -> io::Result<bool>
{
    return match fs::metadata(&rs_file) {
        Ok(rs_metadata) => {
            let lalrpop_metadata = try!(fs::metadata(&lalrpop_file));
            Ok(compare_modification_times(&lalrpop_metadata, &rs_metadata))
        }
        Err(e) => {
            match e.kind() {
                io::ErrorKind::NotFound => Ok(true),
                _ => Err(e),
            }
        }
    };

    #[cfg(unix)]
    fn compare_modification_times(lalrpop_metadata: &fs::Metadata,
                                  rs_metadata: &fs::Metadata)
                                  -> bool
    {
        use std::os::unix::fs::MetadataExt;
        lalrpop_metadata.mtime() >= rs_metadata.mtime()
    }

    #[cfg(windows)]
    fn compare_modification_times(lalrpop_metadata: &fs::Metadata,
                                  rs_metadata: &fs::Metadata)
                                  -> bool
    {
        use std::os::windows::fs::MetadataExt;
        lalrpop_metadata.last_write_time() >= rs_metadata.last_write_time()
    }

    #[cfg(not(any(unix,windows)))]
    fn compare_modification_times(lalrpop_metadata: &fs::Metadata,
                                  rs_metadata: &fs::Metadata)
                                  -> bool
    {
        true
    }
}

fn make_read_only(rs_file: &Path) -> io::Result<()> {
    let rs_metadata = try!(fs::metadata(&rs_file));
    let mut rs_permissions = rs_metadata.permissions();
    rs_permissions.set_readonly(true);
    fs::set_permissions(&rs_file, rs_permissions)
}

fn lalrpop_files<P:AsRef<Path>>(root_dir: P) -> io::Result<Vec<PathBuf>> {
    let mut result = vec![];
    for entry in try!(fs::read_dir(root_dir)) {
        let entry = try!(entry);
        let file_type = try!(entry.file_type());

        let path = entry.path();

        if file_type.is_dir() {
            result.extend(try!(lalrpop_files(&path)));
        }

        if
            file_type.is_file() &&
            path.extension().is_some() &&
            path.extension().unwrap() == "lalrpop"
        {
            result.push(path);
        }
    }
    Ok(result)
}

fn parse_and_normalize_grammar(path: PathBuf) -> io::Result<r::Grammar> {
    let input = try!(FileText::from_path(path));

    let grammar = match parser::parse_grammar(input.text()) {
        Ok(grammar) => grammar,

        Err(ParseError::InvalidToken { location }) => {
            let ch = input.text()[location..].chars().next().unwrap();
            report_error(&input,
                         pt::Span(location, location),
                         &format!("invalid character `{}`", ch));
        }

        Err(ParseError::UnrecognizedToken { token: None, expected: _ }) => {
            let len = input.text().len();
            report_error(&input,
                         pt::Span(len, len),
                         &format!("unexpected end of file"));
        }

        Err(ParseError::UnrecognizedToken { token: Some((lo, _, hi)), expected }) => {
            assert!(expected.is_empty()); // didn't implement this yet :)
            let text = &input.text()[lo..hi];
            report_error(&input,
                         pt::Span(lo, hi),
                         &format!("unexpected token: `{}`", text));
        }

        Err(ParseError::ExtraToken { token: (lo, _, hi) }) => {
            let text = &input.text()[lo..hi];
            report_error(&input,
                         pt::Span(lo, hi),
                         &format!("extra token at end of input: `{}`", text));
        }

        Err(ParseError::User { error }) => {
            let string = match error.code {
                tok::ErrorCode::UnrecognizedToken =>
                    "unrecognized token",
                tok::ErrorCode::UnterminatedEscape =>
                    "unterminated escape; missing '`'?",
                tok::ErrorCode::UnterminatedStringLiteral =>
                    "unterminated string literal; missing `\"`?",
                tok::ErrorCode::ExpectedStringLiteral =>
                    "expected string literal; missing `\"`?",
                tok::ErrorCode::UnterminatedCode =>
                    "unterminated code block; perhaps a missing `;`, `)`, `]` or `}`?"
            };

            report_error(&input,
                         pt::Span(error.location, error.location + 1),
                         string)
        }
    };

    match normalize::normalize(grammar) {
        Ok(grammar) => Ok(grammar),
        Err(error) => {
            report_error(&input,
                         error.span,
                         &error.message)
        }
    }
}

fn report_error(file_text: &FileText, span: pt::Span, message: &str) -> ! {
    println!("{} error: {}", file_text.span_str(span), message);

    let out = io::stdout();
    let mut out = out.lock();
    file_text.highlight(span, &mut out).unwrap();

    exit(1);
}

fn emit_uses<W:Write>(grammar: &r::Grammar,
                      rust: &mut RustWrite<W>)
                      -> io::Result<()>
{
    rust.write_uses("", grammar)
}

fn emit_recursive_ascent(output_path: &Path, grammar: &r::Grammar) -> io::Result<()>
{
    let output_file = try!(fs::File::create(output_path));
    let mut rust = RustWrite::new(output_file);

    // We generate a module structure like this:
    //
    // ```
    // mod <output-file> {
    //     // For each public symbol:
    //     pub fn parse_XYZ();
    //     mod __XYZ { ... }
    //
    //     // For each bit of action code:
    //     <action-code>
    // }
    // ```
    //
    // Note that the action code goes in the outer module.  This is
    // intentional because it means that the foo.lalrpop file serves
    // as a module in the rust hierarchy, so if the action code
    // includes things like `super::` it will resolve in the natural
    // way.

    // often some of the uses are not used here
    rust!(rust, "#![allow(unused_imports)]");

    // we always thread the parameters through to the action code,
    // even if they are not used, and hence we need to disable the
    // unused variables lint, which otherwise gets very excited.
    if !grammar.parameters.is_empty() {
        rust!(rust, "#![allow(unused_variables)]");
    }

    try!(emit_uses(grammar, &mut rust));

    if grammar.start_nonterminals.is_empty() {
        println!("Error: no public symbols declared in grammar");
        exit(1);
    }

    for (&user_nt, &start_nt) in &grammar.start_nonterminals {
        // We generate these, so there should always be exactly 1
        // production. Otherwise the LR(1) algorithm doesn't know
        // where to stop!
        assert_eq!(grammar.productions_for(start_nt).len(), 1);

        let states = match lr1::build_states(&grammar, start_nt) {
            Ok(states) => states,
            Err(error) => {
                try!(lr1::report_error(&mut io::stdout(), &grammar, &error));
                exit(1)
            }
        };

        try!(lr1::ascent::compile(&grammar, user_nt, start_nt, &states, &mut rust));

        rust!(rust, "pub use self::{}parse{}::parse_{};",
              grammar.prefix, start_nt, user_nt);
    }

    if let Some(ref intern_token) = grammar.intern_token {
        try!(intern_token::compile(&grammar, intern_token, &mut rust));
    }

    try!(emit_action_code(grammar, &mut rust));

    try!(emit_to_triple_trait(grammar, &mut rust));

    Ok(())
}

fn emit_action_code<W:Write>(grammar: &r::Grammar,
                             rust: &mut RustWrite<W>)
                             -> io::Result<()>
{
    for (i, defn) in grammar.action_fn_defns.iter().enumerate() {
        rust!(rust, "");

        let ret_type = if defn.fallible {
            format!("Result<{},{}ParseError<{},{},{}>>",
                    defn.ret_type,
                    grammar.prefix,
                    grammar.types.terminal_loc_type(),
                    grammar.types.terminal_token_type(),
                    grammar.types.error_type())
        } else {
            format!("{}", defn.ret_type)
        };

        try!(rust.write_pub_fn_header(
            grammar,
            format!("{}action{}", grammar.prefix, i),
            vec![],
            defn.arg_patterns.iter()
                             .zip(defn.arg_types.iter())
                             .map(|(p, t)| format!("{}: {}", p, t))
                             .collect(),
            ret_type,
            vec![]));
        rust!(rust, "{{");
        rust!(rust, "{}", defn.code);
        rust!(rust, "}}");
    }
    Ok(())
}

fn emit_to_triple_trait<W:Write>(grammar: &r::Grammar,
                                 rust: &mut RustWrite<W>)
                                 -> io::Result<()>
{
    #![allow(non_snake_case)]

    let L = grammar.types.terminal_loc_type();
    let T = grammar.types.terminal_token_type();
    let E = grammar.types.error_type();

    let mut user_type_parameters = String::new();
    for type_parameter in &grammar.type_parameters {
        user_type_parameters.push_str(&format!("{}, ", type_parameter));
    }

    rust!(rust, "");
    rust!(rust, "pub trait {}ToTriple<{}> {{", grammar.prefix, user_type_parameters);
    rust!(rust, "type Error;");
    rust!(rust, "fn to_triple(value: Self) -> Result<({},{},{}),Self::Error>;", L, T, L);
    rust!(rust, "}}");

    rust!(rust, "");
    if grammar.types.opt_terminal_loc_type().is_some() {
        rust!(rust, "impl<{}> {}ToTriple<{}> for ({}, {}, {}) {{",
              user_type_parameters, grammar.prefix, user_type_parameters, L, T, L);
        rust!(rust, "type Error = {};", E);
        rust!(rust, "fn to_triple(value: Self) -> Result<({},{},{}),{}> {{", L, T, L, E);
        rust!(rust, "Ok(value)");
        rust!(rust, "}}");
        rust!(rust, "}}");

        rust!(rust, "impl<{}> {}ToTriple<{}> for Result<({}, {}, {}),{}> {{",
              user_type_parameters, grammar.prefix, user_type_parameters, L, T, L, E);
        rust!(rust, "type Error = {};", E);
        rust!(rust, "fn to_triple(value: Self) -> Result<({},{},{}),{}> {{", L, T, L, E);
        rust!(rust, "value");
        rust!(rust, "}}");
        rust!(rust, "}}");
    } else {
        rust!(rust, "impl<{}> {}ToTriple<{}> for {} {{",
              user_type_parameters, grammar.prefix, user_type_parameters, T);
        rust!(rust, "type Error = {};", E);
        rust!(rust, "fn to_triple(value: Self) -> Result<((),{},()),{}> {{", T, E);
        rust!(rust, "Ok(((), value, ()))");
        rust!(rust, "}}");
        rust!(rust, "}}");

        rust!(rust, "impl<{}> {}ToTriple<{}> for Result<({}),{}> {{",
              user_type_parameters, grammar.prefix, user_type_parameters, T, E);
        rust!(rust, "type Error = {};", E);
        rust!(rust, "fn to_triple(value: Self) -> Result<((),{},()),{}> {{", T, E);
        rust!(rust, "value.map(|v| ((), v, ()))");
        rust!(rust, "}}");
        rust!(rust, "}}");
    }

    Ok(())
}
<|endoftext|>


<commit_before>use ffi::prelude::LLVMTypeRef;
use ffi::{core, target, LLVMTypeKind};
use libc::{c_int, c_uint};
use compile::Compile;
use context::{Context, GetContext};
use target::TargetData;
use util::{self, Sub};
use std::{fmt, mem};
use std::marker::PhantomData;
use std::iter::Iterator;
use std::ops::Deref;

/// Defines how a value should be laid out in memory.
pub struct Type(PhantomData<[u8]>);
native_ref!(&Type = LLVMTypeRef);
impl Type {
    #[inline(always)]
    /// Get the type given as an LLVM type descriptor in the context given.
    pub fn get<'a, T>(context:&'a Context) -> &'a Type where T:Compile<'a> {
        T::get_type(context)
    }
    /// Make a new function signature with the return type and arguments given.
    pub fn new_function<'a>(ret: &'a Type, args: &[&'a Type]) -> &'a FunctionType {
        unsafe { core::LLVMFunctionType(ret.into(), args.as_ptr() as *mut LLVMTypeRef, args.len() as c_uint, 0) }.into()
    }
    /// Make a new array with the length given.
    pub fn new_array<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMArrayType(element.into(), length as c_uint) }.into()
    }
    /// Make a new vector with the length given.
    pub fn new_vector<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMVectorType(element.into(), length as c_uint) }.into()
    }
    /// Make a new pointer with the given element type.
    pub fn new_pointer<'a>(elem: &'a Type) -> &'a Type {
        unsafe { core::LLVMPointerType(elem.into(), 0 as c_uint) }.into()
    }
    /// Make a new structure type with the given types.
    pub fn new_struct<'a>(context:&'a Context, elems: &[&'a Type], packed: bool) -> &'a Type {
        unsafe { core::LLVMStructTypeInContext(context.into(), elems.as_ptr() as *mut LLVMTypeRef, elems.len() as c_uint, packed as c_int) }.into()
    }
    /// Returns true if the size of the type is known at compile-time.
    ///
    /// This is equivalent to the type implementing `Sized` in Rust
    pub fn is_sized(&self) -> bool {
        unsafe { core::LLVMTypeIsSized(self.into()) != 0 }
    }
    /// Returns true if this type is a function.
    pub fn is_function(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint
    }
    /// Returns true if this type is a struct.
    pub fn is_struct(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint
    }
    /// Returns true if this type is void.
    pub fn is_void(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMVoidTypeKind as c_uint
    }
    /// Returns true if this type is a pointer.
    pub fn is_pointer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMPointerTypeKind as c_uint
    }
    /// Returns true if this type is an integer.
    pub fn is_integer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMIntegerTypeKind as c_uint
    }
    /// Returns true if this type is any floating-point number.
    pub fn is_float(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) } as c_uint;
        kind == LLVMTypeKind::LLVMHalfTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMFloatTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMDoubleTypeKind as c_uint
    }
    /// Returns the size of the type in bytes.
    pub fn get_size(&self, target: &TargetData) -> usize {
        unsafe { target::LLVMABISizeOfType(target.into(), self.into()) as usize }
    }
    /// Returns the element of this pointer type.
    pub fn get_element(&self) -> Option<&Type> {
        unsafe { mem::transmute(core::LLVMGetElementType(self.into())) }
    }
}
get_context!(Type, LLVMGetTypeContext);
to_str!(Type, LLVMPrintTypeToString);

/// A structure type, such as a tuple or struct.
pub struct StructType;
native_ref!(&StructType = LLVMTypeRef);
impl StructType {
    /// Make a new struct with the given fields and packed representation.
    pub fn new<'a>(context: &'a Context, fields: &[&'a Type], packed: bool) -> &'a StructType {
        unsafe { core::LLVMStructTypeInContext(context.into(), fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int) }.into()
    }
    /// Make a new named struct with the given fields and packed representation.
    pub fn new_named<'a>(context: &'a Context, name: &str, fields: &[&'a Type], packed: bool) -> &'a StructType {
        util::with_cstr(name, |name| unsafe {
            let ty = core::LLVMStructCreateNamed(context.into(), name);
            core::LLVMStructSetBody(ty, fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int);
            ty.into()
        })
    }
    /// Returns the elements that make up this struct.
    pub fn get_elements(&self) -> Vec<&Type> {
        unsafe {
            let size = core::LLVMCountStructElementTypes(self.into());
            let mut els:Vec<_> = (0..size).map(|_| mem::uninitialized()).collect();
            core::LLVMGetStructElementTypes(self.into(), els.as_mut_ptr() as *mut LLVMTypeRef);
            els
        }
    }
}
unsafe impl Sub<Type> for StructType {
    fn is(ty: &Type) -> bool {
        unsafe {
            let kind = core::LLVMGetTypeKind(ty.into());
            kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint
        }
    }
}
deref!(StructType, Type);
get_context!(StructType, LLVMGetTypeContext);
to_str!(StructType, LLVMPrintTypeToString);

/// A function signature type.
pub struct FunctionType;
native_ref!(&FunctionType = LLVMTypeRef);
deref!(FunctionType, Type);
unsafe impl Sub<Type> for FunctionType {
    fn is(mut ty: &Type) -> bool {
        unsafe {
            while let Some(elem) = ty.get_element() {
                ty = elem;
            }
            let kind = core::LLVMGetTypeKind(ty.into());
            kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint
        }
    }
}
impl FunctionType {
    /// Returns the number of parameters this signature takes.
    pub fn num_params(&self) -> usize {
        unsafe { core::LLVMCountParamTypes(self.into()) as usize }
    }
    /// Returns a vector of this signature's parameters' types.
    pub fn get_params(&self) -> Vec<&Type> {
        unsafe {
            let count = core::LLVMCountParamTypes(self.into());
            let mut types:Vec<_> = (0..count).map(|_| mem::uninitialized()).collect();
            core::LLVMGetParamTypes(self.into(), types.as_mut_ptr() as *mut LLVMTypeRef);
            types
        }
    }
    /// Returns the type that this function returns.
    pub fn get_return(&self) -> &Type {
        unsafe { core::LLVMGetReturnType(self.into()).into() }
    }
}
get_context!(FunctionType, LLVMGetTypeContext);
to_str!(FunctionType, LLVMPrintTypeToString);
<commit_msg>Add macro to types module for auto-implementing `Sub`<commit_after>use ffi::prelude::LLVMTypeRef;
use ffi::{core, target, LLVMTypeKind};
use libc::{c_int, c_uint};
use compile::Compile;
use context::{Context, GetContext};
use target::TargetData;
use util::{self, Sub};
use std::{fmt, mem};
use std::marker::PhantomData;
use std::iter::Iterator;
use std::ops::Deref;

macro_rules! sub {
    ($ty:ty, $kind:ident) => (
unsafe impl Sub<::Type> for $ty {
    fn is(ty: &Type) -> bool {
        unsafe {
            let kind = core::LLVMGetTypeKind(ty.into());
            kind as c_uint == LLVMTypeKind::$kind as c_uint
        }
    }
}
deref!{$ty, Type}
    )
}

/// Defines how a value should be laid out in memory.
pub struct Type(PhantomData<[u8]>);
native_ref!(&Type = LLVMTypeRef);
impl Type {
    #[inline(always)]
    /// Get the type given as an LLVM type descriptor in the context given.
    pub fn get<'a, T>(context:&'a Context) -> &'a Type where T:Compile<'a> {
        T::get_type(context)
    }
    /// Make a new function signature with the return type and arguments given.
    pub fn new_function<'a>(ret: &'a Type, args: &[&'a Type]) -> &'a FunctionType {
        unsafe { core::LLVMFunctionType(ret.into(), args.as_ptr() as *mut LLVMTypeRef, args.len() as c_uint, 0) }.into()
    }
    /// Make a new array with the length given.
    pub fn new_array<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMArrayType(element.into(), length as c_uint) }.into()
    }
    /// Make a new vector with the length given.
    pub fn new_vector<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMVectorType(element.into(), length as c_uint) }.into()
    }
    /// Make a new pointer with the given element type.
    pub fn new_pointer<'a>(elem: &'a Type) -> &'a Type {
        unsafe { core::LLVMPointerType(elem.into(), 0 as c_uint) }.into()
    }
    /// Returns true if the size of the type is known at compile-time.
    ///
    /// This is equivalent to the type implementing `Sized` in Rust
    pub fn is_sized(&self) -> bool {
        unsafe { core::LLVMTypeIsSized(self.into()) != 0 }
    }
    /// Returns true if this type is a function.
    pub fn is_function(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint
    }
    /// Returns true if this type is a struct.
    pub fn is_struct(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint
    }
    /// Returns true if this type is void.
    pub fn is_void(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMVoidTypeKind as c_uint
    }
    /// Returns true if this type is a pointer.
    pub fn is_pointer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMPointerTypeKind as c_uint
    }
    /// Returns true if this type is an integer.
    pub fn is_integer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMIntegerTypeKind as c_uint
    }
    /// Returns true if this type is any floating-point number.
    pub fn is_float(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) } as c_uint;
        kind == LLVMTypeKind::LLVMHalfTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMFloatTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMDoubleTypeKind as c_uint
    }
    /// Returns the size of the type in bytes.
    pub fn get_size(&self, target: &TargetData) -> usize {
        unsafe { target::LLVMABISizeOfType(target.into(), self.into()) as usize }
    }
    /// Returns the element of this pointer type.
    pub fn get_element(&self) -> Option<&Type> {
        unsafe { mem::transmute(core::LLVMGetElementType(self.into())) }
    }
}
get_context!(Type, LLVMGetTypeContext);
to_str!(Type, LLVMPrintTypeToString);

/// A structure type, such as a tuple or struct.
pub struct StructType;
native_ref!(&StructType = LLVMTypeRef);
sub!{StructType, LLVMStructTypeKind}
impl StructType {
    /// Make a new struct with the given fields and packed representation.
    pub fn new<'a>(context: &'a Context, fields: &[&'a Type], packed: bool) -> &'a StructType {
        unsafe { core::LLVMStructTypeInContext(context.into(), fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int) }.into()
    }
    /// Make a new named struct with the given fields and packed representation.
    pub fn new_named<'a>(context: &'a Context, name: &str, fields: &[&'a Type], packed: bool) -> &'a StructType {
        util::with_cstr(name, |name| unsafe {
            let ty = core::LLVMStructCreateNamed(context.into(), name);
            core::LLVMStructSetBody(ty, fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int);
            ty.into()
        })
    }
    /// Returns the elements that make up this struct.
    pub fn get_elements(&self) -> Vec<&Type> {
        unsafe {
            let size = core::LLVMCountStructElementTypes(self.into());
            let mut els:Vec<_> = (0..size).map(|_| mem::uninitialized()).collect();
            core::LLVMGetStructElementTypes(self.into(), els.as_mut_ptr() as *mut LLVMTypeRef);
            els
        }
    }
}
get_context!(StructType, LLVMGetTypeContext);
to_str!(StructType, LLVMPrintTypeToString);

/// A function signature type.
pub struct FunctionType;
native_ref!(&FunctionType = LLVMTypeRef);
deref!(FunctionType, Type);
unsafe impl Sub<Type> for FunctionType {
    fn is(mut ty: &Type) -> bool {
        unsafe {
            while let Some(elem) = ty.get_element() {
                ty = elem;
            }
            let kind = core::LLVMGetTypeKind(ty.into());
            kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint
        }
    }
}
impl FunctionType {
    /// Returns the number of parameters this signature takes.
    pub fn num_params(&self) -> usize {
        unsafe { core::LLVMCountParamTypes(self.into()) as usize }
    }
    /// Returns a vector of this signature's parameters' types.
    pub fn get_params(&self) -> Vec<&Type> {
        unsafe {
            let count = core::LLVMCountParamTypes(self.into());
            let mut types:Vec<_> = (0..count).map(|_| mem::uninitialized()).collect();
            core::LLVMGetParamTypes(self.into(), types.as_mut_ptr() as *mut LLVMTypeRef);
            types
        }
    }
    /// Returns the type that this function returns.
    pub fn get_return(&self) -> &Type {
        unsafe { core::LLVMGetReturnType(self.into()).into() }
    }
}
get_context!(FunctionType, LLVMGetTypeContext);
to_str!(FunctionType, LLVMPrintTypeToString);
<|endoftext|>


<commit_before>extern crate libc;

// Data types in this library are all *logical*. They can be expressed as
// either a primitive physical type (bytes or bits of some fixed size), a
// nested type consisting of other data types, or another data type (e.g. a
// timestamp encoded as an int64)
// See arrow::Type
#[repr(C)]
pub enum Ty {
  // A degenerate NULL type represented as 0 bytes/bits
  NA = 0,

  // A boolean value represented as 1 bit
  BOOL = 1,

  // Little-endian integer types
  UINT8 = 2,
  INT8 = 3,
  UINT16 = 4,
  INT16 = 5,
  UINT32 = 6,
  INT32 = 7,
  UINT64 = 8,
  INT64 = 9,

  // 4-byte floating point value
  FLOAT = 10,

  // 8-byte floating point value
  DOUBLE = 11,

  // CHAR(N): fixed-length UTF8 string with length N
  CHAR = 12,

  // UTF8 variable-length string as List<Char>
  STRING = 13,

  // VARCHAR(N): Null-terminated string type embedded in a CHAR(N + 1)
  VARCHAR = 14,

  // Variable-length bytes (no guarantee of UTF8-ness)
  BINARY = 15,

  // By default, int32 days since the UNIX epoch
  DATE = 16,

  // Exact timestamp encoded with int64 since UNIX epoch
  // Default unit millisecond
  TIMESTAMP = 17,

  // Timestamp as double seconds since the UNIX epoch
  TIMESTAMP_DOUBLE = 18,

  // Exact time encoded with int64, default unit millisecond
  TIME = 19,

  // Precision- and scale-based decimal type. Storage type depends on the
  // parameters.
  DECIMAL = 20,

  // Decimal value encoded as a text string
  DECIMAL_TEXT = 21,

  // A list of some logical data type
  LIST = 30,

  // Struct of logical types
  STRUCT = 31,

  // Unions of logical types
  DENSE_UNION = 32,
  SPARSE_UNION = 33,

  // Union<Null, Int32, Double, String, Bool>
  JSON_SCALAR = 50,

  // User-defined type
  USER = 60
}

pub enum DataType {}
pub enum Field {}
pub enum Schema {}

// TODO: add safe APIs
// TODO: singleton instances of types

extern "C" {
  pub fn new_primitive_type(ty: Ty) -> *const DataType;
  pub fn new_list_type(data_type: *const DataType) -> *const DataType;
  pub fn new_binary_type() -> *const DataType;
  pub fn new_string_type() -> *const DataType;
  pub fn new_struct_type(field_num: i32, fields: &[*const Field]) -> *const DataType;

  pub fn data_type_equals(data_type1: *const DataType, data_type2: *const DataType) -> bool;
  pub fn value_size(data_type: *const DataType) -> i32;
  pub fn data_type_to_string(data_type: *const DataType) -> *const libc::c_char;
  pub fn release_data_type(data_type: *const DataType);

  pub fn new_field(
, data_type: *const DataType, nullable: bool) -> *const Field;
  pub fn field_equals(field1: *const Field, field2: *const Field) -> bool;
  pub fn field_to_string(field: *const Field) -> *const libc::c_char;
  pub fn release_field(field: *const Field);

  pub fn new_schema(field_num: i32, fields: &[*const Field]) -> *const Schema;
  pub fn schema_equals(s1: *const Schema, s2: *const Schema) -> bool;
  pub fn schema_to_string(schema: *const Schema) -> *const libc::c_char;
  pub fn release_schema(schema: *const Schema);
}
<commit_msg>fix typo<commit_after>extern crate libc;

// Data types in this library are all *logical*. They can be expressed as
// either a primitive physical type (bytes or bits of some fixed size), a
// nested type consisting of other data types, or another data type (e.g. a
// timestamp encoded as an int64)
// See arrow::Type
#[repr(C)]
pub enum Ty {
  // A degenerate NULL type represented as 0 bytes/bits
  NA = 0,

  // A boolean value represented as 1 bit
  BOOL = 1,

  // Little-endian integer types
  UINT8 = 2,
  INT8 = 3,
  UINT16 = 4,
  INT16 = 5,
  UINT32 = 6,
  INT32 = 7,
  UINT64 = 8,
  INT64 = 9,

  // 4-byte floating point value
  FLOAT = 10,

  // 8-byte floating point value
  DOUBLE = 11,

  // CHAR(N): fixed-length UTF8 string with length N
  CHAR = 12,

  // UTF8 variable-length string as List<Char>
  STRING = 13,

  // VARCHAR(N): Null-terminated string type embedded in a CHAR(N + 1)
  VARCHAR = 14,

  // Variable-length bytes (no guarantee of UTF8-ness)
  BINARY = 15,

  // By default, int32 days since the UNIX epoch
  DATE = 16,

  // Exact timestamp encoded with int64 since UNIX epoch
  // Default unit millisecond
  TIMESTAMP = 17,

  // Timestamp as double seconds since the UNIX epoch
  TIMESTAMP_DOUBLE = 18,

  // Exact time encoded with int64, default unit millisecond
  TIME = 19,

  // Precision- and scale-based decimal type. Storage type depends on the
  // parameters.
  DECIMAL = 20,

  // Decimal value encoded as a text string
  DECIMAL_TEXT = 21,

  // A list of some logical data type
  LIST = 30,

  // Struct of logical types
  STRUCT = 31,

  // Unions of logical types
  DENSE_UNION = 32,
  SPARSE_UNION = 33,

  // Union<Null, Int32, Double, String, Bool>
  JSON_SCALAR = 50,

  // User-defined type
  USER = 60
}

pub enum DataType {}
pub enum Field {}
pub enum Schema {}

// TODO: add safe APIs
// TODO: singleton instances of types

extern "C" {
  pub fn new_primitive_type(ty: Ty) -> *const DataType;
  pub fn new_list_type(data_type: *const DataType) -> *const DataType;
  pub fn new_binary_type() -> *const DataType;
  pub fn new_string_type() -> *const DataType;
  pub fn new_struct_type(field_num: i32, fields: &[*const Field]) -> *const DataType;

  pub fn data_type_equals(data_type1: *const DataType, data_type2: *const DataType) -> bool;
  pub fn value_size(data_type: *const DataType) -> i32;
  pub fn data_type_to_string(data_type: *const DataType) -> *const libc::c_char;
  pub fn release_data_type(data_type: *const DataType);

  pub fn new_field(name: *const libc::c_char, data_type: *const DataType, nullable: bool) -> *const Field;
  pub fn field_equals(field1: *const Field, field2: *const Field) -> bool;
  pub fn field_to_string(field: *const Field) -> *const libc::c_char;
  pub fn release_field(field: *const Field);

  pub fn new_schema(field_num: i32, fields: &[*const Field]) -> *const Schema;
  pub fn schema_equals(s1: *const Schema, s2: *const Schema) -> bool;
  pub fn schema_to_string(schema: *const Schema) -> *const libc::c_char;
  pub fn release_schema(schema: *const Schema);
}
<|endoftext|>