<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use colored::*;
use common::Span;
use std::fmt::Write;

pub struct SourcePrinter;

const PRINT_WHITESPACE: bool = false;

impl SourcePrinter {
    pub fn new() -> Self {
        Self
    }

    pub fn write_span<W: Write>(
        &self,
        writer: &mut W,
        span: &Span,
        source: &str,
    ) -> std::fmt::Result {
        let start_char_index = span.start as usize;
        let end_char_index = span.end as usize;

        let start_byte_index =
            if let Some((byte_index, _)) = source.char_indices().nth(start_char_index) {
                byte_index
            } else {
                panic!("ERROR START OUT OF RANGE".to_string());
            };
        let end_byte_index =
            if let Some((byte_index, _)) = source.char_indices().nth(end_char_index) {
                byte_index
            } else {
                panic!("ERROR END OUT OF RANGE".to_string());
            };

        let mut line_end_byte_indices = Vec::new();
        for (byte_index, chr) in source.char_indices() {
            if chr == '\n' {
                line_end_byte_indices.push(byte_index + 1)
            }
        }
        if source.ends_with('\n') {
            line_end_byte_indices.pop();
        }

        let byte_index_to_line_index = |byte_index: usize| -> usize {
            line_end_byte_indices
                .binary_search(&byte_index)
                .unwrap_or_else(|x| x)
        };

        let line_index_to_byte_range = |line_index: usize| {
            let end = line_end_byte_indices
                .get(line_index)
                .cloned()
                .unwrap_or_else(|| source.len());
            let start = if line_index == 0 {
                0
            } else {
                line_end_byte_indices
                    .get(line_index - 1)
                    .cloned()
                    .unwrap_or_else(|| source.len())
            };
            start..end
        };

        const CONTEXT: usize = 1;

        let first_line_index = byte_index_to_line_index(start_char_index);
        let last_line_index = byte_index_to_line_index(end_char_index);

        let first_printed_line_index = first_line_index.saturating_sub(CONTEXT);
        let last_printed_line_index = (last_line_index + CONTEXT).min(line_end_byte_indices.len());

        let mut currently_hightlighted = false;
        for line_index in first_printed_line_index..=last_printed_line_index {
            write!(
                writer,
                "{}",
                format!(" {:>4} \u{2502} ", line_index + 1).bold()
            )
            .unwrap();
            let mut something_highlighted_on_line = false;
            let mut marker = String::new();
            for byte_index in line_index_to_byte_range(line_index) {
                if byte_index == end_byte_index {
                    currently_hightlighted = false
                } else if byte_index == start_byte_index {
                    currently_hightlighted = true;
                }

                let chr = match source
                    .char_indices()
                    .find(|(idx, _)| *idx == byte_index)
                    .map(|(_, chr)| chr)
                {
                    Some('\n') => {
                        if PRINT_WHITESPACE {
                            '␤'
                        } else {
                            continue;
                        }
                    }
                    Some('\r') => {
                        if PRINT_WHITESPACE {
                            '␍'
                        } else {
                            continue;
                        }
                    }
                    Some(c) => c,
                    None => continue,
                };

                if currently_hightlighted {
                    write!(writer, "{}", chr.to_string().red()).unwrap();
                    marker.push_str("^");
                    something_highlighted_on_line = true;
                } else {
                    write!(writer, "{}", chr).unwrap();
                    if !something_highlighted_on_line {
                        // TODO should push 2 spaces for emojis, unicode-width crate might help
                        marker.push(' ');
                    }
                }
            }
            writeln!(writer)?;
            if something_highlighted_on_line {
                writeln!(writer, "      \u{2502} {}", marker.red()).unwrap();
            }
        }

        Ok(())
    }
}
<commit_msg>downgrade panic! in source_printer<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use colored::*;
use common::Span;
use std::fmt::Write;

pub struct SourcePrinter;

const PRINT_WHITESPACE: bool = false;

impl SourcePrinter {
    pub fn new() -> Self {
        Self
    }

    pub fn write_span<W: Write>(
        &self,
        writer: &mut W,
        span: &Span,
        source: &str,
    ) -> std::fmt::Result {
        let start_char_index = span.start as usize;
        let end_char_index = span.end as usize;

        let start_byte_index =
            if let Some((byte_index, _)) = source.char_indices().nth(start_char_index) {
                byte_index
            } else {
                return write!(
                    writer,
                    "Internal error: Unable to print source, start index ({}) out of range.",
                    start_char_index
                );
            };
        let end_byte_index =
            if let Some((byte_index, _)) = source.char_indices().nth(end_char_index) {
                byte_index
            } else {
                return write!(
                    writer,
                    "Internal error: Unable to print source, end index ({}) out of range.",
                    end_char_index
                );
            };

        let mut line_end_byte_indices = Vec::new();
        for (byte_index, chr) in source.char_indices() {
            if chr == '\n' {
                line_end_byte_indices.push(byte_index + 1)
            }
        }
        if source.ends_with('\n') {
            line_end_byte_indices.pop();
        }

        let byte_index_to_line_index = |byte_index: usize| -> usize {
            line_end_byte_indices
                .binary_search(&byte_index)
                .unwrap_or_else(|x| x)
        };

        let line_index_to_byte_range = |line_index: usize| {
            let end = line_end_byte_indices
                .get(line_index)
                .cloned()
                .unwrap_or_else(|| source.len());
            let start = if line_index == 0 {
                0
            } else {
                line_end_byte_indices
                    .get(line_index - 1)
                    .cloned()
                    .unwrap_or_else(|| source.len())
            };
            start..end
        };

        const CONTEXT: usize = 1;

        let first_line_index = byte_index_to_line_index(start_char_index);
        let last_line_index = byte_index_to_line_index(end_char_index);

        let first_printed_line_index = first_line_index.saturating_sub(CONTEXT);
        let last_printed_line_index = (last_line_index + CONTEXT).min(line_end_byte_indices.len());

        let mut currently_hightlighted = false;
        for line_index in first_printed_line_index..=last_printed_line_index {
            write!(
                writer,
                "{}",
                format!(" {:>4} \u{2502} ", line_index + 1).bold()
            )
            .unwrap();
            let mut something_highlighted_on_line = false;
            let mut marker = String::new();
            for byte_index in line_index_to_byte_range(line_index) {
                if byte_index == end_byte_index {
                    currently_hightlighted = false
                } else if byte_index == start_byte_index {
                    currently_hightlighted = true;
                }

                let chr = match source
                    .char_indices()
                    .find(|(idx, _)| *idx == byte_index)
                    .map(|(_, chr)| chr)
                {
                    Some('\n') => {
                        if PRINT_WHITESPACE {
                            '␤'
                        } else {
                            continue;
                        }
                    }
                    Some('\r') => {
                        if PRINT_WHITESPACE {
                            '␍'
                        } else {
                            continue;
                        }
                    }
                    Some(c) => c,
                    None => continue,
                };

                if currently_hightlighted {
                    write!(writer, "{}", chr.to_string().red()).unwrap();
                    marker.push_str("^");
                    something_highlighted_on_line = true;
                } else {
                    write!(writer, "{}", chr).unwrap();
                    if !something_highlighted_on_line {
                        // TODO should push 2 spaces for emojis, unicode-width crate might help
                        marker.push(' ');
                    }
                }
            }
            writeln!(writer)?;
            if something_highlighted_on_line {
                writeln!(writer, "      \u{2502} {}", marker.red()).unwrap();
            }
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use super::grammars::{LexicalGrammar, SyntaxGrammar, VariableType};
use super::rules::{AliasMap, Symbol, SymbolType};
use super::tables::{ChildType, VariableInfo};
use serde_derive::Serialize;
use std::collections::BTreeMap;

#[derive(Debug, Serialize, PartialEq, Eq, Default)]
pub(crate) struct NodeInfoJSON {
    #[serde(rename = "type")]
    name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    fields: Option<BTreeMap<String, FieldInfoJSON>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    subtypes: Option<Vec<NodeTypeJSON>>,
}

#[derive(Debug, Serialize, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct NodeTypeJSON {
    #[serde(rename = "type")]
    kind: String,
    named: bool,
}

#[derive(Debug, Serialize, PartialEq, Eq)]
pub(crate) struct FieldInfoJSON {
    multiple: bool,
    required: bool,
    types: Vec<NodeTypeJSON>,
}

pub(crate) fn generate_node_types_json(
    syntax_grammar: &SyntaxGrammar,
    lexical_grammar: &LexicalGrammar,
    simple_aliases: &AliasMap,
    variable_info: &Vec<VariableInfo>,
) -> Vec<NodeInfoJSON> {
    let mut node_types_json = BTreeMap::new();

    let child_type_to_node_type = |child_type: &ChildType| match child_type {
        ChildType::Aliased(alias) => NodeTypeJSON {
            kind: alias.value.clone(),
            named: alias.is_named,
        },
        ChildType::Normal(symbol) => {
            if let Some(alias) = simple_aliases.get(&symbol) {
                NodeTypeJSON {
                    kind: alias.value.clone(),
                    named: alias.is_named,
                }
            } else {
                match symbol.kind {
                    SymbolType::NonTerminal => {
                        let variable = &syntax_grammar.variables[symbol.index];
                        NodeTypeJSON {
                            kind: variable.name.clone(),
                            named: variable.kind != VariableType::Anonymous,
                        }
                    }
                    SymbolType::Terminal => {
                        let variable = &lexical_grammar.variables[symbol.index];
                        NodeTypeJSON {
                            kind: variable.name.clone(),
                            named: variable.kind != VariableType::Anonymous,
                        }
                    }
                    SymbolType::External => {
                        let variable = &syntax_grammar.external_tokens[symbol.index];
                        NodeTypeJSON {
                            kind: variable.name.clone(),
                            named: variable.kind != VariableType::Anonymous,
                        }
                    }
                    _ => panic!("Unexpected symbol type"),
                }
            }
        }
    };

    for (i, info) in variable_info.iter().enumerate() {
        let symbol = Symbol::non_terminal(i);
        let variable = &syntax_grammar.variables[i];
        let name = simple_aliases
            .get(&Symbol::non_terminal(i))
            .map_or(&variable.name, |alias| &alias.value);

        if syntax_grammar.supertype_symbols.contains(&symbol) {
            let node_type_json =
                node_types_json
                    .entry(name.clone())
                    .or_insert_with(|| NodeInfoJSON {
                        name: name.clone(),
                        fields: None,
                        subtypes: None,
                    });
            let mut subtypes = info
                .child_types
                .iter()
                .map(child_type_to_node_type)
                .collect::<Vec<_>>();
            subtypes.sort_unstable();
            subtypes.dedup();
            node_type_json.subtypes = Some(subtypes);
        } else if variable.kind.is_visible() {
            let node_type_json =
                node_types_json
                    .entry(name.clone())
                    .or_insert_with(|| NodeInfoJSON {
                        name: name.clone(),
                        fields: None,
                        subtypes: None,
                    });
            let mut fields_json = BTreeMap::new();
            for (field, field_info) in info.fields.iter() {
                let field_info_json = fields_json.entry(field.clone()).or_insert(FieldInfoJSON {
                    multiple: false,
                    required: true,
                    types: Vec::new(),
                });

                field_info_json.multiple |= field_info.multiple;
                field_info_json.required &= field_info.required;
                field_info_json
                    .types
                    .extend(field_info.types.iter().map(child_type_to_node_type));
                field_info_json.types.sort_unstable();
                field_info_json.types.dedup();
            }
            node_type_json.fields = Some(fields_json);
        }
    }

    node_types_json.into_iter().map(|e| e.1).collect()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::generate::build_tables::build_parse_table::get_variable_info;
    use crate::generate::grammars::{InputGrammar, Variable, VariableType};
    use crate::generate::prepare_grammar::prepare_grammar;
    use crate::generate::rules::Rule;

    #[test]
    fn test_node_types_simple() {
        let node_types = get_node_types(InputGrammar {
            name: String::new(),
            extra_tokens: Vec::new(),
            external_tokens: Vec::new(),
            expected_conflicts: Vec::new(),
            variables_to_inline: Vec::new(),
            word_token: None,
            supertype_symbols: vec![],
            variables: vec![
                Variable {
                    name: "v1".to_string(),
                    kind: VariableType::Named,
                    rule: Rule::seq(vec![
                        Rule::field("f1".to_string(), Rule::named("v2")),
                        Rule::field("f2".to_string(), Rule::string(";")),
                    ]),
                },
                Variable {
                    name: "v2".to_string(),
                    kind: VariableType::Named,
                    rule: Rule::string("x"),
                },
            ],
        });

        assert_eq!(
            node_types[0],
            NodeInfoJSON {
                name: "v1".to_string(),
                subtypes: None,
                fields: Some(
                    vec![
                        (
                            "f1".to_string(),
                            FieldInfoJSON {
                                multiple: false,
                                required: true,
                                types: vec![NodeTypeJSON {
                                    kind: "v2".to_string(),
                                    named: true,
                                }]
                            }
                        ),
                        (
                            "f2".to_string(),
                            FieldInfoJSON {
                                multiple: false,
                                required: true,
                                types: vec![NodeTypeJSON {
                                    kind: ";".to_string(),
                                    named: false,
                                }]
                            }
                        ),
                    ]
                    .into_iter()
                    .collect()
                )
            }
        );
    }

    #[test]
    fn test_node_types_with_supertypes() {
        let node_types = get_node_types(InputGrammar {
            name: String::new(),
            extra_tokens: Vec::new(),
            external_tokens: Vec::new(),
            expected_conflicts: Vec::new(),
            variables_to_inline: Vec::new(),
            word_token: None,
            supertype_symbols: vec!["_v2".to_string()],
            variables: vec![
                Variable {
                    name: "v1".to_string(),
                    kind: VariableType::Named,
                    rule: Rule::field("f1".to_string(), Rule::named("_v2")),
                },
                Variable {
                    name: "_v2".to_string(),
                    kind: VariableType::Hidden,
                    rule: Rule::choice(vec![
                        Rule::named("v3"),
                        Rule::named("v4"),
                        Rule::string("*"),
                    ]),
                },
                Variable {
                    name: "v3".to_string(),
                    kind: VariableType::Named,
                    rule: Rule::string("x"),
                },
                Variable {
                    name: "v4".to_string(),
                    kind: VariableType::Named,
                    rule: Rule::string("y"),
                },
            ],
        });

        assert_eq!(
            node_types[0],
            NodeInfoJSON {
                name: "_v2".to_string(),
                fields: None,
                subtypes: Some(vec![
                    NodeTypeJSON {
                        kind: "*".to_string(),
                        named: false,
                    },
                    NodeTypeJSON {
                        kind: "v3".to_string(),
                        named: true,
                    },
                    NodeTypeJSON {
                        kind: "v4".to_string(),
                        named: true,
                    },
                ]),
            }
        );
        assert_eq!(
            node_types[1],
            NodeInfoJSON {
                name: "v1".to_string(),
                subtypes: None,
                fields: Some(
                    vec![(
                        "f1".to_string(),
                        FieldInfoJSON {
                            multiple: false,
                            required: true,
                            types: vec![NodeTypeJSON {
                                kind: "_v2".to_string(),
                                named: true,
                            }]
                        }
                    ),]
                    .into_iter()
                    .collect()
                )
            }
        );
    }

    fn get_node_types(grammar: InputGrammar) -> Vec<NodeInfoJSON> {
        let (syntax_grammar, lexical_grammar, _, simple_aliases) =
            prepare_grammar(&grammar).unwrap();
        let variable_info = get_variable_info(&syntax_grammar, &lexical_grammar).unwrap();
        generate_node_types_json(
            &syntax_grammar,
            &lexical_grammar,
            &simple_aliases,
            &variable_info,
        )
    }
}
<commit_msg>Include tokens in node-types.json<commit_after>use super::grammars::{LexicalGrammar, SyntaxGrammar, VariableType};
use super::rules::{AliasMap, Symbol, SymbolType};
use super::tables::{ChildType, VariableInfo};
use serde_derive::Serialize;
use std::collections::BTreeMap;

#[derive(Debug, Serialize, PartialEq, Eq, Default)]
pub(crate) struct NodeInfoJSON {
    #[serde(rename = "type")]
    kind: String,
    named: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    fields: Option<BTreeMap<String, FieldInfoJSON>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    subtypes: Option<Vec<NodeTypeJSON>>,
}

#[derive(Debug, Serialize, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct NodeTypeJSON {
    #[serde(rename = "type")]
    kind: String,
    named: bool,
}

#[derive(Debug, Serialize, PartialEq, Eq)]
pub(crate) struct FieldInfoJSON {
    multiple: bool,
    required: bool,
    types: Vec<NodeTypeJSON>,
}

pub(crate) fn generate_node_types_json(
    syntax_grammar: &SyntaxGrammar,
    lexical_grammar: &LexicalGrammar,
    simple_aliases: &AliasMap,
    variable_info: &Vec<VariableInfo>,
) -> Vec<NodeInfoJSON> {
    let mut node_types_json = BTreeMap::new();

    let child_type_to_node_type = |child_type: &ChildType| match child_type {
        ChildType::Aliased(alias) => NodeTypeJSON {
            kind: alias.value.clone(),
            named: alias.is_named,
        },
        ChildType::Normal(symbol) => {
            if let Some(alias) = simple_aliases.get(&symbol) {
                NodeTypeJSON {
                    kind: alias.value.clone(),
                    named: alias.is_named,
                }
            } else {
                match symbol.kind {
                    SymbolType::NonTerminal => {
                        let variable = &syntax_grammar.variables[symbol.index];
                        NodeTypeJSON {
                            kind: variable.name.clone(),
                            named: variable.kind != VariableType::Anonymous,
                        }
                    }
                    SymbolType::Terminal => {
                        let variable = &lexical_grammar.variables[symbol.index];
                        NodeTypeJSON {
                            kind: variable.name.clone(),
                            named: variable.kind != VariableType::Anonymous,
                        }
                    }
                    SymbolType::External => {
                        let variable = &syntax_grammar.external_tokens[symbol.index];
                        NodeTypeJSON {
                            kind: variable.name.clone(),
                            named: variable.kind != VariableType::Anonymous,
                        }
                    }
                    _ => panic!("Unexpected symbol type"),
                }
            }
        }
    };

    for (i, info) in variable_info.iter().enumerate() {
        let symbol = Symbol::non_terminal(i);
        let variable = &syntax_grammar.variables[i];
        let name = simple_aliases
            .get(&Symbol::non_terminal(i))
            .map_or(&variable.name, |alias| &alias.value);

        if syntax_grammar.supertype_symbols.contains(&symbol) {
            let node_type_json =
                node_types_json
                    .entry(name.clone())
                    .or_insert_with(|| NodeInfoJSON {
                        kind: name.clone(),
                        named: true,
                        fields: None,
                        subtypes: None,
                    });
            let mut subtypes = info
                .child_types
                .iter()
                .map(child_type_to_node_type)
                .collect::<Vec<_>>();
            subtypes.sort_unstable();
            subtypes.dedup();
            node_type_json.subtypes = Some(subtypes);
        } else if variable.kind.is_visible() {
            let node_type_json =
                node_types_json
                    .entry(name.clone())
                    .or_insert_with(|| NodeInfoJSON {
                        kind: name.clone(),
                        named: true,
                        fields: None,
                        subtypes: None,
                    });
            let mut fields_json = BTreeMap::new();
            for (field, field_info) in info.fields.iter() {
                let field_info_json = fields_json.entry(field.clone()).or_insert(FieldInfoJSON {
                    multiple: false,
                    required: true,
                    types: Vec::new(),
                });

                field_info_json.multiple |= field_info.multiple;
                field_info_json.required &= field_info.required;
                field_info_json
                    .types
                    .extend(field_info.types.iter().map(child_type_to_node_type));
                field_info_json.types.sort_unstable();
                field_info_json.types.dedup();
            }
            node_type_json.fields = Some(fields_json);
        }
    }

    let mut result = node_types_json.into_iter().map(|e| e.1).collect::<Vec<_>>();

    for variable in &lexical_grammar.variables {
        if variable.kind == VariableType::Named {
            result.push(NodeInfoJSON {
                kind: variable.name.clone(),
                named: true,
                fields: None,
                subtypes: None,
            });
        } else if variable.kind == VariableType::Anonymous {
            result.push(NodeInfoJSON {
                kind: variable.name.clone(),
                named: false,
                fields: None,
                subtypes: None,
            });
        }
    }

    result
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::generate::build_tables::build_parse_table::get_variable_info;
    use crate::generate::grammars::{InputGrammar, Variable, VariableType};
    use crate::generate::prepare_grammar::prepare_grammar;
    use crate::generate::rules::Rule;

    #[test]
    fn test_node_types_simple() {
        let node_types = get_node_types(InputGrammar {
            name: String::new(),
            extra_tokens: Vec::new(),
            external_tokens: Vec::new(),
            expected_conflicts: Vec::new(),
            variables_to_inline: Vec::new(),
            word_token: None,
            supertype_symbols: vec![],
            variables: vec![
                Variable {
                    name: "v1".to_string(),
                    kind: VariableType::Named,
                    rule: Rule::seq(vec![
                        Rule::field("f1".to_string(), Rule::named("v2")),
                        Rule::field("f2".to_string(), Rule::string(";")),
                    ]),
                },
                Variable {
                    name: "v2".to_string(),
                    kind: VariableType::Named,
                    rule: Rule::string("x"),
                },
            ],
        });

        assert_eq!(
            node_types[0],
            NodeInfoJSON {
                kind: "v1".to_string(),
                named: true,
                subtypes: None,
                fields: Some(
                    vec![
                        (
                            "f1".to_string(),
                            FieldInfoJSON {
                                multiple: false,
                                required: true,
                                types: vec![NodeTypeJSON {
                                    kind: "v2".to_string(),
                                    named: true,
                                }]
                            }
                        ),
                        (
                            "f2".to_string(),
                            FieldInfoJSON {
                                multiple: false,
                                required: true,
                                types: vec![NodeTypeJSON {
                                    kind: ";".to_string(),
                                    named: false,
                                }]
                            }
                        ),
                    ]
                    .into_iter()
                    .collect()
                )
            }
        );
        assert_eq!(
            node_types[1],
            NodeInfoJSON {
                kind: ";".to_string(),
                named: false,
                subtypes: None,
                fields: None
            }
        );
        assert_eq!(
            node_types[2],
            NodeInfoJSON {
                kind: "v2".to_string(),
                named: true,
                subtypes: None,
                fields: None
            }
        );
    }

    #[test]
    fn test_node_types_with_supertypes() {
        let node_types = get_node_types(InputGrammar {
            name: String::new(),
            extra_tokens: Vec::new(),
            external_tokens: Vec::new(),
            expected_conflicts: Vec::new(),
            variables_to_inline: Vec::new(),
            word_token: None,
            supertype_symbols: vec!["_v2".to_string()],
            variables: vec![
                Variable {
                    name: "v1".to_string(),
                    kind: VariableType::Named,
                    rule: Rule::field("f1".to_string(), Rule::named("_v2")),
                },
                Variable {
                    name: "_v2".to_string(),
                    kind: VariableType::Hidden,
                    rule: Rule::choice(vec![
                        Rule::named("v3"),
                        Rule::named("v4"),
                        Rule::string("*"),
                    ]),
                },
                Variable {
                    name: "v3".to_string(),
                    kind: VariableType::Named,
                    rule: Rule::string("x"),
                },
                Variable {
                    name: "v4".to_string(),
                    kind: VariableType::Named,
                    rule: Rule::string("y"),
                },
            ],
        });

        assert_eq!(
            node_types[0],
            NodeInfoJSON {
                kind: "_v2".to_string(),
                named: true,
                fields: None,
                subtypes: Some(vec![
                    NodeTypeJSON {
                        kind: "*".to_string(),
                        named: false,
                    },
                    NodeTypeJSON {
                        kind: "v3".to_string(),
                        named: true,
                    },
                    NodeTypeJSON {
                        kind: "v4".to_string(),
                        named: true,
                    },
                ]),
            }
        );
        assert_eq!(
            node_types[1],
            NodeInfoJSON {
                kind: "v1".to_string(),
                named: true,
                subtypes: None,
                fields: Some(
                    vec![(
                        "f1".to_string(),
                        FieldInfoJSON {
                            multiple: false,
                            required: true,
                            types: vec![NodeTypeJSON {
                                kind: "_v2".to_string(),
                                named: true,
                            }]
                        }
                    ),]
                    .into_iter()
                    .collect()
                )
            }
        );
    }

    fn get_node_types(grammar: InputGrammar) -> Vec<NodeInfoJSON> {
        let (syntax_grammar, lexical_grammar, _, simple_aliases) =
            prepare_grammar(&grammar).unwrap();
        let variable_info = get_variable_info(&syntax_grammar, &lexical_grammar).unwrap();
        generate_node_types_json(
            &syntax_grammar,
            &lexical_grammar,
            &simple_aliases,
            &variable_info,
        )
    }
}
<|endoftext|>


<commit_before>//! Provide helpers for making ioctl system calls
//!
//! Currently supports Linux on all architectures. Other platforms welcome!
//!
//! This library is pretty low-level and messy. `ioctl` is not fun.
//!
//! What is an `ioctl`?
//! ===================
//!
//! The `ioctl` syscall is the grab-bag syscall on POSIX systems. Don't want
//! to add a new syscall? Make it an `ioctl`! `ioctl` refers to both the syscall,
//! and the commands that can be send with it. `ioctl` stands for "IO control",
//! and the commands are always sent to a file descriptor.
//!
//! It is common to see `ioctl`s used for the following purposes:
//!
//! * Provide read/write access to out-of-band data related
//!   to a device such as configuration (for instance, setting
//!   serial port options)
//! * Provide a mechanism for performing full-duplex data
//!   transfers (for instance, xfer on SPI devices).
//! * Provide access to control functions on a device (for example,
//!   on Linux you can send commands like pause, resume, and eject
//!   to the CDROM device.
//! * Do whatever else the device driver creator thought made most sense.
//!
//! `ioctl`s are synchronous system calls and are similar to read and
//! write calls in that regard.
//!
//! What does this module support?
//! ===============================
//!
//! This library provides the `ioctl!` macro, for binding `ioctl`s.
//! Here's a few examples of how that can work for SPI under Linux
//! from [rust-spidev](https://github.com/posborne/rust-spidev).
//!
//! ```
//! #[allow(non_camel_case_types)]
//! pub struct spi_ioc_transfer {
//!     pub tx_buf: u64,
//!     pub rx_buf: u64,
//!     pub len: u32,
//!
//!     // optional overrides
//!     pub speed_hz: u32,
//!     pub delay_usecs: u16,
//!     pub bits_per_word: u8,
//!     pub cs_change: u8,
//!     pub pad: u32,
//! }
//!
//! #[cfg(linux)]
//! mod ioctl {
//!     use super::*;
//!
//!     const SPI_IOC_MAGIC: u8 = 'k' as u8;
//!     const SPI_IOC_NR_TRANSFER: u8 = 0;
//!     const SPI_IOC_NR_MODE: u8 = 1;
//!     const SPI_IOC_NR_LSB_FIRST: u8 = 2;
//!     const SPI_IOC_NR_BITS_PER_WORD: u8 = 3;
//!     const SPI_IOC_NR_MAX_SPEED_HZ: u8 = 4;
//!     const SPI_IOC_NR_MODE32: u8 = 5;
//!
//!     ioctl!(read  get_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8);
//!     ioctl!(read  get_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u32);
//!     ioctl!(write set_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8);
//!     ioctl!(write set_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE32; u32);
//!     ioctl!(read  get_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8);
//!     ioctl!(write set_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8);
//!     ioctl!(read  get_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8);
//!     ioctl!(write set_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8);
//!     ioctl!(read  get_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32);
//!     ioctl!(write set_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32);
//!     ioctl!(write spidev_transfer with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer);
//!     ioctl!(write buf spidev_transfer_buf with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer);
//! }
//!
//! // doctest workaround
//! fn main() {}
//! ```
//!
//! Spidev uses the `_IOC` macros that are encouraged (as far as
//! `ioctl` can be encouraged at all) for newer drivers.  Many
//! drivers, however, just use magic numbers with no attached
//! semantics.  For those, the `ioctl!(bad ...)` variant should be
//! used (the "bad" terminology is from the Linux kernel).
//!
//! How do I get the magic numbers?
//! ===============================
//!
//! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot
//! of lines defining macros which use `_IOR`, `_IOW`, `_IOC`, and `_IORW`.  These macros
//! correspond to the `ior!`, `iow!`, `ioc!`, and `iorw!` macros defined in this crate.
//! Additionally, there is the `ioctl!` macro for creating a wrapper around `ioctl` that is
//! somewhat more type-safe.
//!
//! Most `ioctl`s have no or little documentation. You'll need to scrounge through
//! the source to figure out what they do and how they should be used.
//!
#[cfg(any(target_os = "linux", target_os = "android"))]
#[path = "platform/linux.rs"]
#[macro_use]
mod platform;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "netbsd",
          target_os = "openbsd",
          target_os = "freebsd",
          target_os = "dragonfly"))]
#[path = "platform/bsd.rs"]
#[macro_use]
mod platform;

pub use self::platform::*;

/// A hack to get the macros to work nicely.
#[doc(hidden)]
pub use ::libc as libc;

/// Convert raw ioctl return value to a Nix result
#[macro_export]
#[doc(hidden)]
macro_rules! convert_ioctl_res {
    ($w:expr) => (
        {
            $crate::Errno::result($w)
        }
    );
}

#[macro_export]
macro_rules! ioctl {
    (bad $name:ident with $nr:expr) => (
        pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
                            data: *mut u8)
                            -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
            convert_ioctl_res!($crate::sys::ioctl::libc::ioctl(fd, $nr as $crate::sys::ioctl::libc::c_ulong, data))
        }
        );
    (bad none $name:ident with $nr:expr) => (
        pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int)
                            -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
            convert_ioctl_res!($crate::sys::ioctl::libc::ioctl(fd, $nr as $crate::sys::ioctl::libc::c_ulong))
        }
        );
    (none $name:ident with $ioty:expr, $nr:expr) => (
        pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int)
                            -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
            convert_ioctl_res!($crate::sys::ioctl::libc::ioctl(fd, io!($ioty, $nr) as $crate::sys::ioctl::libc::c_ulong))
        }
        );
    (read $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
                            val: *mut $ty)
                            -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
            convert_ioctl_res!($crate::sys::ioctl::libc::ioctl(fd, ior!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val))
        }
        );
    (write $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
                            val: $ty)
                            -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
            convert_ioctl_res!($crate::sys::ioctl::libc::ioctl(fd, iow!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val))
        }
        );
    (readwrite $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
                            val: *mut $ty)
                            -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
            convert_ioctl_res!($crate::sys::ioctl::libc::ioctl(fd, iorw!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::libc::c_ulong, val))
        }
        );
    (read buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
                            val: *mut $ty,
                            len: usize)
                            -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
            convert_ioctl_res!($crate::sys::ioctl::libc::ioctl(fd, ior!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val))
        }
        );
    (write buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
                            val: *const $ty,
                            len: usize) -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
            convert_ioctl_res!($crate::sys::ioctl::libc::ioctl(fd, iow!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val))
        }
        );
    (readwrite buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::sys::ioctl::libc::c_int,
                            val: *mut $ty,
                            len: usize)
                            -> $crate::Result<$crate::sys::ioctl::libc::c_int> {
            convert_ioctl_res!($crate::sys::ioctl::libc::ioctl(fd, iorw!($ioty, $nr, len) as $crate::sys::ioctl::libc::c_ulong, val))
        }
        );
}
<commit_msg>Remove unnecessary path aliasing<commit_after>//! Provide helpers for making ioctl system calls
//!
//! Currently supports Linux on all architectures. Other platforms welcome!
//!
//! This library is pretty low-level and messy. `ioctl` is not fun.
//!
//! What is an `ioctl`?
//! ===================
//!
//! The `ioctl` syscall is the grab-bag syscall on POSIX systems. Don't want
//! to add a new syscall? Make it an `ioctl`! `ioctl` refers to both the syscall,
//! and the commands that can be send with it. `ioctl` stands for "IO control",
//! and the commands are always sent to a file descriptor.
//!
//! It is common to see `ioctl`s used for the following purposes:
//!
//! * Provide read/write access to out-of-band data related
//!   to a device such as configuration (for instance, setting
//!   serial port options)
//! * Provide a mechanism for performing full-duplex data
//!   transfers (for instance, xfer on SPI devices).
//! * Provide access to control functions on a device (for example,
//!   on Linux you can send commands like pause, resume, and eject
//!   to the CDROM device.
//! * Do whatever else the device driver creator thought made most sense.
//!
//! `ioctl`s are synchronous system calls and are similar to read and
//! write calls in that regard.
//!
//! What does this module support?
//! ===============================
//!
//! This library provides the `ioctl!` macro, for binding `ioctl`s.
//! Here's a few examples of how that can work for SPI under Linux
//! from [rust-spidev](https://github.com/posborne/rust-spidev).
//!
//! ```
//! #[allow(non_camel_case_types)]
//! pub struct spi_ioc_transfer {
//!     pub tx_buf: u64,
//!     pub rx_buf: u64,
//!     pub len: u32,
//!
//!     // optional overrides
//!     pub speed_hz: u32,
//!     pub delay_usecs: u16,
//!     pub bits_per_word: u8,
//!     pub cs_change: u8,
//!     pub pad: u32,
//! }
//!
//! #[cfg(linux)]
//! mod ioctl {
//!     use super::*;
//!
//!     const SPI_IOC_MAGIC: u8 = 'k' as u8;
//!     const SPI_IOC_NR_TRANSFER: u8 = 0;
//!     const SPI_IOC_NR_MODE: u8 = 1;
//!     const SPI_IOC_NR_LSB_FIRST: u8 = 2;
//!     const SPI_IOC_NR_BITS_PER_WORD: u8 = 3;
//!     const SPI_IOC_NR_MAX_SPEED_HZ: u8 = 4;
//!     const SPI_IOC_NR_MODE32: u8 = 5;
//!
//!     ioctl!(read  get_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8);
//!     ioctl!(read  get_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u32);
//!     ioctl!(write set_mode_u8 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE; u8);
//!     ioctl!(write set_mode_u32 with SPI_IOC_MAGIC, SPI_IOC_NR_MODE32; u32);
//!     ioctl!(read  get_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8);
//!     ioctl!(write set_lsb_first with SPI_IOC_MAGIC, SPI_IOC_NR_LSB_FIRST; u8);
//!     ioctl!(read  get_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8);
//!     ioctl!(write set_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_NR_BITS_PER_WORD; u8);
//!     ioctl!(read  get_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32);
//!     ioctl!(write set_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_NR_MAX_SPEED_HZ; u32);
//!     ioctl!(write spidev_transfer with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer);
//!     ioctl!(write buf spidev_transfer_buf with SPI_IOC_MAGIC, SPI_IOC_NR_TRANSFER; spi_ioc_transfer);
//! }
//!
//! // doctest workaround
//! fn main() {}
//! ```
//!
//! Spidev uses the `_IOC` macros that are encouraged (as far as
//! `ioctl` can be encouraged at all) for newer drivers.  Many
//! drivers, however, just use magic numbers with no attached
//! semantics.  For those, the `ioctl!(bad ...)` variant should be
//! used (the "bad" terminology is from the Linux kernel).
//!
//! How do I get the magic numbers?
//! ===============================
//!
//! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot
//! of lines defining macros which use `_IOR`, `_IOW`, `_IOC`, and `_IORW`.  These macros
//! correspond to the `ior!`, `iow!`, `ioc!`, and `iorw!` macros defined in this crate.
//! Additionally, there is the `ioctl!` macro for creating a wrapper around `ioctl` that is
//! somewhat more type-safe.
//!
//! Most `ioctl`s have no or little documentation. You'll need to scrounge through
//! the source to figure out what they do and how they should be used.
//!
#[cfg(any(target_os = "linux", target_os = "android"))]
#[path = "platform/linux.rs"]
#[macro_use]
mod platform;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "netbsd",
          target_os = "openbsd",
          target_os = "freebsd",
          target_os = "dragonfly"))]
#[path = "platform/bsd.rs"]
#[macro_use]
mod platform;

pub use self::platform::*;

/// Convert raw ioctl return value to a Nix result
#[macro_export]
#[doc(hidden)]
macro_rules! convert_ioctl_res {
    ($w:expr) => (
        {
            $crate::Errno::result($w)
        }
    );
}

/// Generates ioctl functions. See [::sys::ioctl](sys/ioctl/index.html).
#[macro_export]
macro_rules! ioctl {
    (bad $name:ident with $nr:expr) => (
        pub unsafe fn $name(fd: $crate::libc::c_int,
                            data: *mut u8)
                            -> $crate::Result<$crate::libc::c_int> {
            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::libc::c_ulong, data))
        }
        );
    (bad none $name:ident with $nr:expr) => (
        pub unsafe fn $name(fd: $crate::libc::c_int)
                            -> $crate::Result<$crate::libc::c_int> {
            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::libc::c_ulong))
        }
        );
    (none $name:ident with $ioty:expr, $nr:expr) => (
        pub unsafe fn $name(fd: $crate::libc::c_int)
                            -> $crate::Result<$crate::libc::c_int> {
            convert_ioctl_res!($crate::libc::ioctl(fd, io!($ioty, $nr) as $crate::libc::c_ulong))
        }
        );
    (read $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::libc::c_int,
                            val: *mut $ty)
                            -> $crate::Result<$crate::libc::c_int> {
            convert_ioctl_res!($crate::libc::ioctl(fd, ior!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::libc::c_ulong, val))
        }
        );
    (write $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::libc::c_int,
                            val: $ty)
                            -> $crate::Result<$crate::libc::c_int> {
            convert_ioctl_res!($crate::libc::ioctl(fd, iow!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::libc::c_ulong, val))
        }
        );
    (readwrite $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::libc::c_int,
                            val: *mut $ty)
                            -> $crate::Result<$crate::libc::c_int> {
            convert_ioctl_res!($crate::libc::ioctl(fd, iorw!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::libc::c_ulong, val))
        }
        );
    (read buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::libc::c_int,
                            val: *mut $ty,
                            len: usize)
                            -> $crate::Result<$crate::libc::c_int> {
            convert_ioctl_res!($crate::libc::ioctl(fd, ior!($ioty, $nr, len) as $crate::libc::c_ulong, val))
        }
        );
    (write buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::libc::c_int,
                            val: *const $ty,
                            len: usize) -> $crate::Result<$crate::libc::c_int> {
            convert_ioctl_res!($crate::libc::ioctl(fd, iow!($ioty, $nr, len) as $crate::libc::c_ulong, val))
        }
        );
    (readwrite buf $name:ident with $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: $crate::libc::c_int,
                            val: *mut $ty,
                            len: usize)
                            -> $crate::Result<$crate::libc::c_int> {
            convert_ioctl_res!($crate::libc::ioctl(fd, iorw!($ioty, $nr, len) as $crate::libc::c_ulong, val))
        }
        );
}
<|endoftext|>


<commit_before>// while a WIP
#![allow(unused_variables)]
use rutorch::*;
use std::ops::{Index, IndexMut};
use std::convert::From;
use std::cmp::max;
use std::hash::{Hash, Hasher};

use storage::*;
use ::*;
pub use tensor::tensor_ops::*;
use rand;
use {Ixs, RcMut};

pub enum TensorType {
    Float,
    Double,
    Byte,
    Char,
    Short,
    Int,
    Long,
}

#[derive(Hash)]
pub enum TensorKind {
    FloatTensor(Tensor<f32>),
    LongTensor(Tensor<i64>),
}
pub enum NumKind {
    Float(f32),
    Double(f64),
    Long(i64),
}

pub type TensorList<T> = Vec<Tensor<T>>;
pub type TensorKindList = Vec<TensorKind>;
pub type RefTensorList<'a, T> = Vec<&'a mut Tensor<T>>;
pub type RefTensorKindList<'a> = Vec<&'a TensorKind>;
pub type TensorId = usize;

impl TensorKind {
    pub fn new(&self) -> Self {
        unimplemented!()
    }
    pub fn in_thft(&self) -> *mut THFloatTensor {
        unimplemented!();
    }
    pub fn in_thlt(&self) -> *mut THLongTensor {
        unimplemented!();
    }
    //    pub fn backend(&self) -> &
}

impl Index<usize> for TensorKind {
    type Output = NumKind;
    fn index(&self, idx: usize) -> &Self::Output {
        unimplemented!()
    }
}
impl PartialEq for TensorKind {
    fn eq(&self, other: &Self) -> bool {
        use self::TensorKind::{FloatTensor, LongTensor};
        match (self, other) {
            (&FloatTensor(ref t1), &FloatTensor(ref t2)) => t1.id() == t2.id(),
            (&LongTensor(ref t1), &LongTensor(ref t2)) => t1.id() == t2.id(),
            _ => false,
        }
    }
}
impl Eq for TensorKind {}
impl Clone for TensorKind {
    fn clone(&self) -> Self {
        use self::TensorKind::{FloatTensor, LongTensor};
        match *self {
            FloatTensor(ref t) => FloatTensor(t.clone()),
            LongTensor(ref t) => LongTensor(t.clone()),
        }
    }
}

impl<T> From<Tensor<T>> for TensorKind {
    #[allow(unused_variables)]
    default fn from(input: Tensor<T>) -> Self {
        unreachable!()
    }
}

impl From<Tensor<f32>> for TensorKind {
    fn from(input: Tensor<f32>) -> Self {
        TensorKind::FloatTensor(input)
    }
}

impl From<Tensor<i64>> for TensorKind {
    fn from(input: Tensor<i64>) -> Self {
        TensorKind::LongTensor(input)
    }
}

impl<T> From<TensorKind> for Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: TensorKind) -> Self {
        panic!("bad cast")
    }
}

impl<'a, T> From<&'a TensorKind> for &'a Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: &'a TensorKind) -> Self {
        panic!("bad cast")
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<f32> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::FloatTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<i64> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::LongTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl From<TensorKind> for Tensor<f32> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::FloatTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}

impl From<TensorKind> for Tensor<i64> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::LongTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}
pub struct Tensor<T> {
    pub value: RcMut<TensorImpl<T, Output = T>>,
}
impl<T: Copy> Hash for Tensor<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.id().hash(state)
    }
}

impl<T: Copy> Index<usize> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: usize) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

impl<T: Copy> Index<i32> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: i32) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

pub trait New<D, T> {
    fn new(args: D) -> T;
    fn new_(&self, args: D) -> T;
}

impl<T> New<usize, Tensor<T>> for Tensor<T> {
    fn new(args: usize) -> Self {
        unimplemented!()
    }
    fn new_(&self, args: usize) -> Self {
        unimplemented!()
    }
}
impl<T> New<Vec<usize>, Tensor<T>> for Tensor<T> {
    fn new(args: Vec<usize>) -> Self {
        unimplemented!()
    }
    fn new_(&self, args: Vec<usize>) -> Self {
        unimplemented!()
    }
}

impl<T> Tensor<T> {
    pub fn len(&self) -> usize {
        unimplemented!()
    }
    pub fn s(&self, dim: usize) -> Self {
        unimplemented!()
    }
}

impl<T> Default for Tensor<T> {
    fn default() -> Self {
        unimplemented!()
    }
}

impl<T> Clone for Tensor<T> {
    fn clone(&self) -> Self {
        Tensor { value: self.value.clone() }
    }
}

impl<T: Copy> Index<isize> for Tensor<T> {
    type Output = T;

    fn index(&self, idx: isize) -> &Self::Output {
        unimplemented!()
    }
}

type RefTI<T> = RcMut<TensorImpl<T, Output = T>>;
type TIArg<T> = TensorImpl<T, Output = T>;
pub trait TensorImpl<T>: Index<Ixs, Output = T> {
    //fn view<'a>(&self, dims: &[i32]) -> Tensor<'a>;
    fn new(&self) -> RefTI<T>;
    fn add(&self, value: T, output: &TIArg<T>);
    fn inner(&self) -> *mut ::std::os::raw::c_void;
}

impl TensorImpl<f32> for FloatTensor {
    fn new(&self) -> RefTI<f32> {
        // XXX place holder implementation
        RcMutNew(FloatTensor::new())
    }
    fn add(&self, value: f32, output: &TIArg<f32>) {
        let out = typecast!(output.inner(), THFloatTensor);
        unsafe {
            THFloatTensor_add(out, self.t, value);
        };
    }
    fn inner(&self) -> *mut ::std::os::raw::c_void {
        self.t as *mut ::std::os::raw::c_void
    }
}

impl Index<isize> for FloatTensor {
    type Output = f32;
    fn index(&self, idx: isize) -> &Self::Output {
        unimplemented!()
    }
}

pub struct FloatTensor {
    t: *mut THFloatTensor,
    storage: FloatStorage,
    dims: Vec<isize>,
}

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

impl FloatTensor {
    pub fn new() -> Self {
        unsafe {
            FloatTensor {
                t: THFloatTensor_new(),
                storage: FloatStorage::new(),
                dims: Vec::new(),
            }
        }
    }
    pub fn with_capacity(dims: &[isize]) -> Self {
        let size = dims.iter().product();
        let storage = FloatStorage::with_capacity(size);
        let strides = vec![1; dims.len()];
        let mut t = THFloatTensor {
            size: dims.clone().as_ptr() as *mut ::std::os::raw::c_long,
            stride: strides.as_ptr() as *mut ::std::os::raw::c_long,
            nDimension: dims.len() as i32,
            storage: storage.t,
            storageOffset: 0,
            refcount: 1,
            flag: TH_TENSOR_REFCOUNTED as i8,
        };
        FloatTensor {
            t: &mut t,
            storage: storage,
            dims: Vec::from(dims),
        }
    }
    pub fn randn(dims: &[isize]) -> Self {
        /* XXX */
        let mut t = FloatTensor::with_capacity(dims);
        for x in t.storage.iter_mut() {
            *x = rand::random::<f32>()
        }
        t
    }
}

impl<'a> Index<&'a [isize]> for FloatTensor {
    type Output = f32;

    fn index(&self, idx: &'a [isize]) -> &Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &self.storage[index]
    }
}

impl<'a> IndexMut<&'a [isize]> for FloatTensor {
    fn index_mut(&mut self, idx: &'a [isize]) -> &mut Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &mut self.storage[index]
    }
}
<commit_msg>write conversion routines for NumKind for support TensorKind dispatch<commit_after>// while a WIP
#![allow(unused_variables)]
use rutorch::*;
use std::ops::{Index, IndexMut};
use std::convert::From;
use std::cmp::max;
use std::hash::{Hash, Hasher};

use storage::*;
use ::*;
pub use tensor::tensor_ops::*;
use rand;
use {Ixs, RcMut};

pub enum TensorType {
    Float,
    Double,
    Byte,
    Char,
    Short,
    Int,
    Long,
}

#[derive(Hash)]
pub enum TensorKind {
    FloatTensor(Tensor<f32>),
    LongTensor(Tensor<i64>),
}
pub enum NumKind {
    Float(f32),
    Double(f64),
    Long(i64),
}

impl NumKind {
    pub fn intof32(&self) -> f32 {
        use self::NumKind::{Float, Double, Long};
        match *self {
            Float(v) => v,
            Double(v) => unimplemented!(),
            Long(v) => unimplemented!(),
        }
    }
    pub fn intoi64(&self) -> i64 {
        use self::NumKind::{Float, Double, Long};
        match *self {
            Float(v) => unimplemented!(),
            Double(v) => unimplemented!(),
            Long(v) => v,
        }
    }
}

impl<T: Copy> From<T> for NumKind {
    #[allow(unused_variables)]
    default fn from(input: T) -> Self {
        unreachable!()
    }
}
impl From<f32> for NumKind {
    fn from(input: f32) -> Self {
        NumKind::Float(input)
    }
}
impl From<f64> for NumKind {
    fn from(input: f64) -> Self {
        NumKind::Double(input)
    }
}
impl From<i64> for NumKind {
    fn from(input: i64) -> Self {
        NumKind::Long(input)
    }
}

pub type TensorList<T> = Vec<Tensor<T>>;
pub type TensorKindList = Vec<TensorKind>;
pub type RefTensorList<'a, T> = Vec<&'a mut Tensor<T>>;
pub type RefTensorKindList<'a> = Vec<&'a TensorKind>;
pub type TensorId = usize;

impl TensorKind {
    pub fn new(&self) -> Self {
        unimplemented!()
    }
    pub fn in_thft(&self) -> *mut THFloatTensor {
        unimplemented!();
    }
    pub fn in_thlt(&self) -> *mut THLongTensor {
        unimplemented!();
    }
    //    pub fn backend(&self) -> &
}

impl Index<usize> for TensorKind {
    type Output = NumKind;
    fn index(&self, idx: usize) -> &Self::Output {
        unimplemented!()
    }
}
impl PartialEq for TensorKind {
    fn eq(&self, other: &Self) -> bool {
        use self::TensorKind::{FloatTensor, LongTensor};
        match (self, other) {
            (&FloatTensor(ref t1), &FloatTensor(ref t2)) => t1.id() == t2.id(),
            (&LongTensor(ref t1), &LongTensor(ref t2)) => t1.id() == t2.id(),
            _ => false,
        }
    }
}
impl Eq for TensorKind {}
impl Clone for TensorKind {
    fn clone(&self) -> Self {
        use self::TensorKind::{FloatTensor, LongTensor};
        match *self {
            FloatTensor(ref t) => FloatTensor(t.clone()),
            LongTensor(ref t) => LongTensor(t.clone()),
        }
    }
}

impl<T> From<Tensor<T>> for TensorKind {
    #[allow(unused_variables)]
    default fn from(input: Tensor<T>) -> Self {
        unreachable!()
    }
}

impl From<Tensor<f32>> for TensorKind {
    fn from(input: Tensor<f32>) -> Self {
        TensorKind::FloatTensor(input)
    }
}

impl From<Tensor<i64>> for TensorKind {
    fn from(input: Tensor<i64>) -> Self {
        TensorKind::LongTensor(input)
    }
}

impl<T> From<TensorKind> for Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: TensorKind) -> Self {
        panic!("bad cast")
    }
}

impl<'a, T> From<&'a TensorKind> for &'a Tensor<T> {
    #[allow(unused_variables)]
    default fn from(input: &'a TensorKind) -> Self {
        panic!("bad cast")
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<f32> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::FloatTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl<'a> From<&'a TensorKind> for &'a Tensor<i64> {
    fn from(input: &'a TensorKind) -> Self {
        match *input {
            TensorKind::LongTensor(ref t) => t,
            _ => unreachable!(),
        }
    }
}

impl From<TensorKind> for Tensor<f32> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::FloatTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}

impl From<TensorKind> for Tensor<i64> {
    fn from(input: TensorKind) -> Self {
        match input {
            TensorKind::LongTensor(v) => v,
            _ => unimplemented!(),
        }
    }
}
pub struct Tensor<T> {
    pub value: RcMut<TensorImpl<T, Output = T>>,
}
impl<T: Copy> Hash for Tensor<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.id().hash(state)
    }
}

impl<T: Copy> Index<usize> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: usize) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

impl<T: Copy> Index<i32> for Tensor<T> {
    type Output = T;
    fn index(&self, idx: i32) -> &Self::Output {

        //        self.value.borrow_mut().index(idx as isize)
        unimplemented!()
    }
}

pub trait New<D, T> {
    fn new(args: D) -> T;
    fn new_(&self, args: D) -> T;
}

impl<T> New<usize, Tensor<T>> for Tensor<T> {
    fn new(args: usize) -> Self {
        unimplemented!()
    }
    fn new_(&self, args: usize) -> Self {
        unimplemented!()
    }
}
impl<T> New<Vec<usize>, Tensor<T>> for Tensor<T> {
    fn new(args: Vec<usize>) -> Self {
        unimplemented!()
    }
    fn new_(&self, args: Vec<usize>) -> Self {
        unimplemented!()
    }
}

impl<T> Tensor<T> {
    pub fn len(&self) -> usize {
        unimplemented!()
    }
    pub fn s(&self, dim: usize) -> Self {
        unimplemented!()
    }
}

impl<T> Default for Tensor<T> {
    fn default() -> Self {
        unimplemented!()
    }
}

impl<T> Clone for Tensor<T> {
    fn clone(&self) -> Self {
        Tensor { value: self.value.clone() }
    }
}

impl<T: Copy> Index<isize> for Tensor<T> {
    type Output = T;

    fn index(&self, idx: isize) -> &Self::Output {
        unimplemented!()
    }
}

type RefTI<T> = RcMut<TensorImpl<T, Output = T>>;
type TIArg<T> = TensorImpl<T, Output = T>;
pub trait TensorImpl<T>: Index<Ixs, Output = T> {
    //fn view<'a>(&self, dims: &[i32]) -> Tensor<'a>;
    fn new(&self) -> RefTI<T>;
    fn add(&self, value: T, output: &TIArg<T>);
    fn inner(&self) -> *mut ::std::os::raw::c_void;
}

impl TensorImpl<f32> for FloatTensor {
    fn new(&self) -> RefTI<f32> {
        // XXX place holder implementation
        RcMutNew(FloatTensor::new())
    }
    fn add(&self, value: f32, output: &TIArg<f32>) {
        let out = typecast!(output.inner(), THFloatTensor);
        unsafe {
            THFloatTensor_add(out, self.t, value);
        };
    }
    fn inner(&self) -> *mut ::std::os::raw::c_void {
        self.t as *mut ::std::os::raw::c_void
    }
}

impl Index<isize> for FloatTensor {
    type Output = f32;
    fn index(&self, idx: isize) -> &Self::Output {
        unimplemented!()
    }
}

pub struct FloatTensor {
    t: *mut THFloatTensor,
    storage: FloatStorage,
    dims: Vec<isize>,
}

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

impl FloatTensor {
    pub fn new() -> Self {
        unsafe {
            FloatTensor {
                t: THFloatTensor_new(),
                storage: FloatStorage::new(),
                dims: Vec::new(),
            }
        }
    }
    pub fn with_capacity(dims: &[isize]) -> Self {
        let size = dims.iter().product();
        let storage = FloatStorage::with_capacity(size);
        let strides = vec![1; dims.len()];
        let mut t = THFloatTensor {
            size: dims.clone().as_ptr() as *mut ::std::os::raw::c_long,
            stride: strides.as_ptr() as *mut ::std::os::raw::c_long,
            nDimension: dims.len() as i32,
            storage: storage.t,
            storageOffset: 0,
            refcount: 1,
            flag: TH_TENSOR_REFCOUNTED as i8,
        };
        FloatTensor {
            t: &mut t,
            storage: storage,
            dims: Vec::from(dims),
        }
    }
    pub fn randn(dims: &[isize]) -> Self {
        /* XXX */
        let mut t = FloatTensor::with_capacity(dims);
        for x in t.storage.iter_mut() {
            *x = rand::random::<f32>()
        }
        t
    }
}

impl<'a> Index<&'a [isize]> for FloatTensor {
    type Output = f32;

    fn index(&self, idx: &'a [isize]) -> &Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &self.storage[index]
    }
}

impl<'a> IndexMut<&'a [isize]> for FloatTensor {
    fn index_mut(&mut self, idx: &'a [isize]) -> &mut Self::Output {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &mut self.storage[index]
    }
}
<|endoftext|>


<commit_before>use std::collections::LinkedList;

use token::Token;

use std::cell::Cell;
use std::rc::Rc;
use regex::Regex;
use context::Context;
use token::Posn;

pub trait ESCharExt {
    fn is_es_newline(self) -> bool;
    fn is_es_whitespace(self) -> bool;
}

impl ESCharExt for char {
    fn is_es_newline(self) -> bool {
        match self {
            '\u{000a}' | '\u{000d}' | '\u{2028}' | '\u{2029}' => true,
            _ => false
        }
    }

    fn is_es_whitespace(self) -> bool {
        match self {
              '\u{0009}' | '\u{000b}' | '\u{000c}' | '\u{0020}' | '\u{00a0}'
            | '\u{1680}' | '\u{2000}' | '\u{2001}' | '\u{2002}' | '\u{2003}' | '\u{2004}'
            | '\u{2005}' | '\u{2006}' | '\u{2009}' | '\u{200a}' | '\u{202f}' | '\u{205f}'
            | '\u{3000}' | '\u{feff}' => true,
            _ => false
        }
    }
}

struct LineOrientedReader<I> {
    chars: I,
    curr_char: Option<char>,
    next_char: Option<char>,
    curr_posn: Posn
}

impl<I> LineOrientedReader<I> where I: Iterator<Item=char> {
    pub fn new(mut chars: I) -> LineOrientedReader<I> {
        let curr_char = chars.next();
        let next_char = if curr_char.is_some() { chars.next() } else { None };
        LineOrientedReader {
            chars: chars,
            curr_char: curr_char,
            next_char: next_char,
            curr_posn: Posn {
                offset: 0,
                line: 0,
                column: 0
            }
        }
    }

    pub fn curr_char(&mut self) -> Option<char> { self.curr_char }
    pub fn curr_posn(&mut self) -> Posn { self.curr_posn }

    pub fn bump(&mut self) {
        let curr_char = self.next_char;
        let next_char = if curr_char.is_some() { self.chars.next() } else { None };

        self.curr_char = curr_char;
        self.next_char = next_char;

        if (curr_char == Some('\r') && next_char != Some('\n')) ||
           curr_char == Some('\n') ||
           curr_char == Some('\u{2028}') ||
           curr_char == Some('\u{2029}') {
            self.curr_posn.line += 1;
            self.curr_posn.column = 0;
        } else {
            self.curr_posn.column += 1;
        }

        self.curr_posn.offset += 1;
    }
}

struct TokenBuffer {
    tokens: LinkedList<Token>
}

impl TokenBuffer {
    fn new() -> TokenBuffer {
        TokenBuffer {
            tokens: LinkedList::new()
        }
    }

    fn ensure_nonempty(&mut self, get: &mut fn() -> Token) {
        if self.tokens.len() == 0 {
            self.tokens.push_back(get());
        }
    }

    fn read_token(&mut self) -> Token {
        assert!(self.tokens.len() > 0);
        self.tokens.pop_front().unwrap()
    }
}

pub struct Lexer<I> {
    reader: LineOrientedReader<I>,
    cx: Rc<Cell<Context>>,
    lookahead: TokenBuffer
}

impl<I> Lexer<I> where I: Iterator<Item=char> {
    // constructor

    pub fn new(chars: I, cx: Rc<Cell<Context>>) -> Lexer<I> {
        Lexer {
            reader: LineOrientedReader::new(chars),
            cx: cx,
            lookahead: TokenBuffer::new()
        }
    }

    // public methods

    pub fn read_token(&mut self) -> Token {
        self.lookahead.ensure_nonempty(|| {
            self.read_next_token()
        });
        unimplemented!()
    }

    // private methods

    fn read_next_token(&mut self) -> Token {
        unimplemented!()
    }

    fn is_whitespace(&mut self) -> bool {
        match self.reader.curr_char() {
            Some(ch) => ch.is_es_whitespace(),
            None => false
        }
    }

    fn eat(&mut self) -> Option<char> {
        let ch = self.reader.curr_char();
        self.reader.bump();
        ch
    }

    fn skip_whitespace(&mut self) {
        while self.is_whitespace() {
            self.reader.bump();
        }
    }
}

impl<I> Iterator for Lexer<I> where I: Iterator<Item=char> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.skip_whitespace();
        self.eat()
            .map(|ch| {
                match ch {
                    '1' => Token::DecimalInt(String::from_str("1")),
                    '+' => Token::Plus,
                    _ => Token::Error(ch)
                }
            })
    }
}
<commit_msg>RFC suggests I should use `ref || { ... }`. try that? nope, syntax error.    Compiling bissap v0.0.1 (file:///Users/dherman/Sources/bissap) src/lexer.rs:125:40: 125:43 error: expected identifier, found keyword `ref` src/lexer.rs:125         self.lookahead.ensure_nonempty(ref || { src/lexer.rs:125:40: 125:43 error: expected identifier, found keyword `ref` src/lexer.rs:125         self.lookahead.ensure_nonempty(ref || {                                                         ^~~                                                         ^~~<commit_after>use std::collections::LinkedList;

use token::Token;

use std::cell::Cell;
use std::rc::Rc;
use regex::Regex;
use context::Context;
use token::Posn;

pub trait ESCharExt {
    fn is_es_newline(self) -> bool;
    fn is_es_whitespace(self) -> bool;
}

impl ESCharExt for char {
    fn is_es_newline(self) -> bool {
        match self {
            '\u{000a}' | '\u{000d}' | '\u{2028}' | '\u{2029}' => true,
            _ => false
        }
    }

    fn is_es_whitespace(self) -> bool {
        match self {
              '\u{0009}' | '\u{000b}' | '\u{000c}' | '\u{0020}' | '\u{00a0}'
            | '\u{1680}' | '\u{2000}' | '\u{2001}' | '\u{2002}' | '\u{2003}' | '\u{2004}'
            | '\u{2005}' | '\u{2006}' | '\u{2009}' | '\u{200a}' | '\u{202f}' | '\u{205f}'
            | '\u{3000}' | '\u{feff}' => true,
            _ => false
        }
    }
}

struct LineOrientedReader<I> {
    chars: I,
    curr_char: Option<char>,
    next_char: Option<char>,
    curr_posn: Posn
}

impl<I> LineOrientedReader<I> where I: Iterator<Item=char> {
    pub fn new(mut chars: I) -> LineOrientedReader<I> {
        let curr_char = chars.next();
        let next_char = if curr_char.is_some() { chars.next() } else { None };
        LineOrientedReader {
            chars: chars,
            curr_char: curr_char,
            next_char: next_char,
            curr_posn: Posn {
                offset: 0,
                line: 0,
                column: 0
            }
        }
    }

    pub fn curr_char(&mut self) -> Option<char> { self.curr_char }
    pub fn curr_posn(&mut self) -> Posn { self.curr_posn }

    pub fn bump(&mut self) {
        let curr_char = self.next_char;
        let next_char = if curr_char.is_some() { self.chars.next() } else { None };

        self.curr_char = curr_char;
        self.next_char = next_char;

        if (curr_char == Some('\r') && next_char != Some('\n')) ||
           curr_char == Some('\n') ||
           curr_char == Some('\u{2028}') ||
           curr_char == Some('\u{2029}') {
            self.curr_posn.line += 1;
            self.curr_posn.column = 0;
        } else {
            self.curr_posn.column += 1;
        }

        self.curr_posn.offset += 1;
    }
}

struct TokenBuffer {
    tokens: LinkedList<Token>
}

impl TokenBuffer {
    fn new() -> TokenBuffer {
        TokenBuffer {
            tokens: LinkedList::new()
        }
    }

    fn ensure_nonempty(&mut self, get: fn() -> Token) {
        if self.tokens.len() == 0 {
            self.tokens.push_back(get());
        }
    }

    fn read_token(&mut self) -> Token {
        assert!(self.tokens.len() > 0);
        self.tokens.pop_front().unwrap()
    }
}

pub struct Lexer<I> {
    reader: LineOrientedReader<I>,
    cx: Rc<Cell<Context>>,
    lookahead: TokenBuffer
}

impl<I> Lexer<I> where I: Iterator<Item=char> {
    // constructor

    pub fn new(chars: I, cx: Rc<Cell<Context>>) -> Lexer<I> {
        Lexer {
            reader: LineOrientedReader::new(chars),
            cx: cx,
            lookahead: TokenBuffer::new()
        }
    }

    // public methods

    pub fn read_token(&mut self) -> Token {
        self.lookahead.ensure_nonempty(ref || {
            self.read_next_token()
        });
        unimplemented!()
    }

    // private methods

    fn read_next_token(&mut self) -> Token {
        unimplemented!()
    }

    fn is_whitespace(&mut self) -> bool {
        match self.reader.curr_char() {
            Some(ch) => ch.is_es_whitespace(),
            None => false
        }
    }

    fn eat(&mut self) -> Option<char> {
        let ch = self.reader.curr_char();
        self.reader.bump();
        ch
    }

    fn skip_whitespace(&mut self) {
        while self.is_whitespace() {
            self.reader.bump();
        }
    }
}

impl<I> Iterator for Lexer<I> where I: Iterator<Item=char> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.skip_whitespace();
        self.eat()
            .map(|ch| {
                match ch {
                    '1' => Token::DecimalInt(String::from_str("1")),
                    '+' => Token::Plus,
                    _ => Token::Error(ch)
                }
            })
    }
}
<|endoftext|>


<commit_before>use crate::utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq};
use crate::utils::{higher, sugg};
use if_chain::if_chain;
use rustc::hir;
use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;

declare_clippy_lint! {
    /// **What it does:** Checks for `a = a op b` or `a = b commutative_op a`
    /// patterns.
    ///
    /// **Why is this bad?** These can be written as the shorter `a op= b`.
    ///
    /// **Known problems:** While forbidden by the spec, `OpAssign` traits may have
    /// implementations that differ from the regular `Op` impl.
    ///
    /// **Example:**
    /// ```ignore
    /// let mut a = 5;
    /// ...
    /// a = a + b;
    /// ```
    pub ASSIGN_OP_PATTERN,
    style,
    "assigning the result of an operation on a variable to that same variable"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `a op= a op b` or `a op= b op a` patterns.
    ///
    /// **Why is this bad?** Most likely these are bugs where one meant to write `a
    /// op= b`.
    ///
    /// **Known problems:** Clippy cannot know for sure if `a op= a op b` should have
    /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore it suggests both.
    /// If `a op= a op b` is really the correct behaviour it should be
    /// written as `a = a op a op b` as it's less confusing.
    ///
    /// **Example:**
    /// ```ignore
    /// let mut a = 5;
    /// ...
    /// a += a + b;
    /// ```
    pub MISREFACTORED_ASSIGN_OP,
    complexity,
    "having a variable on both sides of an assign op"
}

#[derive(Copy, Clone, Default)]
pub struct AssignOps;

impl LintPass for AssignOps {
    fn get_lints(&self) -> LintArray {
        lint_array!(ASSIGN_OP_PATTERN, MISREFACTORED_ASSIGN_OP)
    }

    fn name(&self) -> &'static str {
        "AssignOps"
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
    #[allow(clippy::too_many_lines)]
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
        match &expr.node {
            hir::ExprKind::AssignOp(op, lhs, rhs) => {
                if let hir::ExprKind::Binary(binop, l, r) = &rhs.node {
                    if op.node != binop.node { return; }
                    // lhs op= l op r
                    if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, l) {
                        lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, r);
                    }
                    // lhs op= l commutative_op r
                    if is_commutative(op.node) && SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, r) {
                        lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, l);
                    }
                }
            },
            hir::ExprKind::Assign(assignee, e) => {
                if let hir::ExprKind::Binary(op, l, r) = &e.node {
                    #[allow(clippy::cognitive_complexity)]
                    let lint = |assignee: &hir::Expr, rhs: &hir::Expr| {
                        let ty = cx.tables.expr_ty(assignee);
                        let rty = cx.tables.expr_ty(rhs);
                        macro_rules! ops {
                            ($op:expr,
                             $cx:expr,
                             $ty:expr,
                             $rty:expr,
                             $($trait_name:ident),+) => {
                                match $op {
                                    $(hir::BinOpKind::$trait_name => {
                                        let [krate, module] = crate::utils::paths::OPS_MODULE;
                                        let path = [krate, module, concat!(stringify!($trait_name), "Assign")];
                                        let trait_id = if let Some(trait_id) = get_trait_def_id($cx, &path) {
                                            trait_id
                                        } else {
                                            return; // useless if the trait doesn't exist
                                        };
                                        // check that we are not inside an `impl AssignOp` of this exact operation
                                        let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id);
                                        let parent_impl = cx.tcx.hir().get_parent_item(parent_fn);
                                        // the crate node is the only one that is not in the map
                                        if_chain! {
                                            if parent_impl != hir::CRATE_HIR_ID;
                                            if let hir::Node::Item(item) = cx.tcx.hir().get_by_hir_id(parent_impl);
                                            if let hir::ItemKind::Impl(_, _, _, _, Some(trait_ref), _, _) =
                                                &item.node;
                                            if trait_ref.path.def.def_id() == trait_id;
                                            then { return; }
                                        }
                                        implements_trait($cx, $ty, trait_id, &[$rty])
                                    },)*
                                    _ => false,
                                }
                            }
                        }
                        if ops!(
                            op.node,
                            cx,
                            ty,
                            rty.into(),
                            Add,
                            Sub,
                            Mul,
                            Div,
                            Rem,
                            And,
                            Or,
                            BitAnd,
                            BitOr,
                            BitXor,
                            Shr,
                            Shl
                        ) {
                            span_lint_and_then(
                                cx,
                                ASSIGN_OP_PATTERN,
                                expr.span,
                                "manual implementation of an assign operation",
                                |db| {
                                    if let (Some(snip_a), Some(snip_r)) =
                                        (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span))
                                    {
                                        db.span_suggestion(
                                            expr.span,
                                            "replace it with",
                                            format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
                                            Applicability::MachineApplicable,
                                        );
                                    }
                                },
                            );
                        }
                    };

                    let mut visitor = ExprVisitor {
                        assignee,
                        counter: 0,
                        cx,
                    };

                    walk_expr(&mut visitor, e);

                    if visitor.counter == 1 {
                        // a = a op b
                        if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, l) {
                            lint(assignee, r);
                        }
                        // a = b commutative_op a
                        // Limited to primitive type as these ops are know to be commutative
                        if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r)
                            && cx.tables.expr_ty(assignee).is_primitive_ty()
                        {
                            match op.node {
                                hir::BinOpKind::Add
                                | hir::BinOpKind::Mul
                                | hir::BinOpKind::And
                                | hir::BinOpKind::Or
                                | hir::BinOpKind::BitXor
                                | hir::BinOpKind::BitAnd
                                | hir::BinOpKind::BitOr => {
                                    lint(assignee, l);
                                },
                                _ => {},
                            }
                        }
                    }
                }
            },
            _ => {},
        }
    }
}

fn lint_misrefactored_assign_op(cx: &LateContext<'_, '_>, expr: &hir::Expr, op: hir::BinOp, rhs: &hir::Expr, assignee: &hir::Expr, rhs_other: &hir::Expr) {
    span_lint_and_then(
        cx,
        MISREFACTORED_ASSIGN_OP,
        expr.span,
        "variable appears on both sides of an assignment operation",
        |db| {
            if let (Some(snip_a), Some(snip_r)) =
                (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span))
            {
                let a = &sugg::Sugg::hir(cx, assignee, "..");
                let r = &sugg::Sugg::hir(cx, rhs, "..");
                let long =
                    format!("{} = {}", snip_a, sugg::make_binop(higher::binop(op.node), a, r));
                db.span_suggestion(
                    expr.span,
                    &format!(
                        "Did you mean {} = {} {} {} or {}? Consider replacing it with",
                        snip_a,
                        snip_a,
                        op.node.as_str(),
                        snip_r,
                        long
                    ),
                    format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
                    Applicability::MachineApplicable,
                );
                db.span_suggestion(
                    expr.span,
                    "or",
                    long,
                    Applicability::MachineApplicable, // snippet
                );
            }
        },
    );
}

fn is_commutative(op: hir::BinOpKind) -> bool {
    use rustc::hir::BinOpKind::*;
    match op {
        Add | Mul | And | Or | BitXor | BitAnd | BitOr | Eq | Ne => true,
        Sub | Div | Rem | Shl | Shr | Lt | Le | Ge | Gt => false,
    }
}

struct ExprVisitor<'a, 'tcx: 'a> {
    assignee: &'a hir::Expr,
    counter: u8,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx: 'a> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
        if SpanlessEq::new(self.cx).ignore_fn().eq_expr(self.assignee, expr) {
            self.counter += 1;
        }

        walk_expr(self, expr);
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}
<commit_msg>cargo fmt<commit_after>use crate::utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq};
use crate::utils::{higher, sugg};
use if_chain::if_chain;
use rustc::hir;
use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;

declare_clippy_lint! {
    /// **What it does:** Checks for `a = a op b` or `a = b commutative_op a`
    /// patterns.
    ///
    /// **Why is this bad?** These can be written as the shorter `a op= b`.
    ///
    /// **Known problems:** While forbidden by the spec, `OpAssign` traits may have
    /// implementations that differ from the regular `Op` impl.
    ///
    /// **Example:**
    /// ```ignore
    /// let mut a = 5;
    /// ...
    /// a = a + b;
    /// ```
    pub ASSIGN_OP_PATTERN,
    style,
    "assigning the result of an operation on a variable to that same variable"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `a op= a op b` or `a op= b op a` patterns.
    ///
    /// **Why is this bad?** Most likely these are bugs where one meant to write `a
    /// op= b`.
    ///
    /// **Known problems:** Clippy cannot know for sure if `a op= a op b` should have
    /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore it suggests both.
    /// If `a op= a op b` is really the correct behaviour it should be
    /// written as `a = a op a op b` as it's less confusing.
    ///
    /// **Example:**
    /// ```ignore
    /// let mut a = 5;
    /// ...
    /// a += a + b;
    /// ```
    pub MISREFACTORED_ASSIGN_OP,
    complexity,
    "having a variable on both sides of an assign op"
}

#[derive(Copy, Clone, Default)]
pub struct AssignOps;

impl LintPass for AssignOps {
    fn get_lints(&self) -> LintArray {
        lint_array!(ASSIGN_OP_PATTERN, MISREFACTORED_ASSIGN_OP)
    }

    fn name(&self) -> &'static str {
        "AssignOps"
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
    #[allow(clippy::too_many_lines)]
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
        match &expr.node {
            hir::ExprKind::AssignOp(op, lhs, rhs) => {
                if let hir::ExprKind::Binary(binop, l, r) = &rhs.node {
                    if op.node != binop.node {
                        return;
                    }
                    // lhs op= l op r
                    if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, l) {
                        lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, r);
                    }
                    // lhs op= l commutative_op r
                    if is_commutative(op.node) && SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, r) {
                        lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, l);
                    }
                }
            },
            hir::ExprKind::Assign(assignee, e) => {
                if let hir::ExprKind::Binary(op, l, r) = &e.node {
                    #[allow(clippy::cognitive_complexity)]
                    let lint = |assignee: &hir::Expr, rhs: &hir::Expr| {
                        let ty = cx.tables.expr_ty(assignee);
                        let rty = cx.tables.expr_ty(rhs);
                        macro_rules! ops {
                            ($op:expr,
                             $cx:expr,
                             $ty:expr,
                             $rty:expr,
                             $($trait_name:ident),+) => {
                                match $op {
                                    $(hir::BinOpKind::$trait_name => {
                                        let [krate, module] = crate::utils::paths::OPS_MODULE;
                                        let path = [krate, module, concat!(stringify!($trait_name), "Assign")];
                                        let trait_id = if let Some(trait_id) = get_trait_def_id($cx, &path) {
                                            trait_id
                                        } else {
                                            return; // useless if the trait doesn't exist
                                        };
                                        // check that we are not inside an `impl AssignOp` of this exact operation
                                        let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id);
                                        let parent_impl = cx.tcx.hir().get_parent_item(parent_fn);
                                        // the crate node is the only one that is not in the map
                                        if_chain! {
                                            if parent_impl != hir::CRATE_HIR_ID;
                                            if let hir::Node::Item(item) = cx.tcx.hir().get_by_hir_id(parent_impl);
                                            if let hir::ItemKind::Impl(_, _, _, _, Some(trait_ref), _, _) =
                                                &item.node;
                                            if trait_ref.path.def.def_id() == trait_id;
                                            then { return; }
                                        }
                                        implements_trait($cx, $ty, trait_id, &[$rty])
                                    },)*
                                    _ => false,
                                }
                            }
                        }
                        if ops!(
                            op.node,
                            cx,
                            ty,
                            rty.into(),
                            Add,
                            Sub,
                            Mul,
                            Div,
                            Rem,
                            And,
                            Or,
                            BitAnd,
                            BitOr,
                            BitXor,
                            Shr,
                            Shl
                        ) {
                            span_lint_and_then(
                                cx,
                                ASSIGN_OP_PATTERN,
                                expr.span,
                                "manual implementation of an assign operation",
                                |db| {
                                    if let (Some(snip_a), Some(snip_r)) =
                                        (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span))
                                    {
                                        db.span_suggestion(
                                            expr.span,
                                            "replace it with",
                                            format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
                                            Applicability::MachineApplicable,
                                        );
                                    }
                                },
                            );
                        }
                    };

                    let mut visitor = ExprVisitor {
                        assignee,
                        counter: 0,
                        cx,
                    };

                    walk_expr(&mut visitor, e);

                    if visitor.counter == 1 {
                        // a = a op b
                        if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, l) {
                            lint(assignee, r);
                        }
                        // a = b commutative_op a
                        // Limited to primitive type as these ops are know to be commutative
                        if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r)
                            && cx.tables.expr_ty(assignee).is_primitive_ty()
                        {
                            match op.node {
                                hir::BinOpKind::Add
                                | hir::BinOpKind::Mul
                                | hir::BinOpKind::And
                                | hir::BinOpKind::Or
                                | hir::BinOpKind::BitXor
                                | hir::BinOpKind::BitAnd
                                | hir::BinOpKind::BitOr => {
                                    lint(assignee, l);
                                },
                                _ => {},
                            }
                        }
                    }
                }
            },
            _ => {},
        }
    }
}

fn lint_misrefactored_assign_op(
    cx: &LateContext<'_, '_>,
    expr: &hir::Expr,
    op: hir::BinOp,
    rhs: &hir::Expr,
    assignee: &hir::Expr,
    rhs_other: &hir::Expr,
) {
    span_lint_and_then(
        cx,
        MISREFACTORED_ASSIGN_OP,
        expr.span,
        "variable appears on both sides of an assignment operation",
        |db| {
            if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) {
                let a = &sugg::Sugg::hir(cx, assignee, "..");
                let r = &sugg::Sugg::hir(cx, rhs, "..");
                let long = format!("{} = {}", snip_a, sugg::make_binop(higher::binop(op.node), a, r));
                db.span_suggestion(
                    expr.span,
                    &format!(
                        "Did you mean {} = {} {} {} or {}? Consider replacing it with",
                        snip_a,
                        snip_a,
                        op.node.as_str(),
                        snip_r,
                        long
                    ),
                    format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
                    Applicability::MachineApplicable,
                );
                db.span_suggestion(
                    expr.span,
                    "or",
                    long,
                    Applicability::MachineApplicable, // snippet
                );
            }
        },
    );
}

fn is_commutative(op: hir::BinOpKind) -> bool {
    use rustc::hir::BinOpKind::*;
    match op {
        Add | Mul | And | Or | BitXor | BitAnd | BitOr | Eq | Ne => true,
        Sub | Div | Rem | Shl | Shr | Lt | Le | Ge | Gt => false,
    }
}

struct ExprVisitor<'a, 'tcx: 'a> {
    assignee: &'a hir::Expr,
    counter: u8,
    cx: &'a LateContext<'a, 'tcx>,
}

impl<'a, 'tcx: 'a> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
        if SpanlessEq::new(self.cx).ignore_fn().eq_expr(self.assignee, expr) {
            self.counter += 1;
        }

        walk_expr(self, expr);
    }
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }
}
<|endoftext|>