<commit_before>use common;
use rand;
use rand::Rng;
use runner;
use serde_yaml;
use std::{io, str};
use std::collections::BTreeMap;
use std::fs::File;

#[derive(Debug, PartialEq, Eq)]
pub enum Token {
    Junk,
    Comma,
    FullStop,
    QuestionMark,
    OpenBracket,
    CloseBracket,
    Colon,
    Quote,
    SingleQuote,
    Newline,
    Word(String),
    Begin,
}

impl Token {
    pub fn string(self: Token) -> String {
        return match self {
                Token::Word(word) => word,
                Token::Junk => String::from(" "),
                Token::Comma => String::from(", "),
                Token::FullStop => String::from(". "),
                Token::QuestionMark => String::from("? "),
                Token::OpenBracket => String::from("("),
                Token::CloseBracket => String::from(")"),
                Token::Colon => String::from(": "),
                Token::Quote => String::from("\""),
                Token::SingleQuote => String::from("\'"),
                Token::Newline => String::from("\n"),
                Token::Begin => String::from(""),
            }
            .to_lowercase();
    }
}

fn is_alphabetic(c: char) -> bool {
    c.is_alphabetic()
}

fn alpha_or_word_chars(c: char) -> bool {
    c.is_alphabetic() || c == '\'' || c == '’' || c == '-' || c == '\u{2014}' // em-dash
}

named!(word_match<&str, (&str, &str)>,
    tuple!(
        take_while1!(is_alphabetic),
        take_while!(alpha_or_word_chars)
    )
);

named!(get_token<&str, Token>,
    alt!(
        tag_s!(".") => {|_| Token::FullStop} |
        tag_s!(",") => {|_| Token::Comma} |
        tag_s!(":") => {|_| Token::Colon} |
        tag_s!("?") => {|_| Token::QuestionMark} |
        tag_s!("(") => {|_| Token::OpenBracket} |
        tag_s!(")") => {|_| Token::CloseBracket} |
        is_a_s!("\"“”") => {|_| Token::Quote} |
        is_a_s!("\r\n") => {|_| Token::Newline} |
        is_a_s!("\'") => {|_| Token::SingleQuote} |
        word_match => { |(begin, rest)| {
                let mut word = String::from(begin);
                word += rest;
                Token::Word(word)
            }
        } |
        take_s!( 1 )  => { |_| Token::Junk }
    )
);

fn empty_filter(x: Token) -> Option<Token> {
    Some(x)
}

pub fn get_tokens(filename: &str) -> Result<Vec<Token>, io::Error> {
    return common::get_words_core_fn(filename, get_token, empty_filter);
}

#[derive(Serialize, Deserialize, Debug)]
pub struct MarkovSymbols {
    count: u16,
    tokens: BTreeMap<String, u16>,
}

impl MarkovSymbols {
    fn new() -> MarkovSymbols {
        MarkovSymbols {
            count: 0,
            tokens: BTreeMap::new(),
        }
    }

    fn add_token(self: &mut MarkovSymbols, token: &String) {
        *self.tokens.entry(token.clone()).or_insert(0) += 1;
        self.count += 1;
    }

    fn get_key(self: &MarkovSymbols) -> String {
        let mut rng = rand::thread_rng();
        let keys = self.tokens.keys();
        self.tokens.keys().nth(rng.gen_range(0, keys.len())).unwrap().clone()
    }

    fn count(self: &MarkovSymbols) -> u16 {
        self.count
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct MarkovScores {
    tokens: BTreeMap<u8, MarkovSymbols>,
    count: u16,
}

fn title_case(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().chain(c.flat_map(|t| t.to_lowercase())).collect(),
    }
}

impl MarkovScores {
    fn new() -> MarkovScores {
        MarkovScores {
            tokens: BTreeMap::new(),
            count: 0,
        }
    }

    fn get_key(self: &MarkovScores, score: &u8) -> Option<String> {
        return match self.tokens.get(score) {
            Some(score_hash) => {
                let mut rng = rand::thread_rng();
                let zero_score = self.tokens.get(&0).and_then(|x| Some(x.count())).unwrap_or(0);
                if zero_score == 0 {
                    return Some(score_hash.get_key());
                }
                let choice = rng.gen_range(0, self.count);
                if choice < zero_score {
                    let zero_token = self.tokens.get(&0).unwrap().get_key();
                    let mut rest = self.get_key(score).unwrap();
                    if zero_token == "." || zero_token == "?" || zero_token == "\n" {
                        rest = title_case(&rest);
                    }
                    Some(zero_token + &rest)
                } else {
                    let normal = score_hash.get_key();
                    if normal == "i" {
                        Some(String::from("I"))
                    } else {
                        Some(normal)
                    }
                }
            }
            None => None,
        };
    }

    fn add_token(self: &mut MarkovScores, score: u8, token: &String) {
        let score_entry = self.tokens.entry(score).or_insert(MarkovSymbols::new());
        score_entry.add_token(token);
        self.count += 1;
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct MarkovInfo {
    scores: MarkovScores,
    lookup: BTreeMap<String, MarkovScores>,
}

impl MarkovInfo {
    fn new() -> MarkovInfo {
        MarkovInfo {
            scores: MarkovScores::new(),
            lookup: BTreeMap::new(),
        }
    }

    fn add_token(self: &mut MarkovInfo, last: String, token: &String) {
        let token_score = runner::score(&token);
        let last_hash = self.lookup.entry(last.clone()).or_insert(MarkovScores::new());
        last_hash.add_token(token_score, token);
        self.scores.add_token(token_score, token);
    }

    fn default_get(self: &MarkovInfo, score: u8) -> String {
        match self.scores.get_key(&score) {
            Some(score_hash) => score_hash,
            None => {
                warn!("Have no words with score {} so making up one", score);
                let mut ret = String::new();
                for _ in 0..(score / 10) {
                    ret.push('z');
                }
                for _ in 0..(score % 10) {
                    ret.push('a');
                }
                return ret;
            }
        }
    }

    fn get_token(self: &MarkovInfo, last: &String, score: u8) -> String {
        debug!("Looking up for '{}' and {}", last, score);
        return match self.lookup.get(last) {
            Some(word) => {
                match word.get_key(&score) {
                    Some(score_hash) => score_hash,
                    None => self.default_get(score),
                }
            }
            None => self.default_get(score),
        };
    }
}

pub fn generate_markov<'a>(filename: &str) -> Result<MarkovInfo, io::Error> {
    let tokens = get_tokens(filename)?;
    let str_tokens = tokens.into_iter()
        .filter(|t: &Token| -> bool { if let &Token::Junk = t { false } else { true } })
        .map(|t| t.string());
    let mut res = MarkovInfo::new();
    let mut last = Token::Begin.string();
    for token in str_tokens {
        res.add_token(last, &token);
        last = token.clone();
    }
    Ok(res)
}

pub fn make_beatnik(wottasquare: &str, markov_fname: &str) -> Result<String, io::Error> {
    let buffer = File::open(markov_fname).unwrap();
    let markov: MarkovInfo = serde_yaml::from_reader(&buffer).map_err(common::io_str_error)?;
    let words = runner::get_wottas(wottasquare)?;
    let mut last = Token::Begin.string();
    let mut out = String::new();
    for word in words {
        let mut token = markov.get_token(&last, word.score());
        if last == "" {
            token = title_case(&token);
        } else if !last.starts_with(".") && !last.starts_with("?") {
            out.push_str(" ");
        }

        out.push_str(&token);
        last = token;
    }
    return Ok(out);
}

#[cfg(test)]
mod tests {
    use common;
    use quickcheck::TestResult;
    use super::{empty_filter, get_token};

    #[test]
    fn copes_with_utf_8() {
        common::get_words_core("why—I".as_bytes(), get_token, empty_filter).unwrap();
    }

    quickcheck! {
      fn token_test(xs: String) -> TestResult {
          return match common::get_words_core(xs.as_bytes(), get_token, empty_filter) {
              Ok(_) => TestResult::passed(),
              Err(err) => {
                  println!("Error: '{}'", xs);
                  TestResult::error(format!("{:?}", err))
              }
          }
      }
  }
}
<commit_msg>Random choice of words based on distribution<commit_after>use common;
use rand;
use rand::Rng;
use runner;
use serde_yaml;
use std::{io, str};
use std::collections::BTreeMap;
use std::fs::File;

#[derive(Debug, PartialEq, Eq)]
pub enum Token {
    Junk,
    Comma,
    FullStop,
    QuestionMark,
    OpenBracket,
    CloseBracket,
    Colon,
    Quote,
    SingleQuote,
    Newline,
    Word(String),
    Begin,
}

impl Token {
    pub fn string(self: Token) -> String {
        return match self {
                Token::Word(word) => word,
                Token::Junk => String::from(" "),
                Token::Comma => String::from(", "),
                Token::FullStop => String::from(". "),
                Token::QuestionMark => String::from("? "),
                Token::OpenBracket => String::from("("),
                Token::CloseBracket => String::from(")"),
                Token::Colon => String::from(": "),
                Token::Quote => String::from("\""),
                Token::SingleQuote => String::from("\'"),
                Token::Newline => String::from("\n"),
                Token::Begin => String::from(""),
            }
            .to_lowercase();
    }
}

fn is_alphabetic(c: char) -> bool {
    c.is_alphabetic()
}

fn alpha_or_word_chars(c: char) -> bool {
    c.is_alphabetic() || c == '\'' || c == '’' || c == '-' || c == '\u{2014}' // em-dash
}

named!(word_match<&str, (&str, &str)>,
    tuple!(
        take_while1!(is_alphabetic),
        take_while!(alpha_or_word_chars)
    )
);

named!(get_token<&str, Token>,
    alt!(
        tag_s!(".") => {|_| Token::FullStop} |
        tag_s!(",") => {|_| Token::Comma} |
        tag_s!(":") => {|_| Token::Colon} |
        tag_s!("?") => {|_| Token::QuestionMark} |
        tag_s!("(") => {|_| Token::OpenBracket} |
        tag_s!(")") => {|_| Token::CloseBracket} |
        is_a_s!("\"“”") => {|_| Token::Quote} |
        is_a_s!("\r\n") => {|_| Token::Newline} |
        is_a_s!("\'") => {|_| Token::SingleQuote} |
        word_match => { |(begin, rest)| {
                let mut word = String::from(begin);
                word += rest;
                Token::Word(word)
            }
        } |
        take_s!( 1 )  => { |_| Token::Junk }
    )
);

fn empty_filter(x: Token) -> Option<Token> {
    Some(x)
}

pub fn get_tokens(filename: &str) -> Result<Vec<Token>, io::Error> {
    return common::get_words_core_fn(filename, get_token, empty_filter);
}

#[derive(Serialize, Deserialize, Debug)]
pub struct MarkovSymbols {
    count: u16,
    tokens: BTreeMap<String, u16>,
}

impl MarkovSymbols {
    fn new() -> MarkovSymbols {
        MarkovSymbols {
            count: 0,
            tokens: BTreeMap::new(),
        }
    }

    fn add_token(self: &mut MarkovSymbols, token: &String) {
        *self.tokens.entry(token.clone()).or_insert(0) += 1;
        self.count += 1;
    }

    fn get_key(self: &MarkovSymbols) -> String {
        let mut rng = rand::thread_rng();
        let mut choice = rng.gen_range(0, self.count);
        for (key, value) in self.tokens.iter() {
            if &choice < value {
                return key.clone();
            }
            choice -= *value;
        }
        panic!("Didn't find token within range");
    }

    fn count(self: &MarkovSymbols) -> u16 {
        self.count
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct MarkovScores {
    tokens: BTreeMap<u8, MarkovSymbols>,
    count: u16,
}

fn title_case(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().chain(c.flat_map(|t| t.to_lowercase())).collect(),
    }
}

impl MarkovScores {
    fn new() -> MarkovScores {
        MarkovScores {
            tokens: BTreeMap::new(),
            count: 0,
        }
    }

    fn get_key(self: &MarkovScores, score: &u8) -> Option<String> {
        return match self.tokens.get(score) {
            Some(score_hash) => {
                let mut rng = rand::thread_rng();
                let zero_score = self.tokens.get(&0).and_then(|x| Some(x.count())).unwrap_or(0);
                if zero_score == 0 {
                    return Some(score_hash.get_key());
                }
                let choice = rng.gen_range(0, self.count);
                if choice < zero_score {
                    let zero_token = self.tokens.get(&0).unwrap().get_key();
                    let mut rest = self.get_key(score).unwrap();
                    if zero_token == "." || zero_token == "?" || zero_token == "\n" {
                        rest = title_case(&rest);
                    }
                    Some(zero_token + &rest)
                } else {
                    let normal = score_hash.get_key();
                    if normal == "i" {
                        Some(String::from("I"))
                    } else {
                        Some(normal)
                    }
                }
            }
            None => None,
        };
    }

    fn add_token(self: &mut MarkovScores, score: u8, token: &String) {
        let score_entry = self.tokens.entry(score).or_insert(MarkovSymbols::new());
        score_entry.add_token(token);
        self.count += 1;
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct MarkovInfo {
    scores: MarkovScores,
    lookup: BTreeMap<String, MarkovScores>,
}

impl MarkovInfo {
    fn new() -> MarkovInfo {
        MarkovInfo {
            scores: MarkovScores::new(),
            lookup: BTreeMap::new(),
        }
    }

    fn add_token(self: &mut MarkovInfo, last: String, token: &String) {
        let token_score = runner::score(&token);
        let last_hash = self.lookup.entry(last.clone()).or_insert(MarkovScores::new());
        last_hash.add_token(token_score, token);
        self.scores.add_token(token_score, token);
    }

    fn default_get(self: &MarkovInfo, score: u8) -> String {
        match self.scores.get_key(&score) {
            Some(score_hash) => score_hash,
            None => {
                warn!("Have no words with score {} so making up one", score);
                let mut ret = String::new();
                for _ in 0..(score / 10) {
                    ret.push('z');
                }
                for _ in 0..(score % 10) {
                    ret.push('a');
                }
                return ret;
            }
        }
    }

    fn get_token(self: &MarkovInfo, last: &String, score: u8) -> String {
        debug!("Looking up for '{}' and {}", last, score);
        return match self.lookup.get(last) {
            Some(word) => {
                match word.get_key(&score) {
                    Some(score_hash) => score_hash,
                    None => self.default_get(score),
                }
            }
            None => self.default_get(score),
        };
    }
}

pub fn generate_markov<'a>(filename: &str) -> Result<MarkovInfo, io::Error> {
    let tokens = get_tokens(filename)?;
    let str_tokens = tokens.into_iter()
        .filter(|t: &Token| -> bool { if let &Token::Junk = t { false } else { true } })
        .map(|t| t.string());
    let mut res = MarkovInfo::new();
    let mut last = Token::Begin.string();
    for token in str_tokens {
        res.add_token(last, &token);
        last = token.clone();
    }
    Ok(res)
}

pub fn make_beatnik(wottasquare: &str, markov_fname: &str) -> Result<String, io::Error> {
    let buffer = File::open(markov_fname).unwrap();
    let markov: MarkovInfo = serde_yaml::from_reader(&buffer).map_err(common::io_str_error)?;
    let words = runner::get_wottas(wottasquare)?;
    let mut last = Token::Begin.string();
    let mut out = String::new();
    for word in words {
        let mut token = markov.get_token(&last, word.score());
        if last == "" {
            token = title_case(&token);
        } else if !token.starts_with(".") && !token.starts_with("?") && !token.starts_with(",") {
            out.push_str(" ");
        }

        out.push_str(&token);
        last = token;
    }
    return Ok(out);
}

#[cfg(test)]
mod tests {
    use common;
    use quickcheck::TestResult;
    use super::{empty_filter, get_token};

    #[test]
    fn copes_with_utf_8() {
        common::get_words_core("why—I".as_bytes(), get_token, empty_filter).unwrap();
    }

    quickcheck! {
      fn token_test(xs: String) -> TestResult {
          return match common::get_words_core(xs.as_bytes(), get_token, empty_filter) {
              Ok(_) => TestResult::passed(),
              Err(err) => {
                  println!("Error: '{}'", xs);
                  TestResult::error(format!("{:?}", err))
              }
          }
      }
  }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::io::{Read, Write};
use memmap::{Mmap, Protection};
use byteorder::{ByteOrder, LittleEndian};

const RAM_SIZE: usize     = 0x1800000; // 24 MB
const BOOTROM_SIZE: usize = 0x0100000; // 1 MB

pub struct Memory {
    mmap: Mmap,
    bootrom: Mmap
}

// ToDo: add write/read for u8, u16, u32, u64

impl Memory {
    pub fn new() -> Memory {
        let mmap = match Mmap::anonymous(RAM_SIZE, Protection::ReadWrite) {
            Ok(v) => v,
            Err(e) => panic!("{}", e)
        };

        let bootrom = match Mmap::anonymous(BOOTROM_SIZE, Protection::ReadWrite) {
            Ok(v) => v,
            Err(e) => panic!("{}", e)
        };

        Memory {
            mmap: mmap,
            bootrom: bootrom
        }
    }

    pub fn read(&mut self, address: u32, data: &mut [u8]) {
        match address {
            0x00000000 ... 0x07FFFFFF => { // Main Memory (RAM)
                let mmap = unsafe { self.mmap.as_slice() };

                match {&mmap[address as usize ..]}.read(data) {
                    Ok(_) => {}
                    Err(e) => panic!("{}", e)
                }
            },
            0x08000000 ... 0x0BFFFFFF => { // Embedded Framebuffer (EFB)
                println!("memory address not implemented");
            },
            0x0C000000 ... 0x0C000FFF => { // Command Processor (CP)
                println!("memory address not implemented");
            },
            0x0C001000 ... 0x0C001FFF => { // Pixel Engine (PE)
                println!("memory address not implemented");
            },
            0x0C002000 ... 0x0C002FFF => { // Video Interface (VI)
                println!("memory address not implemented");
            },
            0x0C003000 ... 0x0C003FFF => { // Peripheral Interface (PI)
                println!("memory address not implemented");
            },
            0x0C004000 ... 0x0C004FFF => { // Memory Interface (MI)
                println!("memory address not implemented");
            },
            0x0C005000 ... 0x0C005FFF => { // DSP and DMA Audio Interface (AID)
                println!("memory address not implemented");
            },
            0x0C006000 ... 0x0C0063FF => { // DVD Interface (DI)
                println!("memory address not implemented");
            },
            0x0C006400 ... 0x0C0067FF => { // Serial Interface (SI)
                println!("memory address not implemented");
            },
            0x0C006800 ... 0x0C0068FF => { // External Interface (EXI)
                println!("memory address not implemented");
            },
            0x0C006C00 ... 0x0C006CFF => { // Audio Streaming Interface (AIS)
                println!("memory address not implemented");
            },
            0x0C008000 ... 0x0C008FFF => { // PI FIFO (GX)
                println!("memory address not implemented");
            },
            0xFFF00000 ... 0xFFFFFFFF => { // Bootrom
                let bootrom = unsafe { self.bootrom.as_slice() };

                match {&bootrom[(address - 0xFFF00000) as usize ..]}.read(data) {
                    Ok(_) => {}
                    Err(e) => panic!("{}", e)
                }
            },
            _ => panic!("read from invalid memory address {:#x}", address)
        }
    }

    pub fn read_u32(&mut self, address: u32) -> u32 {
        let mut data = [0u8; 4];

        self.read(address, &mut data);

        LittleEndian::read_u32(&data)
    }

    pub fn write(&mut self, address: u32, data: &[u8]) { // FixMe: probably change to size
        match address {
            0x00000000 ... 0x07FFFFFF => { // Main Memory (RAM)
                let mut mmap = unsafe { self.mmap.as_mut_slice() };

                match {&mut mmap[address as usize ..]}.write(data) {
                    Ok(_) => {}
                    Err(e) => panic!("{}", e)
                }
            },
            0x08000000 ... 0x0BFFFFFF => { // Embedded Framebuffer (EFB)
                println!("memory address not implemented");
            },
            0x0C000000 ... 0x0C000FFF => { // Command Processor (CP)
                println!("memory address not implemented");
            },
            0x0C001000 ... 0x0C001FFF => { // Pixel Engine (PE)
                println!("memory address not implemented");
            },
            0x0C002000 ... 0x0C002FFF => { // Video Interface (VI)
                println!("memory address not implemented");
            },
            0x0C003000 ... 0x0C003FFF => { // Peripheral Interface (PI)
                println!("memory address not implemented");
            },
            0x0C004000 ... 0x0C004FFF => { // Memory Interface (MI)
                println!("memory address not implemented");
            },
            0x0C005000 ... 0x0C005FFF => { // DSP and DMA Audio Interface (AID)
                println!("memory address not implemented");
            },
            0x0C006000 ... 0x0C0063FF => { // DVD Interface (DI)
                println!("memory address not implemented");
            },
            0x0C006400 ... 0x0C0067FF => { // Serial Interface (SI)
                println!("memory address not implemented");
            },
            0x0C006800 ... 0x0C0068FF => { // External Interface (EXI)
                println!("memory address not implemented");
            },
            0x0C006C00 ... 0x0C006CFF => { // Audio Streaming Interface (AIS)
                println!("memory address not implemented");
            },
            0x0C008000 ... 0x0C008FFF => { // PI FIFO (GX)
                println!("memory address not implemented");
            },
            0xFFF00000 ... 0xFFFFFFFF => { // Bootrom
                let mut bootrom = unsafe { self.bootrom.as_mut_slice() };

                match {&mut bootrom[(address - 0xFFF00000) as usize ..]}.write(data) {
                    Ok(_) => {}
                    Err(e) => panic!("{}", e)
                }
            },
            _ => panic!("write to invalid memory address {:#x}", address)
        }
    }

    pub fn write_u16(&mut self, address: u32, value: u16) {
        let mut data = [0u8; 2];

        LittleEndian::write_u16(&mut data, value);

        self.write(address, &data);
    }

    pub fn write_u32(&mut self, address: u32, value: u32) {
        let mut data = [0u8; 4];

        LittleEndian::write_u32(&mut data, value);

        self.write(address, &data);
    }
}

impl fmt::Debug for Memory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "fixme")
    }
}
<commit_msg>memory debug output more specific<commit_after>use std::fmt;
use std::io::{Read, Write};
use memmap::{Mmap, Protection};
use byteorder::{ByteOrder, LittleEndian};

const RAM_SIZE: usize     = 0x1800000; // 24 MB
const BOOTROM_SIZE: usize = 0x0100000; // 1 MB

pub struct Memory {
    mmap: Mmap,
    bootrom: Mmap
}

// ToDo: add write/read for u8, u16, u32, u64

impl Memory {
    pub fn new() -> Memory {
        let mmap = match Mmap::anonymous(RAM_SIZE, Protection::ReadWrite) {
            Ok(v) => v,
            Err(e) => panic!("{}", e)
        };

        let bootrom = match Mmap::anonymous(BOOTROM_SIZE, Protection::ReadWrite) {
            Ok(v) => v,
            Err(e) => panic!("{}", e)
        };

        Memory {
            mmap: mmap,
            bootrom: bootrom
        }
    }

    pub fn read(&mut self, address: u32, data: &mut [u8]) {
        match address {
            0x00000000 ... 0x07FFFFFF => { // Main Memory (RAM)
                let mmap = unsafe { self.mmap.as_slice() };

                match {&mmap[address as usize ..]}.read(data) {
                    Ok(_) => {}
                    Err(e) => panic!("{}", e)
                }
            },
            0x08000000 ... 0x0BFFFFFF => { // Embedded Framebuffer (EFB)
                println!("embedded framebuffer not implemented");
            },
            0x0C000000 ... 0x0C000FFF => { // Command Processor (CP)
                println!("command processor not implemented");
            },
            0x0C001000 ... 0x0C001FFF => { // Pixel Engine (PE)
                println!("pixel engine not implemented");
            },
            0x0C002000 ... 0x0C002FFF => { // Video Interface (VI)
                println!("video interface not implemented");
            },
            0x0C003000 ... 0x0C003FFF => { // Peripheral Interface (PI)
                println!("peripheral interface not implemented");
            },
            0x0C004000 ... 0x0C004FFF => { // Memory Interface (MI)
                println!("memory interface not implemented");
            },
            0x0C005000 ... 0x0C005FFF => { // DSP and DMA Audio Interface (AID)
                println!("dsp + dma audio interface not implemented");
            },
            0x0C006000 ... 0x0C0063FF => { // DVD Interface (DI)
                println!("dvd interface not implemented");
            },
            0x0C006400 ... 0x0C0067FF => { // Serial Interface (SI)
                println!("serial interface not implemented");
            },
            0x0C006800 ... 0x0C0068FF => { // External Interface (EXI)
                println!("external interface not implemented");
            },
            0x0C006C00 ... 0x0C006CFF => { // Audio Streaming Interface (AIS)
                println!("audio streaming interface not implemented");
            },
            0x0C008000 ... 0x0C008FFF => { // PI FIFO (GX)
                println!("gx fifo not implemented");
            },
            0xFFF00000 ... 0xFFFFFFFF => { // Bootrom
                let bootrom = unsafe { self.bootrom.as_slice() };

                match {&bootrom[(address - 0xFFF00000) as usize ..]}.read(data) {
                    Ok(_) => {}
                    Err(e) => panic!("{}", e)
                }
            },
            _ => panic!("read from invalid memory address {:#x}", address)
        }
    }

    pub fn read_u32(&mut self, address: u32) -> u32 {
        let mut data = [0u8; 4];

        self.read(address, &mut data);

        LittleEndian::read_u32(&data)
    }

    pub fn write(&mut self, address: u32, data: &[u8]) { // FixMe: probably change to size
        match address {
            0x00000000 ... 0x07FFFFFF => { // Main Memory (RAM)
                let mut mmap = unsafe { self.mmap.as_mut_slice() };

                match {&mut mmap[address as usize ..]}.write(data) {
                    Ok(_) => {}
                    Err(e) => panic!("{}", e)
                }
            },
            0x08000000 ... 0x0BFFFFFF => { // Embedded Framebuffer (EFB)
                println!("embedded framebuffer not implemented");
            },
            0x0C000000 ... 0x0C000FFF => { // Command Processor (CP)
                println!("command processor not implemented");
            },
            0x0C001000 ... 0x0C001FFF => { // Pixel Engine (PE)
                println!("pixel engine not implemented");
            },
            0x0C002000 ... 0x0C002FFF => { // Video Interface (VI)
                println!("video interface not implemented");
            },
            0x0C003000 ... 0x0C003FFF => { // Peripheral Interface (PI)
                println!("peripheral interface not implemented");
            },
            0x0C004000 ... 0x0C004FFF => { // Memory Interface (MI)
                println!("memory interface not implemented");
            },
            0x0C005000 ... 0x0C005FFF => { // DSP and DMA Audio Interface (AID)
                println!("dsp + dma audio interface not implemented");
            },
            0x0C006000 ... 0x0C0063FF => { // DVD Interface (DI)
                println!("dvd interface not implemented");
            },
            0x0C006400 ... 0x0C0067FF => { // Serial Interface (SI)
                println!("serial interface not implemented");
            },
            0x0C006800 ... 0x0C0068FF => { // External Interface (EXI)
                println!("external interface not implemented");
            },
            0x0C006C00 ... 0x0C006CFF => { // Audio Streaming Interface (AIS)
                println!("audio streaming interface not implemented");
            },
            0x0C008000 ... 0x0C008FFF => { // PI FIFO (GX)
                println!("gx fifo not implemented");
            },
            0xFFF00000 ... 0xFFFFFFFF => { // Bootrom
                let mut bootrom = unsafe { self.bootrom.as_mut_slice() };

                match {&mut bootrom[(address - 0xFFF00000) as usize ..]}.write(data) {
                    Ok(_) => {}
                    Err(e) => panic!("{}", e)
                }
            },
            _ => panic!("write to invalid memory address {:#x}", address)
        }
    }

    pub fn write_u16(&mut self, address: u32, value: u16) {
        let mut data = [0u8; 2];

        LittleEndian::write_u16(&mut data, value);

        self.write(address, &data);
    }

    pub fn write_u32(&mut self, address: u32, value: u32) {
        let mut data = [0u8; 4];

        LittleEndian::write_u32(&mut data, value);

        self.write(address, &data);
    }
}

impl fmt::Debug for Memory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "fixme")
    }
}
<|endoftext|>


<commit_before>use ast::{Expr, BinOp, UnOp, Dec};
use lexer::{Lexer, Token};

struct Parser {
  lexer: Lexer,
  current_token: Token,
}

impl Parser {
  pub fn new(text: String) -> Parser {
    let mut lexer = Lexer::new(text);

    let token = lexer.get_next_token();

    Parser {
      lexer: lexer,
      current_token: token,
    }
  }

  fn eat(&mut self, expected: Token) {
    let actual = self.current_token.clone();

    if expected != actual {
      panic!("expected token: {:?} actual: {:?}", expected, actual)
    }

    self.current_token = self.lexer.get_next_token();
    debug!("new current token: {:?}", self.current_token);
  }

  fn ternary(&mut self, e1: Expr, e2: Expr, e3: Expr) -> Expr {
    Expr::Ternary(to_box(e1), to_box(e2), to_box(e3))
  }

  fn binop(&mut self, bop: BinOp, e1: Expr, e2: Expr) -> Expr {
    Expr::Bop(bop, to_box(e1), to_box(e2))
  }

  fn factor(&mut self) -> Expr {
    match self.current_token.clone() {
      Token::Int(n) => {
        self.eat(Token::Int(n.clone()));
        return Expr::Int(n);
      },
      Token::Bool(b) => {
        self.eat(Token::Bool(b.clone()));
        return Expr::Bool(b);
      },
      Token::Var(s) => {
        self.eat(Token::Var(s.clone()));

        // fn call rule
        if self.current_token == Token::LParen {
          self.eat(Token::LParen);
          let params = self.parse_fn_params();
          self.eat(Token::RParen);

          return Expr::FnCall(to_box(Expr::Var(s)), params);
        }

        return Expr::Var(s);
      },
      Token::FnDecl => {
        return self.parse_fn();
      },
      Token::LParen => {
        self.eat(Token::LParen);
        let node = self.statement();
        self.eat(Token::RParen);
        return node;
      },
      Token::LBracket => {
        self.eat(Token::LBracket);
        let node = self.block();
        self.eat(Token::RBracket);
        return node;
      },
      Token::Not => {
        self.eat(Token::Not);
        return Expr::Uop(UnOp::Not, to_box(self.factor()));
      },
      Token::Minus => {
        self.eat(Token::Minus);
        return Expr::Uop(UnOp::Neg, to_box(self.factor()));
      },
      _ => {
        debug!("invalid factor: {:?}", self.current_token);
        panic!();
      },
    }
  }

  pub fn term(&mut self) -> Expr {
    let mut node = self.factor();

    let mut op = self.current_token.clone();

    while op.is_term_op() {
      self.eat(op.clone());
      let right_node = self.term();

      node = match op {
        Token::Times => self.binop(BinOp::Times, node, right_node),
        Token::Div => self.binop(BinOp::Div, node, right_node),
        _ => panic!(),
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn binop_expr(&mut self) -> Expr {
    let mut node = self.term();

    let mut op = self.current_token.clone();

    while op.is_expr_op() {
      debug!("expr looping on op {:?}", op);
      self.eat(op.clone());

      let right_node = self.term();

      node = match op {
        Token::Plus => self.binop(BinOp::Plus, node, right_node),
        Token::Minus => self.binop(BinOp::Minus, node, right_node),
        Token::Eq => self.binop(BinOp::Eq, node, right_node),
        Token::Ne => self.binop(BinOp::Ne, node, right_node),
        Token::Leq => self.binop(BinOp::Leq, node, right_node),
        Token::Geq => self.binop(BinOp::Geq, node, right_node),
        Token::Lt => self.binop(BinOp::Lt, node, right_node),
        Token::Gt => self.binop(BinOp::Gt, node, right_node),
        Token::And => self.binop(BinOp::And, node, right_node),
        Token::Or => self.binop(BinOp::Or, node, right_node),
        Token::Mod => self.binop(BinOp::Mod, node, right_node),
        Token::Assign => self.binop(BinOp::Assign, node, right_node),
        _ => panic!(),
      };

      op = self.current_token.clone();
    }

    node
  }

  fn parse_var(&mut self) -> Expr {
    self.eat(Token::VarDecl);
    let var = self.term();
    self.eat(Token::Assign);
    let e2 = self.statement();
    self.eat(Token::Seq);
    let e3 = self.block();

    return Expr::Decl(Dec::DVar, to_box(var), to_box(e2), to_box(e3));
  }

  fn parse_let(&mut self) -> Expr {
    self.eat(Token::Let);
    let var = self.term();
    self.eat(Token::Assign);
    let e2 = self.statement();
    self.eat(Token::Seq);
    let e3 = self.block();

    return Expr::Decl(Dec::DConst, to_box(var), to_box(e2), to_box(e3));
  }

  fn parse_fn_params(&mut self) -> Vec<Expr> {
    let mut params = Vec::new();
    let mut token = self.current_token.clone();

    while token != Token::RParen {
      debug!("getting fn params");
      let term = self.binop_expr();

      params.push(term);

      if self.current_token == Token::Comma {
        self.eat(Token::Comma);
      }

      token = self.current_token.clone();
    }

    params
  }

  fn parse_fn_decl_params(&mut self) -> Vec<Expr> {
    let mut params = Vec::new();
    let mut token = self.current_token.clone();

    while token != Token::RParen {
      debug!("getting fn decl params");
      match token.clone() {
        Token::Var(s) => {
          self.eat(Token::Var(s.clone()));
          params.push(Expr::Var(s));
        },
        Token::Comma => self.eat(Token::Comma),
        _ => panic!()
      }

      token = self.current_token.clone();
    }

    params
  }

  fn parse_fn(&mut self) -> Expr {
    debug!("parsing named fn...");
    self.eat(Token::FnDecl);

    let var = match self.current_token.clone() {
      Token::Var(s) => {
        self.eat(Token::Var(s.clone()));
        Some(Expr::Var(s))
      },
      _ => None,
    };

    self.eat(Token::LParen);
    let params = self.parse_fn_decl_params();
    self.eat(Token::RParen);
    self.eat(Token::LBracket);
    let body = self.statement();
    self.eat(Token::RBracket);

    match var {
      Some(v) => {
        self.eat(Token::Seq);
        let e3 = self.statement();

        let func = Expr::Func(Some(to_box(v.clone())), to_box(body.clone()), params);

        Expr::Decl(Dec::DConst, to_box(v), to_box(func), to_box(e3))
      },
      None => {
        Expr::Func(None, to_box(body.clone()), params)
      }
    }
  }

  fn parse_if(&mut self) -> Expr {
    self.eat(Token::If);
    let e1 = self.binop_expr();
    let e2 = self.statement();
    let e3 = self.statement();
    return self.ternary(e1, e2, e3);
  }

  pub fn statement(&mut self) -> Expr {
    if self.current_token == Token::Let {
      return self.parse_let();
    } else if self.current_token == Token::VarDecl {
      return self.parse_var();
    } else if self.current_token == Token::If {
      return self.parse_if();
    } else if self.current_token == Token::Else {
      self.eat(Token::Else);
      return self.statement();
    }

    let mut node = self.binop_expr();
    let mut op = self.current_token.clone();

    while op.is_statement_op() {
      self.eat(op.clone());

      node = match op {
        Token::Ternary => {
          let e2 = self.block();
          self.eat(Token::Else);
          let e3 = self.statement();
          self.ternary(node, e2, e3)
        },
        _ => panic!()
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn block(&mut self) -> Expr {
    let mut node = self.statement();
    let mut op = self.current_token.clone();

    while op.is_block_op() {
      self.eat(op.clone());
      let e2 = self.statement();

      node = match op {
        Token::Seq => self.binop(BinOp::Seq, node, e2),
        _ => panic!()
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn program(&mut self) -> Expr {
    self.block()
  }
}

fn to_box(e: Expr) -> Box<Expr> {
  Box::new(e)
}

pub fn parse(input: &str) -> Expr {
  let mut parser = Parser::new(input.to_string());
  let expr = parser.program();

  debug!("parsed expr: {:#?}", expr);
  debug!("original: {:#?}", input);

  expr
}
<commit_msg>moving up parser helpers<commit_after>use ast::{Expr, BinOp, UnOp, Dec};
use lexer::{Lexer, Token};

struct Parser {
  lexer: Lexer,
  current_token: Token,
}

impl Parser {
  pub fn new(text: String) -> Parser {
    let mut lexer = Lexer::new(text);

    let token = lexer.get_next_token();

    Parser {
      lexer: lexer,
      current_token: token,
    }
  }

  fn eat(&mut self, expected: Token) {
    let actual = self.current_token.clone();

    if expected != actual {
      panic!("expected token: {:?} actual: {:?}", expected, actual)
    }

    self.current_token = self.lexer.get_next_token();
    debug!("new current token: {:?}", self.current_token);
  }

  fn ternary(&mut self, e1: Expr, e2: Expr, e3: Expr) -> Expr {
    Expr::Ternary(to_box(e1), to_box(e2), to_box(e3))
  }

  fn binop(&mut self, bop: BinOp, e1: Expr, e2: Expr) -> Expr {
    Expr::Bop(bop, to_box(e1), to_box(e2))
  }

  fn parse_var(&mut self) -> Expr {
    self.eat(Token::VarDecl);
    let var = self.term();
    self.eat(Token::Assign);
    let e2 = self.statement();
    self.eat(Token::Seq);
    let e3 = self.block();

    return Expr::Decl(Dec::DVar, to_box(var), to_box(e2), to_box(e3));
  }

  fn parse_let(&mut self) -> Expr {
    self.eat(Token::Let);
    let var = self.term();
    self.eat(Token::Assign);
    let e2 = self.statement();
    self.eat(Token::Seq);
    let e3 = self.block();

    return Expr::Decl(Dec::DConst, to_box(var), to_box(e2), to_box(e3));
  }

  fn parse_fn_params(&mut self) -> Vec<Expr> {
    let mut params = Vec::new();
    let mut token = self.current_token.clone();

    while token != Token::RParen {
      debug!("getting fn params");
      let term = self.binop_expr();

      params.push(term);

      if self.current_token == Token::Comma {
        self.eat(Token::Comma);
      }

      token = self.current_token.clone();
    }

    params
  }

  fn parse_fn_decl_params(&mut self) -> Vec<Expr> {
    let mut params = Vec::new();
    let mut token = self.current_token.clone();

    while token != Token::RParen {
      debug!("getting fn decl params");
      match token.clone() {
        Token::Var(s) => {
          self.eat(Token::Var(s.clone()));
          params.push(Expr::Var(s));
        },
        Token::Comma => self.eat(Token::Comma),
        _ => panic!()
      }

      token = self.current_token.clone();
    }

    params
  }

  fn parse_fn(&mut self) -> Expr {
    debug!("parsing named fn...");
    self.eat(Token::FnDecl);

    let var = match self.current_token.clone() {
      Token::Var(s) => {
        self.eat(Token::Var(s.clone()));
        Some(Expr::Var(s))
      },
      _ => None,
    };

    self.eat(Token::LParen);
    let params = self.parse_fn_decl_params();
    self.eat(Token::RParen);
    self.eat(Token::LBracket);
    let body = self.statement();
    self.eat(Token::RBracket);

    match var {
      Some(v) => {
        self.eat(Token::Seq);
        let e3 = self.statement();

        let func = Expr::Func(Some(to_box(v.clone())), to_box(body.clone()), params);

        Expr::Decl(Dec::DConst, to_box(v), to_box(func), to_box(e3))
      },
      None => {
        Expr::Func(None, to_box(body.clone()), params)
      }
    }
  }

  fn parse_if(&mut self) -> Expr {
    self.eat(Token::If);
    let e1 = self.binop_expr();
    let e2 = self.statement();
    let e3 = self.statement();
    return self.ternary(e1, e2, e3);
  }

  fn factor(&mut self) -> Expr {
    match self.current_token.clone() {
      Token::Int(n) => {
        self.eat(Token::Int(n.clone()));
        return Expr::Int(n);
      },
      Token::Bool(b) => {
        self.eat(Token::Bool(b.clone()));
        return Expr::Bool(b);
      },
      Token::Var(s) => {
        self.eat(Token::Var(s.clone()));

        // fn call rule
        if self.current_token == Token::LParen {
          self.eat(Token::LParen);
          let params = self.parse_fn_params();
          self.eat(Token::RParen);

          return Expr::FnCall(to_box(Expr::Var(s)), params);
        }

        return Expr::Var(s);
      },
      Token::FnDecl => {
        return self.parse_fn();
      },
      Token::LParen => {
        self.eat(Token::LParen);
        let node = self.statement();
        self.eat(Token::RParen);
        return node;
      },
      Token::LBracket => {
        self.eat(Token::LBracket);
        let node = self.block();
        self.eat(Token::RBracket);
        return node;
      },
      Token::Not => {
        self.eat(Token::Not);
        return Expr::Uop(UnOp::Not, to_box(self.factor()));
      },
      Token::Minus => {
        self.eat(Token::Minus);
        return Expr::Uop(UnOp::Neg, to_box(self.factor()));
      },
      _ => {
        debug!("invalid factor: {:?}", self.current_token);
        panic!();
      },
    }
  }

  pub fn term(&mut self) -> Expr {
    let mut node = self.factor();

    let mut op = self.current_token.clone();

    while op.is_term_op() {
      self.eat(op.clone());
      let right_node = self.term();

      node = match op {
        Token::Times => self.binop(BinOp::Times, node, right_node),
        Token::Div => self.binop(BinOp::Div, node, right_node),
        _ => panic!(),
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn binop_expr(&mut self) -> Expr {
    let mut node = self.term();

    let mut op = self.current_token.clone();

    while op.is_expr_op() {
      debug!("expr looping on op {:?}", op);
      self.eat(op.clone());

      let right_node = self.term();

      node = match op {
        Token::Plus => self.binop(BinOp::Plus, node, right_node),
        Token::Minus => self.binop(BinOp::Minus, node, right_node),
        Token::Eq => self.binop(BinOp::Eq, node, right_node),
        Token::Ne => self.binop(BinOp::Ne, node, right_node),
        Token::Leq => self.binop(BinOp::Leq, node, right_node),
        Token::Geq => self.binop(BinOp::Geq, node, right_node),
        Token::Lt => self.binop(BinOp::Lt, node, right_node),
        Token::Gt => self.binop(BinOp::Gt, node, right_node),
        Token::And => self.binop(BinOp::And, node, right_node),
        Token::Or => self.binop(BinOp::Or, node, right_node),
        Token::Mod => self.binop(BinOp::Mod, node, right_node),
        Token::Assign => self.binop(BinOp::Assign, node, right_node),
        _ => panic!(),
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn statement(&mut self) -> Expr {
    if self.current_token == Token::Let {
      return self.parse_let();
    } else if self.current_token == Token::VarDecl {
      return self.parse_var();
    } else if self.current_token == Token::If {
      return self.parse_if();
    } else if self.current_token == Token::Else {
      self.eat(Token::Else);
      return self.statement();
    }

    let mut node = self.binop_expr();
    let mut op = self.current_token.clone();

    while op.is_statement_op() {
      self.eat(op.clone());

      node = match op {
        Token::Ternary => {
          let e2 = self.block();
          self.eat(Token::Else);
          let e3 = self.statement();
          self.ternary(node, e2, e3)
        },
        _ => panic!()
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn block(&mut self) -> Expr {
    let mut node = self.statement();
    let mut op = self.current_token.clone();

    while op.is_block_op() {
      self.eat(op.clone());
      let e2 = self.statement();

      node = match op {
        Token::Seq => self.binop(BinOp::Seq, node, e2),
        _ => panic!()
      };

      op = self.current_token.clone();
    }

    node
  }

  pub fn program(&mut self) -> Expr {
    self.block()
  }
}

fn to_box(e: Expr) -> Box<Expr> {
  Box::new(e)
}

pub fn parse(input: &str) -> Expr {
  let mut parser = Parser::new(input.to_string());
  let expr = parser.program();

  debug!("parsed expr: {:#?}", expr);
  debug!("original: {:#?}", input);

  expr
}
<|endoftext|>


<commit_before>use token::Token;
use tokenizer::Tokenizer;
use ast::expression::Expression;
use ast::root::Root;
use ast::node::Node;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::comment::SassComment;
use error::{Result, SassError, ErrorKind};

pub struct Parser<'a> {
    pub tokenizer: Tokenizer<'a>,
}

impl<'a> Iterator for Parser<'a> {
    type Item = Result<Root>;

    fn next(&mut self) -> Option<Result<Root>> {
        let mut current_sass_rule = SassRule::new();
        let mut rule_stack = vec![];
        let mut ambiguous_holding_pen = vec![];

        while let Some(Ok(lexeme)) = self.tokenizer.next() {
            match lexeme.token {
                Token::String(ref s) if s.starts_with("$") => {
                    let variable_name = lexeme.clone();
                    // TODO: this better be a colon
                    self.tokenizer.next();
                    let variable_value = match Expression::parse(&mut self.tokenizer) {
                        Ok(e) => e,
                        Err(e) => return Some(Err(e)),
                    };
                    return Some(Ok(Root::Variable(
                        SassVariable {
                            name: variable_name,
                            value: variable_value
                        }
                    )))
                },
                Token::LeftCurlyBrace => {
                    current_sass_rule.selectors.extend_from_slice(&ambiguous_holding_pen);
                    ambiguous_holding_pen = vec![];
                    while let Some(Ok(lexeme)) = self.tokenizer.next() {
                        match lexeme.token {
                            Token::RightCurlyBrace => {
                                if rule_stack.is_empty() {
                                    return Some(Ok(Root::Rule(current_sass_rule)))
                                } else {
                                    let tmp_rule = current_sass_rule;
                                    current_sass_rule = rule_stack.pop().unwrap();
                                    current_sass_rule.children.push(Node::Rule(tmp_rule));
                                }
                            },
                            Token::LeftCurlyBrace => {
                                rule_stack.push(current_sass_rule);
                                current_sass_rule = SassRule::new();
                                current_sass_rule.selectors = ambiguous_holding_pen;
                                ambiguous_holding_pen = vec![];
                            },
                            Token::Colon => {
                                let value = match Expression::parse(&mut self.tokenizer) {
                                    Ok(e) => e,
                                    Err(e) => return Some(Err(e)),
                                };

                                let child = match ambiguous_holding_pen.pop() {
                                    Some(name_lexeme) => {
                                        match name_lexeme.token {
                                            Token::String(ref s) if s.starts_with("$") => {
                                                Node::Variable(
                                                    SassVariable {
                                                        name: name_lexeme.clone(),
                                                        value: value,
                                                    }
                                                )
                                            },
                                            Token::String(_) => {
                                                Node::Property(name_lexeme, value)
                                            },
                                            other => {
                                                return Some(Err(SassError {
                                                    offset: name_lexeme.offset.unwrap_or(0),
                                                    kind: ErrorKind::ParserError,
                                                    message: format!(
                                                        "Expected to have seen a property or variable name, instead saw {:?}", other
                                                    ),
                                                }))
                                            },
                                        }
                                    },
                                    None => {
                                        return Some(Err(SassError {
                                            offset: lexeme.offset.unwrap_or(0),
                                            kind: ErrorKind::ParserError,
                                            message: format!(
                                                "Expected to have seen a property or variable name, did not see any"
                                            ),
                                        }))
                                    },
                                };
                                current_sass_rule.children.push(child);
                            },
                            Token::Comma => {
                                // TODO: else return error
                                if let Some(Ok(after_comma)) = self.tokenizer.next() {
                                    ambiguous_holding_pen.push(after_comma);
                                }
                            },
                            Token::String(_) => {
                                match ambiguous_holding_pen.pop() {
                                    Some(held_lexeme) => {
                                        ambiguous_holding_pen.push(
                                            held_lexeme.combine(&lexeme)
                                        );
                                    },
                                    None => {
                                       ambiguous_holding_pen = vec![lexeme];
                                    },
                                }
                            },
                            Token::Comment(_) => {
                                current_sass_rule.children.push(
                                    Node::Comment(
                                        SassComment { content: lexeme }
                                    )
                                );
                            },
                            other => unreachable!("What is this??? {:?}", other),
                        }
                    }
                    return Some(Ok(Root::Rule(current_sass_rule)))
                },
                Token::Comma => {
                    current_sass_rule.selectors.extend_from_slice(&ambiguous_holding_pen);
                    ambiguous_holding_pen = vec![];
                },
                Token::Comment(_) => {
                    return Some(Ok(Root::Comment(SassComment { content: lexeme })))
                },
                _ => {
                    match ambiguous_holding_pen.pop() {
                        Some(held_lexeme) => {
                            ambiguous_holding_pen.push(
                                held_lexeme.combine(&lexeme)
                            );
                        },
                        None => {
                           ambiguous_holding_pen = vec![lexeme];
                        },
                    }
                }
            }
        }
        None
    }
}

impl<'a> Parser<'a> {
    pub fn new(text: &str) -> Parser {
        Parser {
            tokenizer: Tokenizer::new(&text),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::rule::SassRule;
    use sass::comment::SassComment;
    use sass::variable::SassVariable;
    use ast::expression::Expression;
    use ast::root::Root;
    use ast::node::Node;
    use token::{Token, Lexeme};

    #[test]
    fn it_returns_none_for_empty_string() {
        let mut parser = Parser::new("");
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_a_rule() {
        let mut parser = Parser::new("a { color: blue; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![Lexeme { token: Token::String("a".into()), offset: Some(0) }],
                children: vec![Node::Property(
                    Lexeme { token: Token::String("color".into()), offset: Some(4) },
                    Expression::String(
                        Lexeme { token: Token::String("blue".into()), offset: Some(11) }
                    ),
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_nested_rules() {
        let mut parser = Parser::new("div { span img, span a { color: blue; } }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![Lexeme { token: Token::String("div".into()), offset: Some(0) }],
                children: vec![Node::Rule(
                    SassRule {
                        selectors: vec![
                            Lexeme {
                                token: Token::String("span img".into()),
                                offset: Some(6)
                            },
                            Lexeme {
                                token: Token::String("span a".into()),
                                offset: Some(16)
                            },
                        ],
                        children: vec![Node::Property(
                            Lexeme { token: Token::String("color".into()), offset: Some(25) },
                            Expression::String(
                                Lexeme { token: Token::String("blue".into()), offset: Some(32) }
                            ),
                        )],
                    }
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_rules_with_multiple_selectors() {
        let mut parser = Parser::new("a, b c { color: red; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![
                    Lexeme { token: Token::String("a".into()), offset: Some(0) },
                    Lexeme { token: Token::String("b c".into()), offset: Some(3) },
                ],
                children: vec![Node::Property(
                    Lexeme { token: Token::String("color".into()), offset: Some(9) },
                    Expression::String(
                        Lexeme { token: Token::String("red".into()), offset: Some(16) }
                    ),
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_variable_setting_statements() {
        let mut parser = Parser::new("$color: red;");
        assert_eq!(parser.next(), Some(Ok(Root::Variable(SassVariable {
            name: Lexeme { token: Token::String("$color".into()), offset: Some(0) },
            value: Expression::String(
                Lexeme { token: Token::String("red".into()), offset: Some(8) }
            ),
        }))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_variables_set_within_rules() {
        let mut parser = Parser::new("a { $foo: red; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![
                    Lexeme { token: Token::String("a".into()), offset: Some(0) },
                ],
                children: vec![Node::Variable(SassVariable {
                    name: Lexeme { token: Token::String("$foo".into()), offset: Some(4) },
                    value: Expression::String(
                        Lexeme { token: Token::String("red".into()), offset: Some(10) }
                    ),
                })],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_a_comment() {
        let mut parser = Parser::new("/* hi */");
        assert_eq!(parser.next(), Some(Ok(Root::Comment(SassComment {
            content: Lexeme { token: Token::Comment("/* hi */".into()), offset: Some(0) },
        }))));
        assert_eq!(parser.next(), None);
    }
}
<commit_msg>Put everything in the holding pen<commit_after>use token::Token;
use tokenizer::Tokenizer;
use ast::expression::Expression;
use ast::root::Root;
use ast::node::Node;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::comment::SassComment;
use error::{Result, SassError, ErrorKind};

pub struct Parser<'a> {
    pub tokenizer: Tokenizer<'a>,
}

impl<'a> Iterator for Parser<'a> {
    type Item = Result<Root>;

    fn next(&mut self) -> Option<Result<Root>> {
        let mut current_sass_rule = SassRule::new();
        let mut rule_stack = vec![];
        let mut ambiguous_holding_pen = vec![];

        while let Some(Ok(lexeme)) = self.tokenizer.next() {
            match lexeme.token {
                Token::String(ref s) if s.starts_with("$") => {
                    let variable_name = lexeme.clone();
                    // TODO: this better be a colon
                    self.tokenizer.next();
                    let variable_value = match Expression::parse(&mut self.tokenizer) {
                        Ok(e) => e,
                        Err(e) => return Some(Err(e)),
                    };
                    return Some(Ok(Root::Variable(
                        SassVariable {
                            name: variable_name,
                            value: variable_value
                        }
                    )))
                },
                Token::LeftCurlyBrace => {
                    current_sass_rule.selectors.extend_from_slice(&ambiguous_holding_pen);
                    ambiguous_holding_pen = vec![];
                    while let Some(Ok(lexeme)) = self.tokenizer.next() {
                        match lexeme.token {
                            Token::RightCurlyBrace => {
                                if rule_stack.is_empty() {
                                    return Some(Ok(Root::Rule(current_sass_rule)))
                                } else {
                                    let tmp_rule = current_sass_rule;
                                    current_sass_rule = rule_stack.pop().unwrap();
                                    current_sass_rule.children.push(Node::Rule(tmp_rule));
                                }
                            },
                            Token::LeftCurlyBrace => {
                                rule_stack.push(current_sass_rule);
                                current_sass_rule = SassRule::new();
                                current_sass_rule.selectors = ambiguous_holding_pen;
                                ambiguous_holding_pen = vec![];
                            },
                            Token::Colon => {
                                let value = match Expression::parse(&mut self.tokenizer) {
                                    Ok(e) => e,
                                    Err(e) => return Some(Err(e)),
                                };

                                let child = match ambiguous_holding_pen.pop() {
                                    Some(name_lexeme) => {
                                        match name_lexeme.token {
                                            Token::String(ref s) if s.starts_with("$") => {
                                                Node::Variable(
                                                    SassVariable {
                                                        name: name_lexeme.clone(),
                                                        value: value,
                                                    }
                                                )
                                            },
                                            Token::String(_) => {
                                                Node::Property(name_lexeme, value)
                                            },
                                            other => {
                                                return Some(Err(SassError {
                                                    offset: name_lexeme.offset.unwrap_or(0),
                                                    kind: ErrorKind::ParserError,
                                                    message: format!(
                                                        "Expected to have seen a property or variable name, instead saw {:?}", other
                                                    ),
                                                }))
                                            },
                                        }
                                    },
                                    None => {
                                        return Some(Err(SassError {
                                            offset: lexeme.offset.unwrap_or(0),
                                            kind: ErrorKind::ParserError,
                                            message: format!(
                                                "Expected to have seen a property or variable name, did not see any"
                                            ),
                                        }))
                                    },
                                };
                                current_sass_rule.children.push(child);
                            },
                            Token::Comma => {
                                // TODO: else return error
                                if let Some(Ok(after_comma)) = self.tokenizer.next() {
                                    ambiguous_holding_pen.push(after_comma);
                                }
                            },
                            Token::Comment(_) => {
                                current_sass_rule.children.push(
                                    Node::Comment(
                                        SassComment { content: lexeme }
                                    )
                                );
                            },
                            _ => {
                                match ambiguous_holding_pen.pop() {
                                    Some(held_lexeme) => {
                                        ambiguous_holding_pen.push(
                                            held_lexeme.combine(&lexeme)
                                        );
                                    },
                                    None => {
                                       ambiguous_holding_pen = vec![lexeme];
                                    },
                                }
                            },
                        }
                    }
                    return Some(Ok(Root::Rule(current_sass_rule)))
                },
                Token::Comma => {
                    current_sass_rule.selectors.extend_from_slice(&ambiguous_holding_pen);
                    ambiguous_holding_pen = vec![];
                },
                Token::Comment(_) => {
                    return Some(Ok(Root::Comment(SassComment { content: lexeme })))
                },
                _ => {
                    match ambiguous_holding_pen.pop() {
                        Some(held_lexeme) => {
                            ambiguous_holding_pen.push(
                                held_lexeme.combine(&lexeme)
                            );
                        },
                        None => {
                           ambiguous_holding_pen = vec![lexeme];
                        },
                    }
                }
            }
        }
        None
    }
}

impl<'a> Parser<'a> {
    pub fn new(text: &str) -> Parser {
        Parser {
            tokenizer: Tokenizer::new(&text),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::rule::SassRule;
    use sass::comment::SassComment;
    use sass::variable::SassVariable;
    use ast::expression::Expression;
    use ast::root::Root;
    use ast::node::Node;
    use token::{Token, Lexeme};

    #[test]
    fn it_returns_none_for_empty_string() {
        let mut parser = Parser::new("");
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_a_rule() {
        let mut parser = Parser::new("a { color: blue; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![Lexeme { token: Token::String("a".into()), offset: Some(0) }],
                children: vec![Node::Property(
                    Lexeme { token: Token::String("color".into()), offset: Some(4) },
                    Expression::String(
                        Lexeme { token: Token::String("blue".into()), offset: Some(11) }
                    ),
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_nested_rules() {
        let mut parser = Parser::new("div { span img, span a { color: blue; } }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![Lexeme { token: Token::String("div".into()), offset: Some(0) }],
                children: vec![Node::Rule(
                    SassRule {
                        selectors: vec![
                            Lexeme {
                                token: Token::String("span img".into()),
                                offset: Some(6)
                            },
                            Lexeme {
                                token: Token::String("span a".into()),
                                offset: Some(16)
                            },
                        ],
                        children: vec![Node::Property(
                            Lexeme { token: Token::String("color".into()), offset: Some(25) },
                            Expression::String(
                                Lexeme { token: Token::String("blue".into()), offset: Some(32) }
                            ),
                        )],
                    }
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_rules_with_multiple_selectors() {
        let mut parser = Parser::new("a, b c { color: red; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![
                    Lexeme { token: Token::String("a".into()), offset: Some(0) },
                    Lexeme { token: Token::String("b c".into()), offset: Some(3) },
                ],
                children: vec![Node::Property(
                    Lexeme { token: Token::String("color".into()), offset: Some(9) },
                    Expression::String(
                        Lexeme { token: Token::String("red".into()), offset: Some(16) }
                    ),
                )],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_variable_setting_statements() {
        let mut parser = Parser::new("$color: red;");
        assert_eq!(parser.next(), Some(Ok(Root::Variable(SassVariable {
            name: Lexeme { token: Token::String("$color".into()), offset: Some(0) },
            value: Expression::String(
                Lexeme { token: Token::String("red".into()), offset: Some(8) }
            ),
        }))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_variables_set_within_rules() {
        let mut parser = Parser::new("a { $foo: red; }");
        assert_eq!(parser.next(), Some(Ok(Root::Rule(
            SassRule {
                selectors: vec![
                    Lexeme { token: Token::String("a".into()), offset: Some(0) },
                ],
                children: vec![Node::Variable(SassVariable {
                    name: Lexeme { token: Token::String("$foo".into()), offset: Some(4) },
                    value: Expression::String(
                        Lexeme { token: Token::String("red".into()), offset: Some(10) }
                    ),
                })],
            }
        ))));
        assert_eq!(parser.next(), None);
    }

    #[test]
    fn it_returns_a_comment() {
        let mut parser = Parser::new("/* hi */");
        assert_eq!(parser.next(), Some(Ok(Root::Comment(SassComment {
            content: Lexeme { token: Token::Comment("/* hi */".into()), offset: Some(0) },
        }))));
        assert_eq!(parser.next(), None);
    }
}
<|endoftext|>


<commit_before>use crate::ast;
use crate::lexer;
use crate::token;

#[derive(Debug)]
pub struct Parser {
    lexer: lexer::Lexer,
    current_token: token::Token,
    peek_token: token::Token,
    pub errors: Vec<String>,
}

impl Parser {
    fn new(mut lexer: lexer::Lexer) -> Self {
        let current_token = lexer.next_token();
        let peek_token = lexer.next_token();
        let errors = Vec::new();
        Self {
            lexer,
            current_token,
            peek_token,
            errors,
        }
    }

    fn next_token(&mut self) {
        self.current_token = self.peek_token.clone();
        self.peek_token = self.lexer.next_token();
    }

    pub fn parse_program(&mut self) -> Option<ast::Program> {
        let mut program = ast::Program {
            statements: Vec::new(),
        };
        while self.current_token.token_type != token::EOF {
            let statement = self.parse_statement();
            match statement {
                Some(stmt) => program.statements.push(stmt),
                _ => (), // Just ignore that case
            };
            self.next_token();
        }
        Some(program)
    }

    fn parse_statement(&mut self) -> Option<token::Statements> {
        match self.current_token.token_type.as_ref() {
            token::LET => match self.parse_let_statement() {
                Some(stmt) => Some(token::Statements::LetStatement(stmt)),
                _ => None,
            },
            _ => None,
        }
    }

    fn peek_error(&mut self, token: token::TokenType) {
        let message = format!(
            "expected next token to be {expected}, got {got} instead",
            expected = token,
            got = self.peek_token.token_type,
        );

        self.errors.push(message);
    }

    fn parse_let_statement(&mut self) -> Option<token::LetStatement> {
        let token = self.current_token.clone();

        if self.peek_token.token_type == token::IDENT {
            self.next_token();
        } else {
            self.peek_error(token::IDENT.to_string());
            return None;
        }

        let name = token::Identifier {
            token: self.current_token.clone(),
            value: self.current_token.literal.clone(),
        };

        if self.peek_token.token_type == token::ASSIGN {
            self.next_token();
        } else {
            self.peek_error(token::ASSIGN.to_string());
            return None;
        }

        // TODO: It's a fragile design for now, this code might hang if we don't
        // have a terminating semicolon and next token is token::EOF
        // in this case we'll enter an infinite loop.
        // Doesn't next_token() protect us from this? Apparently - not.
        while !(self.current_token.token_type == token::SEMICOLON) {
            self.next_token() // skip to next statement in our program
        }

        Some(token::LetStatement {
            token,
            name,
            value: "dumb".to_string(),
        })
    }
}

#[cfg(test)]
mod tests {
    use crate::ast::Node;
    use crate::lexer;
    use crate::parser::Parser;
    use crate::token::Statements;

    #[test]
    fn test_let_statements() {
        let input = r###"
          let x = 5;
          let y = 10;
          let bebe = 101010;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 3);

        let expected = vec!["x".to_string(), "y".to_string(), "bebe".to_string()];

        program
            .statements
            .into_iter()
            .zip(expected.into_iter())
            .for_each(|(statement, expected_identifier)| {
                assert_eq!(statement.token_literal(), "let");

                let let_statement = match statement {
                    Statements::LetStatement(statement) => statement,
                    _ => panic!("I didn't expected anything besides `let` statement"),
                };

                assert_eq!(let_statement.name.value, expected_identifier);

                assert_eq!(let_statement.name.token_literal(), expected_identifier);
            });
    }

    #[test]
    fn test_broken_let_statements_and_check_if_errors_appear() {
        let input = r###"
          let x = 5;
          let y = 10;
          let bebe 101010;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            for error in parser.errors {
                assert_eq!(
                    "parser error: expected next token to be =, got INT instead",
                    format!("parser error: {}", error)
                );
            }
        }
    }

    #[test]
    fn test_return_statement() {
        let input = r###"
          return 1;
          return 111;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 2);

        let expected = vec!["1".to_string(), "111".to_string()];

        program
            .statements
            .into_iter()
            .zip(expected.into_iter())
            .for_each(|(statement, expected_identifier)| {
                assert_eq!(statement.token_literal(), "return");

                let return_statement = match statement {
                    Statements::ReturnStatement(statement) => statement,
                    _ => panic!("I didn't expected anything besides `return` statement"),
                };
            });
    }
}
<commit_msg>basic parser for return statement<commit_after>use crate::ast;
use crate::lexer;
use crate::token;

#[derive(Debug)]
pub struct Parser {
    lexer: lexer::Lexer,
    current_token: token::Token,
    peek_token: token::Token,
    pub errors: Vec<String>,
}

impl Parser {
    fn new(mut lexer: lexer::Lexer) -> Self {
        let current_token = lexer.next_token();
        let peek_token = lexer.next_token();
        let errors = Vec::new();
        Self {
            lexer,
            current_token,
            peek_token,
            errors,
        }
    }

    fn next_token(&mut self) {
        self.current_token = self.peek_token.clone();
        self.peek_token = self.lexer.next_token();
    }

    pub fn parse_program(&mut self) -> Option<ast::Program> {
        let mut program = ast::Program {
            statements: Vec::new(),
        };
        while self.current_token.token_type != token::EOF {
            let statement = self.parse_statement();
            match statement {
                Some(stmt) => program.statements.push(stmt),
                _ => (), // Just ignore that case
            };
            self.next_token();
        }
        Some(program)
    }

    fn parse_statement(&mut self) -> Option<token::Statements> {
        match self.current_token.token_type.as_ref() {
            token::LET => match self.parse_let_statement() {
                Some(stmt) => Some(token::Statements::LetStatement(stmt)),
                _ => None,
            },
            token::RETURN => match self.parse_return_statement() {
                Some(stmt) => Some(token::Statements::ReturnStatement(stmt)),
                _ => None,
            },
            _ => None,
        }
    }

    fn peek_error(&mut self, token: token::TokenType) {
        let message = format!(
            "expected next token to be {expected}, got {got} instead",
            expected = token,
            got = self.peek_token.token_type,
        );

        self.errors.push(message);
    }

    fn parse_let_statement(&mut self) -> Option<token::LetStatement> {
        let token = self.current_token.clone();

        if self.peek_token.token_type == token::IDENT {
            self.next_token();
        } else {
            self.peek_error(token::IDENT.to_string());
            return None;
        }

        let name = token::Identifier {
            token: self.current_token.clone(),
            value: self.current_token.literal.clone(),
        };

        if self.peek_token.token_type == token::ASSIGN {
            self.next_token();
        } else {
            self.peek_error(token::ASSIGN.to_string());
            return None;
        }

        // TODO: It's a fragile design for now, this code might hang if we don't
        // have a terminating semicolon and next token is token::EOF
        // in this case we'll enter an infinite loop.
        // Doesn't next_token() protect us from this? Apparently - not.
        while !(self.current_token.token_type == token::SEMICOLON) {
            self.next_token(); // skip to next statement in our program
        }

        Some(token::LetStatement {
            token,
            name,
            value: "dumb".to_string(),
        })
    }

    fn parse_return_statement(&mut self) -> Option<token::ReturnStatement> {
        let statement = token::ReturnStatement {
            token: self.current_token.clone(),
            return_value: "dumb".to_string(), // How to better describe expression?
        };

        self.next_token();

        while !(self.peek_token.token_type == token::SEMICOLON) {
            self.next_token(); // skip everything till `;` for now
        }

        Some(statement)
    }
}

#[cfg(test)]
mod tests {
    use crate::ast::Node;
    use crate::lexer;
    use crate::parser::Parser;
    use crate::token::Statements;

    #[test]
    fn test_let_statements() {
        let input = r###"
          let x = 5;
          let y = 10;
          let bebe = 101010;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 3);

        let expected = vec!["x".to_string(), "y".to_string(), "bebe".to_string()];

        program
            .statements
            .into_iter()
            .zip(expected.into_iter())
            .for_each(|(statement, expected_identifier)| {
                assert_eq!(statement.token_literal(), "let");

                let let_statement = match statement {
                    Statements::LetStatement(statement) => statement,
                    _ => panic!("I didn't expected anything besides `let` statement"),
                };

                assert_eq!(let_statement.name.value, expected_identifier);

                assert_eq!(let_statement.name.token_literal(), expected_identifier);
            });
    }

    #[test]
    fn test_broken_let_statements_and_check_if_errors_appear() {
        let input = r###"
          let x = 5;
          let y = 10;
          let bebe 101010;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            for error in parser.errors {
                assert_eq!(
                    "parser error: expected next token to be =, got INT instead",
                    format!("parser error: {}", error)
                );
            }
        }
    }

    #[test]
    fn test_return_statement() {
        let input = r###"
          return 1;
          return 111;
        "###
        .to_string();

        let lexer = lexer::Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let program = match parser.parse_program() {
            Some(program) => program,
            None => panic!("Could not parse program"),
        };

        // We would like to accumulate every error in program
        // and later render them to user.
        if !parser.errors.is_empty() {
            println!("Parser encountered {} errors", parser.errors.len());
            for error in parser.errors {
                println!("parser error: {}", error);
            }
            panic!("A few parsing error encountered, see them above.");
        }

        assert_eq!(program.statements.len(), 2);

        let expected = vec!["1".to_string(), "111".to_string()];

        program
            .statements
            .into_iter()
            .zip(expected.into_iter())
            .for_each(|(statement, expected_identifier)| {
                assert_eq!(statement.token_literal(), "return");

                let return_statement = match statement {
                    Statements::ReturnStatement(statement) => statement,
                    _ => panic!("I didn't expected anything besides `return` statement"),
                };
            });
    }
}
<|endoftext|>