<commit_before>//! Defines `Body`: a lowered representation of bodies of functions, statics and
//! consts.
mod lower;
pub mod scope;

use std::{mem, ops::Index, sync::Arc};

use drop_bomb::DropBomb;
use either::Either;
use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId};
use ra_arena::{map::ArenaMap, Arena};
use ra_cfg::CfgOptions;
use ra_db::CrateId;
use ra_prof::profile;
use ra_syntax::{ast, AstNode, AstPtr};
use rustc_hash::FxHashMap;
use test_utils::mark;

pub(crate) use lower::LowerCtx;

use crate::{
    attr::Attrs,
    db::DefDatabase,
    expr::{Expr, ExprId, Pat, PatId},
    item_scope::BuiltinShadowMode,
    item_scope::ItemScope,
    nameres::CrateDefMap,
    path::{ModPath, Path},
    src::HasSource,
    AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId,
};

/// A subset of Expander that only deals with cfg attributes. We only need it to
/// avoid cyclic queries in crate def map during enum processing.
pub(crate) struct CfgExpander {
    cfg_options: CfgOptions,
    hygiene: Hygiene,
}

pub(crate) struct Expander {
    cfg_expander: CfgExpander,
    crate_def_map: Arc<CrateDefMap>,
    current_file_id: HirFileId,
    ast_id_map: Arc<AstIdMap>,
    module: ModuleId,
    recursion_limit: usize,
}

impl CfgExpander {
    pub(crate) fn new(
        db: &dyn DefDatabase,
        current_file_id: HirFileId,
        krate: CrateId,
    ) -> CfgExpander {
        let hygiene = Hygiene::new(db.upcast(), current_file_id);
        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
        CfgExpander { cfg_options, hygiene }
    }

    pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs {
        Attrs::new(owner, &self.hygiene)
    }

    pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool {
        let attrs = self.parse_attrs(owner);
        attrs.is_cfg_enabled(&self.cfg_options)
    }
}

impl Expander {
    pub(crate) fn new(
        db: &dyn DefDatabase,
        current_file_id: HirFileId,
        module: ModuleId,
    ) -> Expander {
        let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
        let crate_def_map = db.crate_def_map(module.krate);
        let ast_id_map = db.ast_id_map(current_file_id);
        Expander {
            cfg_expander,
            crate_def_map,
            current_file_id,
            ast_id_map,
            module,
            recursion_limit: 0,
        }
    }

    pub(crate) fn enter_expand<T: ast::AstNode>(
        &mut self,
        db: &dyn DefDatabase,
        local_scope: Option<&ItemScope>,
        macro_call: ast::MacroCall,
    ) -> Option<(Mark, T)> {
        self.recursion_limit += 1;
        if self.recursion_limit > 32 {
            mark::hit!(your_stack_belongs_to_me);
            return None;
        }

        let macro_call = InFile::new(self.current_file_id, &macro_call);

        if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| {
            if let Some(local_scope) = local_scope {
                if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) {
                    return Some(def);
                }
            }
            self.resolve_path_as_macro(db, &path)
        }) {
            let file_id = call_id.as_file();
            if let Some(node) = db.parse_or_expand(file_id) {
                if let Some(expr) = T::cast(node) {
                    log::debug!("macro expansion {:#?}", expr.syntax());

                    let mark = Mark {
                        file_id: self.current_file_id,
                        ast_id_map: mem::take(&mut self.ast_id_map),
                        bomb: DropBomb::new("expansion mark dropped"),
                    };
                    self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
                    self.current_file_id = file_id;
                    self.ast_id_map = db.ast_id_map(file_id);
                    return Some((mark, expr));
                }
            }
        }

        // FIXME: Instead of just dropping the error from expansion
        // report it
        None
    }

    pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
        self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
        self.current_file_id = mark.file_id;
        self.ast_id_map = mem::take(&mut mark.ast_id_map);
        self.recursion_limit -= 1;
        mark.bomb.defuse();
    }

    pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
        InFile { file_id: self.current_file_id, value }
    }

    pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool {
        self.cfg_expander.is_cfg_enabled(owner)
    }

    fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
        Path::from_src(path, &self.cfg_expander.hygiene)
    }

    fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {
        self.crate_def_map
            .resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other)
            .0
            .take_macros()
    }

    fn ast_id<N: AstNode>(&self, item: &N) -> AstId<N> {
        let file_local_id = self.ast_id_map.ast_id(item);
        AstId::new(self.current_file_id, file_local_id)
    }
}

pub(crate) struct Mark {
    file_id: HirFileId,
    ast_id_map: Arc<AstIdMap>,
    bomb: DropBomb,
}

/// The body of an item (function, const etc.).
#[derive(Debug, Eq, PartialEq)]
pub struct Body {
    pub exprs: Arena<Expr>,
    pub pats: Arena<Pat>,
    /// The patterns for the function's parameters. While the parameter types are
    /// part of the function signature, the patterns are not (they don't change
    /// the external type of the function).
    ///
    /// If this `Body` is for the body of a constant, this will just be
    /// empty.
    pub params: Vec<PatId>,
    /// The `ExprId` of the actual body expression.
    pub body_expr: ExprId,
    pub item_scope: ItemScope,
}

pub type ExprPtr = AstPtr<ast::Expr>;
pub type ExprSource = InFile<ExprPtr>;

pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
pub type PatSource = InFile<PatPtr>;

/// An item body together with the mapping from syntax nodes to HIR expression
/// IDs. This is needed to go from e.g. a position in a file to the HIR
/// expression containing it; but for type inference etc., we want to operate on
/// a structure that is agnostic to the actual positions of expressions in the
/// file, so that we don't recompute types whenever some whitespace is typed.
///
/// One complication here is that, due to macro expansion, a single `Body` might
/// be spread across several files. So, for each ExprId and PatId, we record
/// both the HirFileId and the position inside the file. However, we only store
/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
/// this properly for macros.
#[derive(Default, Debug, Eq, PartialEq)]
pub struct BodySourceMap {
    expr_map: FxHashMap<ExprSource, ExprId>,
    expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
    pat_map: FxHashMap<PatSource, PatId>,
    pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
    field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordField>>>,
    expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
}

#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
pub struct SyntheticSyntax;

impl Body {
    pub(crate) fn body_with_source_map_query(
        db: &dyn DefDatabase,
        def: DefWithBodyId,
    ) -> (Arc<Body>, Arc<BodySourceMap>) {
        let _p = profile("body_with_source_map_query");
        let mut params = None;

        let (file_id, module, body) = match def {
            DefWithBodyId::FunctionId(f) => {
                let f = f.lookup(db);
                let src = f.source(db);
                params = src.value.param_list();
                (src.file_id, f.module(db), src.value.body().map(ast::Expr::from))
            }
            DefWithBodyId::ConstId(c) => {
                let c = c.lookup(db);
                let src = c.source(db);
                (src.file_id, c.module(db), src.value.body())
            }
            DefWithBodyId::StaticId(s) => {
                let s = s.lookup(db);
                let src = s.source(db);
                (src.file_id, s.module(db), src.value.body())
            }
        };
        let expander = Expander::new(db, file_id, module);
        let (body, source_map) = Body::new(db, def, expander, params, body);
        (Arc::new(body), Arc::new(source_map))
    }

    pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<Body> {
        db.body_with_source_map(def).0
    }

    fn new(
        db: &dyn DefDatabase,
        def: DefWithBodyId,
        expander: Expander,
        params: Option<ast::ParamList>,
        body: Option<ast::Expr>,
    ) -> (Body, BodySourceMap) {
        lower::lower(db, def, expander, params, body)
    }
}

impl Index<ExprId> for Body {
    type Output = Expr;

    fn index(&self, expr: ExprId) -> &Expr {
        &self.exprs[expr]
    }
}

impl Index<PatId> for Body {
    type Output = Pat;

    fn index(&self, pat: PatId) -> &Pat {
        &self.pats[pat]
    }
}

impl BodySourceMap {
    pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
        self.expr_map_back[expr].clone()
    }

    pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
        let src = node.map(|it| AstPtr::new(it));
        self.expr_map.get(&src).cloned()
    }

    pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> {
        let src = node.map(|it| AstPtr::new(it));
        self.expansions.get(&src).cloned()
    }

    pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
        self.pat_map_back[pat].clone()
    }

    pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
        let src = node.map(|it| Either::Left(AstPtr::new(it)));
        self.pat_map.get(&src).cloned()
    }

    pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> {
        let src = node.map(|it| Either::Right(AstPtr::new(it)));
        self.pat_map.get(&src).cloned()
    }

    pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> {
        self.field_map[&(expr, field)].clone()
    }
}

#[cfg(test)]
mod tests {
    use ra_db::{fixture::WithFixture, SourceDatabase};
    use test_utils::mark;

    use crate::ModuleDefId;

    use super::*;

    fn lower(ra_fixture: &str) -> Arc<Body> {
        let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture);

        let krate = db.crate_graph().iter().next().unwrap();
        let def_map = db.crate_def_map(krate);
        let module = def_map.modules_for_file(file_id).next().unwrap();
        let module = &def_map[module];
        let fn_def = match module.scope.declarations().next().unwrap() {
            ModuleDefId::FunctionId(it) => it,
            _ => panic!(),
        };

        db.body(fn_def.into())
    }

    #[test]
    fn your_stack_belongs_to_me() {
        mark::check!(your_stack_belongs_to_me);
        lower(
            r"
macro_rules! n_nuple {
    ($e:tt) => ();
    ($($rest:tt)*) => {{
        (n_nuple!($($rest)*)None,)
    }};
}
fn main() { n_nuple!(1,2,3); }
",
        );
    }
}
<commit_msg>Bump macro recursion limit in release<commit_after>//! Defines `Body`: a lowered representation of bodies of functions, statics and
//! consts.
mod lower;
pub mod scope;

use std::{mem, ops::Index, sync::Arc};

use drop_bomb::DropBomb;
use either::Either;
use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId};
use ra_arena::{map::ArenaMap, Arena};
use ra_cfg::CfgOptions;
use ra_db::CrateId;
use ra_prof::profile;
use ra_syntax::{ast, AstNode, AstPtr};
use rustc_hash::FxHashMap;
use test_utils::mark;

pub(crate) use lower::LowerCtx;

use crate::{
    attr::Attrs,
    db::DefDatabase,
    expr::{Expr, ExprId, Pat, PatId},
    item_scope::BuiltinShadowMode,
    item_scope::ItemScope,
    nameres::CrateDefMap,
    path::{ModPath, Path},
    src::HasSource,
    AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId,
};

/// A subset of Expander that only deals with cfg attributes. We only need it to
/// avoid cyclic queries in crate def map during enum processing.
pub(crate) struct CfgExpander {
    cfg_options: CfgOptions,
    hygiene: Hygiene,
}

pub(crate) struct Expander {
    cfg_expander: CfgExpander,
    crate_def_map: Arc<CrateDefMap>,
    current_file_id: HirFileId,
    ast_id_map: Arc<AstIdMap>,
    module: ModuleId,
    recursion_limit: usize,
}

#[cfg(test)]
const EXPANSION_RECURSION_LIMIT: usize = 32;

#[cfg(not(test))]
const EXPANSION_RECURSION_LIMIT: usize = 128;

impl CfgExpander {
    pub(crate) fn new(
        db: &dyn DefDatabase,
        current_file_id: HirFileId,
        krate: CrateId,
    ) -> CfgExpander {
        let hygiene = Hygiene::new(db.upcast(), current_file_id);
        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
        CfgExpander { cfg_options, hygiene }
    }

    pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs {
        Attrs::new(owner, &self.hygiene)
    }

    pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool {
        let attrs = self.parse_attrs(owner);
        attrs.is_cfg_enabled(&self.cfg_options)
    }
}

impl Expander {
    pub(crate) fn new(
        db: &dyn DefDatabase,
        current_file_id: HirFileId,
        module: ModuleId,
    ) -> Expander {
        let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
        let crate_def_map = db.crate_def_map(module.krate);
        let ast_id_map = db.ast_id_map(current_file_id);
        Expander {
            cfg_expander,
            crate_def_map,
            current_file_id,
            ast_id_map,
            module,
            recursion_limit: 0,
        }
    }

    pub(crate) fn enter_expand<T: ast::AstNode>(
        &mut self,
        db: &dyn DefDatabase,
        local_scope: Option<&ItemScope>,
        macro_call: ast::MacroCall,
    ) -> Option<(Mark, T)> {
        self.recursion_limit += 1;
        if self.recursion_limit > EXPANSION_RECURSION_LIMIT {
            mark::hit!(your_stack_belongs_to_me);
            return None;
        }

        let macro_call = InFile::new(self.current_file_id, &macro_call);

        if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| {
            if let Some(local_scope) = local_scope {
                if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) {
                    return Some(def);
                }
            }
            self.resolve_path_as_macro(db, &path)
        }) {
            let file_id = call_id.as_file();
            if let Some(node) = db.parse_or_expand(file_id) {
                if let Some(expr) = T::cast(node) {
                    log::debug!("macro expansion {:#?}", expr.syntax());

                    let mark = Mark {
                        file_id: self.current_file_id,
                        ast_id_map: mem::take(&mut self.ast_id_map),
                        bomb: DropBomb::new("expansion mark dropped"),
                    };
                    self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
                    self.current_file_id = file_id;
                    self.ast_id_map = db.ast_id_map(file_id);
                    return Some((mark, expr));
                }
            }
        }

        // FIXME: Instead of just dropping the error from expansion
        // report it
        None
    }

    pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
        self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
        self.current_file_id = mark.file_id;
        self.ast_id_map = mem::take(&mut mark.ast_id_map);
        self.recursion_limit -= 1;
        mark.bomb.defuse();
    }

    pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
        InFile { file_id: self.current_file_id, value }
    }

    pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool {
        self.cfg_expander.is_cfg_enabled(owner)
    }

    fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
        Path::from_src(path, &self.cfg_expander.hygiene)
    }

    fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {
        self.crate_def_map
            .resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other)
            .0
            .take_macros()
    }

    fn ast_id<N: AstNode>(&self, item: &N) -> AstId<N> {
        let file_local_id = self.ast_id_map.ast_id(item);
        AstId::new(self.current_file_id, file_local_id)
    }
}

pub(crate) struct Mark {
    file_id: HirFileId,
    ast_id_map: Arc<AstIdMap>,
    bomb: DropBomb,
}

/// The body of an item (function, const etc.).
#[derive(Debug, Eq, PartialEq)]
pub struct Body {
    pub exprs: Arena<Expr>,
    pub pats: Arena<Pat>,
    /// The patterns for the function's parameters. While the parameter types are
    /// part of the function signature, the patterns are not (they don't change
    /// the external type of the function).
    ///
    /// If this `Body` is for the body of a constant, this will just be
    /// empty.
    pub params: Vec<PatId>,
    /// The `ExprId` of the actual body expression.
    pub body_expr: ExprId,
    pub item_scope: ItemScope,
}

pub type ExprPtr = AstPtr<ast::Expr>;
pub type ExprSource = InFile<ExprPtr>;

pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
pub type PatSource = InFile<PatPtr>;

/// An item body together with the mapping from syntax nodes to HIR expression
/// IDs. This is needed to go from e.g. a position in a file to the HIR
/// expression containing it; but for type inference etc., we want to operate on
/// a structure that is agnostic to the actual positions of expressions in the
/// file, so that we don't recompute types whenever some whitespace is typed.
///
/// One complication here is that, due to macro expansion, a single `Body` might
/// be spread across several files. So, for each ExprId and PatId, we record
/// both the HirFileId and the position inside the file. However, we only store
/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
/// this properly for macros.
#[derive(Default, Debug, Eq, PartialEq)]
pub struct BodySourceMap {
    expr_map: FxHashMap<ExprSource, ExprId>,
    expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
    pat_map: FxHashMap<PatSource, PatId>,
    pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
    field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordField>>>,
    expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
}

#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
pub struct SyntheticSyntax;

impl Body {
    pub(crate) fn body_with_source_map_query(
        db: &dyn DefDatabase,
        def: DefWithBodyId,
    ) -> (Arc<Body>, Arc<BodySourceMap>) {
        let _p = profile("body_with_source_map_query");
        let mut params = None;

        let (file_id, module, body) = match def {
            DefWithBodyId::FunctionId(f) => {
                let f = f.lookup(db);
                let src = f.source(db);
                params = src.value.param_list();
                (src.file_id, f.module(db), src.value.body().map(ast::Expr::from))
            }
            DefWithBodyId::ConstId(c) => {
                let c = c.lookup(db);
                let src = c.source(db);
                (src.file_id, c.module(db), src.value.body())
            }
            DefWithBodyId::StaticId(s) => {
                let s = s.lookup(db);
                let src = s.source(db);
                (src.file_id, s.module(db), src.value.body())
            }
        };
        let expander = Expander::new(db, file_id, module);
        let (body, source_map) = Body::new(db, def, expander, params, body);
        (Arc::new(body), Arc::new(source_map))
    }

    pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<Body> {
        db.body_with_source_map(def).0
    }

    fn new(
        db: &dyn DefDatabase,
        def: DefWithBodyId,
        expander: Expander,
        params: Option<ast::ParamList>,
        body: Option<ast::Expr>,
    ) -> (Body, BodySourceMap) {
        lower::lower(db, def, expander, params, body)
    }
}

impl Index<ExprId> for Body {
    type Output = Expr;

    fn index(&self, expr: ExprId) -> &Expr {
        &self.exprs[expr]
    }
}

impl Index<PatId> for Body {
    type Output = Pat;

    fn index(&self, pat: PatId) -> &Pat {
        &self.pats[pat]
    }
}

impl BodySourceMap {
    pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
        self.expr_map_back[expr].clone()
    }

    pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
        let src = node.map(|it| AstPtr::new(it));
        self.expr_map.get(&src).cloned()
    }

    pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> {
        let src = node.map(|it| AstPtr::new(it));
        self.expansions.get(&src).cloned()
    }

    pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
        self.pat_map_back[pat].clone()
    }

    pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
        let src = node.map(|it| Either::Left(AstPtr::new(it)));
        self.pat_map.get(&src).cloned()
    }

    pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> {
        let src = node.map(|it| Either::Right(AstPtr::new(it)));
        self.pat_map.get(&src).cloned()
    }

    pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> {
        self.field_map[&(expr, field)].clone()
    }
}

#[cfg(test)]
mod tests {
    use ra_db::{fixture::WithFixture, SourceDatabase};
    use test_utils::mark;

    use crate::ModuleDefId;

    use super::*;

    fn lower(ra_fixture: &str) -> Arc<Body> {
        let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture);

        let krate = db.crate_graph().iter().next().unwrap();
        let def_map = db.crate_def_map(krate);
        let module = def_map.modules_for_file(file_id).next().unwrap();
        let module = &def_map[module];
        let fn_def = match module.scope.declarations().next().unwrap() {
            ModuleDefId::FunctionId(it) => it,
            _ => panic!(),
        };

        db.body(fn_def.into())
    }

    #[test]
    fn your_stack_belongs_to_me() {
        mark::check!(your_stack_belongs_to_me);
        lower(
            "
macro_rules! n_nuple {
    ($e:tt) => ();
    ($($rest:tt)*) => {{
        (n_nuple!($($rest)*)None,)
    }};
}
fn main() { n_nuple!(1,2,3); }
",
        );
    }
}
<|endoftext|>


<commit_before>use std::slice;
use std::mem::size_of;
use spin::Mutex as SpinMutex;

#[derive(Debug)]
pub struct OffsetIndex {
    id_offset: u64,
    index: SpinMutex<Vec<u32>>,
}

impl OffsetIndex {
    pub fn new(id_offset: u64) -> OffsetIndex {
        OffsetIndex {
            id_offset: id_offset,
            index: SpinMutex::new(Vec::with_capacity(10 * 1024)),
        }
    }

    pub fn from_bytes(id_offset: u64, bytes: &[u8]) -> OffsetIndex {
        assert!(bytes.len() % size_of::<u32>() == 0, "Bytes len is invalid");
        let pairs: &[u32] = unsafe {
            slice::from_raw_parts(
                bytes.as_ptr() as *const u32, bytes.len() / size_of::<u32>()
            )
        };

        let index = Self::new(id_offset);
        index.index.lock().extend(pairs);
        index
    }

    pub fn as_bytes(&self) -> &[u8] {
        let locked_index = self.index.lock();
        unsafe {
            slice::from_raw_parts(
                locked_index.as_ptr() as *const u8, size_of::<u32>() * locked_index.len()
            )
        }
    }

    pub fn get_offset(&self, id: u64) -> Option<u32> {
        debug_assert!(id >= self.id_offset);
        self.index.lock().get((id - self.id_offset) as usize).cloned()
    }

    pub fn push_offset(&mut self, id: u64, offset: u32) {
        let mut locked_index = self.index.lock();
        assert_eq!(id, self.id_offset + locked_index.len() as u64);
        locked_index.push(offset);
    }
}
<commit_msg>dont reserve much space for offsets upfront<commit_after>use std::slice;
use std::mem::size_of;
use spin::Mutex as SpinMutex;

#[derive(Debug)]
pub struct OffsetIndex {
    id_offset: u64,
    index: SpinMutex<Vec<u32>>,
}

impl OffsetIndex {
    pub fn new(id_offset: u64) -> OffsetIndex {
        OffsetIndex {
            id_offset: id_offset,
            index: SpinMutex::new(Vec::with_capacity(1024)),
        }
    }

    pub fn from_bytes(id_offset: u64, bytes: &[u8]) -> OffsetIndex {
        assert!(bytes.len() % size_of::<u32>() == 0, "Bytes len is invalid");
        let pairs: &[u32] = unsafe {
            slice::from_raw_parts(
                bytes.as_ptr() as *const u32, bytes.len() / size_of::<u32>()
            )
        };

        let index = Self::new(id_offset);
        index.index.lock().extend(pairs);
        index
    }

    pub fn as_bytes(&self) -> &[u8] {
        let locked_index = self.index.lock();
        unsafe {
            slice::from_raw_parts(
                locked_index.as_ptr() as *const u8, size_of::<u32>() * locked_index.len()
            )
        }
    }

    pub fn get_offset(&self, id: u64) -> Option<u32> {
        debug_assert!(id >= self.id_offset);
        self.index.lock().get((id - self.id_offset) as usize).cloned()
    }

    pub fn push_offset(&mut self, id: u64, offset: u32) {
        let mut locked_index = self.index.lock();
        assert_eq!(id, self.id_offset + locked_index.len() as u64);
        locked_index.push(offset);
    }
}
<|endoftext|>


<commit_before>use crate::Msg;
use seed::prelude::*;

pub fn render() -> Node<Msg> {
    div![
        h1!["Status"],
        br![],
        br![],
        br![],
        table![tbody![
            tr![td!["Number of verified primes:"], td!["1.4 billion"],],
            tr![
                td!["Website build status:"],
                td![img![
                    attrs! {At::Src => "https://travis-ci.org/craigmayhew/bigprimes.net.svg?branch=master"}
                ],],
            ]
        ]],
    ]
}
<commit_msg>Removed unusued travis build status<commit_after>use crate::Msg;
use seed::prelude::*;

pub fn render() -> Node<Msg> {
    div![
        h1!["Status"],
        br![],
        br![],
        br![],
        table![tbody![
            tr![td!["Number of verified primes:"], td!["1.4 billion"],],
        ]],
    ]
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Parser nodes represent the grammar that is defined
// by the currently permissible set of commands and their
// parameters.

use std::rc::Rc;

use super::{Completion, Parser};
use super::constants::*;
use tokenizer::Token;

/// Enumeration of node types used to have vectors of `Node` and so on.
pub enum Node {
    /// `Node` variant wrapping a `CommandNode`.
    Command(CommandNode),
    /// `Node` variant wrapping a `ParameterNode`.
    Parameter(ParameterNode),
    /// `Node` variant wrapping a `ParameterNameNode`.
    ParameterName(ParameterNameNode),
    /// `Node` variant wrapping a `RootNode`.
    Root(RootNode),
}

/// The operations that every node must implement.
pub trait NodeOps {
    /// Accept this node with the given `token` as data.
    ///
    /// By default, nothing needs to happen for `accept`.
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token);

    /// Can this node be accepted in the current parser state?
    /// By default, a node can be accepted when it hasn't been seen yet.
    fn acceptable(&self, _parser: &Parser) -> bool;

    /// Given a node and an optional token, provide the completion options.
    ///
    /// By default, completion should complete for the name of the given
    /// node.
    ///
    /// This is the expected behavior for [`CommandNode`] as well as
    /// [`ParameterNameNode`].
    ///
    /// [`CommandNode`]: struct.CommandNode.html
    /// [`ParameterNameNode`]: struct.ParameterNameNode.html
    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text>;

    /// By default, a node matches a `token` when the name of the
    /// node starts with the `token`.
    ///
    /// This is the desired behavior for ...
    fn matches(&self, _parser: &Parser, token: Token) -> bool;
}

/// A parse tree node.
pub struct TreeNode {
    /// The name of this node.
    pub name: String,
    /// The text used to identify this node in help text.
    /// This is typically the node name, either in plain
    /// form or decorated for parameters.
    pub help_symbol: String,
    /// Help text describing this node.
    pub help_text: String,
    /// Hidden nodes are not completed. This doesn't modify matching.
    pub hidden: bool,
    /// Match and complete priority.
    pub priority: i32,
    /// Whether or not this node can be repeated. A repeated
    /// node can be `accept`ed multiple times.
    pub repeatable: bool,
    /// If present, this node will no longer be `acceptable`.
    pub repeat_marker: Option<Rc<Node>>,
    /// Possible successor nodes. Collected while building.
    pub successors: Vec<Rc<Node>>,
}

/// The root of a command tree.
pub struct RootNode {
    /// `TreeNode` data.
    pub node: TreeNode,
}

/// A node representing a command. Constructed via [`Command`] and [`CommandTree`].
///
/// If `wrapped_root` is set then this node wraps another command.
/// This is used for the help command so that it can complete
/// normal commands. The `successors` will be those of the wrapped node.
///
/// [`Command`]: struct.Command.html
/// [`CommandNode`]: struct.CommandNode.html
pub struct CommandNode {
    /// `TreeNode` data.
    pub node: TreeNode,
    /// The handler which is executed once this node has been accepted.
    pub handler: Option<fn(&node: Node) -> ()>,
    /// Parameter nodes for this command
    ///
    /// XXX: This should be Vec<Rc<ParameterNode>> or similar.
    pub parameters: Vec<Rc<Node>>,
    /// If present, the command wrapped by this node.
    pub wrapped_root: Option<Rc<Node>>,
}

/// A node that represented the name portion of a named
/// parameter.
pub struct ParameterNameNode {
    /// `TreeNode` data.
    pub node: TreeNode,
    /// The `parameter` named by this node.
    ///
    /// XXX: This should be Rc<ParameterNode> or similar.
    pub parameter: Rc<Node>,
}

/// A node representing a parameter for a command.
pub struct ParameterNode {
    /// `TreeNode` data.
    pub node: TreeNode,
    /// A `required` parameter must be supplied for the
    /// command line being parsed to be valid.
    pub required: bool,
    /// What type of `ParameterKind` this is.
    pub kind: ParameterKind,
}

impl PartialEq for Node {
    /// Nodes are equal based on pointer equality.
    fn eq(&self, other: &Self) -> bool {
        self as *const _ == other as *const _
    }
}

/// The node in the tree of commands and parameters used in the
/// parser.
///
/// This trait defines the core operations which a node must
/// support.
impl Node {
    /// Get the `TreeNode` data for a given `Node`.
    pub fn node(&self) -> &TreeNode {
        match *self {
            Node::Command(ref command) => &command.node,
            Node::Parameter(ref parameter) => &parameter.node,
            Node::ParameterName(ref name) => &name.node,
            Node::Root(ref root) => &root.node,
        }
    }

    /// Get or calculate successors of this node.
    pub fn successors(&self) -> &Vec<Rc<Node>> {
        match *self {
            Node::Root(ref root) => &root.node.successors,
            _ => &self.node().successors,
        }
    }
}

impl NodeOps for Node {
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token) {
        match *self {
            Node::Command(ref command) => command.accept(parser, token),
            Node::Parameter(ref parameter) => parameter.accept(parser, token),
            Node::ParameterName(ref name) => name.accept(parser, token),
            Node::Root(ref root) => root.accept(parser, token),
        }
    }

    fn acceptable(&self, parser: &Parser) -> bool {
        match *self {
            Node::Command(ref command) => command.acceptable(parser),
            Node::Parameter(ref parameter) => parameter.acceptable(parser),
            Node::ParameterName(ref name) => name.acceptable(parser),
            Node::Root(ref root) => root.acceptable(parser),
        }
    }

    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
        match *self {
            Node::Command(ref command) => command.complete(token),
            Node::Parameter(ref parameter) => parameter.complete(token),
            Node::ParameterName(ref name) => name.complete(token),
            Node::Root(ref root) => root.complete(token),
        }
    }

    fn matches(&self, parser: &Parser, token: Token) -> bool {
        match *self {
            Node::Command(ref command) => command.matches(parser, token),
            Node::Parameter(ref parameter) => parameter.matches(parser, token),
            Node::ParameterName(ref name) => name.matches(parser, token),
            Node::Root(ref root) => root.matches(parser, token),
        }
    }
}

impl RootNode {
    /// Create a new `RootNode`
    pub fn new(successors: Vec<Rc<Node>>) -> Self {
        RootNode {
            node: TreeNode {
                name: "__root__".to_string(),
                help_symbol: "".to_string(),
                help_text: "".to_string(),
                hidden: false,
                priority: PRIORITY_DEFAULT,
                repeat_marker: None,
                repeatable: false,
                successors: successors,
            },
        }
    }
}

impl NodeOps for RootNode {
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token) {}

    fn acceptable(&self, _parser: &Parser) -> bool {
        false
    }

    /// A `RootNode` can not be completed.
    fn complete<'text>(&self, _token: Option<Token<'text>>) -> Completion<'text> {
        panic!("BUG: Can not complete a root node.");
    }

    fn matches(&self, _parser: &Parser, _token: Token) -> bool {
        false
    }
}

impl CommandNode {
    /// Construct a new `CommandNode`.
    pub fn new(name: &str,
               help_text: Option<&str>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               handler: Option<fn(&node: Node) -> ()>,
               parameters: Vec<Rc<Node>>)
               -> Self {
        CommandNode {
            node: TreeNode {
                name: name.to_string(),
                help_symbol: name.to_string(),
                help_text: help_text.unwrap_or("Command").to_string(),
                hidden: hidden,
                priority: priority,
                repeat_marker: None,
                repeatable: false,
                successors: successors,
            },
            handler: handler,
            parameters: parameters,
            wrapped_root: None,
        }
    }
}

impl NodeOps for CommandNode {
    /// Record this command.
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token) {
        if self.handler.is_some() {
            unimplemented!();
            // parser.commands.push(self)
        }
    }

    fn acceptable(&self, _parser: &Parser) -> bool {
        true
    }

    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
        Completion::new(self.node.help_symbol.clone(),
                        self.node.help_text.clone(),
                        token,
                        true,
                        vec![&self.node.name],
                        vec![])
    }

    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.node.name.starts_with(token.text)
    }
}

impl ParameterNameNode {
    /// Construct a new `ParameterNameNode`.
    pub fn new(name: &str,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               parameter: Rc<Node>)
               -> Self {
        let param_node = &parameter.node();
        let help_text = param_node.help_text.clone();
        let help_symbol = name.to_string() + " " + param_node.help_symbol.as_str();
        ParameterNameNode {
            node: TreeNode {
                name: name.to_string(),
                help_symbol: help_symbol,
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                repeat_marker: repeat_marker,
                repeatable: repeatable,
                successors: successors,
            },
            parameter: parameter.clone(),
        }
    }
}

impl NodeOps for ParameterNameNode {
    /// Record this command.
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token) {}

    /// A repeatable node can be accepted.
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.node.repeatable {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }

    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
        Completion::new(self.node.help_symbol.clone(),
                        self.node.help_text.clone(),
                        token,
                        true,
                        vec![&self.node.name],
                        vec![])
    }

    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.node.name.starts_with(token.text)
    }
}

impl ParameterNode {
    /// Construct a new `ParameterNode`.
    pub fn new(name: &str,
               help_text: Option<&str>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               kind: ParameterKind,
               required: bool)
               -> Self {
        let help_symbol = if repeatable {
            String::from("<") + name + ">..."
        } else {
            String::from("<") + name + ">"
        };
        let default_help_text = match kind {
            ParameterKind::Flag => "Flag",
            ParameterKind::Named | ParameterKind::Simple => "Parameter",
        };
        let help_text = help_text.unwrap_or(default_help_text).to_string();
        ParameterNode {
            node: TreeNode {
                name: name.to_string(),
                help_symbol: help_symbol,
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                repeat_marker: repeat_marker,
                repeatable: repeatable,
                successors: successors,
            },
            kind: kind,
            required: required,
        }
    }
}

impl NodeOps for ParameterNode {
    /// Record this parameter value.
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token) {
        if self.node.repeatable {
            unimplemented!();
        } else {
            parser.parameters.insert(self.node.name.clone(), token.text.to_string());
        }
    }

    fn acceptable(&self, _parser: &Parser) -> bool {
        true
    }

    /// By default named and simple parameters complete only to the token
    /// being input while flag parameters complete to the name of the flag.
    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
        match self.kind {
            ParameterKind::Named | ParameterKind::Simple => {
                Completion::new(self.node.help_symbol.clone(),
                                self.node.help_text.clone(),
                                token,
                                true,
                                vec![],
                                vec![])
            }
            ParameterKind::Flag => {
                Completion::new(self.node.help_symbol.clone(),
                                self.node.help_text.clone(),
                                token,
                                true,
                                vec![&self.node.name],
                                vec![])
            }
        }
    }

    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        match self.kind {
            ParameterKind::Named | ParameterKind::Simple => true,
            ParameterKind::Flag => self.node.name.starts_with(token.text),
        }
    }
}
<commit_msg>Fix broken link in docs.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Parser nodes represent the grammar that is defined
// by the currently permissible set of commands and their
// parameters.

use std::rc::Rc;

use super::{Completion, Parser};
use super::constants::*;
use tokenizer::Token;

/// Enumeration of node types used to have vectors of `Node` and so on.
pub enum Node {
    /// `Node` variant wrapping a `CommandNode`.
    Command(CommandNode),
    /// `Node` variant wrapping a `ParameterNode`.
    Parameter(ParameterNode),
    /// `Node` variant wrapping a `ParameterNameNode`.
    ParameterName(ParameterNameNode),
    /// `Node` variant wrapping a `RootNode`.
    Root(RootNode),
}

/// The operations that every node must implement.
pub trait NodeOps {
    /// Accept this node with the given `token` as data.
    ///
    /// By default, nothing needs to happen for `accept`.
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token);

    /// Can this node be accepted in the current parser state?
    /// By default, a node can be accepted when it hasn't been seen yet.
    fn acceptable(&self, _parser: &Parser) -> bool;

    /// Given a node and an optional token, provide the completion options.
    ///
    /// By default, completion should complete for the name of the given
    /// node.
    ///
    /// This is the expected behavior for [`CommandNode`] as well as
    /// [`ParameterNameNode`].
    ///
    /// [`CommandNode`]: struct.CommandNode.html
    /// [`ParameterNameNode`]: struct.ParameterNameNode.html
    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text>;

    /// By default, a node matches a `token` when the name of the
    /// node starts with the `token`.
    ///
    /// This is the desired behavior for ...
    fn matches(&self, _parser: &Parser, token: Token) -> bool;
}

/// A parse tree node.
pub struct TreeNode {
    /// The name of this node.
    pub name: String,
    /// The text used to identify this node in help text.
    /// This is typically the node name, either in plain
    /// form or decorated for parameters.
    pub help_symbol: String,
    /// Help text describing this node.
    pub help_text: String,
    /// Hidden nodes are not completed. This doesn't modify matching.
    pub hidden: bool,
    /// Match and complete priority.
    pub priority: i32,
    /// Whether or not this node can be repeated. A repeated
    /// node can be `accept`ed multiple times.
    pub repeatable: bool,
    /// If present, this node will no longer be `acceptable`.
    pub repeat_marker: Option<Rc<Node>>,
    /// Possible successor nodes. Collected while building.
    pub successors: Vec<Rc<Node>>,
}

/// The root of a command tree.
pub struct RootNode {
    /// `TreeNode` data.
    pub node: TreeNode,
}

/// A node representing a command. Constructed via [`Command`] and [`CommandTree`].
///
/// If `wrapped_root` is set then this node wraps another command.
/// This is used for the help command so that it can complete
/// normal commands. The `successors` will be those of the wrapped node.
///
/// [`Command`]: struct.Command.html
/// [`CommandTree`]: struct.CommandTree.html
pub struct CommandNode {
    /// `TreeNode` data.
    pub node: TreeNode,
    /// The handler which is executed once this node has been accepted.
    pub handler: Option<fn(&node: Node) -> ()>,
    /// Parameter nodes for this command
    ///
    /// XXX: This should be Vec<Rc<ParameterNode>> or similar.
    pub parameters: Vec<Rc<Node>>,
    /// If present, the command wrapped by this node.
    pub wrapped_root: Option<Rc<Node>>,
}

/// A node that represented the name portion of a named
/// parameter.
pub struct ParameterNameNode {
    /// `TreeNode` data.
    pub node: TreeNode,
    /// The `parameter` named by this node.
    ///
    /// XXX: This should be Rc<ParameterNode> or similar.
    pub parameter: Rc<Node>,
}

/// A node representing a parameter for a command.
pub struct ParameterNode {
    /// `TreeNode` data.
    pub node: TreeNode,
    /// A `required` parameter must be supplied for the
    /// command line being parsed to be valid.
    pub required: bool,
    /// What type of `ParameterKind` this is.
    pub kind: ParameterKind,
}

impl PartialEq for Node {
    /// Nodes are equal based on pointer equality.
    fn eq(&self, other: &Self) -> bool {
        self as *const _ == other as *const _
    }
}

/// The node in the tree of commands and parameters used in the
/// parser.
///
/// This trait defines the core operations which a node must
/// support.
impl Node {
    /// Get the `TreeNode` data for a given `Node`.
    pub fn node(&self) -> &TreeNode {
        match *self {
            Node::Command(ref command) => &command.node,
            Node::Parameter(ref parameter) => &parameter.node,
            Node::ParameterName(ref name) => &name.node,
            Node::Root(ref root) => &root.node,
        }
    }

    /// Get or calculate successors of this node.
    pub fn successors(&self) -> &Vec<Rc<Node>> {
        match *self {
            Node::Root(ref root) => &root.node.successors,
            _ => &self.node().successors,
        }
    }
}

impl NodeOps for Node {
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token) {
        match *self {
            Node::Command(ref command) => command.accept(parser, token),
            Node::Parameter(ref parameter) => parameter.accept(parser, token),
            Node::ParameterName(ref name) => name.accept(parser, token),
            Node::Root(ref root) => root.accept(parser, token),
        }
    }

    fn acceptable(&self, parser: &Parser) -> bool {
        match *self {
            Node::Command(ref command) => command.acceptable(parser),
            Node::Parameter(ref parameter) => parameter.acceptable(parser),
            Node::ParameterName(ref name) => name.acceptable(parser),
            Node::Root(ref root) => root.acceptable(parser),
        }
    }

    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
        match *self {
            Node::Command(ref command) => command.complete(token),
            Node::Parameter(ref parameter) => parameter.complete(token),
            Node::ParameterName(ref name) => name.complete(token),
            Node::Root(ref root) => root.complete(token),
        }
    }

    fn matches(&self, parser: &Parser, token: Token) -> bool {
        match *self {
            Node::Command(ref command) => command.matches(parser, token),
            Node::Parameter(ref parameter) => parameter.matches(parser, token),
            Node::ParameterName(ref name) => name.matches(parser, token),
            Node::Root(ref root) => root.matches(parser, token),
        }
    }
}

impl RootNode {
    /// Create a new `RootNode`
    pub fn new(successors: Vec<Rc<Node>>) -> Self {
        RootNode {
            node: TreeNode {
                name: "__root__".to_string(),
                help_symbol: "".to_string(),
                help_text: "".to_string(),
                hidden: false,
                priority: PRIORITY_DEFAULT,
                repeat_marker: None,
                repeatable: false,
                successors: successors,
            },
        }
    }
}

impl NodeOps for RootNode {
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token) {}

    fn acceptable(&self, _parser: &Parser) -> bool {
        false
    }

    /// A `RootNode` can not be completed.
    fn complete<'text>(&self, _token: Option<Token<'text>>) -> Completion<'text> {
        panic!("BUG: Can not complete a root node.");
    }

    fn matches(&self, _parser: &Parser, _token: Token) -> bool {
        false
    }
}

impl CommandNode {
    /// Construct a new `CommandNode`.
    pub fn new(name: &str,
               help_text: Option<&str>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               handler: Option<fn(&node: Node) -> ()>,
               parameters: Vec<Rc<Node>>)
               -> Self {
        CommandNode {
            node: TreeNode {
                name: name.to_string(),
                help_symbol: name.to_string(),
                help_text: help_text.unwrap_or("Command").to_string(),
                hidden: hidden,
                priority: priority,
                repeat_marker: None,
                repeatable: false,
                successors: successors,
            },
            handler: handler,
            parameters: parameters,
            wrapped_root: None,
        }
    }
}

impl NodeOps for CommandNode {
    /// Record this command.
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token) {
        if self.handler.is_some() {
            unimplemented!();
            // parser.commands.push(self)
        }
    }

    fn acceptable(&self, _parser: &Parser) -> bool {
        true
    }

    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
        Completion::new(self.node.help_symbol.clone(),
                        self.node.help_text.clone(),
                        token,
                        true,
                        vec![&self.node.name],
                        vec![])
    }

    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.node.name.starts_with(token.text)
    }
}

impl ParameterNameNode {
    /// Construct a new `ParameterNameNode`.
    pub fn new(name: &str,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               parameter: Rc<Node>)
               -> Self {
        let param_node = &parameter.node();
        let help_text = param_node.help_text.clone();
        let help_symbol = name.to_string() + " " + param_node.help_symbol.as_str();
        ParameterNameNode {
            node: TreeNode {
                name: name.to_string(),
                help_symbol: help_symbol,
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                repeat_marker: repeat_marker,
                repeatable: repeatable,
                successors: successors,
            },
            parameter: parameter.clone(),
        }
    }
}

impl NodeOps for ParameterNameNode {
    /// Record this command.
    fn accept<'text>(&self, _parser: &mut Parser<'text>, _token: Token) {}

    /// A repeatable node can be accepted.
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.node.repeatable {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }

    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
        Completion::new(self.node.help_symbol.clone(),
                        self.node.help_text.clone(),
                        token,
                        true,
                        vec![&self.node.name],
                        vec![])
    }

    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.node.name.starts_with(token.text)
    }
}

impl ParameterNode {
    /// Construct a new `ParameterNode`.
    pub fn new(name: &str,
               help_text: Option<&str>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               kind: ParameterKind,
               required: bool)
               -> Self {
        let help_symbol = if repeatable {
            String::from("<") + name + ">..."
        } else {
            String::from("<") + name + ">"
        };
        let default_help_text = match kind {
            ParameterKind::Flag => "Flag",
            ParameterKind::Named | ParameterKind::Simple => "Parameter",
        };
        let help_text = help_text.unwrap_or(default_help_text).to_string();
        ParameterNode {
            node: TreeNode {
                name: name.to_string(),
                help_symbol: help_symbol,
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                repeat_marker: repeat_marker,
                repeatable: repeatable,
                successors: successors,
            },
            kind: kind,
            required: required,
        }
    }
}

impl NodeOps for ParameterNode {
    /// Record this parameter value.
    fn accept<'text>(&self, parser: &mut Parser<'text>, token: Token) {
        if self.node.repeatable {
            unimplemented!();
        } else {
            parser.parameters.insert(self.node.name.clone(), token.text.to_string());
        }
    }

    fn acceptable(&self, _parser: &Parser) -> bool {
        true
    }

    /// By default named and simple parameters complete only to the token
    /// being input while flag parameters complete to the name of the flag.
    fn complete<'text>(&self, token: Option<Token<'text>>) -> Completion<'text> {
        match self.kind {
            ParameterKind::Named | ParameterKind::Simple => {
                Completion::new(self.node.help_symbol.clone(),
                                self.node.help_text.clone(),
                                token,
                                true,
                                vec![],
                                vec![])
            }
            ParameterKind::Flag => {
                Completion::new(self.node.help_symbol.clone(),
                                self.node.help_text.clone(),
                                token,
                                true,
                                vec![&self.node.name],
                                vec![])
            }
        }
    }

    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        match self.kind {
            ParameterKind::Named | ParameterKind::Simple => true,
            ParameterKind::Flag => self.node.name.starts_with(token.text),
        }
    }
}
<|endoftext|>


<commit_before>use super::{Fallible, Machine, MachineOps};
use super::mem::Register;

use interpret;

fn heap(machine: &Machine) -> Vec<String> {
    machine.mem.heap().iter()
                      .enumerate()
                      .map(|(idx, cell)| format!("H{}: {:?}", idx, cell))
                      .collect()
}

macro_rules! test_heap {
    ($m:expr, $($e:expr),*) => {
        {
            let actual = heap(&$m);
            let expected = vec![$($e.to_string()),*];
            match actual.iter().zip(expected.iter()).find(|&(a, e)| a != e) {
                Some((a, e)) => { panic!( "actual {:?} expected {:?}", a, e); }
                None => { }
            }
            assert_eq!(actual.len(), expected.len());
        }
    }
}

fn figure2_3<M:MachineOps>(machine: &mut M) {
    machine.put_structure(functor!(h/2), Register(2));
    machine.set_variable(Register(1));
    machine.set_variable(Register(4));
    machine.put_structure(functor!(f/1), Register(3));
    machine.set_value(Register(4));
    machine.put_structure(functor!(p/3), Register(0));
    machine.set_value(Register(1));
    machine.set_value(Register(2));
    machine.set_value(Register(3));
}

fn figure2_4<M:MachineOps>(machine: &mut M) -> Fallible {
    try!(machine.get_structure(functor!(p/3), Register(0)));
    machine.unify_variable(Register(1));
    machine.unify_variable(Register(2));
    machine.unify_variable(Register(3));
    try!(machine.get_structure(functor!(f/1), Register(1)));
    machine.unify_variable(Register(4));
    try!(machine.get_structure(functor!(h/2), Register(2)));
    try!(machine.unify_value(Register(3)));
    machine.unify_variable(Register(5));
    try!(machine.get_structure(functor!(f/1), Register(5)));
    machine.unify_variable(Register(6));
    try!(machine.get_structure(functor!(a/0), Register(6)));
    Ok(())
}

#[test]
fn exercise2_1() {
    let mut machine = Machine::new(5);
    figure2_3(&mut machine);

    test_heap!(
        machine,
        "H0: Structure(H1)",
        "H1: Functor(h/2)",
        "H2: Ref(H2)",
        "H3: Ref(H3)",
        "H4: Structure(H5)",
        "H5: Functor(f/1)",
        "H6: Ref(H3)",
        "H7: Structure(H8)",
        "H8: Functor(p/3)",
        "H9: Ref(H2)",
        "H10: Structure(H1)",
        "H11: Structure(H5)");
}

#[test]
fn exercise2_3() {
    let mut machine = Machine::new(7);
    figure2_3(&mut machine);
    figure2_4(&mut machine).unwrap();
    assert_eq!(
        &format!("{:?}", machine.mgu(Register(0))),
        "p(f(f(a)),h(f(f(a)),f(a)),f(f(a)))");
}

#[test]
fn exercise2_3_1() {
    // same as above, but using `interpret` to drive the machine,
    // instead of a hardcoded sequence of instructions

    let mut machine = Machine::new(7);

    {
        let mut machine = machine.dump();
        interpret::query(&mut machine,   &structure!(p(?Z,    h(?Z, ?W),   f(?W))));
        interpret::program(&mut machine, &structure!(p(f(?X), h(?Y, f(a)), ?Y))).unwrap();
    }

    assert_eq!(
        &format!("{:?}", machine.mgu(Register(0))),
        "p(f(f(a)),h(f(f(a)),f(a)),f(f(a)))");
}

#[test]
fn fail_to_unify1() {
    // same as above, but using `interpret` to drive the machine,
    // instead of a hardcoded sequence of instructions

    let mut machine = Machine::new(7);
    interpret::query(&mut machine,   &structure!(p(?Z,    ?Z)));
    assert!(interpret::program(&mut machine, &structure!(p(f(?X), g(?X)))).is_err());
}
<commit_msg>add exercise 2.3.5<commit_after>use super::{Fallible, Machine, MachineOps};
use super::mem::Register;

use interpret;

fn heap(machine: &Machine) -> Vec<String> {
    machine.mem.heap().iter()
                      .enumerate()
                      .map(|(idx, cell)| format!("H{}: {:?}", idx, cell))
                      .collect()
}

macro_rules! test_heap {
    ($m:expr, $($e:expr),*) => {
        {
            let actual = heap(&$m);
            let expected = vec![$($e.to_string()),*];
            match actual.iter().zip(expected.iter()).find(|&(a, e)| a != e) {
                Some((a, e)) => { panic!( "actual {:?} expected {:?}", a, e); }
                None => { }
            }
            assert_eq!(actual.len(), expected.len());
        }
    }
}

fn figure2_3<M:MachineOps>(machine: &mut M) {
    machine.put_structure(functor!(h/2), Register(2));
    machine.set_variable(Register(1));
    machine.set_variable(Register(4));
    machine.put_structure(functor!(f/1), Register(3));
    machine.set_value(Register(4));
    machine.put_structure(functor!(p/3), Register(0));
    machine.set_value(Register(1));
    machine.set_value(Register(2));
    machine.set_value(Register(3));
}

fn figure2_4<M:MachineOps>(machine: &mut M) -> Fallible {
    try!(machine.get_structure(functor!(p/3), Register(0)));
    machine.unify_variable(Register(1));
    machine.unify_variable(Register(2));
    machine.unify_variable(Register(3));
    try!(machine.get_structure(functor!(f/1), Register(1)));
    machine.unify_variable(Register(4));
    try!(machine.get_structure(functor!(h/2), Register(2)));
    try!(machine.unify_value(Register(3)));
    machine.unify_variable(Register(5));
    try!(machine.get_structure(functor!(f/1), Register(5)));
    machine.unify_variable(Register(6));
    try!(machine.get_structure(functor!(a/0), Register(6)));
    Ok(())
}

#[test]
fn exercise2_1() {
    let mut machine = Machine::new(5);
    figure2_3(&mut machine);

    test_heap!(
        machine,
        "H0: Structure(H1)",
        "H1: Functor(h/2)",
        "H2: Ref(H2)",
        "H3: Ref(H3)",
        "H4: Structure(H5)",
        "H5: Functor(f/1)",
        "H6: Ref(H3)",
        "H7: Structure(H8)",
        "H8: Functor(p/3)",
        "H9: Ref(H2)",
        "H10: Structure(H1)",
        "H11: Structure(H5)");
}

#[test]
fn exercise2_3() {
    let mut machine = Machine::new(7);
    figure2_3(&mut machine);
    figure2_4(&mut machine).unwrap();
    assert_eq!(
        &format!("{:?}", machine.mgu(Register(0))),
        "p(f(f(a)),h(f(f(a)),f(a)),f(f(a)))");
}

#[test]
fn exercise2_3_1() {
    // same as above, but using `interpret` to drive the machine,
    // instead of a hardcoded sequence of instructions

    let mut machine = Machine::new(7);

    {
        let mut machine = machine.dump();
        interpret::query(&mut machine,   &structure!(p(?Z,    h(?Z, ?W),   f(?W))));
        interpret::program(&mut machine, &structure!(p(f(?X), h(?Y, f(a)), ?Y))).unwrap();
    }

    assert_eq!(
        &format!("{:?}", machine.mgu(Register(0))),
        "p(f(f(a)),h(f(f(a)),f(a)),f(f(a)))");
}

#[test]
fn fail_to_unify1() {
    // same as above, but using `interpret` to drive the machine,
    // instead of a hardcoded sequence of instructions

    let mut machine = Machine::new(7);
    interpret::query(&mut machine,   &structure!(p(?Z,    ?Z)));
    assert!(interpret::program(&mut machine, &structure!(p(f(?X), g(?X)))).is_err());
}

#[test]
fn exercise2_3_5() {
    // same as above, but using `interpret` to drive the machine,
    // instead of a hardcoded sequence of instructions

    let mut machine = Machine::new(7);
    interpret::query(&mut machine,   &structure!(p(f(?X), h(?Y, f(a)), ?Y)));
    interpret::program(&mut machine, &structure!(p(?Z,    h(?Z, ?W),   f(?W)))).unwrap();

    assert_eq!(
        &format!("{:?}", machine.mgu(Register(0))),
        "p(f(f(a)),h(f(f(a)),f(a)),f(f(a)))");
}
<|endoftext|>


<commit_before>#![cfg(not(syn_disable_nightly_tests))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `libsyntax`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `libsyntax_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `libsyntax`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

extern crate quote;
extern crate rayon;
extern crate regex;
extern crate rustc_data_structures;
extern crate smallvec;
extern crate syn;
extern crate syntax;
extern crate syntax_pos;
extern crate walkdir;

mod features;

use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use smallvec::smallvec;
use syntax::ast;
use syntax::ptr::P;
use syntax_pos::edition::Edition;
use walkdir::{DirEntry, WalkDir};

use std::fs::File;
use std::io::Read;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};

use common::eq::SpanlessEq;
use common::parse;

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
#[cfg_attr(target_os = "windows", ignore = "requires nix .sh")]
fn test_rustc_precedence() {
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            // Our version of `libsyntax` can't parse this tests
            if path
                .to_str()
                .unwrap()
                .ends_with("optional_comma_in_match_arm.rs")
            {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let exprs = collect_exprs(file);
                    test_expressions(exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    syntax::with_globals(Edition::Edition2018, || {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let libsyntax_ast = if let Some(e) = libsyntax_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::libsyntax_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &libsyntax_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, libsyntax_ast);
            }
        }
    });

    (passed, failed)
}

fn libsyntax_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::libsyntax_expr(input).and_then(libsyntax_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on libsyntax objects.
fn libsyntax_brackets(mut libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_data_structures::thin_vec::ThinVec;
    use smallvec::SmallVec;
    use std::mem;
    use syntax::ast::{Expr, ExprKind, Field, Mac, Pat, Stmt, StmtKind, Ty};
    use syntax::mut_visit::{noop_visit_expr, MutVisitor};
    use syntax_pos::DUMMY_SP;

    struct BracketsVisitor {
        failed: bool,
    };

    impl MutVisitor for BracketsVisitor {
        fn visit_expr(&mut self, e: &mut P<Expr>) {
            noop_visit_expr(e, self);
            match e.node {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
                _ => {
                    let inner = mem::replace(
                        e,
                        P(Expr {
                            id: ast::DUMMY_NODE_ID,
                            node: ExprKind::Err,
                            span: DUMMY_SP,
                            attrs: ThinVec::new(),
                        }),
                    );
                    e.node = ExprKind::Paren(inner);
                }
            }
        }

        fn visit_field(&mut self, f: &mut Field) {
            if f.is_shorthand {
                noop_visit_expr(&mut f.expr, self);
            } else {
                self.visit_expr(&mut f.expr);
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn visit_pat(&mut self, pat: &mut P<Pat>) {
            let _ = pat;
        }

        fn visit_ty(&mut self, ty: &mut P<Ty>) {
            let _ = ty;
        }

        fn flat_map_stmt(&mut self, stmt: Stmt) -> SmallVec<[Stmt; 1]> {
            let node = match stmt.node {
                // Don't wrap toplevel expressions in statements.
                StmtKind::Expr(mut e) => {
                    noop_visit_expr(&mut e, self);
                    StmtKind::Expr(e)
                }
                StmtKind::Semi(mut e) => {
                    noop_visit_expr(&mut e, self);
                    StmtKind::Semi(e)
                }
                s => s,
            };

            smallvec![Stmt { node, ..stmt }]
        }

        fn visit_mac(&mut self, mac: &mut Mac) {
            // By default when folding over macros, libsyntax panics. This is
            // because it's usually not what you want, you want to run after
            // macro expansion. We do want to do that (syn doesn't do macro
            // expansion), so we implement visit_mac to just return the macro
            // unchanged.
            let _ = mac;
        }
    }

    let mut folder = BracketsVisitor { failed: false };
    folder.visit_expr(&mut libsyntax_expr);
    if folder.failed {
        None
    } else {
        Some(libsyntax_expr)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::*;
    use syn::*;

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                node => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, node)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::*;
    use syn::punctuated::Punctuated;
    use syn::*;

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            self.0.push(expr);

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<commit_msg>Update test suite to nightly-2019-08-26<commit_after>#![cfg(not(syn_disable_nightly_tests))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `libsyntax`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `libsyntax_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `libsyntax`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

extern crate quote;
extern crate rayon;
extern crate regex;
extern crate rustc_data_structures;
extern crate smallvec;
extern crate syn;
extern crate syntax;
extern crate syntax_pos;
extern crate walkdir;

mod features;

use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use smallvec::smallvec;
use syntax::ast;
use syntax::ptr::P;
use syntax_pos::edition::Edition;
use walkdir::{DirEntry, WalkDir};

use std::fs::File;
use std::io::Read;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};

use common::eq::SpanlessEq;
use common::parse;

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
#[cfg_attr(target_os = "windows", ignore = "requires nix .sh")]
fn test_rustc_precedence() {
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            // Our version of `libsyntax` can't parse this tests
            if path
                .to_str()
                .unwrap()
                .ends_with("optional_comma_in_match_arm.rs")
            {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let exprs = collect_exprs(file);
                    test_expressions(exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    syntax::with_globals(Edition::Edition2018, || {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let libsyntax_ast = if let Some(e) = libsyntax_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::libsyntax_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - libsyntax failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &libsyntax_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, libsyntax_ast);
            }
        }
    });

    (passed, failed)
}

fn libsyntax_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::libsyntax_expr(input).and_then(libsyntax_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on libsyntax objects.
fn libsyntax_brackets(mut libsyntax_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_data_structures::thin_vec::ThinVec;
    use smallvec::SmallVec;
    use std::mem;
    use syntax::ast::{Expr, ExprKind, Field, Mac, Pat, Stmt, StmtKind, Ty};
    use syntax::mut_visit::{noop_visit_expr, MutVisitor};
    use syntax_pos::DUMMY_SP;

    struct BracketsVisitor {
        failed: bool,
    };

    impl MutVisitor for BracketsVisitor {
        fn visit_expr(&mut self, e: &mut P<Expr>) {
            noop_visit_expr(e, self);
            match e.node {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
                _ => {
                    let inner = mem::replace(
                        e,
                        P(Expr {
                            id: ast::DUMMY_NODE_ID,
                            node: ExprKind::Err,
                            span: DUMMY_SP,
                            attrs: ThinVec::new(),
                        }),
                    );
                    e.node = ExprKind::Paren(inner);
                }
            }
        }

        fn flat_map_field(&mut self, mut f: Field) -> SmallVec<[Field; 1]> {
            if f.is_shorthand {
                noop_visit_expr(&mut f.expr, self);
            } else {
                self.visit_expr(&mut f.expr);
            }
            SmallVec::from([f])
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn visit_pat(&mut self, pat: &mut P<Pat>) {
            let _ = pat;
        }

        fn visit_ty(&mut self, ty: &mut P<Ty>) {
            let _ = ty;
        }

        fn flat_map_stmt(&mut self, stmt: Stmt) -> SmallVec<[Stmt; 1]> {
            let node = match stmt.node {
                // Don't wrap toplevel expressions in statements.
                StmtKind::Expr(mut e) => {
                    noop_visit_expr(&mut e, self);
                    StmtKind::Expr(e)
                }
                StmtKind::Semi(mut e) => {
                    noop_visit_expr(&mut e, self);
                    StmtKind::Semi(e)
                }
                s => s,
            };

            smallvec![Stmt { node, ..stmt }]
        }

        fn visit_mac(&mut self, mac: &mut Mac) {
            // By default when folding over macros, libsyntax panics. This is
            // because it's usually not what you want, you want to run after
            // macro expansion. We do want to do that (syn doesn't do macro
            // expansion), so we implement visit_mac to just return the macro
            // unchanged.
            let _ = mac;
        }
    }

    let mut folder = BracketsVisitor { failed: false };
    folder.visit_expr(&mut libsyntax_expr);
    if folder.failed {
        None
    } else {
        Some(libsyntax_expr)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::*;
    use syn::*;

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                node => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, node)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::*;
    use syn::punctuated::Punctuated;
    use syn::*;

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            self.0.push(expr);

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<|endoftext|>