<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone,Copy,PartialEq,Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(mut index), ProgramStatus::Normal) => {
                while index < self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpForward => {
                            let jump_report = self.start_jump_forward(vm, index);
                            index = jump_report.0;
                            self.status = jump_report.1;
                        },
                        Command::JumpBackward => index = self.jump_backward(&vm, index),
                        command => {
                            vm.apply(command);
                            index += 1;
                        }
                    }
                }
                self.instruction_pointer = Some(index);
            },

            (Some(index), ProgramStatus::Seeking(goal_depth)) => {
                let (new_index, new_status) = self.seek_forward(index, goal_depth);
                self.instruction_pointer = Some(new_index);
                self.status = new_status;
                self.execute(vm);
            },

            _ => {}
        }
    }

    fn jump_backward (&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth = self.current_depth - 1;
                starting_index + 1
            },
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.current_depth += 1,
                        Command::JumpForward => {
                            if self.current_depth == goal_depth { return index + 1 }
                            self.current_depth -= 1;
                        },
                        _ => {},
                    }
                }
                panic!("No starting brace found!");
            },
        }
    }

    fn seek_forward(&mut self, starting_index: usize, goal_depth: u64) -> (usize, ProgramStatus) {
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth += 1,
                Command::JumpBackward => self.current_depth -= 1,
                _ => {},
            }
            if self.current_depth == goal_depth {
                return (index + 1, ProgramStatus::Normal);
            }
        }
        return (self.instructions.len(), ProgramStatus::Seeking(goal_depth));
    }

    fn start_jump_forward(&mut self, vm: &VM, index: usize) -> (usize, ProgramStatus) {
        match vm.cells[vm.data_pointer] {
            0 => {
                let goal_depth = self.current_depth;
                return self.seek_forward(index, goal_depth);
            },
            _ => {
                self.current_depth += 1;
                return (index + 1, ProgramStatus::Normal);
            }
        }
    }
}
<commit_msg>Add unit tests for program.seek_forward<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone,Copy,PartialEq,Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(mut index), ProgramStatus::Normal) => {
                while index < self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpForward => {
                            let jump_report = self.start_jump_forward(vm, index);
                            index = jump_report.0;
                            self.status = jump_report.1;
                        },
                        Command::JumpBackward => index = self.jump_backward(&vm, index),
                        command => {
                            vm.apply(command);
                            index += 1;
                        }
                    }
                }
                self.instruction_pointer = Some(index);
            },

            (Some(index), ProgramStatus::Seeking(goal_depth)) => {
                let (new_index, new_status) = self.seek_forward(index, goal_depth);
                self.instruction_pointer = Some(new_index);
                self.status = new_status;
                self.execute(vm);
            },

            _ => {}
        }
    }

    fn jump_backward (&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth = self.current_depth - 1;
                starting_index + 1
            },
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.current_depth += 1,
                        Command::JumpForward => {
                            if self.current_depth == goal_depth { return index + 1 }
                            self.current_depth -= 1;
                        },
                        _ => {},
                    }
                }
                panic!("No starting brace found!");
            },
        }
    }

    fn seek_forward(&mut self, starting_index: usize, goal_depth: u64) -> (usize, ProgramStatus) {
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth += 1,
                Command::JumpBackward => self.current_depth -= 1,
                _ => {},
            }
            if self.current_depth == goal_depth {
                return (index + 1, ProgramStatus::Normal);
            }
        }
        return (self.instructions.len(), ProgramStatus::Seeking(goal_depth));
    }

    fn start_jump_forward(&mut self, vm: &VM, index: usize) -> (usize, ProgramStatus) {
        match vm.cells[vm.data_pointer] {
            0 => {
                let goal_depth = self.current_depth;
                return self.seek_forward(index, goal_depth);
            },
            _ => {
                self.current_depth += 1;
                return (index + 1, ProgramStatus::Normal);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    pub fn test_seek_forward_normal() {
        let mut program = Program {
            instruction_pointer: Some(0),
            current_depth: 0,
            status: ProgramStatus::Normal,
            instructions: vec![ Command::JumpForward
                              , Command::JumpForward
                              , Command::JumpBackward
                              , Command::JumpBackward]};
        let actual = program.seek_forward(0, 0);
        let expected = (4, ProgramStatus::Normal);
        assert_eq!(actual, expected);
    }

    #[test]
    pub fn test_seek_forward_seeking() {
        let mut program = Program {
            instruction_pointer: Some(0),
            current_depth: 0,
            status: ProgramStatus::Normal,
            instructions: vec![ Command::JumpForward
                              , Command::JumpForward
                              , Command::JumpBackward]};
        let actual = program.seek_forward(0, 0);
        let expected = (3, ProgramStatus::Seeking(0));
        assert_eq!(actual, expected);
    }
}
<|endoftext|>


<commit_before>use crate::utils::{snippet, span_lint, span_lint_and_sugg};
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use std::borrow::Cow;
use crate::syntax::ast::*;
use crate::syntax::parse::{parser, token};
use crate::syntax::tokenstream::{ThinTokenStream, TokenStream};

/// **What it does:** This lint warns when you use `println!("")` to
/// print a newline.
///
/// **Why is this bad?** You should use `println!()`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// println!("");
/// ```
declare_clippy_lint! {
    pub PRINTLN_EMPTY_STRING,
    style,
    "using `println!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `print!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `println!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// print!("Hello {}!\n", name);
/// ```
/// use println!() instead
/// ```rust
/// println!("Hello {}!", name);
/// ```
declare_clippy_lint! {
    pub PRINT_WITH_NEWLINE,
    style,
    "using `print!()` with a format string that ends in a single newline"
}

/// **What it does:** Checks for printing on *stdout*. The purpose of this lint
/// is to catch debugging remnants.
///
/// **Why is this bad?** People often print on *stdout* while debugging an
/// application and might forget to remove those prints afterward.
///
/// **Known problems:** Only catches `print!` and `println!` calls.
///
/// **Example:**
/// ```rust
/// println!("Hello world!");
/// ```
declare_clippy_lint! {
    pub PRINT_STDOUT,
    restriction,
    "printing on stdout"
}

/// **What it does:** Checks for use of `Debug` formatting. The purpose of this
/// lint is to catch debugging remnants.
///
/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
/// debugging Rust code. It should not be used in in user-facing output.
///
/// **Example:**
/// ```rust
/// println!("{:?}", foo);
/// ```
declare_clippy_lint! {
    pub USE_DEBUG,
    restriction,
    "use of `Debug`-based formatting"
}

/// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
///
/// **Why is this bad?** Using literals as `println!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `println!("{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// println!("{}", "foo");
/// ```
/// use the literal without formatting:
/// ```rust
/// println!("foo");
/// ```
declare_clippy_lint! {
    pub PRINT_LITERAL,
    style,
    "printing a literal with a format string"
}

/// **What it does:** This lint warns when you use `writeln!(buf, "")` to
/// print a newline.
///
/// **Why is this bad?** You should use `writeln!(buf)`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// writeln!("");
/// ```
declare_clippy_lint! {
    pub WRITELN_EMPTY_STRING,
    style,
    "using `writeln!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `write!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `writeln!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// write!(buf, "Hello {}!\n", name);
/// ```
declare_clippy_lint! {
    pub WRITE_WITH_NEWLINE,
    style,
    "using `write!()` with a format string that ends in a single newline"
}

/// **What it does:** This lint warns about the use of literals as `write!`/`writeln!` args.
///
/// **Why is this bad?** Using literals as `writeln!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// writeln!(buf, "{}", "foo");
/// ```
declare_clippy_lint! {
    pub WRITE_LITERAL,
    style,
    "writing a literal with a format string"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            PRINT_WITH_NEWLINE,
            PRINTLN_EMPTY_STRING,
            PRINT_STDOUT,
            USE_DEBUG,
            PRINT_LITERAL,
            WRITE_WITH_NEWLINE,
            WRITELN_EMPTY_STRING,
            WRITE_LITERAL
        )
    }
}

impl EarlyLintPass for Pass {
    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
        if mac.node.path == "println" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `println!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
                if fmtstr == "" {
                    span_lint_and_sugg(
                        cx,
                        PRINTLN_EMPTY_STRING,
                        mac.span,
                        "using `println!(\"\")`",
                        "replace it with",
                        "println!()".to_string(),
                    );
                }
            }
        } else if mac.node.path == "print" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
                if fmtstr.ends_with("\\n") &&
                   // don't warn about strings with several `\n`s (#3126)
                   fmtstr.matches("\\n").count() == 1
                {
                    span_lint(
                        cx,
                        PRINT_WITH_NEWLINE,
                        mac.span,
                        "using `print!()` with a format string that ends in a \
                         single newline, consider using `println!()` instead",
                    );
                }
            }
        } else if mac.node.path == "write" {
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true).0 {
                if fmtstr.ends_with("\\n") &&
                   // don't warn about strings with several `\n`s (#3126)
                   fmtstr.matches("\\n").count() == 1
                {
                    span_lint(
                        cx,
                        WRITE_WITH_NEWLINE,
                        mac.span,
                        "using `write!()` with a format string that ends in a \
                         single newline, consider using `writeln!()` instead",
                    );
                }
            }
        } else if mac.node.path == "writeln" {
            let check_tts = check_tts(cx, &mac.node.tts, true);
            if let Some(fmtstr) = check_tts.0 {
                if fmtstr == "" {
                    let suggestion = check_tts
                        .1
                        .map_or(Cow::Borrowed("v"), |expr| snippet(cx, expr.span, "v"));

                    span_lint_and_sugg(
                        cx,
                        WRITELN_EMPTY_STRING,
                        mac.span,
                        format!("using `writeln!({}, \"\")`", suggestion).as_str(),
                        "replace it with",
                        format!("writeln!({})", suggestion),
                    );
                }
            }
        }
    }
}

fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> (Option<String>, Option<Expr>) {
    use crate::fmt_macros::*;
    let tts = TokenStream::from(tts.clone());
    let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, None, false, false);
    let mut expr: Option<Expr> = None;
    if is_write {
        expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
            Ok(p) => Some(p.into_inner()),
            Err(_) => return (None, None),
        };
        // might be `writeln!(foo)`
        if parser.expect(&token::Comma).map_err(|mut err| err.cancel()).is_err() {
            return (None, expr);
        }
    }

    let fmtstr = match parser.parse_str().map_err(|mut err| err.cancel()) {
        Ok(token) => token.0.to_string(),
        Err(_) => return (None, expr),
    };
    let tmp = fmtstr.clone();
    let mut args = vec![];
    let mut fmt_parser = Parser::new(&tmp, None);
    while let Some(piece) = fmt_parser.next() {
        if !fmt_parser.errors.is_empty() {
            return (None, expr);
        }
        if let Piece::NextArgument(arg) = piece {
            if arg.format.ty == "?" {
                // FIXME: modify rustc's fmt string parser to give us the current span
                span_lint(cx, USE_DEBUG, parser.prev_span, "use of `Debug`-based formatting");
            }
            args.push(arg);
        }
    }
    let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
    let mut idx = 0;
    loop {
        if !parser.eat(&token::Comma) {
            return (Some(fmtstr), expr);
        }
        let token_expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
            Ok(expr) => expr,
            Err(_) => return (Some(fmtstr), None),
        };
        const SIMPLE: FormatSpec<'_> = FormatSpec {
            fill: None,
            align: AlignUnknown,
            flags: 0,
            precision: CountImplied,
            width: CountImplied,
            ty: "",
        };
        match &token_expr.node {
            ExprKind::Lit(_) => {
                let mut all_simple = true;
                let mut seen = false;
                for arg in &args {
                    match arg.position {
                        ArgumentImplicitlyIs(n) | ArgumentIs(n) => if n == idx {
                            all_simple &= arg.format == SIMPLE;
                            seen = true;
                        },
                        ArgumentNamed(_) => {},
                    }
                }
                if all_simple && seen {
                    span_lint(cx, lint, token_expr.span, "literal with an empty format string");
                }
                idx += 1;
            },
            ExprKind::Assign(lhs, rhs) => {
                if let ExprKind::Lit(_) = rhs.node {
                    if let ExprKind::Path(_, p) = &lhs.node {
                        let mut all_simple = true;
                        let mut seen = false;
                        for arg in &args {
                            match arg.position {
                                ArgumentImplicitlyIs(_) | ArgumentIs(_) => {},
                                ArgumentNamed(name) => if *p == name {
                                    seen = true;
                                    all_simple &= arg.format == SIMPLE;
                                },
                            }
                        }
                        if all_simple && seen {
                            span_lint(cx, lint, rhs.span, "literal with an empty format string");
                        }
                    }
                }
            },
            _ => idx += 1,
        }
    }
}
<commit_msg>Fix items_after_statements for `const`s<commit_after>use crate::utils::{snippet, span_lint, span_lint_and_sugg};
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use std::borrow::Cow;
use crate::syntax::ast::*;
use crate::syntax::parse::{parser, token};
use crate::syntax::tokenstream::{ThinTokenStream, TokenStream};

/// **What it does:** This lint warns when you use `println!("")` to
/// print a newline.
///
/// **Why is this bad?** You should use `println!()`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// println!("");
/// ```
declare_clippy_lint! {
    pub PRINTLN_EMPTY_STRING,
    style,
    "using `println!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `print!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `println!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// print!("Hello {}!\n", name);
/// ```
/// use println!() instead
/// ```rust
/// println!("Hello {}!", name);
/// ```
declare_clippy_lint! {
    pub PRINT_WITH_NEWLINE,
    style,
    "using `print!()` with a format string that ends in a single newline"
}

/// **What it does:** Checks for printing on *stdout*. The purpose of this lint
/// is to catch debugging remnants.
///
/// **Why is this bad?** People often print on *stdout* while debugging an
/// application and might forget to remove those prints afterward.
///
/// **Known problems:** Only catches `print!` and `println!` calls.
///
/// **Example:**
/// ```rust
/// println!("Hello world!");
/// ```
declare_clippy_lint! {
    pub PRINT_STDOUT,
    restriction,
    "printing on stdout"
}

/// **What it does:** Checks for use of `Debug` formatting. The purpose of this
/// lint is to catch debugging remnants.
///
/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
/// debugging Rust code. It should not be used in in user-facing output.
///
/// **Example:**
/// ```rust
/// println!("{:?}", foo);
/// ```
declare_clippy_lint! {
    pub USE_DEBUG,
    restriction,
    "use of `Debug`-based formatting"
}

/// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
///
/// **Why is this bad?** Using literals as `println!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `println!("{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// println!("{}", "foo");
/// ```
/// use the literal without formatting:
/// ```rust
/// println!("foo");
/// ```
declare_clippy_lint! {
    pub PRINT_LITERAL,
    style,
    "printing a literal with a format string"
}

/// **What it does:** This lint warns when you use `writeln!(buf, "")` to
/// print a newline.
///
/// **Why is this bad?** You should use `writeln!(buf)`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// writeln!("");
/// ```
declare_clippy_lint! {
    pub WRITELN_EMPTY_STRING,
    style,
    "using `writeln!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `write!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `writeln!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// write!(buf, "Hello {}!\n", name);
/// ```
declare_clippy_lint! {
    pub WRITE_WITH_NEWLINE,
    style,
    "using `write!()` with a format string that ends in a single newline"
}

/// **What it does:** This lint warns about the use of literals as `write!`/`writeln!` args.
///
/// **Why is this bad?** Using literals as `writeln!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// writeln!(buf, "{}", "foo");
/// ```
declare_clippy_lint! {
    pub WRITE_LITERAL,
    style,
    "writing a literal with a format string"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            PRINT_WITH_NEWLINE,
            PRINTLN_EMPTY_STRING,
            PRINT_STDOUT,
            USE_DEBUG,
            PRINT_LITERAL,
            WRITE_WITH_NEWLINE,
            WRITELN_EMPTY_STRING,
            WRITE_LITERAL
        )
    }
}

impl EarlyLintPass for Pass {
    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
        if mac.node.path == "println" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `println!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
                if fmtstr == "" {
                    span_lint_and_sugg(
                        cx,
                        PRINTLN_EMPTY_STRING,
                        mac.span,
                        "using `println!(\"\")`",
                        "replace it with",
                        "println!()".to_string(),
                    );
                }
            }
        } else if mac.node.path == "print" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
                if fmtstr.ends_with("\\n") &&
                   // don't warn about strings with several `\n`s (#3126)
                   fmtstr.matches("\\n").count() == 1
                {
                    span_lint(
                        cx,
                        PRINT_WITH_NEWLINE,
                        mac.span,
                        "using `print!()` with a format string that ends in a \
                         single newline, consider using `println!()` instead",
                    );
                }
            }
        } else if mac.node.path == "write" {
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true).0 {
                if fmtstr.ends_with("\\n") &&
                   // don't warn about strings with several `\n`s (#3126)
                   fmtstr.matches("\\n").count() == 1
                {
                    span_lint(
                        cx,
                        WRITE_WITH_NEWLINE,
                        mac.span,
                        "using `write!()` with a format string that ends in a \
                         single newline, consider using `writeln!()` instead",
                    );
                }
            }
        } else if mac.node.path == "writeln" {
            let check_tts = check_tts(cx, &mac.node.tts, true);
            if let Some(fmtstr) = check_tts.0 {
                if fmtstr == "" {
                    let suggestion = check_tts
                        .1
                        .map_or(Cow::Borrowed("v"), |expr| snippet(cx, expr.span, "v"));

                    span_lint_and_sugg(
                        cx,
                        WRITELN_EMPTY_STRING,
                        mac.span,
                        format!("using `writeln!({}, \"\")`", suggestion).as_str(),
                        "replace it with",
                        format!("writeln!({})", suggestion),
                    );
                }
            }
        }
    }
}

fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> (Option<String>, Option<Expr>) {
    use crate::fmt_macros::*;
    let tts = TokenStream::from(tts.clone());
    let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, None, false, false);
    let mut expr: Option<Expr> = None;
    if is_write {
        expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
            Ok(p) => Some(p.into_inner()),
            Err(_) => return (None, None),
        };
        // might be `writeln!(foo)`
        if parser.expect(&token::Comma).map_err(|mut err| err.cancel()).is_err() {
            return (None, expr);
        }
    }

    let fmtstr = match parser.parse_str().map_err(|mut err| err.cancel()) {
        Ok(token) => token.0.to_string(),
        Err(_) => return (None, expr),
    };
    let tmp = fmtstr.clone();
    let mut args = vec![];
    let mut fmt_parser = Parser::new(&tmp, None);
    while let Some(piece) = fmt_parser.next() {
        if !fmt_parser.errors.is_empty() {
            return (None, expr);
        }
        if let Piece::NextArgument(arg) = piece {
            if arg.format.ty == "?" {
                // FIXME: modify rustc's fmt string parser to give us the current span
                span_lint(cx, USE_DEBUG, parser.prev_span, "use of `Debug`-based formatting");
            }
            args.push(arg);
        }
    }
    let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
    let mut idx = 0;
    loop {
        const SIMPLE: FormatSpec<'_> = FormatSpec {
            fill: None,
            align: AlignUnknown,
            flags: 0,
            precision: CountImplied,
            width: CountImplied,
            ty: "",
        };
        if !parser.eat(&token::Comma) {
            return (Some(fmtstr), expr);
        }
        let token_expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
            Ok(expr) => expr,
            Err(_) => return (Some(fmtstr), None),
        };
        match &token_expr.node {
            ExprKind::Lit(_) => {
                let mut all_simple = true;
                let mut seen = false;
                for arg in &args {
                    match arg.position {
                        ArgumentImplicitlyIs(n) | ArgumentIs(n) => if n == idx {
                            all_simple &= arg.format == SIMPLE;
                            seen = true;
                        },
                        ArgumentNamed(_) => {},
                    }
                }
                if all_simple && seen {
                    span_lint(cx, lint, token_expr.span, "literal with an empty format string");
                }
                idx += 1;
            },
            ExprKind::Assign(lhs, rhs) => {
                if let ExprKind::Lit(_) = rhs.node {
                    if let ExprKind::Path(_, p) = &lhs.node {
                        let mut all_simple = true;
                        let mut seen = false;
                        for arg in &args {
                            match arg.position {
                                ArgumentImplicitlyIs(_) | ArgumentIs(_) => {},
                                ArgumentNamed(name) => if *p == name {
                                    seen = true;
                                    all_simple &= arg.format == SIMPLE;
                                },
                            }
                        }
                        if all_simple && seen {
                            span_lint(cx, lint, rhs.span, "literal with an empty format string");
                        }
                    }
                }
            },
            _ => idx += 1,
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains the logic used to resolve identifiers to their locals or globals.

use ast::*;
use visit::*;

use std::mem;
use std::collections::HashSet;

/// A resolver will work on a single scope and resolve any `VNamed` references
struct Resolver<'a> {
    locals: HashSet<String>,
}

impl <'a> Resolver<'a> {
    fn is_declared(&mut self, name: &String) -> bool {
        self.locals.contains(name)
    }

    fn add_local(&mut self, name: String) {
        self.locals.insert(name);
    }

    fn resolve_var(&mut self, v: &mut Variable) {
        if let VNamed(..) = v.value {
            let mut name = String::new();

            if let VNamed(ref mut vname) = v.value {
                mem::swap(vname, &mut name);
            }

            mem::replace(&mut v.value, if self.is_declared(&name) {
                VLocal(name)
            } else {
                VGlobal(name)
            });
        } else {
            // Only VNamed variables should be existing at this point
            unreachable!();
        }
    }
}

impl <'a> Visitor for Resolver<'a> {
    fn visit_stmt(&mut self, s: &mut Stmt) {
        match s.value {
            SDecl(ref mut names, ref mut exprs) => {
                for name in names {
                    self.add_local(name.clone());
                }

                for expr in exprs {
                    walk_expr(expr, self);
                }
            },
            _ => {
                walk_stmt(s, self);
            }
        }
    }

    fn visit_var(&mut self, v: &mut Variable) {
        self.resolve_var(v);
    }

    fn visit_block(&mut self, b: &mut Block) {
        resolve_block(b);
    }
}

pub fn resolve_block(b: &mut Block) {
    let mut res = Resolver {
        locals: HashSet::new(),
    };

    walk_block(b, &mut res);

    for local in res.locals {
        b.locals.push(local);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use parser::block;
    use span::Spanned;
    use ast::*;

    #[test]
    fn test() {
        let mut b = block(r#"
i = 0
do
    local i
    local j = i
    j = i
end
j = i
"#).unwrap();
        resolve_block(&mut b);

        assert_eq!(b, Spanned::default(_Block::new(vec![
            Spanned::default(SAssign(
                vec![Spanned::default(VGlobal("i".to_string()))],
                vec![Spanned::default(ELit(TInt(0)))],
            )),
            Spanned::default(SDo(Spanned::default(_Block::with_locals(vec![
                Spanned::default(SDecl(vec!["i".to_string()], vec![])),
                Spanned::default(SDecl(vec!["j".to_string()], vec![
                    Spanned::default(EVar(Spanned::default(VLocal("i".to_string())))),
                ])),
                Spanned::default(SAssign(
                    vec![Spanned::default(VLocal("j".to_string()))],
                    vec![Spanned::default(EVar(Spanned::default(VLocal("i".to_string()))))],
                )),
            ], vec!["i".to_string(), "j".to_string()])))),
            Spanned::default(SAssign(
                vec![Spanned::default(VGlobal("j".to_string()))],
                vec![Spanned::default(EVar(Spanned::default(VGlobal("i".to_string()))))],
            )),
        ])));
    }
}
<commit_msg>Fixed resolver to work with VIndex<commit_after>//! This module contains the logic used to resolve identifiers to their locals or globals.

use ast::*;
use visit::*;

use std::mem;
use std::collections::HashSet;

/// A resolver will work on a single scope and resolve any `VNamed` references
struct Resolver<'a> {
    locals: HashSet<String>,
}

impl <'a> Resolver<'a> {
    fn is_declared(&mut self, name: &String) -> bool {
        self.locals.contains(name)
    }

    fn add_local(&mut self, name: String) {
        self.locals.insert(name);
    }

    fn resolve_var(&mut self, v: &mut Variable) {
        match v.value {
            VNamed(..) => {
                let mut name = String::new();

                if let VNamed(ref mut vname) = v.value {
                    mem::swap(vname, &mut name);
                }

                mem::replace(&mut v.value, if self.is_declared(&name) {
                    VLocal(name)
                } else {
                    VGlobal(name)
                });
            },
            VIndex(..) => {
                walk_var(v, self);
            },
            _ => {
                panic!("unexpected variable: {:?}", v.value);
            }
        }
    }
}

impl <'a> Visitor for Resolver<'a> {
    fn visit_stmt(&mut self, s: &mut Stmt) {
        match s.value {
            SDecl(ref mut names, ref mut exprs) => {
                for name in names {
                    self.add_local(name.clone());
                }

                for expr in exprs {
                    walk_expr(expr, self);
                }
            },
            _ => {
                walk_stmt(s, self);
            }
        }
    }

    fn visit_var(&mut self, v: &mut Variable) {
        self.resolve_var(v);
    }

    fn visit_block(&mut self, b: &mut Block) {
        resolve_block(b);
    }
}

pub fn resolve_block(b: &mut Block) {
    let mut res = Resolver {
        locals: HashSet::new(),
    };

    walk_block(b, &mut res);

    for local in res.locals {
        b.locals.push(local);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use parser::block;
    use span::Spanned;
    use ast::*;

    #[test]
    fn test() {
        let mut b = block(r#"
i = 0
do
    local i
    local j = i
    i[j] = j
end
j = i
"#).unwrap();
        resolve_block(&mut b);

        assert_eq!(b, Spanned::default(_Block::new(vec![
            Spanned::default(SAssign(
                vec![Spanned::default(VGlobal("i".to_string()))],
                vec![Spanned::default(ELit(TInt(0)))],
            )),
            Spanned::default(SDo(Spanned::default(_Block::with_locals(vec![
                Spanned::default(SDecl(vec!["i".to_string()], vec![])),
                Spanned::default(SDecl(vec!["j".to_string()], vec![
                    Spanned::default(EVar(Spanned::default(VLocal("i".to_string())))),
                ])),
                Spanned::default(SAssign(
                    vec![Spanned::default(VIndex(
                        Box::new(Spanned::default(VLocal("i".to_string()))),
                        Box::new(Spanned::default(EVar(Spanned::default(VLocal("j".to_string())))))
                    ))],
                    vec![Spanned::default(EVar(Spanned::default(VLocal("j".to_string()))))],
                )),
            ], vec!["i".to_string(), "j".to_string()])))),
            Spanned::default(SAssign(
                vec![Spanned::default(VGlobal("j".to_string()))],
                vec![Spanned::default(EVar(Spanned::default(VGlobal("i".to_string()))))],
            )),
        ])));
    }
}
<|endoftext|>


<commit_before>
pub struct Scanner {
    source: String,
    tokens: Vec<Token>,
    start: i32,
    current: i32,
    line: i32,
}

impl Scanner {
    pub fn new(source: String) -> Self {
        Scanner {
            source: source,
            tokens: Vec::new(),
            start: 0,
            current: 0,
            line: 1,
        }
    }

    pub fn scan_tokens(&mut self) -> Vec<Token> {
        while !self.is_at_end() {
            self.start = self.current;
            self.scan_token();
        }
        self.tokens.push(Token::new(TokenType::EOF, "", self.line));
        self.tokens.to_vec()
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len() as i32
    }

    fn scan_token(&mut self) {}
}

#[derive(Clone, Debug)]
pub struct Token {
    token_type: TokenType,
    lexeme: String,
    line: i32,
}

impl Token {
    pub fn new(token_type: TokenType, lexeme: &str, line: i32) -> Self {
        Token {
            token_type: token_type,
            lexeme: lexeme.to_owned(),
            line: line,
        }
    }
}

#[derive(Clone, Debug)]
#[allow(non_camel_case_types)]
pub enum TokenType {
    // Single-character tokens.
    LEFT_PAREN,
    RIGHT_PAREN,
    LEFT_BRACE,
    RIGHT_BRACE,
    COMMA,
    DOT,
    MINUS,
    PLUS,
    SEMICOLON,
    SLASH,
    STAR,

    // One or two character tokens.
    BANG,
    BANG_EQUAL,
    EQUAL,
    EQUAL_EQUAL,
    GREATER,
    GREATER_EQUAL,
    LESS,
    LESS_EQUAL,

    // Literals.
    IDENTIFIER,
    STRING,
    NUMBER,

    // Keywords.
    AND,
    CLASS,
    ELSE,
    FALSE,
    FUN,
    FOR,
    IF,
    NIL,
    OR,
    PRINT,
    RETURN,
    SUPER,
    THIS,
    TRUE,
    VAR,
    WHILE,

    EOF,
}
<commit_msg>add the scan token method<commit_after>
pub struct Scanner {
    source: String,
    tokens: Vec<Token>,
    start: usize,
    current: usize,
    line: i32,
}

impl Scanner {
    pub fn new(source: String) -> Self {
        Scanner {
            source: source,
            tokens: Vec::new(),
            start: 0,
            current: 0,
            line: 1,
        }
    }

    pub fn scan_tokens(&mut self) -> Vec<Token> {
        while !self.is_at_end() {
            self.start = self.current;
            self.scan_token();
        }
        self.tokens.push(Token::new(TokenType::EOF, "", self.line));
        self.tokens.to_vec()
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn scan_token(&mut self) {
        let c = self.advance();
        match c {
            '(' => self.add_token(TokenType::LEFT_PAREN),
            ')' => self.add_token(TokenType::RIGHT_PAREN),
            '{' => self.add_token(TokenType::LEFT_BRACE),
            '}' => self.add_token(TokenType::RIGHT_BRACE),
            ',' => self.add_token(TokenType::COMMA),
            '.' => self.add_token(TokenType::DOT),
            '-' => self.add_token(TokenType::MINUS),
            '+' => self.add_token(TokenType::PLUS),
            ';' => self.add_token(TokenType::SEMICOLON),
            '*' => self.add_token(TokenType::STAR),
            _ => {}
        }
    }

    fn advance(&mut self) -> char {
        self.current += 1;
        let b = self.source.as_bytes();
        b[self.current - 1] as char
    }

    fn add_token(&mut self, token_type: TokenType) {
        let s = &self.source[self.start as usize..self.current as usize];
        self.tokens.push(Token::new(token_type, s, self.line));
    }
}

#[derive(Clone, Debug)]
pub struct Token {
    token_type: TokenType,
    lexeme: String,
    line: i32,
}

impl Token {
    pub fn new(token_type: TokenType, lexeme: &str, line: i32) -> Self {
        Token {
            token_type: token_type,
            lexeme: lexeme.to_owned(),
            line: line,
        }
    }
}

#[derive(Clone, Debug)]
#[allow(non_camel_case_types)]
pub enum TokenType {
    // Single-character tokens.
    LEFT_PAREN,
    RIGHT_PAREN,
    LEFT_BRACE,
    RIGHT_BRACE,
    COMMA,
    DOT,
    MINUS,
    PLUS,
    SEMICOLON,
    SLASH,
    STAR,

    // One or two character tokens.
    BANG,
    BANG_EQUAL,
    EQUAL,
    EQUAL_EQUAL,
    GREATER,
    GREATER_EQUAL,
    LESS,
    LESS_EQUAL,

    // Literals.
    IDENTIFIER,
    STRING,
    NUMBER,

    // Keywords.
    AND,
    CLASS,
    ELSE,
    FALSE,
    FUN,
    FOR,
    IF,
    NIL,
    OR,
    PRINT,
    RETURN,
    SUPER,
    THIS,
    TRUE,
    VAR,
    WHILE,

    EOF,
}
<|endoftext|>


<commit_before>use std::mem;
use std::ffi;
use std::str;
use std::ffi::CString;

// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link(name="SDL", kind="framework")]
    extern {}

    #[cfg(not(mac_framework))]
    #[link(name="SDL")]
    extern {}
}

#[cfg(not(target_os="macos"))]
mod others {
    #[link(name="SDL")]
    extern {}
}

pub mod ll {
    #![allow(non_camel_case_types)]

    use libc::{c_int, c_uint, uint32_t};
    use libc::types::os::arch::c95::c_schar;

    pub type SDL_errorcode = c_uint;
    pub const SDL_ENOMEM: SDL_errorcode = 0;
    pub const SDL_EFREAD: SDL_errorcode = 1;
    pub const SDL_EFWRITE: SDL_errorcode = 2;
    pub const SDL_EFSEEK: SDL_errorcode = 3;
    pub const SDL_UNSUPPORTED: SDL_errorcode = 4;
    pub const SDL_LASTERROR: SDL_errorcode = 5;

    pub type SDL_InitFlag = uint32_t;
    pub const SDL_INIT_TIMER: SDL_InitFlag = 0x00000001;
    pub const SDL_INIT_AUDIO: SDL_InitFlag = 0x00000010;
    pub const SDL_INIT_VIDEO: SDL_InitFlag = 0x00000020;
    pub const SDL_INIT_CDROM: SDL_InitFlag = 0x00000100;
    pub const SDL_INIT_JOYSTICK: SDL_InitFlag = 0x00000200;
    pub const SDL_INIT_NOPARACHUTE: SDL_InitFlag = 0x00100000;
    pub const SDL_INIT_EVENTTHREAD: SDL_InitFlag = 0x01000000;
    pub const SDL_INIT_EVERYTHING: SDL_InitFlag = 0x0000FFFF;

    extern "C" {
        pub fn SDL_ClearError();
        pub fn SDL_Error(code: SDL_errorcode);
        pub fn SDL_SetError(fmt: *const c_schar);
        pub fn SDL_GetError() -> *mut c_schar;
        pub fn SDL_Quit();
        pub fn SDL_QuitSubSystem(flags: SDL_InitFlag);
        pub fn SDL_Init(flags: uint32_t) -> c_int;
        pub fn SDL_InitSubSystem(flags: SDL_InitFlag) -> c_int;
        pub fn SDL_WasInit(flags: SDL_InitFlag) -> SDL_InitFlag;
        pub fn SDL_GetTicks() -> uint32_t;
    }
}

#[derive(PartialEq)]
#[repr(C)]
pub struct Rect {
    pub x: i16,
    pub y: i16,
    pub w: u16,
    pub h: u16
}

impl Copy for Rect {}

#[allow(non_snake_case)]
pub fn Rect(x: i16, y: i16, w: u16, h: u16) -> Rect {
    Rect { x: x, y: y, w: w, h: h }
}

impl Rect {
    pub fn new(x: i16, y: i16, w: u16, h: u16) -> Rect {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h
        }
    }
}

#[derive(PartialEq, Eq)]
pub enum InitFlag {
     Timer = ll::SDL_INIT_TIMER as isize,
     Audio = ll::SDL_INIT_AUDIO as isize,
     Video = ll::SDL_INIT_VIDEO as isize,
     CDRom = ll::SDL_INIT_CDROM as isize,
     Joystick = ll::SDL_INIT_JOYSTICK as isize,
     NoParachute = ll::SDL_INIT_NOPARACHUTE as isize,
     EventThread = ll::SDL_INIT_EVENTTHREAD as isize,
     Everything = ll::SDL_INIT_EVERYTHING as isize,
}

impl Copy for InitFlag {}

#[derive(PartialEq, Eq)]
pub enum Error {
     NoMem = ll::SDL_ENOMEM as isize,
     Read = ll::SDL_EFREAD as isize,
     Write = ll::SDL_EFWRITE as isize,
     Seek = ll::SDL_EFSEEK as isize,
     Unsupported = ll::SDL_UNSUPPORTED as isize
}

impl Copy for Error {}

pub fn init(flags: &[InitFlag]) -> bool {
    unsafe {
        ll::SDL_Init(flags.iter().fold(0u32, |flags, &flag| {
            flags | flag as ll::SDL_InitFlag
        })) == 0
    }
}

pub fn init_subsystem(flags: &[InitFlag]) -> bool {
    unsafe {
        ll::SDL_InitSubSystem(flags.iter().fold(0u32, |flags, &flag| {
            flags | flag as ll::SDL_InitFlag
        })) == 0
    }
}

pub fn quit_subsystem(flags: &[InitFlag]) {
    let flags = flags.iter().fold(0u32, |flags, &flag| {
        flags | flag as ll::SDL_InitFlag
    });

    unsafe { ll::SDL_QuitSubSystem(flags); }
}

pub fn quit() {
    unsafe { ll::SDL_Quit(); }
}

pub fn was_inited(flags: &[InitFlag]) -> Vec<InitFlag> {
    let flags = flags.iter().fold(0u32, |flags, &flag| {
        flags | flag as ll::SDL_InitFlag
    });
    let bitflags = unsafe { ll::SDL_WasInit(flags) };

    let flags = [InitFlag::Timer,
        InitFlag::Audio,
        InitFlag::Video,
        InitFlag::CDRom,
        InitFlag::Joystick,
        InitFlag::NoParachute,
        InitFlag::EventThread,
        InitFlag::Everything];

    flags.iter().filter_map(|&flag| {
        if bitflags & (flag as ll::SDL_InitFlag) != 0 { Some(flag) }
        else { None }
    }).collect()
}

pub fn get_error() -> String {
    unsafe {
        let cstr = ll::SDL_GetError() as *const i8;
        let slice = ffi::c_str_to_bytes(&cstr);

        str::from_utf8(slice).unwrap().to_string()
    }
}

pub fn set_error(err: &str) {
    unsafe { ll::SDL_SetError(CString::from_slice(err.as_bytes()).as_ptr()); }
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode) }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}

pub fn get_ticks() -> usize {
    unsafe { ll::SDL_GetTicks() as usize }
}
<commit_msg>Remove unused import<commit_after>use std::ffi;
use std::str;
use std::ffi::CString;

// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link(name="SDL", kind="framework")]
    extern {}

    #[cfg(not(mac_framework))]
    #[link(name="SDL")]
    extern {}
}

#[cfg(not(target_os="macos"))]
mod others {
    #[link(name="SDL")]
    extern {}
}

pub mod ll {
    #![allow(non_camel_case_types)]

    use libc::{c_int, c_uint, uint32_t};
    use libc::types::os::arch::c95::c_schar;

    pub type SDL_errorcode = c_uint;
    pub const SDL_ENOMEM: SDL_errorcode = 0;
    pub const SDL_EFREAD: SDL_errorcode = 1;
    pub const SDL_EFWRITE: SDL_errorcode = 2;
    pub const SDL_EFSEEK: SDL_errorcode = 3;
    pub const SDL_UNSUPPORTED: SDL_errorcode = 4;
    pub const SDL_LASTERROR: SDL_errorcode = 5;

    pub type SDL_InitFlag = uint32_t;
    pub const SDL_INIT_TIMER: SDL_InitFlag = 0x00000001;
    pub const SDL_INIT_AUDIO: SDL_InitFlag = 0x00000010;
    pub const SDL_INIT_VIDEO: SDL_InitFlag = 0x00000020;
    pub const SDL_INIT_CDROM: SDL_InitFlag = 0x00000100;
    pub const SDL_INIT_JOYSTICK: SDL_InitFlag = 0x00000200;
    pub const SDL_INIT_NOPARACHUTE: SDL_InitFlag = 0x00100000;
    pub const SDL_INIT_EVENTTHREAD: SDL_InitFlag = 0x01000000;
    pub const SDL_INIT_EVERYTHING: SDL_InitFlag = 0x0000FFFF;

    extern "C" {
        pub fn SDL_ClearError();
        pub fn SDL_Error(code: SDL_errorcode);
        pub fn SDL_SetError(fmt: *const c_schar);
        pub fn SDL_GetError() -> *mut c_schar;
        pub fn SDL_Quit();
        pub fn SDL_QuitSubSystem(flags: SDL_InitFlag);
        pub fn SDL_Init(flags: uint32_t) -> c_int;
        pub fn SDL_InitSubSystem(flags: SDL_InitFlag) -> c_int;
        pub fn SDL_WasInit(flags: SDL_InitFlag) -> SDL_InitFlag;
        pub fn SDL_GetTicks() -> uint32_t;
    }
}

#[derive(PartialEq)]
#[repr(C)]
pub struct Rect {
    pub x: i16,
    pub y: i16,
    pub w: u16,
    pub h: u16
}

impl Copy for Rect {}

#[allow(non_snake_case)]
pub fn Rect(x: i16, y: i16, w: u16, h: u16) -> Rect {
    Rect { x: x, y: y, w: w, h: h }
}

impl Rect {
    pub fn new(x: i16, y: i16, w: u16, h: u16) -> Rect {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h
        }
    }
}

#[derive(PartialEq, Eq)]
pub enum InitFlag {
     Timer = ll::SDL_INIT_TIMER as isize,
     Audio = ll::SDL_INIT_AUDIO as isize,
     Video = ll::SDL_INIT_VIDEO as isize,
     CDRom = ll::SDL_INIT_CDROM as isize,
     Joystick = ll::SDL_INIT_JOYSTICK as isize,
     NoParachute = ll::SDL_INIT_NOPARACHUTE as isize,
     EventThread = ll::SDL_INIT_EVENTTHREAD as isize,
     Everything = ll::SDL_INIT_EVERYTHING as isize,
}

impl Copy for InitFlag {}

#[derive(PartialEq, Eq)]
pub enum Error {
     NoMem = ll::SDL_ENOMEM as isize,
     Read = ll::SDL_EFREAD as isize,
     Write = ll::SDL_EFWRITE as isize,
     Seek = ll::SDL_EFSEEK as isize,
     Unsupported = ll::SDL_UNSUPPORTED as isize
}

impl Copy for Error {}

pub fn init(flags: &[InitFlag]) -> bool {
    unsafe {
        ll::SDL_Init(flags.iter().fold(0u32, |flags, &flag| {
            flags | flag as ll::SDL_InitFlag
        })) == 0
    }
}

pub fn init_subsystem(flags: &[InitFlag]) -> bool {
    unsafe {
        ll::SDL_InitSubSystem(flags.iter().fold(0u32, |flags, &flag| {
            flags | flag as ll::SDL_InitFlag
        })) == 0
    }
}

pub fn quit_subsystem(flags: &[InitFlag]) {
    let flags = flags.iter().fold(0u32, |flags, &flag| {
        flags | flag as ll::SDL_InitFlag
    });

    unsafe { ll::SDL_QuitSubSystem(flags); }
}

pub fn quit() {
    unsafe { ll::SDL_Quit(); }
}

pub fn was_inited(flags: &[InitFlag]) -> Vec<InitFlag> {
    let flags = flags.iter().fold(0u32, |flags, &flag| {
        flags | flag as ll::SDL_InitFlag
    });
    let bitflags = unsafe { ll::SDL_WasInit(flags) };

    let flags = [InitFlag::Timer,
        InitFlag::Audio,
        InitFlag::Video,
        InitFlag::CDRom,
        InitFlag::Joystick,
        InitFlag::NoParachute,
        InitFlag::EventThread,
        InitFlag::Everything];

    flags.iter().filter_map(|&flag| {
        if bitflags & (flag as ll::SDL_InitFlag) != 0 { Some(flag) }
        else { None }
    }).collect()
}

pub fn get_error() -> String {
    unsafe {
        let cstr = ll::SDL_GetError() as *const i8;
        let slice = ffi::c_str_to_bytes(&cstr);

        str::from_utf8(slice).unwrap().to_string()
    }
}

pub fn set_error(err: &str) {
    unsafe { ll::SDL_SetError(CString::from_slice(err.as_bytes()).as_ptr()); }
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode) }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}

pub fn get_ticks() -> usize {
    unsafe { ll::SDL_GetTicks() as usize }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nicholas Bishop
//
// Closest-point method adapted from "Real-Time Collision Detection"
// by Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use vector::{distance3, dot3, lerp3, Vec3f};

/// Line segment between two points
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Segment3f {
    pub start: Vec3f,
    pub end: Vec3f
}

impl Segment3f {
    /// Create a segment between two points
    pub fn new(start: &Vec3f, end: &Vec3f) -> Segment3f {
        Segment3f {
            start: *start,
            end: *end
        }
    }

    /// Length of the line segment
    pub fn length(&self) -> f32 {
        distance3(self.start, self.end)
    }

    /// Convert a distance in coordinate space to a distance in the
    /// line segment's parametric space. The sign of the input is
    /// kept.
    pub fn distance_to_parametric_delta(&self, distance: f32) -> f32 {
        distance / self.length()
    }

    /// Convert a parametric delta to coordinate space. The sign of
    /// the input is kept.
    pub fn distance_from_parametric_delta(&self, delta: f32) -> f32 {
        delta * self.length()
    }

    /// Linearly interpolate between the segment's endpoints by the
    /// factor `t`. When `t` is zero the result is `self.start`, and
    /// when `t` is one the result is `self.end`. The range of `t` is
    /// not clamped.
    pub fn point_from_parametric(&self, t: f32) -> Vec3f {
        lerp3(&self.start, &self.end, t)
    }

    /// Find the point on the segment closest to the input point. The
    /// return value contains both the parametric and actual location
    /// of the closest point.
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn closest_point_to_point(&self, point: &Vec3f) -> (f32, Vec3f) {
        let a = self.start;
        let b = self.end;

        let ab = b - a;
        // Project point onto ab, but deferring divide by dot3(ab, ab)
        let t = dot3(*point - a, ab);
        if t <= 0.0f32 {
            // point projects outside the [a,b] interval, on the a
            // side; clamp to a
            (0.0f32, a)
        } else {
            // Always nonnegative since denom = ||ab|| ∧ 2
            let denom = dot3(ab, ab);
            if t >= denom {
                // point projects outside the [a,b] interval, on the b
                // side; clamp to b
                (1.0f32, b)
            } else {
                // point projects inside the [a,b] interval; must do
                // deferred divide now
                (t / denom, a + ab * t)
            }
        }
    }
}

#[test]
fn test_segment_length() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(0, 0, 0),
                           &vec3f(0, 0, 9));
    assert!(s.length() == 9.0);
}

#[test]
fn test_segment_distance_conversion() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(0, 1, 0),
                           &vec3f(0, 7, 0));

    let inputs = [
        (0.0f32, 0.0f32),
        (6.0, 1.0),
        (12.0, 2.0),
        (-3.0, -0.5)];

    for &(distance, delta) in inputs.iter() {
        assert!(s.distance_to_parametric_delta(distance) == delta);
        assert!(s.distance_from_parametric_delta(delta) == distance);
    }
}

#[test]
fn test_point_from_parametric() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(0, 0, -1),
                           &vec3f(0, 0, 3));
    assert_eq!(s.point_from_parametric(0.0), vec3f(0, 0, -1));
    assert_eq!(s.point_from_parametric(1.0), vec3f(0, 0, 3));
    assert_eq!(s.point_from_parametric(0.5), vec3f(0, 0, 1));
}

#[test]
fn test_segment_closest_point_to_point() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(2, 0, 0),
                           &vec3f(3, 0, 0));
    assert!(s.closest_point_to_point(&vec3f(1, 0, 0)) ==
            (0.0, vec3f(2, 0, 0)));
    assert!(s.closest_point_to_point(&vec3f(4, 0, 0)) ==
            (1.0, vec3f(3, 0, 0)));
    assert!(s.closest_point_to_point(&vec3f(2.5, 1, 0)) ==
            (0.5, vec3f(2.5, 0, 0)));
}
<commit_msg>Use assert_eq instead of assert<commit_after>// Copyright 2015 Nicholas Bishop
//
// Closest-point method adapted from "Real-Time Collision Detection"
// by Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use vector::{distance3, dot3, lerp3, Vec3f};

/// Line segment between two points
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Segment3f {
    pub start: Vec3f,
    pub end: Vec3f
}

impl Segment3f {
    /// Create a segment between two points
    pub fn new(start: &Vec3f, end: &Vec3f) -> Segment3f {
        Segment3f {
            start: *start,
            end: *end
        }
    }

    /// Length of the line segment
    pub fn length(&self) -> f32 {
        distance3(self.start, self.end)
    }

    /// Convert a distance in coordinate space to a distance in the
    /// line segment's parametric space. The sign of the input is
    /// kept.
    pub fn distance_to_parametric_delta(&self, distance: f32) -> f32 {
        distance / self.length()
    }

    /// Convert a parametric delta to coordinate space. The sign of
    /// the input is kept.
    pub fn distance_from_parametric_delta(&self, delta: f32) -> f32 {
        delta * self.length()
    }

    /// Linearly interpolate between the segment's endpoints by the
    /// factor `t`. When `t` is zero the result is `self.start`, and
    /// when `t` is one the result is `self.end`. The range of `t` is
    /// not clamped.
    pub fn point_from_parametric(&self, t: f32) -> Vec3f {
        lerp3(&self.start, &self.end, t)
    }

    /// Find the point on the segment closest to the input point. The
    /// return value contains both the parametric and actual location
    /// of the closest point.
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn closest_point_to_point(&self, point: &Vec3f) -> (f32, Vec3f) {
        let a = self.start;
        let b = self.end;

        let ab = b - a;
        // Project point onto ab, but deferring divide by dot3(ab, ab)
        let t = dot3(*point - a, ab);
        if t <= 0.0f32 {
            // point projects outside the [a,b] interval, on the a
            // side; clamp to a
            (0.0f32, a)
        } else {
            // Always nonnegative since denom = ||ab|| ∧ 2
            let denom = dot3(ab, ab);
            if t >= denom {
                // point projects outside the [a,b] interval, on the b
                // side; clamp to b
                (1.0f32, b)
            } else {
                // point projects inside the [a,b] interval; must do
                // deferred divide now
                (t / denom, a + ab * t)
            }
        }
    }
}

#[test]
fn test_segment_length() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(0, 0, 0),
                           &vec3f(0, 0, 9));
    assert_eq!(s.length(), 9.0);
}

#[test]
fn test_segment_distance_conversion() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(0, 1, 0),
                           &vec3f(0, 7, 0));

    let inputs = [
        (0.0f32, 0.0f32),
        (6.0, 1.0),
        (12.0, 2.0),
        (-3.0, -0.5)];

    for &(distance, delta) in inputs.iter() {
        assert_eq!(s.distance_to_parametric_delta(distance), delta);
        assert_eq!(s.distance_from_parametric_delta(delta), distance);
    }
}

#[test]
fn test_point_from_parametric() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(0, 0, -1),
                           &vec3f(0, 0, 3));
    assert_eq!(s.point_from_parametric(0.0), vec3f(0, 0, -1));
    assert_eq!(s.point_from_parametric(1.0), vec3f(0, 0, 3));
    assert_eq!(s.point_from_parametric(0.5), vec3f(0, 0, 1));
}

#[test]
fn test_segment_closest_point_to_point() {
    use vector::vec3f;
    let s = Segment3f::new(&vec3f(2, 0, 0),
                           &vec3f(3, 0, 0));
    assert_eq!(s.closest_point_to_point(&vec3f(1, 0, 0)),
               (0.0, vec3f(2, 0, 0)));
    assert_eq!(s.closest_point_to_point(&vec3f(4, 0, 0)),
               (1.0, vec3f(3, 0, 0)));
    assert_eq!(s.closest_point_to_point(&vec3f(2.5, 1, 0)),
               (0.5, vec3f(2.5, 0, 0)));
}
<|endoftext|>


<commit_before>//! Module defining all sensor related structures.

use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
use utils::Optional;
use status::Status;

//--- Templates ---//

/// A trait for all possible sensor templates.
/// the SensorTemplate's are capable of registring themself in a Status struct
pub trait SensorTemplate : Send+Sync {
    fn to_sensor(&self, value_str: &str, status: &mut Status);
}

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensorTemplate {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
}

impl SensorTemplate for PeopleNowPresentSensorTemplate {
    fn to_sensor(&self, value_str: &str, status: &mut Status) {
        // TODO error handling
        let value = value_str.parse::<i64>().unwrap();
        let sensor = PeopleNowPresentSensor {
            location: self.location.clone(),
            name: self.name.clone(),
            names: self.names.clone(),
            description: self.description.clone(),
            value: value,
        };
        // TODO handle empty
        status.sensors.as_mut().map_or((), |v| {
            match v.people_now_present {
                Optional::Value(ref mut vec_sensors) => vec_sensors.push(sensor),
                Optional::Absent => v.people_now_present = Optional::Value(vec![sensor]),
            }
        });
    }
}

#[derive(Debug, Clone)]
pub struct TemperatureSensorTemplate {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
}

impl SensorTemplate for TemperatureSensorTemplate {
    fn to_sensor(&self, value_str: &str, status: &mut Status) {
        // TODO error handling
        let value = value_str.parse::<f64>().unwrap();
        let sensor = TemperatureSensor {
            unit: self.unit.clone(),
            location: self.location.clone(),
            name: self.name.clone(),
            description: self.description.clone(),
            value: value,
        };
        // TODO handle empty
        status.sensors.as_mut().map_or((), |v| {
            match v.temperature {
                Optional::Value(ref mut vec_sensors) => vec_sensors.push(sensor),
                Optional::Absent => v.temperature = Optional::Value(vec![sensor]),
            }
        });
    }
}

//--- Structures ---//

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensor {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
    pub value: i64,
}

#[derive(Debug, Clone)]
pub struct TemperatureSensor {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
    pub value: f64,
}

#[derive(Debug, Clone)]
pub struct Sensors {
    pub people_now_present: Optional<Vec<PeopleNowPresentSensor>>,
    pub temperature: Optional<Vec<TemperatureSensor>>,
}

//--- Serialization ---//

impl ToJson for Sensors {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.people_now_present.as_ref().map_or((), |v| { d.insert("people_now_present".to_string(), v.to_json()); });
        self.temperature.as_ref().map_or((), |v| { d.insert("temperature".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for PeopleNowPresentSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        self.location.as_ref().map_or((), |v| { d.insert("location".to_string(), v.to_json()); });
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.names.as_ref().map_or((), |v| { d.insert("names".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for TemperatureSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        d.insert("unit".to_string(), self.unit.to_json());
        d.insert("location".to_string(), self.location.to_json());
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}
<commit_msg>spaceapi: Fix typos in SensorTemplate documentation<commit_after>//! Module defining all sensor related structures.

use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
use utils::Optional;
use status::Status;

//--- Templates ---//

/// A trait for all possible sensor templates.
/// the `SensorTemplate`s are capable of registering themselves in a `Status` struct
pub trait SensorTemplate : Send+Sync {
    fn to_sensor(&self, value_str: &str, status: &mut Status);
}

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensorTemplate {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
}

impl SensorTemplate for PeopleNowPresentSensorTemplate {
    fn to_sensor(&self, value_str: &str, status: &mut Status) {
        // TODO error handling
        let value = value_str.parse::<i64>().unwrap();
        let sensor = PeopleNowPresentSensor {
            location: self.location.clone(),
            name: self.name.clone(),
            names: self.names.clone(),
            description: self.description.clone(),
            value: value,
        };
        // TODO handle empty
        status.sensors.as_mut().map_or((), |v| {
            match v.people_now_present {
                Optional::Value(ref mut vec_sensors) => vec_sensors.push(sensor),
                Optional::Absent => v.people_now_present = Optional::Value(vec![sensor]),
            }
        });
    }
}

#[derive(Debug, Clone)]
pub struct TemperatureSensorTemplate {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
}

impl SensorTemplate for TemperatureSensorTemplate {
    fn to_sensor(&self, value_str: &str, status: &mut Status) {
        // TODO error handling
        let value = value_str.parse::<f64>().unwrap();
        let sensor = TemperatureSensor {
            unit: self.unit.clone(),
            location: self.location.clone(),
            name: self.name.clone(),
            description: self.description.clone(),
            value: value,
        };
        // TODO handle empty
        status.sensors.as_mut().map_or((), |v| {
            match v.temperature {
                Optional::Value(ref mut vec_sensors) => vec_sensors.push(sensor),
                Optional::Absent => v.temperature = Optional::Value(vec![sensor]),
            }
        });
    }
}

//--- Structures ---//

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensor {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
    pub value: i64,
}

#[derive(Debug, Clone)]
pub struct TemperatureSensor {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
    pub value: f64,
}

#[derive(Debug, Clone)]
pub struct Sensors {
    pub people_now_present: Optional<Vec<PeopleNowPresentSensor>>,
    pub temperature: Optional<Vec<TemperatureSensor>>,
}

//--- Serialization ---//

impl ToJson for Sensors {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.people_now_present.as_ref().map_or((), |v| { d.insert("people_now_present".to_string(), v.to_json()); });
        self.temperature.as_ref().map_or((), |v| { d.insert("temperature".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for PeopleNowPresentSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        self.location.as_ref().map_or((), |v| { d.insert("location".to_string(), v.to_json()); });
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.names.as_ref().map_or((), |v| { d.insert("names".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for TemperatureSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        d.insert("unit".to_string(), self.unit.to_json());
        d.insert("location".to_string(), self.location.to_json());
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}
<|endoftext|>


<commit_before>extern crate num;

/**
  Models an infinite signal, negative indices return
  always zero (to ensure causality of the signal),
  uninitialized positive indices, too.
  Can be used with any type that implements
  num::traits::Num and Clone.
*/
#[allow(dead_code)]
pub struct ZeroPaddedSignal<T> {
  values: Vec<T>,
}

impl<T: num::traits::Num + Clone> ZeroPaddedSignal<T> {
  /**
    Returns the number of initialized values.
  */
  #[allow(dead_code)]
  pub fn size(&self) -> usize {
    self.values.len()
  }

  /**
    Returns the value at the given index, zero if index
    is negative or uninitialized.
  */
  #[allow(dead_code)]
  pub fn get(&self, idx: isize) -> T {
    /* Check for negative index: */
    if idx < 0 {
      /* Negative, return zero: */
      T::zero()
    } else {
      /* Not negative, cast to unsigned: */
      let idx = idx as usize;
      /* Check if the index is initialized: */
      if let Some(v) = self.values.get(idx).cloned() {
        /* It is, return the value: */
        v
      } else {
        /* It's not, return zero: */
        T::zero()
      }
    }
  }

  /**
    Returns a vector of signal values, starting with index start,
    ending with index end.
  */
  #[allow(dead_code)]
  pub fn to_vector(&self, start: isize, end: isize) -> Vec<T> {
    /* Create an empty vector: */
    let mut x: Vec<T> = Vec::new();
    /* Loop through the given range: */
    for i in start..(end+1) {
      /* Add the values to the vector: */
      x.push(self.get(i));
    }
    /* Make the vector immutable: */
    let x = x;
    /* Return the vector: */
    x
  }

  /**
    Creates a new signal by doing Linear Prediction using
    the given coefficients.
  */
  #[allow(dead_code)]
  pub fn linear_prediction(&self, a: Vec<T>) -> ZeroPaddedSignal<T> {
    /* Create a vector for the values: */
    let mut vals: Vec<T> = Vec::new();
    /* Calculate the size of the new signal: */
    let size: usize = self.size() + a.len();
    /* Iterate over the new indices: */
    for i in 0..size {
      let mut val: T = T::zero();
      /* ... and the coefficients: */
      for j in 0..a.len() {
        /* Calculate and typecast the index in the old signal: */
        let idx = (i as isize) - ((j+1) as isize);
        /* Weight the value and add it up: */
        if let Some(v) = a.get(j).cloned() {
          val = val + v*self.get(idx);
        }
      }
      /* Add the value to the vector: */
      vals.push(val);
    }
    /* Create a signal from the vector and return it: */
    let x: ZeroPaddedSignal<T> = ZeroPaddedSignal { values: vals };
    x
  }

  /**
    Sets the signal value at the given index. If there's
    a gap between the last initialized index and the given
    one, the values between are initialized with zero.
  */
  #[allow(dead_code)]
  pub fn set(&mut self, idx: usize, val: T) {
    /* Initialize the gap values with zero, if necessary: */
    for _ in self.size()..(idx+1) {
      self.values.push(T::zero());
    }
    /* Set the new value: */
    self.values[idx] = val;
  }
}

/**

*/
#[allow(dead_code)]
struct MaximumLengthSequence {
  coefficients: Vec<u8>,
  state: Vec<u8>
}

impl MaximumLengthSequence {
  #[allow(dead_code)]
  pub fn new(coefficients: Vec<u8>, state: Vec<u8>)
    -> MaximumLengthSequence {
    /* Vectors must not be empty: */
    assert!(coefficients.len() > 0);
    assert!(state.len() > 0);
    /* Lengths of coefficients vector and state vector must match: */
    assert_eq!(coefficients.len(), state.len());
    /* Return the instance: */
    MaximumLengthSequence {
      coefficients: coefficients,
      state: state
    }
  }
}

#[cfg(test)]
mod tests {
  use super::ZeroPaddedSignal;
  use super::MaximumLengthSequence;

  #[test]
  fn zero_padded_signal() {
    /* Create test signals: */
    let mut x1: ZeroPaddedSignal<u32> = ZeroPaddedSignal {
      values: vec![42,7,11]
    };
    /* Test size method: */
    assert_eq!( 3, x1.size());
    /* Test get method: */
    assert_eq!( 0, x1.get(  -1));
    assert_eq!(42, x1.get(   0));
    assert_eq!( 7, x1.get(   1));
    assert_eq!(11, x1.get(   2));
    assert_eq!( 0, x1.get(   3));
    assert_eq!( 0, x1.get( 100));
    assert_eq!( 0, x1.get(-100));
    /* Test to_vector method: */
    assert_eq!(vec![0,0,0,42,7,11,0], x1.to_vector(-3,3));
    assert_eq!(0, x1.to_vector(3,-3).len());
    /* Test set method: */
    x1.set(0, 5);
    assert_eq!(vec![5,7,11], x1.values);
    x1.set(5, 12);
    assert_eq!(vec![5,7,11,0,0,12], x1.values);
    x1.set(6,100);
    assert_eq!(vec![5,7,11,0,0,12,100], x1.values);
  }

  #[test]
  fn linear_prediction() {
    /* Create test signals: */
    let x2: ZeroPaddedSignal<f64> = ZeroPaddedSignal {
      values: vec![1.,1.,1.,1.,1.,1.]
    };
    /* Test linear_prediction method: */
    assert_eq_floatvec!(
      vec![0.,0.8,0.8,0.8,0.7,0.7,0.7,-0.1,-0.1,-0.1],
      x2.linear_prediction(vec![0.8,0.,0.,-0.1]).values,
      1e-15
    );
  }

  #[test]
  fn maximum_length_sequence1() {
    let x1 = MaximumLengthSequence::new(vec![1,0,1], vec![1,0,1]);
  }

  #[test]
  #[should_panic(expected = "assertion failed: \
    coefficients.len() > 0")]
  fn maximum_length_sequence2() {
    let _ = MaximumLengthSequence::new(vec![], vec![1]);
  }

  #[test]
  #[should_panic(expected = "assertion failed: \
    state.len() > 0")]
  fn maximum_length_sequence3() {
    let _ = MaximumLengthSequence::new(vec![1], vec![]);
  }

  #[test]
  #[should_panic(expected = "assertion failed: \
    `(left == right)` (left: `2`, right: `1`)")]
  fn maximum_length_sequence4() {
    let _ = MaximumLengthSequence::new(vec![1,0], vec![1]);
  }
}
<commit_msg>signals.rs: More work on MaximumLengthSequence<commit_after>extern crate num;

/**
  Models an infinite signal, negative indices return
  always zero (to ensure causality of the signal),
  uninitialized positive indices, too.
  Can be used with any type that implements
  num::traits::Num and Clone.
*/
#[allow(dead_code)]
pub struct ZeroPaddedSignal<T> {
  values: Vec<T>,
}

impl<T: num::traits::Num + Clone> ZeroPaddedSignal<T> {
  /**
    Returns the number of initialized values.
  */
  #[allow(dead_code)]
  pub fn size(&self) -> usize {
    self.values.len()
  }

  /**
    Returns the value at the given index, zero if index
    is negative or uninitialized.
  */
  #[allow(dead_code)]
  pub fn get(&self, idx: isize) -> T {
    /* Check for negative index: */
    if idx < 0 {
      /* Negative, return zero: */
      T::zero()
    } else {
      /* Not negative, cast to unsigned: */
      let idx = idx as usize;
      /* Check if the index is initialized: */
      if let Some(v) = self.values.get(idx).cloned() {
        /* It is, return the value: */
        v
      } else {
        /* It's not, return zero: */
        T::zero()
      }
    }
  }

  /**
    Returns a vector of signal values, starting with index start,
    ending with index end.
  */
  #[allow(dead_code)]
  pub fn to_vector(&self, start: isize, end: isize) -> Vec<T> {
    /* Create an empty vector: */
    let mut x: Vec<T> = Vec::new();
    /* Loop through the given range: */
    for i in start..(end+1) {
      /* Add the values to the vector: */
      x.push(self.get(i));
    }
    /* Make the vector immutable: */
    let x = x;
    /* Return the vector: */
    x
  }

  /**
    Creates a new signal by doing Linear Prediction using
    the given coefficients.
  */
  #[allow(dead_code)]
  pub fn linear_prediction(&self, a: Vec<T>) -> ZeroPaddedSignal<T> {
    /* Create a vector for the values: */
    let mut vals: Vec<T> = Vec::new();
    /* Calculate the size of the new signal: */
    let size: usize = self.size() + a.len();
    /* Iterate over the new indices: */
    for i in 0..size {
      let mut val: T = T::zero();
      /* ... and the coefficients: */
      for j in 0..a.len() {
        /* Calculate and typecast the index in the old signal: */
        let idx = (i as isize) - ((j+1) as isize);
        /* Weight the value and add it up: */
        if let Some(v) = a.get(j).cloned() {
          val = val + v*self.get(idx);
        }
      }
      /* Add the value to the vector: */
      vals.push(val);
    }
    /* Create a signal from the vector and return it: */
    let x: ZeroPaddedSignal<T> = ZeroPaddedSignal { values: vals };
    x
  }

  /**
    Sets the signal value at the given index. If there's
    a gap between the last initialized index and the given
    one, the values between are initialized with zero.
  */
  #[allow(dead_code)]
  pub fn set(&mut self, idx: usize, val: T) {
    /* Initialize the gap values with zero, if necessary: */
    for _ in self.size()..(idx+1) {
      self.values.push(T::zero());
    }
    /* Set the new value: */
    self.values[idx] = val;
  }
}

/**
  TODO
*/
#[allow(dead_code)]
struct MaximumLengthSequence<T> {
  coefficients: Vec<bool>,
  state: Vec<bool>,
  val_false: T,
  val_true: T
}

impl<T: num::traits::Num + Copy> MaximumLengthSequence<T> {
  /**
    Creates a new instance using the given coefficients
    and the given initial state.
  */
  #[allow(dead_code)]
  pub fn new(coefficients: Vec<bool>, state: Vec<bool>)
    -> MaximumLengthSequence<T> {
    /* Vectors must not be empty: */
    assert!(coefficients.len() > 0);
    assert!(state.len() > 0);
    /* Lengths of coefficients vector and state vector must match: */
    assert_eq!(coefficients.len(), state.len());
    /* Return the instance: */
    MaximumLengthSequence::<T> {
      coefficients: coefficients,
      state: state,
      val_false: T::zero(),
      val_true: T::one()
    }
  }

  /**
    Sets the two values the sequence can be.
  */
  #[allow(dead_code)]
  pub fn set_vals(&mut self, val_false: T, val_true: T) {
    self.val_false = val_false;
    self.val_true = val_true;
  }

  /**
    Returns the next value and switches to the next state.
  */
  #[allow(dead_code)]
  pub fn next(&mut self) -> T {
    /* Create the variable we need to return later: */
    let x: T;
    if self.state[self.state.len()-1] {
      x = self.val_true;
    } else {
      x = self.val_false;
    }
    /* Set the new state: */
    self.state = self.next_state(&self.state);
    /* Return the value: */
    x
  }

  /**
    Returns the next state for the given one.
  */
  fn next_state(&self, state: &Vec<bool>) -> Vec<bool> {
    /* Create a new state vector: */
    let mut new_state: Vec<bool> = Vec::new();
    /* Calculate the new values: */
    for i in 0..state.len() {
      /* TODO */
      new_state.push(false);
    }
    /* Make the new state immutable and return it: */
    let new_state = new_state;
    new_state
  }
}

#[cfg(test)]
mod tests {
  use super::ZeroPaddedSignal;
  use super::MaximumLengthSequence;

  #[test]
  fn zero_padded_signal() {
    /* Create test signals: */
    let mut x1: ZeroPaddedSignal<u32> = ZeroPaddedSignal {
      values: vec![42,7,11]
    };
    /* Test size method: */
    assert_eq!( 3, x1.size());
    /* Test get method: */
    assert_eq!( 0, x1.get(  -1));
    assert_eq!(42, x1.get(   0));
    assert_eq!( 7, x1.get(   1));
    assert_eq!(11, x1.get(   2));
    assert_eq!( 0, x1.get(   3));
    assert_eq!( 0, x1.get( 100));
    assert_eq!( 0, x1.get(-100));
    /* Test to_vector method: */
    assert_eq!(vec![0,0,0,42,7,11,0], x1.to_vector(-3,3));
    assert_eq!(0, x1.to_vector(3,-3).len());
    /* Test set method: */
    x1.set(0, 5);
    assert_eq!(vec![5,7,11], x1.values);
    x1.set(5, 12);
    assert_eq!(vec![5,7,11,0,0,12], x1.values);
    x1.set(6,100);
    assert_eq!(vec![5,7,11,0,0,12,100], x1.values);
  }

  #[test]
  fn linear_prediction() {
    /* Create test signals: */
    let x2: ZeroPaddedSignal<f64> = ZeroPaddedSignal {
      values: vec![1.,1.,1.,1.,1.,1.]
    };
    /* Test linear_prediction method: */
    assert_eq_floatvec!(
      vec![0.,0.8,0.8,0.8,0.7,0.7,0.7,-0.1,-0.1,-0.1],
      x2.linear_prediction(vec![0.8,0.,0.,-0.1]).values,
      1e-15
    );
  }

  #[test]
  fn maximum_length_sequence1() {
    let x1: MaximumLengthSequence<u8> =
      MaximumLengthSequence::new(vec![true,false,true],
        vec![true,true,true]);
  }

  #[test]
  #[should_panic(expected = "assertion failed: \
    coefficients.len() > 0")]
  fn maximum_length_sequence2() {
    let _: MaximumLengthSequence<u8> = MaximumLengthSequence::new(
      vec![], vec![true]);
  }

  #[test]
  #[should_panic(expected = "assertion failed: \
    state.len() > 0")]
  fn maximum_length_sequence3() {
    let _: MaximumLengthSequence<u8> = MaximumLengthSequence::new(
      vec![true], vec![]);
  }

  #[test]
  #[should_panic(expected = "assertion failed: \
    `(left == right)` (left: `2`, right: `1`)")]
  fn maximum_length_sequence4() {
    let _: MaximumLengthSequence<u8> = MaximumLengthSequence::new(
      vec![true,false], vec![true]);
  }
}
<|endoftext|>


<commit_before>use value::{Value};

#[derive(Clone, Debug, Copy)]
pub enum Primitive {
    Add,
    Subtract,
    Split,
    Count,
    Contains,
    Sum,
    Mean,
    StandardDeviation,
    Empty,
}

pub fn resolve_as_scalar<'a>(mut ix: usize, constants: &'a [Value], outer: &'a [Value]) -> &'a Value {
    if ix < constants.len() {
        return &constants[ix];
    } else {
        ix = ix - constants.len()
    }
    return &outer[ix];
}

pub fn resolve_as_vector<'a>(mut ix: usize, constants: &'a [Value], outer: &'a [Value], inner: &'a [Vec<Value>]) -> Vec<&'a Value> {
    if ix < constants.len() {
        return vec![&constants[ix]; inner.len()];
    } else {
        ix = ix - constants.len()
    }
    if ix < outer.len() {
        return vec![&outer[ix]; inner.len()];
    } else {
        ix = ix - outer.len()
    }
    return inner.iter().map(|values| &values[ix]).collect();
}

impl Primitive {
    pub fn eval_from_join<'a>(&self, arguments: &[usize], inputs: &[&Value]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        let values = arguments.iter().map(|ix| inputs[*ix]).collect::<Vec<_>>();
        match (*self, &values[..]) {
            // NOTE be aware that arguments will be in alphabetical order by field id
            (Add, [&Float(a), &Float(b)]) => vec![vec![Float(a+b)]],
            (Subtract, [&Float(a), &Float(b)]) => vec![vec![Float(a-b)]],
            (Contains, [&String(ref inner), &String(ref outer)]) => vec![vec![Bool(outer.contains(inner))]],
            (Split, [&String(ref split), &String(ref string)]) => {
                string.split(split).enumerate().map(|(ix, segment)| vec![Float(ix as f64), String(segment.to_owned())]).collect()
            },
            (Count, _) => panic!("Cannot use {:?} in a join", self),
            (Sum, _) => panic!("Cannot use {:?} in a join", self),
            (Mean, _) => panic!("Cannot use {:?} in a join", self),
            (StandardDeviation, _) => panic!("Cannot use {:?} in a join", self),
            (Empty, _) => panic!("Cannot use {:?} in a join", self),
            _ => panic!("Type error while calling: {:?} {:?}", self, &arguments)
        }
    }

    pub fn eval_from_aggregate<'a>(&self, arguments: &[usize], constants: &[Value], outer: &[Value], inner: &[Vec<Value>]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        match (*self, arguments) {
            // NOTE be aware that arguments will be in alphabetical order by field id
            (Add, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Subtract, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Contains, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Split, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Count, [_]) => {
                vec![vec![Float(inner.len() as f64)]]
            },
            (Sum, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                vec![vec![Float(sum)]]
            },
            (Mean, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let mean = sum / (in_values.len() as f64);
                vec![vec![Float(mean)]]
            },
            (StandardDeviation, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let sum_squares = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float.powi(2),
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let standard_deviation = ((sum_squares - sum.powi(2)) / (in_values.len() as f64)).sqrt();
                vec![vec![Float(standard_deviation)]]
            },
            (Empty, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                vec![vec![Bool(in_values.len() == 0)]]
            },
            _ => panic!("Wrong number of arguments while calling: {:?} {:?}", self, arguments),
        }
    }

    pub fn from_str(string: &str) -> Self {
        match string {
            "add" => Primitive::Add,
            "subtract" => Primitive::Subtract,
            "contains" => Primitive::Contains,
            "split" => Primitive::Split,
            "count" => Primitive::Count,
            "sum" => Primitive::Sum,
            "mean" => Primitive::Mean,
            "standard deviation" => Primitive::StandardDeviation,
            "empty" => Primitive::Empty,
            _ => panic!("Unknown primitive: {:?}", string),
        }
    }
}

pub fn primitives() -> Vec<(&'static str, Vec<&'static str>, Vec<&'static str>, Vec<&'static str>)> {
    vec![
        ("add", vec!["in A", "in B"], vec![], vec!["out"]),
        ("subtract", vec!["in A", "in B"], vec![], vec!["out"]),
        ("contains", vec!["inner", "outer"], vec![], vec!["out"]),
        ("split", vec!["split", "string"], vec![], vec!["ix", "segment"]),
        ("count", vec![], vec!["in"], vec!["out"]),
        ("sum", vec![], vec!["in"], vec!["out"]),
        ("mean", vec![], vec!["in"], vec!["out"]),
        ("standard deviation", vec![], vec!["in"], vec!["out"]),
        ("empty", vec![], vec!["in"], vec!["out"]),
    ]
}
<commit_msg>Add scalar concat primitive<commit_after>use value::{Value};

#[derive(Clone, Debug, Copy)]
pub enum Primitive {
    Add,
    Subtract,
    Split,
    Concat,
    Count,
    Contains,
    Sum,
    Mean,
    StandardDeviation,
    Empty,
}

pub fn resolve_as_scalar<'a>(mut ix: usize, constants: &'a [Value], outer: &'a [Value]) -> &'a Value {
    if ix < constants.len() {
        return &constants[ix];
    } else {
        ix = ix - constants.len()
    }
    return &outer[ix];
}

pub fn resolve_as_vector<'a>(mut ix: usize, constants: &'a [Value], outer: &'a [Value], inner: &'a [Vec<Value>]) -> Vec<&'a Value> {
    if ix < constants.len() {
        return vec![&constants[ix]; inner.len()];
    } else {
        ix = ix - constants.len()
    }
    if ix < outer.len() {
        return vec![&outer[ix]; inner.len()];
    } else {
        ix = ix - outer.len()
    }
    return inner.iter().map(|values| &values[ix]).collect();
}

impl Primitive {
    pub fn eval_from_join<'a>(&self, arguments: &[usize], inputs: &[&Value]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        let values = arguments.iter().map(|ix| inputs[*ix]).collect::<Vec<_>>();
        match (*self, &values[..]) {
            // NOTE be aware that arguments will be in alphabetical order by field id
            (Add, [&Float(a), &Float(b)]) => vec![vec![Float(a+b)]],
            (Subtract, [&Float(a), &Float(b)]) => vec![vec![Float(a-b)]],
            (Contains, [&String(ref inner), &String(ref outer)]) => vec![vec![Bool(outer.contains(inner))]],
            (Split, [&String(ref split), &String(ref string)]) => {
                string.split(split).enumerate().map(|(ix, segment)| vec![Float(ix as f64), String(segment.to_owned())]).collect()
            },
            (Concat, [&String(ref a), &String(ref b)]) => vec![vec![String(a.to_owned() + b)]],
            (Count, _) => panic!("Cannot use {:?} in a join", self),
            (Sum, _) => panic!("Cannot use {:?} in a join", self),
            (Mean, _) => panic!("Cannot use {:?} in a join", self),
            (StandardDeviation, _) => panic!("Cannot use {:?} in a join", self),
            (Empty, _) => panic!("Cannot use {:?} in a join", self),
            _ => panic!("Type error while calling: {:?} {:?}", self, &arguments)
        }
    }

    pub fn eval_from_aggregate<'a>(&self, arguments: &[usize], constants: &[Value], outer: &[Value], inner: &[Vec<Value>]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        match (*self, arguments) {
            // NOTE be aware that arguments will be in alphabetical order by field id
            (Add, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Subtract, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Contains, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Split, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Concat, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Count, [_]) => {
                vec![vec![Float(inner.len() as f64)]]
            },
            (Sum, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                vec![vec![Float(sum)]]
            },
            (Mean, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let mean = sum / (in_values.len() as f64);
                vec![vec![Float(mean)]]
            },
            (StandardDeviation, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let sum_squares = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float.powi(2),
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                let standard_deviation = ((sum_squares - sum.powi(2)) / (in_values.len() as f64)).sqrt();
                vec![vec![Float(standard_deviation)]]
            },
            (Empty, [in_ix]) => {
                let in_values = resolve_as_vector(in_ix, constants, outer, inner);
                vec![vec![Bool(in_values.len() == 0)]]
            },
            _ => panic!("Wrong number of arguments while calling: {:?} {:?}", self, arguments),
        }
    }

    pub fn from_str(string: &str) -> Self {
        match string {
            "add" => Primitive::Add,
            "subtract" => Primitive::Subtract,
            "contains" => Primitive::Contains,
            "split" => Primitive::Split,
            "concat" => Primitive::Concat,
            "count" => Primitive::Count,
            "sum" => Primitive::Sum,
            "mean" => Primitive::Mean,
            "standard deviation" => Primitive::StandardDeviation,
            "empty" => Primitive::Empty,
            _ => panic!("Unknown primitive: {:?}", string),
        }
    }
}

pub fn primitives() -> Vec<(&'static str, Vec<&'static str>, Vec<&'static str>, Vec<&'static str>)> {
    vec![
        ("add", vec!["in A", "in B"], vec![], vec!["out"]),
        ("subtract", vec!["in A", "in B"], vec![], vec!["out"]),
        ("contains", vec!["inner", "outer"], vec![], vec!["out"]),
        ("split", vec!["split", "string"], vec![], vec!["ix", "segment"]),
        ("concat", vec!["a", "b"], vec![], vec!["out"]),
        ("count", vec![], vec!["in"], vec!["out"]),
        ("sum", vec![], vec!["in"], vec!["out"]),
        ("mean", vec![], vec!["in"], vec!["out"]),
        ("standard deviation", vec![], vec!["in"], vec!["out"]),
        ("empty", vec![], vec!["in"], vec!["out"]),
    ]
}
<|endoftext|>