<commit_before>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Joseph Crail <jbcrail@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#[cfg(unix)]
use super::libc;
use std::env;
use std::fs;
use std::io::{Error, ErrorKind, Result};
use std::path::{Component, Path, PathBuf};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CanonicalizeMode {
    None,
    Normal,
    Existing,
    Missing,
}

fn resolve<P: AsRef<Path>>(original: P) -> Result<PathBuf> {
    const MAX_LINKS_FOLLOWED: u32 = 255;
    let mut followed = 0;
    let mut result = original.as_ref().to_path_buf();
    loop {
        if followed == MAX_LINKS_FOLLOWED {
            return Err(Error::new(ErrorKind::InvalidInput, "maximum links followed"));
        }

        match fs::symlink_metadata(&result) {
            Err(e) => return Err(e),
            Ok(ref m) if !m.file_type().is_symlink() => break,
            Ok(..) => {
                followed += 1;
                match fs::read_link(&result) {
                    Ok(path) => {
                        result.pop();
                        result.push(path);
                    },
                    Err(e) => {
                        return Err(e);
                    }
                }
            }
        }
    }
    Ok(result)
}

pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> Result<PathBuf> {
    // Create an absolute path
    let original = original.as_ref();
    let original = if original.is_absolute() {
        original.to_path_buf()
    } else {
        env::current_dir().unwrap().join(original)
    };

    let mut result = PathBuf::new();
    let mut parts = vec!();

    // Split path by directory separator; add prefix (Windows-only) and root
    // directory to final path buffer; add remaining parts to temporary
    // vector for canonicalization.
    for part in original.components() {
        match part {
            Component::Prefix(_) | Component::RootDir => {
                result.push(part.as_os_str());
            },
            Component::CurDir => {},
            Component::ParentDir => {
                parts.pop();
            },
            Component::Normal(_) => {
                parts.push(part.as_os_str());
            }
        }
    }

    // Resolve the symlinks where possible
    if !parts.is_empty() {
        for part in parts[..parts.len()-1].iter() {
            result.push(part);

            if can_mode == CanonicalizeMode::None {
                continue;
            }

            match resolve(&result) {
                Err(e) => match can_mode {
                    CanonicalizeMode::Missing => continue,
                    _ => return Err(e)
                },
                Ok(path) => {
                    result.pop();
                    result.push(path);
                }
            }
        }

        result.push(parts.last().unwrap());

        match resolve(&result) {
            Err(e) => { if can_mode == CanonicalizeMode::Existing { return Err(e); } },
            Ok(path) => {
                result.pop();
                result.push(path);
            }
        }
    }
    Ok(result)
}

#[cfg(unix)]
pub fn is_stdin_interactive() -> bool {
    unsafe { libc::isatty(libc::STDIN_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdin_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stdout_interactive() -> bool {
    unsafe { libc::isatty(libc::STDOUT_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdout_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stderr_interactive() -> bool {
    unsafe { libc::isatty(libc::STDERR_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stderr_interactive() -> bool {
    false
}
<commit_msg>uucore::fs: add `fn resolve_relative_path`<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Joseph Crail <jbcrail@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

#[cfg(unix)]
use super::libc;
use std::env;
use std::fs;
use std::io::{Error, ErrorKind};
use std::io::Result as IOResult;
use std::path::{Component, Path, PathBuf};
use std::borrow::Cow;

#[cfg(unix)]
pub fn resolve_relative_path<'a>(path: &'a Path) -> Cow<'a, Path> {
    if path.is_absolute() {
        return path.into();
    }
    let mut result = env::current_dir().unwrap_or(PathBuf::from("/"));
    for comp in path.components() {
        match comp {
            Component::ParentDir => {
                result.pop();
            }
            Component::CurDir => (),
            Component::Normal(s) => result.push(s),
            _ => unreachable!(),
        }
    }
    result.into()
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CanonicalizeMode {
    None,
    Normal,
    Existing,
    Missing,
}

fn resolve<P: AsRef<Path>>(original: P) -> IOResult<PathBuf> {
    const MAX_LINKS_FOLLOWED: u32 = 255;
    let mut followed = 0;
    let mut result = original.as_ref().to_path_buf();
    loop {
        if followed == MAX_LINKS_FOLLOWED {
            return Err(Error::new(ErrorKind::InvalidInput, "maximum links followed"));
        }

        match fs::symlink_metadata(&result) {
            Err(e) => return Err(e),
            Ok(ref m) if !m.file_type().is_symlink() => break,
            Ok(..) => {
                followed += 1;
                match fs::read_link(&result) {
                    Ok(path) => {
                        result.pop();
                        result.push(path);
                    }
                    Err(e) => {
                        return Err(e);
                    }
                }
            }
        }
    }
    Ok(result)
}

pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> IOResult<PathBuf> {
    // Create an absolute path
    let original = original.as_ref();
    let original = if original.is_absolute() {
        original.to_path_buf()
    } else {
        env::current_dir().unwrap().join(original)
    };

    let mut result = PathBuf::new();
    let mut parts = vec![];

    // Split path by directory separator; add prefix (Windows-only) and root
    // directory to final path buffer; add remaining parts to temporary
    // vector for canonicalization.
    for part in original.components() {
        match part {
            Component::Prefix(_) |
            Component::RootDir => {
                result.push(part.as_os_str());
            }
            Component::CurDir => (),
            Component::ParentDir => {
                parts.pop();
            }
            Component::Normal(_) => {
                parts.push(part.as_os_str());
            }
        }
    }

    // Resolve the symlinks where possible
    if !parts.is_empty() {
        for part in parts[..parts.len() - 1].iter() {
            result.push(part);

            if can_mode == CanonicalizeMode::None {
                continue;
            }

            match resolve(&result) {
                Err(e) => {
                    match can_mode {
                        CanonicalizeMode::Missing => continue,
                        _ => return Err(e),
                    }
                }
                Ok(path) => {
                    result.pop();
                    result.push(path);
                }
            }
        }

        result.push(parts.last().unwrap());

        match resolve(&result) {
            Err(e) => {
                if can_mode == CanonicalizeMode::Existing {
                    return Err(e);
                }
            }
            Ok(path) => {
                result.pop();
                result.push(path);
            }
        }
    }
    Ok(result)
}

#[cfg(unix)]
pub fn is_stdin_interactive() -> bool {
    unsafe { libc::isatty(libc::STDIN_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdin_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stdout_interactive() -> bool {
    unsafe { libc::isatty(libc::STDOUT_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdout_interactive() -> bool {
    false
}

#[cfg(unix)]
pub fn is_stderr_interactive() -> bool {
    unsafe { libc::isatty(libc::STDERR_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stderr_interactive() -> bool {
    false
}
<|endoftext|>


<commit_before>use game::{Game, View, ViewAction};
use game::data::Rectangle;
use game::gfx::{CopySprite, Sprite};
use data::load_character;
use sdl2::pixels::Color;
use sdl2::render::Renderer;
use sdl2::rect::Point;
use conv::prelude::*;
use chrono::*;

const PLAYER_SPEED: f64 = 150.0;
const CHARACTER_W: f64 = 56.0;
const CHARACTER_H: f64 = 43.0;

const TERRAIN_W: f64 = 100.0;
const TERRAIN_H: f64 = 50.0;

const TILES_W: usize = 32;
const TILES_H: usize = 20;

#[derive(Clone)]
struct Background {
  pos: f64,
  sprite: Sprite,
}

impl Background {
  fn render(&mut self, renderer: &mut Renderer) {
    let size = self.sprite.size();

    let (window_w, window_h) = renderer.output_size().unwrap();
    let scale = window_h as f64 / size.1;
    renderer.copy_sprite(&self.sprite, Rectangle {
      x: 0.0,
      y: 0.0,
      w: size.0,
      h: window_h as f64,
    })
  }
}

#[derive(Clone, Copy)]
enum CharacterFrame {
  Down = 0,
  DownLeft = 1,
  Left = 2,
  UpLeft = 3,
  Up = 4,
  UpRight = 5,
  Right = 6,
  DownRight = 7
}

#[derive(Clone, Copy)]
enum TerrainFrame {
  Sand = 0,
  Grass = 1,
  Water = 2,
  Wood = 3,
}

struct Character {
  rect: Rectangle,
  sprites: Vec<Sprite>,
  current: CharacterFrame,
}

struct TerrainTile {
  rect: Rectangle,
  terrain_sprites: Vec<Sprite>,
  current: TerrainFrame,
}

pub struct GameView {
  player: Character,
  tiles: Vec<TerrainTile>,
  background: Background,
}

impl GameView {
  pub fn new(game: &mut Game) -> GameView {
    let spritesheet = Sprite::load(&mut game.renderer, "assets/character.png").unwrap();
    let character_datapoints = load_character();
    let terrain_spritesheet = Sprite::load(&mut game.renderer, "assets/terrain.png").unwrap();
    let mut sprites = Vec::with_capacity(9);
    let mut terrain_sprites = Vec::with_capacity(TILES_W);
    let mut tiles = Vec::with_capacity(TILES_W * TILES_H * 2);

    for x in 0..3 {
      terrain_sprites.push(terrain_spritesheet.region(Rectangle {
        w: TERRAIN_W,
        h: TERRAIN_H,
        x: TERRAIN_W * x as f64,
        y: 0.0 as f64,
      }).unwrap());
    }

    for x in 0..8 {
      sprites.push(spritesheet.region(character_datapoints[x]).unwrap());
    }

    for x in 0..TILES_W {
      for y in 0..TILES_H {
        let x2: f64 = 100.0 * 1.5 as f64;
        let y2: f64 = 50.0 * 1.5 as f64;
        tiles.push(TerrainTile {
          rect: Rectangle {
            x: 100.0 * x as f64,
            y: 50.0 * y as f64,
            w: TERRAIN_W,
            h: TERRAIN_H,
          },
          terrain_sprites: terrain_sprites.clone(),
          current: TerrainFrame::Grass,
        });

        tiles.push(TerrainTile {
          rect: Rectangle {
            x: 100.0 * f64::value_from((x+1)).unwrap() - x2 as f64,
            y: 50.0 * f64::value_from((y+1)).unwrap() - y2 as f64,
            w: TERRAIN_W,
            h: TERRAIN_H,
          },
          terrain_sprites: terrain_sprites.clone(),
          current: TerrainFrame::Sand,
        });
      }
    }

    GameView {
      player: Character {
        rect: Rectangle {
          x: 64.0,
          y: 64.0,
          w: CHARACTER_W,
          h: CHARACTER_H,
        },
        sprites: sprites.clone(),
        current: CharacterFrame::Down,
      },

      tiles: tiles,

      background: Background {
        pos: 0.0,
        sprite: Sprite::load(&mut game.renderer, "assets/background.png").unwrap(),
      },
    }
  }
}

impl View for GameView {
  fn render(&mut self, game: &mut Game, elapsed: f64) -> ViewAction {
    if game.events.now.quit || game.events.now.key_escape == Some(true) {
      return ViewAction::Quit;
    }

    let diagonal = (game.events.key_up ^ game.events.key_down) && (game.events.key_left ^ game.events.key_right);
    let moved = if diagonal { 1.0 / 2.0f64.sqrt() } else { 1.0 } * PLAYER_SPEED * elapsed;
    let dx = match (game.events.key_left, game.events.key_right) {
      (true, true) | (false, false) => 0.0,
      (true, false) => -moved,
      (false, true) => moved,
    };

    let dy = match (game.events.key_up, game.events.key_down) {
      (true, true) | (false, false) => 0.0,
      (true, false) => -moved,
      (false, true) => moved,
    };

    self.player.rect.x += dx;
    self.player.rect.y += dy;

    let movable_region = Rectangle {
      x: 0.0,
      y: 0.0,
      w: game.output_size().0 * 0.70,
      h: game.output_size().1,
    };

    self.player.rect = self.player.rect.move_inside(movable_region).unwrap();
    self.player.current =
    if dx == 0.0 && dy < 0.0       { CharacterFrame::Up }
    else if dx > 0.0 && dy < 0.0   { CharacterFrame::UpRight }
    else if dx < 0.0 && dy < 0.0   { CharacterFrame::UpLeft }
    else if dx == 0.0 && dy == 0.0 { CharacterFrame::Down }
    else if dx > 0.0 && dy == 0.0  { CharacterFrame::Right }
    else if dx < 0.0 && dy == 0.0  { CharacterFrame::Left }
    else if dx == 0.0 && dy > 0.0  { CharacterFrame::Down }
    else if dx > 0.0 && dy > 0.0   { CharacterFrame::DownRight }
    else if dx < 0.0 && dy > 0.0   { CharacterFrame::DownLeft }
    else { unreachable!() };

    game.renderer.set_draw_color(Color::RGBA(120, 120, 120, 0));
    self.background.render(&mut game.renderer);
    game.renderer.clear();

    for x in 0..TILES_W {
      for y in 0..TILES_H {
        let index = x * TILES_H + y;
        game.renderer.copy_sprite(&self.tiles[index].terrain_sprites[self.tiles[index].current as usize], self.tiles[index].rect);
      }
    }

    match game.events.mouseClick {
      Some(m) => {
        game.renderer.set_draw_color(Color::RGBA(255, 0, 0, 0));
        game.renderer.draw_line(Point::new(m.0, m.1 ), Point::new(m.0-10, m.1));
      },
      None => {},
    }

    // player
    game.renderer.set_draw_color(Color::RGBA(119,119,119,0));
    game.renderer.copy_sprite(&self.player.sprites[self.player.current as usize], self.player.rect);

    ViewAction::None
  }
}
<commit_msg>Fix character running animation<commit_after>use game::{Game, View, ViewAction};
use game::data::Rectangle;
use game::gfx::{CopySprite, Sprite};
use data::load_character;
use sdl2::pixels::Color;
use sdl2::render::Renderer;
use sdl2::rect::Point;
use conv::prelude::*;
use chrono::*;

const PLAYER_SPEED: f64 = 150.0;
const CHARACTER_W: f64 = 56.0;
const CHARACTER_H: f64 = 43.0;

const TERRAIN_W: f64 = 100.0;
const TERRAIN_H: f64 = 50.0;

const TILES_W: usize = 32;
const TILES_H: usize = 20;

#[derive(Clone)]
struct Background {
  pos: f64,
  sprite: Sprite,
}

impl Background {
  fn render(&mut self, renderer: &mut Renderer) {
    let size = self.sprite.size();

    let (window_w, window_h) = renderer.output_size().unwrap();
    let scale = window_h as f64 / size.1;
    renderer.copy_sprite(&self.sprite, Rectangle {
      x: 0.0,
      y: 0.0,
      w: size.0,
      h: window_h as f64,
    })
  }
}

#[derive(Clone, Copy)]
enum CharacterFrame {
  Still = 0,
  Right = 1,
  UpRight = 28,
  Up = 56,
  UpLeft = 84,
  Left = 108,
  DownLeft = 122,
  Down = 150,
  DownRight = 178
}

#[derive(Clone, Copy)]
enum TerrainFrame {
  Sand = 0,
  Grass = 1,
  Water = 2,
  Wood = 3,
}

struct Character {
  rect: Rectangle,
  sprites: Vec<Sprite>,
  current: CharacterFrame,
  animIndex: u32
}

struct TerrainTile {
  rect: Rectangle,
  terrain_sprites: Vec<Sprite>,
  current: TerrainFrame,
}

pub struct GameView {
  player: Character,
  tiles: Vec<TerrainTile>,
  background: Background,
}

impl GameView {
  pub fn new(game: &mut Game) -> GameView {
    let spritesheet = Sprite::load(&mut game.renderer, "assets/character.png").unwrap();
    let character_datapoints = load_character();
    let terrain_spritesheet = Sprite::load(&mut game.renderer, "assets/terrain.png").unwrap();
    let mut sprites = Vec::with_capacity(256);
    let mut terrain_sprites = Vec::with_capacity(TILES_W);
    let mut tiles = Vec::with_capacity(TILES_W * TILES_H * 2);

    for x in 0..3 {
      terrain_sprites.push(terrain_spritesheet.region(Rectangle {
        w: TERRAIN_W,
        h: TERRAIN_H,
        x: TERRAIN_W * x as f64,
        y: 0.0 as f64,
      }).unwrap());
    }

    for x in 0..194 {
      sprites.push(spritesheet.region(character_datapoints[x]).unwrap());
    }

    for x in 0..TILES_W {
      for y in 0..TILES_H {
        let x2: f64 = 100.0 * 1.5 as f64;
        let y2: f64 = 50.0 * 1.5 as f64;
        tiles.push(TerrainTile {
          rect: Rectangle {
            x: 100.0 * x as f64,
            y: 50.0 * y as f64,
            w: TERRAIN_W,
            h: TERRAIN_H,
          },
          terrain_sprites: terrain_sprites.clone(),
          current: TerrainFrame::Grass,
        });

        tiles.push(TerrainTile {
          rect: Rectangle {
            x: 100.0 * f64::value_from((x+1)).unwrap() - x2 as f64,
            y: 50.0 * f64::value_from((y+1)).unwrap() - y2 as f64,
            w: TERRAIN_W,
            h: TERRAIN_H,
          },
          terrain_sprites: terrain_sprites.clone(),
          current: TerrainFrame::Sand,
        });
      }
    }

    GameView {
      player: Character {
        rect: Rectangle {
          x: 64.0,
          y: 64.0,
          w: CHARACTER_W,
          h: CHARACTER_H,
        },
        sprites: sprites.clone(),
        current: CharacterFrame::Down,
        animIndex: 0
      },

      tiles: tiles,

      background: Background {
        pos: 0.0,
        sprite: Sprite::load(&mut game.renderer, "assets/background.png").unwrap(),
      },
    }
  }
}

impl View for GameView {
  fn render(&mut self, game: &mut Game, elapsed: f64) -> ViewAction {
    if game.events.now.quit || game.events.now.key_escape == Some(true) {
      return ViewAction::Quit;
    }

    let diagonal = (game.events.key_up ^ game.events.key_down) && (game.events.key_left ^ game.events.key_right);
    let moved = if diagonal { 1.0 / 2.0f64.sqrt() } else { 1.0 } * PLAYER_SPEED * elapsed;
    let dx = match (game.events.key_left, game.events.key_right) {
      (true, true) | (false, false) => 0.0,
      (true, false) => -moved,
      (false, true) => moved,
    };

    let dy = match (game.events.key_up, game.events.key_down) {
      (true, true) | (false, false) => 0.0,
      (true, false) => -moved,
      (false, true) => moved,
    };

    self.player.rect.x += dx;
    self.player.rect.y += dy;

    let movable_region = Rectangle {
      x: 0.0,
      y: 0.0,
      w: game.output_size().0 * 0.70,
      h: game.output_size().1,
    };

    self.player.rect = self.player.rect.move_inside(movable_region).unwrap();
    self.player.current =
    if dx == 0.0 && dy < 0.0       { CharacterFrame::Up }
    else if dx > 0.0 && dy < 0.0   { CharacterFrame::UpRight }
    else if dx < 0.0 && dy < 0.0   { CharacterFrame::UpLeft }
    else if dx == 0.0 && dy == 0.0 { CharacterFrame::Still }
    else if dx > 0.0 && dy == 0.0  { CharacterFrame::Right }
    else if dx < 0.0 && dy == 0.0  { CharacterFrame::Left }
    else if dx == 0.0 && dy > 0.0  { CharacterFrame::Down }
    else if dx > 0.0 && dy > 0.0   { CharacterFrame::DownRight }
    else if dx < 0.0 && dy > 0.0   { CharacterFrame::DownLeft }
    else { unreachable!() };

    game.renderer.set_draw_color(Color::RGBA(120, 120, 120, 0));
    self.background.render(&mut game.renderer);
    game.renderer.clear();

    for x in 0..TILES_W {
      for y in 0..TILES_H {
        let index = x * TILES_H + y;
        game.renderer.copy_sprite(&self.tiles[index].terrain_sprites[self.tiles[index].current as usize], self.tiles[index].rect);
      }
    }

    match game.events.mouseClick {
      Some(m) => {
        game.renderer.set_draw_color(Color::RGBA(255, 0, 0, 0));
        game.renderer.draw_line(Point::new(m.0, m.1 ), Point::new(m.0-10, m.1));
      },
      None => {},
    }

    // player
    game.renderer.set_draw_color(Color::RGBA(119,119,119,0));

    game.renderer.copy_sprite(&self.player.sprites[self.player.current as usize + self.player.animIndex as usize], self.player.rect);
    self.player.animIndex =
      if dx == 0.0 && dy == 0.0 { 0u32 }
      else if self.player.animIndex < 13u32 { self.player.animIndex + 1u32 }
      else { 0u32 };

    ViewAction::None
  }
}
<|endoftext|>


<commit_before>#![feature(question_mark)]
#[macro_use]
extern crate rustfbp;
extern crate capnp;

#[derive(Debug)]
struct Graph {
    nodes: Vec<(String, String)>,
    edges: Vec<(String, String, String, String, String, String)>,
    iips: Vec<(String, String, String, String)>,
    ext_in: Vec<(String, String, String, String)>,
    ext_out: Vec<(String, String, String, String)>,
}

#[derive(PartialEq, Debug)]
enum State {
    Break, Comp, Port, IIP,
    CompPort, CompPortBind, CompPortBindPort,
    CompPortExternal, CompPortExternalPort,
    PortExternal, PortExternalPort,
    IIPBind, IIPBindPort,
    ErrorS
}
use State::*;

enum Literal {
    Comp(String, String),
    Port(String, String),
    IIP(String),
    Bind, External,
}

component! {
    nucleus_flow_parser_semantic, contracts(fbp_graph, fbp_lexical, fbp_semantic_error)
    inputs(input: fbp_lexical),
    inputs_array(),
    outputs(output: fbp_graph, error: fbp_semantic_error),
    outputs_array(),
    option(),
    acc(),
    fn run(&mut self) -> Result<()> {
        let mut ip = try!(self.ports.recv("input"));
        let literal: fbp_lexical::Reader = try!(ip.get_root());
        let literal = try!(literal.which());

        match literal {
            fbp_lexical::Start(path) => {
                match handle_stream(&self)? {
                    Ok(graph) => { send_graph(&self, try!(path), &graph)? },
                    Err(errors) => {
                        let mut new_ip = IP::new();
                        {
                            let mut ip = new_ip.init_root::<fbp_semantic_error::Builder>();
                            ip.set_path(path?);
                            {
                                let mut nodes = ip.init_parsing(errors.len() as u32);
                                let mut i = 0;
                                for n in &errors {
                                    nodes.borrow().set(i, &n[..]);
                                    i += 1;
                                }
                            }
                        }
                        let _ = self.ports.send("error", new_ip);
                    },
                }
            }
            _ => { return Err(result::Error::Misc("bad stream".to_string())); },
        }
        Ok(())
    }
}

fn handle_stream(comp: &nucleus_flow_parser_semantic) -> Result<std::result::Result<Graph, Vec<String>>> {
    let mut state = Break;
    let mut stack: Vec<Literal> = vec![];
    let mut graph = Graph {
        nodes: vec![],
        edges: vec![],
        iips: vec![],
        ext_in: vec![],
        ext_out: vec![]
    };
    let mut errors: Vec<String> = vec![];
    let mut line: usize = 1;

    loop {

        let mut ip = comp.ports.recv("input")?;
        let literal: fbp_lexical::Reader = ip.get_root()?;
        let literal = literal.which()?;
        match literal {
            fbp_lexical::End(_) => {
                break;
            },
            fbp_lexical::Token(t) => {
                let token = t.which()?;
                match token {
                    fbp_lexical::token::Bind(_) => {
                        state = match state {
                            CompPort => { CompPortBind },
                            ErrorS => { ErrorS },
                            IIP => { IIPBind },
                            _ => {
                                errors.push(format!("line {} : -> found, one of {} expected", line, get_expected(&state)));
                                ErrorS
                            },
                        };
                    },
                    fbp_lexical::token::External(_) => {
                        state = match state {
                            CompPort => { CompPortExternal },
                            Port => { PortExternal },
                            ErrorS => { ErrorS },
                            _ => {
                                errors.push(format!("line {} : => found, one of {} expected", line, get_expected(&state)));
                                ErrorS
                            },
                        };
                    },
                    fbp_lexical::token::Port(port) => {
                        stack.push(Literal::Port(port.get_name()?.to_string(), port.get_selection()?.to_string()));
                        state = match state {
                            Comp => { CompPort },
                            CompPortBind => { CompPortBindPort },
                            CompPortExternal => {
                                let in_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let out_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let out_c = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                {
                                    let (in_p_n, _) = if let Literal::Port(n, s) = in_p { (n, s) } else { unreachable!() };
                                    let (out_c_n, _) = if let Literal::Comp(ref n, ref s) = out_c { (n, s) } else { unreachable!() };
                                    let (out_p_n, out_p_s) = if let Literal::Port(n, s) = out_p { (n, s) } else { unreachable!() };
                                    graph.ext_out.push((out_c_n.clone(), out_p_n, out_p_s, in_p_n));
                                }
                                CompPortExternalPort },
                            Break => { Port },
                            PortExternal => { PortExternalPort },
                            ErrorS => { ErrorS },
                            IIPBind => { IIPBindPort },
                            _ => {
                                errors.push(format!("line {} : Port {}[{}] found, one of {} expected", line, port.get_name()?, port.get_selection()?, get_expected(&state)));
                                ErrorS
                            },
                        };
                    },
                    fbp_lexical::token::Comp(comp) => {
                        if comp.get_sort()? != "" {
                            graph.nodes.push((comp.get_name()?.to_string(), comp.get_sort()?.to_string()));
                        }
                        stack.push(Literal::Comp(comp.get_name()?.to_string(), comp.get_sort()?.to_string()));
                        state = match state {
                            CompPortBindPort => {
                                let in_c = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let in_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let out_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let out_c = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                {
                                    let (in_c_n, _) = if let Literal::Comp(ref n, ref s) = in_c { (n, s) } else { unreachable!() };
                                    let (in_p_n, in_p_s) = if let Literal::Port(n, s) = in_p { (n, s) } else { unreachable!() };
                                    let (out_p_n, out_p_s) = if let Literal::Port(n, s) = out_p { (n, s) } else { unreachable!() };
                                    let (out_c_n, _) = if let Literal::Comp(n, s) = out_c { (n, s) } else { unreachable!() };
                                    graph.edges.push((out_c_n, out_p_n, out_p_s, in_p_n, in_p_s, in_c_n.clone()));
                                }
                                stack.push(in_c);
                                Comp
                            },
                            PortExternalPort => {
                                let in_c = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let in_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let out_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                {
                                    let (in_c_n, _) = if let Literal::Comp(ref n, ref s) = in_c { (n, s) } else { unreachable!() };
                                    let (in_p_n, in_p_s) = if let Literal::Port(n, s) = in_p { (n, s) } else { unreachable!() };
                                    let (out_p_n, out_p_s) = if let Literal::Port(n, s) = out_p { (n, s) } else { unreachable!() };
                                    graph.ext_in.push((out_p_n, in_p_n, in_p_s, in_c_n.clone()));
                                }
                                stack.push(in_c);
                                Comp
                            }
                            IIPBindPort => {
                                let in_c = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let in_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let iip = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                {
                                    let (in_c_n, _) = if let Literal::Comp(ref n, ref s) = in_c { (n, s) } else { unreachable!() };
                                    let (in_p_n, in_p_s) = if let Literal::Port(n, s) = in_p { (n, s) } else { unreachable!() };
                                    let iip = if let Literal::IIP(iip) = iip { iip } else { unreachable!() };
                                    graph.iips.push((iip, in_p_n, in_p_s, in_c_n.clone()));
                                }
                                stack.push(in_c);
                                Comp
                            }
                            Break => { Comp },
                            ErrorS => { stack = vec![stack.pop().ok_or(result::Error::Misc("stack problem".into()))?]; Comp },
                            _ => {
                                errors.push(format!("line {} : Comp {}({}) found, one of {} expected", line, comp.get_name()?, comp.get_sort()?, get_expected(&state)));
                                ErrorS
                            },
                        }
                    },
                    fbp_lexical::token::Iip(iip) => {
                        let iip = iip?;
                        stack.push(Literal::IIP(iip.to_string()));
                        state = match state {
                            ErrorS => { IIP },
                            Break => { IIP },
                            _ => {
                                errors.push(format!("line {} : IIP '{}' found, one of {} expected", line, iip, get_expected(&state)));
                                ErrorS
                            },
                        };
                    },
                    fbp_lexical::token::Break(_) => {
                        line += 1;
                        state = match state {
                            CompPortBind => { state },
                            IIPBind => { state },
                            Comp => { stack.clear(); Break },
                            CompPortExternalPort => { stack.clear(); Break },
                            Break => { Break },
                            ErrorS => { ErrorS },
                            _ => {
                                errors.push(format!("line {} : NewLine found, one of {} expected", line, get_expected(&state)));
                                ErrorS
                            },
                        };
                    }
                }
            },
            _ => { panic!("bad stream"); },
        }
    }
    if errors.len() > 0 {
        Ok(Err(errors))
    } else {
        Ok(Ok(graph))
    }
}

fn get_expected(state: &State) -> String {
    match *state {
        Break => { "[Component, Port, IIP, NewLine]".into() },
        Comp => { "[Port, NewLine]".into() },
        Port => { "[Component, ->, =>]".into() },
        IIP => { "[->]".into() },
        CompPort => { "[->, =>]".into() },
        CompPortBind => { "[Port]".into() },
        CompPortBindPort => { "[Component]".into() },
        CompPortExternal => { "[Port]".into() },
        CompPortExternalPort => { "[NewLine]".into() },
        PortExternal => { "[Port]".into() },
        PortExternalPort => { "[Component]".into() },
        IIPBind => { "[Port]".into() },
        IIPBindPort => { "[Component]".into() },
        ErrorS => { unreachable!() }
    }
}

fn send_graph(comp: &nucleus_flow_parser_semantic, path: &str, graph: &Graph) -> Result<()> {
    let mut new_ip = IP::new();
    {
        let mut ip = new_ip.init_root::<fbp_graph::Builder>();
        ip.set_path(path);
        {
            let mut nodes = ip.borrow().init_nodes(graph.nodes.len() as u32);
            let mut i = 0;
            for n in &graph.nodes {
                nodes.borrow().get(i).set_name(&n.0[..]);
                nodes.borrow().get(i).set_sort(&n.1[..]);
                i += 1;
            }
        }
        {
            let mut edges = ip.borrow().init_edges(graph.edges.len() as u32);
            let mut i = 0;
            for e in &graph.edges {
                edges.borrow().get(i).set_o_name(&e.0[..]);
                edges.borrow().get(i).set_o_port(&e.1[..]);
                edges.borrow().get(i).set_o_selection(&e.2[..]);
                edges.borrow().get(i).set_i_port(&e.3[..]);
                edges.borrow().get(i).set_i_selection(&e.4[..]);
                edges.borrow().get(i).set_i_name(&e.5[..]);
                i += 1;
            }
        }
        {
            let mut iips = ip.borrow().init_iips(graph.iips.len() as u32);
            let mut i = 0;
            for iip in &graph.iips {
                iips.borrow().get(i).set_iip(&iip.0[..]);
                iips.borrow().get(i).set_port(&iip.1[..]);
                iips.borrow().get(i).set_selection(&iip.2[..]);
                iips.borrow().get(i).set_comp(&iip.3[..]);
                i += 1;
            }
        }
        {
            let mut ext = ip.borrow().init_external_inputs(graph.ext_in.len() as u32);
            let mut i = 0;
            for e in &graph.ext_in {
                ext.borrow().get(i).set_name(&e.0[..]);
                ext.borrow().get(i).set_port(&e.1[..]);
                ext.borrow().get(i).set_selection(&e.2[..]);
                ext.borrow().get(i).set_comp(&e.3[..]);
                i += 1;
            }
        }
        {
            let mut ext = ip.borrow().init_external_outputs(graph.ext_out.len() as u32);
            let mut i = 0;
            for e in &graph.ext_out {
                ext.borrow().get(i).set_comp(&e.0[..]);
                ext.borrow().get(i).set_port(&e.1[..]);
                ext.borrow().get(i).set_selection(&e.2[..]);
                ext.borrow().get(i).set_name(&e.3[..]);
                i += 1;
            }
        }
    }
    let _ = comp.ports.send("output", new_ip);
    Ok(())
}
<commit_msg>Problem: parser errors a bit vague<commit_after>#![feature(question_mark)]
#[macro_use]
extern crate rustfbp;
extern crate capnp;

#[derive(Debug)]
struct Graph {
    nodes: Vec<(String, String)>,
    edges: Vec<(String, String, String, String, String, String)>,
    iips: Vec<(String, String, String, String)>,
    ext_in: Vec<(String, String, String, String)>,
    ext_out: Vec<(String, String, String, String)>,
}

#[derive(PartialEq, Debug)]
enum State {
    Break, Comp, Port, IIP,
    CompPort, CompPortBind, CompPortBindPort,
    CompPortExternal, CompPortExternalPort,
    PortExternal, PortExternalPort,
    IIPBind, IIPBindPort,
    ErrorS
}
use State::*;

enum Literal {
    Comp(String, String),
    Port(String, String),
    IIP(String),
    Bind, External,
}

component! {
    nucleus_flow_parser_semantic, contracts(fbp_graph, fbp_lexical, fbp_semantic_error)
    inputs(input: fbp_lexical),
    inputs_array(),
    outputs(output: fbp_graph, error: fbp_semantic_error),
    outputs_array(),
    option(),
    acc(),
    fn run(&mut self) -> Result<()> {
        let mut ip = try!(self.ports.recv("input"));
        let literal: fbp_lexical::Reader = try!(ip.get_root());
        let literal = try!(literal.which());

        match literal {
            fbp_lexical::Start(path) => {
                match handle_stream(&self)? {
                    Ok(graph) => { send_graph(&self, try!(path), &graph)? },
                    Err(errors) => {
                        let mut new_ip = IP::new();
                        {
                            let mut ip = new_ip.init_root::<fbp_semantic_error::Builder>();
                            ip.set_path(path?);
                            {
                                let mut nodes = ip.init_parsing(errors.len() as u32);
                                let mut i = 0;
                                for n in &errors {
                                    nodes.borrow().set(i, &n[..]);
                                    i += 1;
                                }
                            }
                        }
                        let _ = self.ports.send("error", new_ip);
                    },
                }
            }
            _ => { return Err(result::Error::Misc("bad stream".to_string())); },
        }
        Ok(())
    }
}

fn handle_stream(comp: &nucleus_flow_parser_semantic) -> Result<std::result::Result<Graph, Vec<String>>> {
    let mut state = Break;
    let mut stack: Vec<Literal> = vec![];
    let mut graph = Graph {
        nodes: vec![],
        edges: vec![],
        iips: vec![],
        ext_in: vec![],
        ext_out: vec![]
    };
    let mut errors: Vec<String> = vec![];
    let mut line: usize = 1;

    loop {

        let mut ip = comp.ports.recv("input")?;
        let literal: fbp_lexical::Reader = ip.get_root()?;
        let literal = literal.which()?;
        match literal {
            fbp_lexical::End(_) => {
                break;
            },
            fbp_lexical::Token(t) => {
                let token = t.which()?;
                match token {
                    fbp_lexical::token::Bind(_) => {
                        state = match state {
                            CompPort => { CompPortBind },
                            ErrorS => { ErrorS },
                            IIP => { IIPBind },
                            _ => {
                                errors.push(format!("line {} : Found a \"->\", when \"{}\" was expected.", line, get_expected(&state)));
                                ErrorS
                            },
                        };
                    },
                    fbp_lexical::token::External(_) => {
                        state = match state {
                            CompPort => { CompPortExternal },
                            Port => { PortExternal },
                            ErrorS => { ErrorS },
                            _ => {
                                errors.push(format!("line {} : Found a \"=>\", when \"{}\" was expected.", line, get_expected(&state)));
                                ErrorS
                            },
                        };
                    },
                    fbp_lexical::token::Port(port) => {
                        stack.push(Literal::Port(port.get_name()?.to_string(), port.get_selection()?.to_string()));
                        state = match state {
                            Comp => { CompPort },
                            CompPortBind => { CompPortBindPort },
                            CompPortExternal => {
                                let in_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let out_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let out_c = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                {
                                    let (in_p_n, _) = if let Literal::Port(n, s) = in_p { (n, s) } else { unreachable!() };
                                    let (out_c_n, _) = if let Literal::Comp(ref n, ref s) = out_c { (n, s) } else { unreachable!() };
                                    let (out_p_n, out_p_s) = if let Literal::Port(n, s) = out_p { (n, s) } else { unreachable!() };
                                    graph.ext_out.push((out_c_n.clone(), out_p_n, out_p_s, in_p_n));
                                }
                                CompPortExternalPort },
                            Break => { Port },
                            PortExternal => { PortExternalPort },
                            ErrorS => { ErrorS },
                            IIPBind => { IIPBindPort },
                            _ => {
                                errors.push(format!("line {} : Found port \"{}[{}]\", when \"{}\" was expected.", line, port.get_name()?, port.get_selection()?, get_expected(&state)));
                                ErrorS
                            },
                        };
                    },
                    fbp_lexical::token::Comp(comp) => {
                        if comp.get_sort()? != "" {
                            graph.nodes.push((comp.get_name()?.to_string(), comp.get_sort()?.to_string()));
                        }
                        stack.push(Literal::Comp(comp.get_name()?.to_string(), comp.get_sort()?.to_string()));
                        state = match state {
                            CompPortBindPort => {
                                let in_c = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let in_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let out_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let out_c = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                {
                                    let (in_c_n, _) = if let Literal::Comp(ref n, ref s) = in_c { (n, s) } else { unreachable!() };
                                    let (in_p_n, in_p_s) = if let Literal::Port(n, s) = in_p { (n, s) } else { unreachable!() };
                                    let (out_p_n, out_p_s) = if let Literal::Port(n, s) = out_p { (n, s) } else { unreachable!() };
                                    let (out_c_n, _) = if let Literal::Comp(n, s) = out_c { (n, s) } else { unreachable!() };
                                    graph.edges.push((out_c_n, out_p_n, out_p_s, in_p_n, in_p_s, in_c_n.clone()));
                                }
                                stack.push(in_c);
                                Comp
                            },
                            PortExternalPort => {
                                let in_c = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let in_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let out_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                {
                                    let (in_c_n, _) = if let Literal::Comp(ref n, ref s) = in_c { (n, s) } else { unreachable!() };
                                    let (in_p_n, in_p_s) = if let Literal::Port(n, s) = in_p { (n, s) } else { unreachable!() };
                                    let (out_p_n, out_p_s) = if let Literal::Port(n, s) = out_p { (n, s) } else { unreachable!() };
                                    graph.ext_in.push((out_p_n, in_p_n, in_p_s, in_c_n.clone()));
                                }
                                stack.push(in_c);
                                Comp
                            }
                            IIPBindPort => {
                                let in_c = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let in_p = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                let iip = stack.pop().ok_or(result::Error::Misc("stack problem".into()))?;
                                {
                                    let (in_c_n, _) = if let Literal::Comp(ref n, ref s) = in_c { (n, s) } else { unreachable!() };
                                    let (in_p_n, in_p_s) = if let Literal::Port(n, s) = in_p { (n, s) } else { unreachable!() };
                                    let iip = if let Literal::IIP(iip) = iip { iip } else { unreachable!() };
                                    graph.iips.push((iip, in_p_n, in_p_s, in_c_n.clone()));
                                }
                                stack.push(in_c);
                                Comp
                            }
                            Break => { Comp },
                            ErrorS => { stack = vec![stack.pop().ok_or(result::Error::Misc("stack problem".into()))?]; Comp },
                            _ => {
                                errors.push(format!("line {} : Found component \"{}({})\", when \"{}\" was expected.", line, comp.get_name()?, comp.get_sort()?, get_expected(&state)));
                                ErrorS
                            },
                        }
                    },
                    fbp_lexical::token::Iip(iip) => {
                        let iip = iip?;
                        stack.push(Literal::IIP(iip.to_string()));
                        state = match state {
                            ErrorS => { IIP },
                            Break => { IIP },
                            _ => {
                                errors.push(format!("line {} : Found an IIP \"{}\", when \"{}\" was expected.", line, iip, get_expected(&state)));
                                ErrorS
                            },
                        };
                    },
                    fbp_lexical::token::Break(_) => {
                        line += 1;
                        state = match state {
                            CompPortBind => { state },
                            IIPBind => { state },
                            Comp => { stack.clear(); Break },
                            CompPortExternalPort => { stack.clear(); Break },
                            Break => { Break },
                            ErrorS => { ErrorS },
                            _ => {
                                errors.push(format!("line {} : Found a \"\n\" or (new line), when \"{}\" was expected.", line, get_expected(&state)));
                                ErrorS
                            },
                        };
                    }
                }
            },
            _ => { panic!("bad stream"); },
        }
    }
    if errors.len() > 0 {
        Ok(Err(errors))
    } else {
        Ok(Ok(graph))
    }
}

fn get_expected(state: &State) -> String {
    match *state {
        Break => { "[Component, Port, IIP, NewLine]".into() },
        Comp => { "[Port, NewLine]".into() },
        Port => { "[Component, ->, =>]".into() },
        IIP => { "[->]".into() },
        CompPort => { "[->, =>]".into() },
        CompPortBind => { "[Port]".into() },
        CompPortBindPort => { "[Component]".into() },
        CompPortExternal => { "[Port]".into() },
        CompPortExternalPort => { "[NewLine]".into() },
        PortExternal => { "[Port]".into() },
        PortExternalPort => { "[Component]".into() },
        IIPBind => { "[Port]".into() },
        IIPBindPort => { "[Component]".into() },
        ErrorS => { unreachable!() }
    }
}

fn send_graph(comp: &nucleus_flow_parser_semantic, path: &str, graph: &Graph) -> Result<()> {
    let mut new_ip = IP::new();
    {
        let mut ip = new_ip.init_root::<fbp_graph::Builder>();
        ip.set_path(path);
        {
            let mut nodes = ip.borrow().init_nodes(graph.nodes.len() as u32);
            let mut i = 0;
            for n in &graph.nodes {
                nodes.borrow().get(i).set_name(&n.0[..]);
                nodes.borrow().get(i).set_sort(&n.1[..]);
                i += 1;
            }
        }
        {
            let mut edges = ip.borrow().init_edges(graph.edges.len() as u32);
            let mut i = 0;
            for e in &graph.edges {
                edges.borrow().get(i).set_o_name(&e.0[..]);
                edges.borrow().get(i).set_o_port(&e.1[..]);
                edges.borrow().get(i).set_o_selection(&e.2[..]);
                edges.borrow().get(i).set_i_port(&e.3[..]);
                edges.borrow().get(i).set_i_selection(&e.4[..]);
                edges.borrow().get(i).set_i_name(&e.5[..]);
                i += 1;
            }
        }
        {
            let mut iips = ip.borrow().init_iips(graph.iips.len() as u32);
            let mut i = 0;
            for iip in &graph.iips {
                iips.borrow().get(i).set_iip(&iip.0[..]);
                iips.borrow().get(i).set_port(&iip.1[..]);
                iips.borrow().get(i).set_selection(&iip.2[..]);
                iips.borrow().get(i).set_comp(&iip.3[..]);
                i += 1;
            }
        }
        {
            let mut ext = ip.borrow().init_external_inputs(graph.ext_in.len() as u32);
            let mut i = 0;
            for e in &graph.ext_in {
                ext.borrow().get(i).set_name(&e.0[..]);
                ext.borrow().get(i).set_port(&e.1[..]);
                ext.borrow().get(i).set_selection(&e.2[..]);
                ext.borrow().get(i).set_comp(&e.3[..]);
                i += 1;
            }
        }
        {
            let mut ext = ip.borrow().init_external_outputs(graph.ext_out.len() as u32);
            let mut i = 0;
            for e in &graph.ext_out {
                ext.borrow().get(i).set_comp(&e.0[..]);
                ext.borrow().get(i).set_port(&e.1[..]);
                ext.borrow().get(i).set_selection(&e.2[..]);
                ext.borrow().get(i).set_name(&e.3[..]);
                i += 1;
            }
        }
    }
    let _ = comp.ports.send("output", new_ip);
    Ok(())
}
<|endoftext|>


<commit_before>// {
//   Derived from : Bjoern Hoehrmann work
//   Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//   See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.

const UTF8_ACCEPT: u32 = 0;
const UTF8_REJECT: u32 = 1;

static UTF8D: &'static [u8] = &[
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
  8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
  0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
  0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
  0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
  1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
  1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
  1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
];

/*
    state UTF8_ACCEPT => initial state or decoding successful
    state UTF8_REJECT => error
    state other => intermediate states need more inputs
*/
#[inline]
pub fn decode_byte(state: u32, byte: u8, codep: &mut u32) -> u32 {
    let cp_type = u32::from(UTF8D[byte as usize]);

    *codep = if state != UTF8_ACCEPT {
        u32::from(byte & 0x3f) | (*codep << 6)
    } else {
        (0xff >> cp_type) & u32::from(byte)
    };

    u32::from(UTF8D[256 + (state * 16) as usize + cp_type as usize])
}

// }

#[inline]
pub fn is_codepoint_start(byte: u8) -> bool {
    if byte < 0x80 {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xE0 && byte <= 0xEC {
        return true;
    }

    if byte >= 0xED && byte <= 0xEF {
        return true;
    }

    if byte >= 0xF0 && byte <= 0xF4 {
        return true;
    }

    false
}

// return 0 on error, or the number of written bytes
pub fn encode(codepoint: u32, out: &mut [u8; 4]) -> usize {
    if codepoint < 0x80 {
        out[0] = codepoint as u8;
        return 1;
    }

    if codepoint < 0x800 {
        out[0] = 0xC0 | (codepoint >> 6) as u8;
        out[1] = 0x80 | (codepoint & 0x3F) as u8;
        return 2;
    }

    if codepoint < 0xFFFF {
        out[0] = 0xE0 | (codepoint >> 12) as u8;
        out[1] = 0x80 | (codepoint >> 6) as u8;
        out[2] = 0x80 | (codepoint & 0x3F) as u8;
        return 3;
    }

    if codepoint < 0x0010_FFFF {
        out[0] = 0xF0 | (codepoint >> 18) as u8;
        out[1] = 0x80 | (codepoint >> 12) as u8;
        out[2] = 0x80 | (codepoint >> 6) as u8;
        out[3] = 0x80 | (codepoint & 0x3F) as u8;
        return 4;
    }

    0
}

// TODO: change this with temporary (cp, offset, size) until from_offset
pub fn get_previous_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    //                 cp    size   offset
    let mut cp_info: [(char, usize, u64); 8] = [
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
    ];
    let mut nr_cpinfo = 0;

    // rewind up to 4 bytes
    // and decode forward / save offset
    let mut off = if from_offset > 4 { from_offset - 4 } else { 0 };
    while off < from_offset {
        let (cp, _, size) = get_codepoint(data, off);

        cp_info[nr_cpinfo] = (cp, size, off);
        nr_cpinfo += 1;

        off += size as u64;
    }

    if nr_cpinfo != 0 {
        cp_info[nr_cpinfo - 1].2
    } else {
        from_offset
    }
}

pub fn get_next_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    let (_, _, size) = get_codepoint(data, from_offset);
    from_offset + size as u64
}

pub fn get_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let mut state = 0;
    let mut codep = 0;
    let mut size = 0;

    for b in data.iter().skip(from_offset as usize) {
        size += 1;
        state = decode_byte(state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }

            UTF8_REJECT => {
                // decode error : invalid sequence
                codep = 0xfffd;
                size = 1; // force restart @ next byte
                break;
            }
            _ => {}
        }
    }

    // TODO return Result<(char, usize), status> -> state != 1|0 -> need mode data
    (::core::codec::text::u32_to_char(codep), from_offset, size)
}

pub fn get_prev_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let offset = get_previous_codepoint_start(data, from_offset);
    get_codepoint(data, offset)
}

#[test]
fn test_codec_encode() {
    let expect_cp: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    let mut mut_cp: [u8; 4] = [0x00, 0x00, 0x00, 0x00];

    let n = encode(0x20ac as u32, &mut mut_cp);
    assert_eq!(n, 3);
    assert_eq!(mut_cp, expect_cp);
}

#[test]
fn test_codec_decode() {
    use core::codec::text::u32_to_char;

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    let sequence: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    for b in &sequence {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence");
                break;
            }
            _ => {
                continue;
            }
        }
    }

    println!("decoded codepoint value {:x}", codep);
    let c = u32_to_char(codep);
    println!("decoded codepoint char {}", c);

    assert_eq!(codep, 0x20ac);
}

#[test]
fn test2_codec_decode() {
    let data: [u8; 27] = [
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0xac, 0xe2,
        0x82, 0x61, 0x0a, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0x61, 0x0a, 0x61, 0x0a,
    ];

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    for b in &data {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(state, *b, &mut codep);
        println!("state  '{}'", state);
        match state {
            UTF8_ACCEPT => {
                println!("decoded cp = '{:?}'", codep);
                state = 0;
                codep = 0;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence, restart");
                state = 0;
                codep = 0;
                state = decode_byte(state, *b, &mut codep);
                match state {
                    UTF8_ACCEPT => {
                        println!("decoded cp = '{:?}'", codep);
                        state = 0;
                        codep = 0;
                    }
                    UTF8_REJECT => {
                        println!("invalid utf8 sequence, restart");
                        state = 0;
                        codep = 0;
                    }
                    _ => {}
                }
            }

            _ => {
                continue;
            }
        }
    }
}

#[test]
fn test_backward_decode() {
    let data: [u8; 24] = [
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac,
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac,
    ];

    let mut start_offset: u64 = 6;
    println!(
        "start_offset {} byte is '{:x}'",
        start_offset, data[start_offset as usize] as u32
    );

    let off = get_previous_codepoint_start(&data, start_offset as u64);
    println!(
        "start_offset({}) - off({}) = {}",
        start_offset,
        off,
        start_offset - off
    );
    let delta = start_offset - off;
    start_offset -= delta;

    println!("new start_offset({})", start_offset);
}
<commit_msg>utf8 lookup table : add #[rustfmt::skip]<commit_after>// {
//   Derived from : Bjoern Hoehrmann work
//   Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//   See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.

const UTF8_ACCEPT: u32 = 0;
const UTF8_REJECT: u32 = 1;

#[rustfmt::skip]
static UTF8D: &'static [u8] = &[
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
  8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
  0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
  0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
  0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
  1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
  1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
  1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
];

/*
    state UTF8_ACCEPT => initial state or decoding successful
    state UTF8_REJECT => error
    state other => intermediate states need more inputs
*/
#[inline]
pub fn decode_byte(state: u32, byte: u8, codep: &mut u32) -> u32 {
    let cp_type = u32::from(UTF8D[byte as usize]);

    *codep = if state != UTF8_ACCEPT {
        u32::from(byte & 0x3f) | (*codep << 6)
    } else {
        (0xff >> cp_type) & u32::from(byte)
    };

    u32::from(UTF8D[256 + (state * 16) as usize + cp_type as usize])
}

// }

#[inline]
pub fn is_codepoint_start(byte: u8) -> bool {
    if byte < 0x80 {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xE0 && byte <= 0xEC {
        return true;
    }

    if byte >= 0xED && byte <= 0xEF {
        return true;
    }

    if byte >= 0xF0 && byte <= 0xF4 {
        return true;
    }

    false
}

// return 0 on error, or the number of written bytes
pub fn encode(codepoint: u32, out: &mut [u8; 4]) -> usize {
    if codepoint < 0x80 {
        out[0] = codepoint as u8;
        return 1;
    }

    if codepoint < 0x800 {
        out[0] = 0xC0 | (codepoint >> 6) as u8;
        out[1] = 0x80 | (codepoint & 0x3F) as u8;
        return 2;
    }

    if codepoint < 0xFFFF {
        out[0] = 0xE0 | (codepoint >> 12) as u8;
        out[1] = 0x80 | (codepoint >> 6) as u8;
        out[2] = 0x80 | (codepoint & 0x3F) as u8;
        return 3;
    }

    if codepoint < 0x0010_FFFF {
        out[0] = 0xF0 | (codepoint >> 18) as u8;
        out[1] = 0x80 | (codepoint >> 12) as u8;
        out[2] = 0x80 | (codepoint >> 6) as u8;
        out[3] = 0x80 | (codepoint & 0x3F) as u8;
        return 4;
    }

    0
}

// TODO: change this with temporary (cp, offset, size) until from_offset
pub fn get_previous_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    //                 cp    size   offset
    let mut cp_info: [(char, usize, u64); 8] = [
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
    ];
    let mut nr_cpinfo = 0;

    // rewind up to 4 bytes
    // and decode forward / save offset
    let mut off = if from_offset > 4 { from_offset - 4 } else { 0 };
    while off < from_offset {
        let (cp, _, size) = get_codepoint(data, off);

        cp_info[nr_cpinfo] = (cp, size, off);
        nr_cpinfo += 1;

        off += size as u64;
    }

    if nr_cpinfo != 0 {
        cp_info[nr_cpinfo - 1].2
    } else {
        from_offset
    }
}

pub fn get_next_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    let (_, _, size) = get_codepoint(data, from_offset);
    from_offset + size as u64
}

pub fn get_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let mut state = 0;
    let mut codep = 0;
    let mut size = 0;

    for b in data.iter().skip(from_offset as usize) {
        size += 1;
        state = decode_byte(state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }

            UTF8_REJECT => {
                // decode error : invalid sequence
                codep = 0xfffd;
                size = 1; // force restart @ next byte
                break;
            }
            _ => {}
        }
    }

    // TODO return Result<(char, usize), status> -> state != 1|0 -> need mode data
    (::core::codec::text::u32_to_char(codep), from_offset, size)
}

pub fn get_prev_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let offset = get_previous_codepoint_start(data, from_offset);
    get_codepoint(data, offset)
}

#[test]
fn test_codec_encode() {
    let expect_cp: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    let mut mut_cp: [u8; 4] = [0x00, 0x00, 0x00, 0x00];

    let n = encode(0x20ac as u32, &mut mut_cp);
    assert_eq!(n, 3);
    assert_eq!(mut_cp, expect_cp);
}

#[test]
fn test_codec_decode() {
    use core::codec::text::u32_to_char;

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    let sequence: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    for b in &sequence {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence");
                break;
            }
            _ => {
                continue;
            }
        }
    }

    println!("decoded codepoint value {:x}", codep);
    let c = u32_to_char(codep);
    println!("decoded codepoint char {}", c);

    assert_eq!(codep, 0x20ac);
}

#[test]
fn test2_codec_decode() {
    let data: [u8; 27] = [
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0xac, 0xe2,
        0x82, 0x61, 0x0a, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0x61, 0x0a, 0x61, 0x0a,
    ];

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    for b in &data {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(state, *b, &mut codep);
        println!("state  '{}'", state);
        match state {
            UTF8_ACCEPT => {
                println!("decoded cp = '{:?}'", codep);
                state = 0;
                codep = 0;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence, restart");
                state = 0;
                codep = 0;
                state = decode_byte(state, *b, &mut codep);
                match state {
                    UTF8_ACCEPT => {
                        println!("decoded cp = '{:?}'", codep);
                        state = 0;
                        codep = 0;
                    }
                    UTF8_REJECT => {
                        println!("invalid utf8 sequence, restart");
                        state = 0;
                        codep = 0;
                    }
                    _ => {}
                }
            }

            _ => {
                continue;
            }
        }
    }
}

#[test]
fn test_backward_decode() {
    let data: [u8; 24] = [
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac,
        0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac, 0xe2, 0x82, 0xac,
    ];

    let mut start_offset: u64 = 6;
    println!(
        "start_offset {} byte is '{:x}'",
        start_offset, data[start_offset as usize] as u32
    );

    let off = get_previous_codepoint_start(&data, start_offset as u64);
    println!(
        "start_offset({}) - off({}) = {}",
        start_offset,
        off,
        start_offset - off
    );
    let delta = start_offset - off;
    start_offset -= delta;

    println!("new start_offset({})", start_offset);
}
<|endoftext|>


<commit_before>
// Statement generation

use common::From2;
use common::StringPosition;
use message::CodegenMessage;

use lexical::SeperatorKind;
use lexical::LexicalLiteral;
use lexical::NumLitValue;

use syntax::Block;
use syntax::Statement;
use syntax::Expression;
use syntax::ExpressionBase;

use syntax::VarDeclStatement;
use syntax::ReturnStatement;
use syntax::BreakStatement;
use syntax::ContinueStatement;
use syntax::ExpressionStatement;
use syntax::LoopStatement;
use syntax::WhileStatement;
use syntax::ForStatement;
use syntax::ElseIfBranch;
use syntax::IfStatement;

use codegen::var_def::Var;
use codegen::var_def::VarID;
use codegen::session::GenerationSession;
use codegen::expression::gen_expr;
use codegen::expression::gen_expr_stmt;
use codegen::Operand;
use codegen::Code;
use codegen::CodeID;
use codegen::TypeID;
use codegen::AssignOperator;
use codegen::BinaryOperator;

// Just a static dispatcher
pub struct StatementGenerator{
}

// VarDeclaration
// pub struct VarDeclStatement {
//     pub is_const: bool,
//     pub ty: SMType,
//     pub name: String,
//     pub init_expr: Option<Expression>,
//     pub pos: [StringPosition; 4],     // position for 'const' or 'var', name, assign, and semicolon
fn gen_var_decl(var_decl: VarDeclStatement, sess: &mut GenerationSession) {

    let pos_all = var_decl.pub_pos_all();
    let typeid = sess.types.try_get_id(var_decl.ty, &mut sess.msgs);

    let varid = sess.vars.try_push(Var::new(var_decl.name.clone(), typeid, var_decl.is_const, pos_all), &mut sess.types, &mut sess.msgs);
    sess.codes.emit_silent(Code::DeclareVar(var_decl.name.clone(), typeid, var_decl.is_const));
    if varid.is_invalid() { return; } // name collision, ignore the statement

    if var_decl.init_expr.is_none() {
        if var_decl.is_const {
            sess.msgs.push(CodegenMessage::ConstVariableDeclareMissingInitializationExpression{ name: var_decl.name, pos: pos_all });
        }
        return;
    }

    // Has some init Expression
    gen_expr_stmt(
        ExpressionStatement{
            left_expr: Expression::new(
                ExpressionBase::Ident(var_decl.name, var_decl.pos[1]),
                Vec::new(),
                var_decl.pos[1],
            ),
            op: Some(SeperatorKind::Assign),
            right_expr: var_decl.init_expr,
            pos: [var_decl.pos[2], var_decl.pos[3]],
        },
        sess,
        true,
    );
}

// pub struct ElseIfBranch {
//     pub expr: Expression,
//     pub body: Block,
//     pub pos: [StringPosition; 2],   // position for if and else
// }
// pub struct IfStatement {
//     pub if_expr: Expression,
//     pub if_body: Block,
//     pub elseifs: Vec<ElseIfBranch>,
//     pub else_body: Option<Block>,
//     pub pos: [StringPosition; 2],  // position for if and else
// }
/// Example
/// ```
/// if a { b; } else if c { d; } else if e { f; } else { g; }
/// ```
/// generate
/// a; brfalse; b; c; brfalse; d; e; brfalse; f; g;
///     to c            to e           to g
fn gen_if(if_stmt: IfStatement, sess: &mut GenerationSession) {

    let if_expr = gen_expr(if_stmt.if_expr, sess);
    let if_goto_pos = sess.codes.emit(Code::GotoIf(if_expr, false, CodeID::dummy()));

    gen_block(if_stmt.if_body, sess, false);
    let next_codeid = sess.codes.next_id();
    sess.codes.refill_addr(if_goto_pos, next_codeid);

    for elseif in if_stmt.elseifs {
        let elseif_expr = gen_expr(elseif.expr, sess);
        let elseif_goto_pos = sess.codes.emit(Code::GotoIf(elseif_expr, false, CodeID::dummy()));
        gen_block(elseif.body, sess, false);
        let next_codeid = sess.codes.next_id();
        sess.codes.refill_addr(elseif_goto_pos, next_codeid);
    }

    match if_stmt.else_body {
        Some(else_body) => gen_block(else_body, sess, false),
        _ => (), // nothing
    }
}

// pub struct ReturnStatement {
//     pub expr: Option<Expression>,
//     pub pos: [StringPosition; 2], // position for return and semicolon
// }
fn gen_return(ret_stmt: ReturnStatement, sess: &mut GenerationSession) {

    let operand = match ret_stmt.expr {
        Some(expr) => gen_expr(expr, sess),
        None => Operand::Lit(LexicalLiteral::Unit),
    };

    sess.codes.emit(Code::Return(operand));
}

// pub struct LoopStatement {
//     pub name: Option<String>,
//     pub body: Block,
//     pub pos: [StringPosition; 2],   // position for 'loop' and loop name
// }
fn gen_loop(loop_stmt: LoopStatement, sess: &mut GenerationSession) {

    let continue_addr = sess.codes.next_id();
    sess.loops.push_loop(loop_stmt.name, continue_addr);

    gen_block(loop_stmt.body, sess, false);

    let break_refill_addr = sess.codes.next_id();
    sess.loops.pop_and_refill(break_refill_addr, &mut sess.codes);
}

// pub struct WhileStatement {
//     pub expr: Expression,
//     pub body: Block,
//     pub pos: StringPosition, // while position
// }
fn gen_while(while_stmt: WhileStatement, sess: &mut GenerationSession) {

    let continue_addr = sess.codes.next_id();
    let _ = gen_expr(while_stmt.expr, sess); // always reeval the expression
    sess.loops.push_loop(None, continue_addr);

    gen_block(while_stmt.body, sess, false);

    let while_refill_addr = sess.codes.next_id();
    sess.loops.pop_and_refill(while_refill_addr, &mut sess.codes);
}

// pub struct ForStatement {
//     pub iter_name: String,
//     pub expr_low: Expression,
//     pub expr_high: Expression,
//     pub body: Block,
//     pub pos: [StringPosition; 4]  // position for 'for', iter_name, 'in', range operator,
// }
fn gen_for(for_stmt: ForStatement, sess: &mut GenerationSession) {

    // scope for iter var
    sess.codes.emit_silent(Code::ScopeBarrier(true));

    let iter_varid = sess.vars.try_push(Var::new(for_stmt.iter_name.clone(), TypeID::Some(14), false, for_stmt.pos[1]), &mut sess.types, &mut sess.msgs);
    sess.codes.emit_silent(Code::DeclareVar(for_stmt.iter_name.clone(), TypeID::Some(14), false));
    let operand = gen_expr(for_stmt.expr_low, sess);
    sess.codes.emit_silent(Code::Assign(Operand::Stack(iter_varid), AssignOperator::Assign, Operand::Lit(LexicalLiteral::Num(Some(NumLitValue::I32(0))))));

    let continue_addr = sess.codes.next_id(); // reeval every time
    let high_operand = gen_expr(for_stmt.expr_high, sess);
    sess.codes.emit_silent(Code::Binary(Operand::Stack(iter_varid), BinaryOperator::Less, high_operand));
    sess.loops.push_loop(None, continue_addr);

    let while_implicit_break_addr = sess.codes.emit(Code::GotoIf(Operand::Register, false, CodeID::dummy()));
    sess.loops.push_last_loop_break_addr(while_implicit_break_addr);

    gen_block(for_stmt.body, sess, true);

    let for_refill_addr = sess.codes.next_id();
    sess.loops.pop_and_refill(for_refill_addr, &mut sess.codes);
    sess.codes.emit_silent(Code::ScopeBarrier(false));
}

// pub struct ContinueStatement {
//     pub name: Option<String>,
//     pub pos: [StringPosition; 3], // position for continue, name and semicolon
// }
fn gen_continue(continue_stmt: ContinueStatement, sess: &mut GenerationSession) {

    match continue_stmt.name {
        Some(name) => match sess.loops.get_loop_continue_addr(&name) {
            Some(continue_addr) => sess.codes.emit_silent(Code::Goto(continue_addr)),
            None => sess.msgs.push(CodegenMessage::CannotFindLoopName{
                name: name,
                pos: StringPosition::from2(continue_stmt.pos[0].start_pos, continue_stmt.pos[2].end_pos)
            }),
        },
        None => match sess.loops.get_last_loop_continue_addr() {
            Some(continue_addr) => sess.codes.emit_silent(Code::Goto(continue_addr)),
            None => sess.msgs.push(CodegenMessage::JumpStatementNotInLoop{
                pos: StringPosition::from2(continue_stmt.pos[0].start_pos, continue_stmt.pos[2].end_pos)
            }),
        },
    }
}
// pub struct BreakStatement {
//     pub name: Option<String>,
//     pub pos: [StringPosition; 3], // position for break, name and semicolon
// }
fn gen_break(break_stmt: BreakStatement, sess: &mut GenerationSession) {

    let break_addr = sess.codes.emit(Code::Goto(CodeID::dummy()));
    match break_stmt.name {
        Some(name) => match sess.loops.push_loop_break_addr(&name, break_addr) {
            Some(()) => (),
            None => sess.msgs.push(CodegenMessage::CannotFindLoopName{
                name: name,
                pos: StringPosition::from2(break_stmt.pos[0].start_pos, break_stmt.pos[2].end_pos)
            }),
        },
        None => match sess.loops.push_last_loop_break_addr(break_addr) {
            Some(()) => (),
            None => sess.msgs.push(CodegenMessage::JumpStatementNotInLoop{
                pos: StringPosition::from2(break_stmt.pos[0].start_pos, break_stmt.pos[2].end_pos)
            }),
        },
    }
}

// fn and for do not require scope enter on block
fn gen_block(block: Block, sess: &mut GenerationSession, no_scope_enter: bool) {

    if !no_scope_enter { sess.codes.emit_silent(Code::ScopeBarrier(true)); }
    for stmt in block.stmts {
        match stmt {
            Statement::VarDecl(var_decl) => gen_var_decl(var_decl, sess),
            Statement::Expression(expr_stmt) => gen_expr_stmt(expr_stmt, sess, false),
            Statement::If(if_stmt) => gen_if(if_stmt, sess),
            Statement::Return(ret_stmt) => gen_return(ret_stmt, sess),
            Statement::Break(break_stmt) => gen_break(break_stmt, sess),
            Statement::Continue(continue_stmt) => gen_continue(continue_stmt, sess),
            Statement::For(for_stmt) => gen_for(for_stmt, sess),
            Statement::Loop(loop_stmt) => gen_loop(loop_stmt, sess),
            Statement::While(while_stmt) => gen_while(while_stmt, sess),
            _ => (),
        }
    }
    if !no_scope_enter { sess.codes.emit_silent(Code::ScopeBarrier(false)); }
}

// Block
impl StatementGenerator {

    pub fn generate(block: Block, sess: &mut GenerationSession) {
        gen_block(block, sess, true);
    }
}<commit_msg>Daily commit<commit_after>
// Statement generation

use common::From2;
use common::StringPosition;
use message::CodegenMessage;

use lexical::SeperatorKind;
use lexical::LexicalLiteral;
use lexical::NumLitValue;

use syntax::Block;
use syntax::Statement;
use syntax::Expression;
use syntax::ExpressionBase;

use syntax::VarDeclStatement;
use syntax::ReturnStatement;
use syntax::BreakStatement;
use syntax::ContinueStatement;
use syntax::ExpressionStatement;
use syntax::LoopStatement;
use syntax::WhileStatement;
use syntax::ForStatement;
use syntax::ElseIfBranch;
use syntax::IfStatement;

use codegen::var_def::Var;
use codegen::var_def::VarID;
use codegen::session::GenerationSession;
use codegen::expression::gen_expr;
use codegen::expression::gen_expr_stmt;
use codegen::Operand;
use codegen::Code;
use codegen::CodeID;
use codegen::TypeID;
use codegen::AssignOperator;
use codegen::BinaryOperator;

// Just a static dispatcher
pub struct StatementGenerator{
}

// VarDeclaration
// pub struct VarDeclStatement {
//     pub is_const: bool,
//     pub ty: SMType,
//     pub name: String,
//     pub init_expr: Option<Expression>,
//     pub pos: [StringPosition; 4],     // position for 'const' or 'var', name, assign, and semicolon
fn gen_var_decl(var_decl: VarDeclStatement, sess: &mut GenerationSession) {

    let pos_all = var_decl.pub_pos_all();
    let typeid = sess.types.try_get_id(var_decl.ty, &mut sess.msgs);

    let varid = sess.vars.try_push(Var::new(var_decl.name.clone(), typeid, var_decl.is_const, pos_all), &mut sess.types, &mut sess.msgs);
    sess.codes.emit_silent(Code::DeclareVar(var_decl.name.clone(), typeid, var_decl.is_const));
    if varid.is_invalid() { return; } // name collision, ignore the statement

    if var_decl.init_expr.is_none() {
        if var_decl.is_const {
            sess.msgs.push(CodegenMessage::ConstVariableDeclareMissingInitializationExpression{ name: var_decl.name, pos: pos_all });
        }
        return;
    }

    // Has some init Expression
    gen_expr_stmt(
        ExpressionStatement{
            left_expr: Expression::new(
                ExpressionBase::Ident(var_decl.name, var_decl.pos[1]),
                Vec::new(),
                var_decl.pos[1],
            ),
            op: Some(SeperatorKind::Assign),
            right_expr: var_decl.init_expr,
            pos: [var_decl.pos[2], var_decl.pos[3]],
        },
        sess,
        true,
    );
}

// pub struct ElseIfBranch {
//     pub expr: Expression,
//     pub body: Block,
//     pub pos: [StringPosition; 2],   // position for if and else
// }
// pub struct IfStatement {
//     pub if_expr: Expression,
//     pub if_body: Block,
//     pub elseifs: Vec<ElseIfBranch>,
//     pub else_body: Option<Block>,
//     pub pos: [StringPosition; 2],  // position for if and else
// }
/// Example
/// ```
/// if a { b; } else if c { d; } else if e { f; } else { g; }
/// ```
/// generate
/// a; brfalse; b; c; brfalse; d; e; brfalse; f; g;
///     to c            to e           to g
fn gen_if(if_stmt: IfStatement, sess: &mut GenerationSession) {

    let if_expr = gen_expr(if_stmt.if_expr, sess);
    let if_goto_pos = sess.codes.emit(Code::GotoIf(if_expr, false, CodeID::dummy()));

    gen_block(if_stmt.if_body, sess, true);
    let next_codeid = sess.codes.next_id();
    sess.codes.refill_addr(if_goto_pos, next_codeid);

    for elseif in if_stmt.elseifs {
        let elseif_expr = gen_expr(elseif.expr, sess);
        let elseif_goto_pos = sess.codes.emit(Code::GotoIf(elseif_expr, false, CodeID::dummy()));
        gen_block(elseif.body, sess, true);
        let next_codeid = sess.codes.next_id();
        sess.codes.refill_addr(elseif_goto_pos, next_codeid);
    }

    match if_stmt.else_body {
        Some(else_body) => gen_block(else_body, sess, true),
        _ => (), // nothing
    }
}

// pub struct ReturnStatement {
//     pub expr: Option<Expression>,
//     pub pos: [StringPosition; 2], // position for return and semicolon
// }
fn gen_return(ret_stmt: ReturnStatement, sess: &mut GenerationSession) {

    let operand = match ret_stmt.expr {
        Some(expr) => gen_expr(expr, sess),
        None => Operand::Lit(LexicalLiteral::Unit),
    };

    sess.codes.emit(Code::Return(operand));
}

// pub struct LoopStatement {
//     pub name: Option<String>,
//     pub body: Block,
//     pub pos: [StringPosition; 2],   // position for 'loop' and loop name
// }
fn gen_loop(loop_stmt: LoopStatement, sess: &mut GenerationSession) {

    let continue_addr = sess.codes.next_id();
    sess.loops.push_loop(loop_stmt.name, continue_addr);

    gen_block(loop_stmt.body, sess, true);
    sess.codes.emit(Code::Goto(continue_addr));

    let break_refill_addr = sess.codes.next_id();
    sess.loops.pop_and_refill(break_refill_addr, &mut sess.codes);
}

// pub struct WhileStatement {
//     pub expr: Expression,
//     pub body: Block,
//     pub pos: StringPosition, // while position
// }
fn gen_while(while_stmt: WhileStatement, sess: &mut GenerationSession) {

    let continue_addr = sess.codes.next_id();
    let _ = gen_expr(while_stmt.expr, sess); // always reeval the expression
    sess.loops.push_loop(None, continue_addr);

    gen_block(while_stmt.body, sess, true);
    sess.codes.emit(Code::Goto(continue_addr));

    let while_refill_addr = sess.codes.next_id();
    sess.loops.pop_and_refill(while_refill_addr, &mut sess.codes);
}

// pub struct ForStatement {
//     pub iter_name: String,
//     pub expr_low: Expression,
//     pub expr_high: Expression,
//     pub body: Block,
//     pub pos: [StringPosition; 4]  // position for 'for', iter_name, 'in', range operator,
// }
fn gen_for(for_stmt: ForStatement, sess: &mut GenerationSession) {

    // scope for iter var
    sess.codes.emit_silent(Code::ScopeBarrier(true));

    let iter_varid = sess.vars.try_push(Var::new(for_stmt.iter_name.clone(), TypeID::Some(14), false, for_stmt.pos[1]), &mut sess.types, &mut sess.msgs);
    sess.codes.emit_silent(Code::DeclareVar(for_stmt.iter_name.clone(), TypeID::Some(14), false));
    let operand = gen_expr(for_stmt.expr_low, sess);
    sess.codes.emit_silent(Code::Assign(Operand::Stack(iter_varid), AssignOperator::Assign, Operand::Lit(LexicalLiteral::Num(Some(NumLitValue::I32(0))))));

    let continue_addr = sess.codes.next_id(); // reeval every time
    let high_operand = gen_expr(for_stmt.expr_high, sess);
    sess.codes.emit_silent(Code::Binary(Operand::Stack(iter_varid), BinaryOperator::Less, high_operand));
    sess.loops.push_loop(None, continue_addr);

    let while_implicit_break_addr = sess.codes.emit(Code::GotoIf(Operand::Register, false, CodeID::dummy()));
    sess.loops.push_last_loop_break_addr(while_implicit_break_addr);

    gen_block(for_stmt.body, sess, false);
    sess.codes.emit(Code::Goto(continue_addr));

    let for_refill_addr = sess.codes.next_id();
    sess.loops.pop_and_refill(for_refill_addr, &mut sess.codes);
    sess.codes.emit_silent(Code::ScopeBarrier(false));
}

// pub struct ContinueStatement {
//     pub name: Option<String>,
//     pub pos: [StringPosition; 3], // position for continue, name and semicolon
// }
fn gen_continue(continue_stmt: ContinueStatement, sess: &mut GenerationSession) {

    match continue_stmt.name {
        Some(name) => match sess.loops.get_loop_continue_addr(&name) {
            Some(continue_addr) => sess.codes.emit_silent(Code::Goto(continue_addr)),
            None => sess.msgs.push(CodegenMessage::CannotFindLoopName{
                name: name,
                pos: StringPosition::from2(continue_stmt.pos[0].start_pos, continue_stmt.pos[2].end_pos)
            }),
        },
        None => match sess.loops.get_last_loop_continue_addr() {
            Some(continue_addr) => sess.codes.emit_silent(Code::Goto(continue_addr)),
            None => sess.msgs.push(CodegenMessage::JumpStatementNotInLoop{
                pos: StringPosition::from2(continue_stmt.pos[0].start_pos, continue_stmt.pos[2].end_pos)
            }),
        },
    }
}
// pub struct BreakStatement {
//     pub name: Option<String>,
//     pub pos: [StringPosition; 3], // position for break, name and semicolon
// }
fn gen_break(break_stmt: BreakStatement, sess: &mut GenerationSession) {

    let break_addr = sess.codes.emit(Code::Goto(CodeID::dummy()));
    match break_stmt.name {
        Some(name) => match sess.loops.push_loop_break_addr(&name, break_addr) {
            Some(()) => (),
            None => sess.msgs.push(CodegenMessage::CannotFindLoopName{
                name: name,
                pos: StringPosition::from2(break_stmt.pos[0].start_pos, break_stmt.pos[2].end_pos)
            }),
        },
        None => match sess.loops.push_last_loop_break_addr(break_addr) {
            Some(()) => (),
            None => sess.msgs.push(CodegenMessage::JumpStatementNotInLoop{
                pos: StringPosition::from2(break_stmt.pos[0].start_pos, break_stmt.pos[2].end_pos)
            }),
        },
    }
}

// fn and for do not require scope enter on block
fn gen_block(block: Block, sess: &mut GenerationSession, emit_scope_barrier: bool) {

    if emit_scope_barrier { sess.codes.emit_silent(Code::ScopeBarrier(true)); }
    for stmt in block.stmts {
        match stmt {
            Statement::VarDecl(var_decl) => gen_var_decl(var_decl, sess),
            Statement::Expression(expr_stmt) => gen_expr_stmt(expr_stmt, sess, false),
            Statement::If(if_stmt) => gen_if(if_stmt, sess),
            Statement::Return(ret_stmt) => gen_return(ret_stmt, sess),
            Statement::Break(break_stmt) => gen_break(break_stmt, sess),
            Statement::Continue(continue_stmt) => gen_continue(continue_stmt, sess),
            Statement::For(for_stmt) => gen_for(for_stmt, sess),
            Statement::Loop(loop_stmt) => gen_loop(loop_stmt, sess),
            Statement::While(while_stmt) => gen_while(while_stmt, sess),
            _ => (),
        }
    }
    if emit_scope_barrier { sess.codes.emit_silent(Code::ScopeBarrier(false)); }
}

// Block
impl StatementGenerator {

    pub fn generate(block: Block, sess: &mut GenerationSession) {
        gen_block(block, sess, false);
    }
}<|endoftext|>


<commit_before>#![no_main]
use libfuzzer_sys::fuzz_target;
use std::str;

extern crate nom;

use nom::{
  branch::alt,
  bytes::complete::tag,
  character::complete::char,
  character::complete::{digit1 as digit, space0 as space},
  combinator::{map_res, verify},
  multi::fold_many0,
  sequence::{delimited, pair},
  IResult,
};

use std::str::FromStr;

fn parens(i: &str) -> IResult<&str, i64> {
      delimited(space, delimited(tag("("), expr, tag(")")), space)(i)
}

fn factor(i: &str) -> IResult<&str, i64> {
  alt((
    map_res(delimited(space, digit, space), FromStr::from_str),
    parens,
  ))(i)
}

fn term(i: &str) -> IResult<&str, i64> {
  let (i, init) = factor(i)?;

  fold_many0(
    alt((
        pair(char('*'), factor),
        pair(char('/'), verify(factor, |i| *i != 0)),
    )),
    init,
    |acc, (op, val): (char, i64)| {
      if op == '*' {
        acc.saturating_mul(val)
      } else {
        acc / val
      }
    },
  )(i)
}

fn expr(i: &str) -> IResult<&str, i64> {
  let (i, init) = term(i)?;

  fold_many0(
    pair(alt((char('+'), char('-'))), term),
    init,
    |acc, (op, val): (char, i64)| {
      if op == '+' {
        acc.saturating_add(val)
      } else {
        acc.saturating_sub(val)
      }
    },
  )(i)
}

fuzz_target!(|data: &[u8]| {
    // fuzzed code goes here
    let temp = match str::from_utf8(data) {
        Ok(v) => {
            //println!("v: {}", v);
            factor(v)
        },
        Err(e) => factor("2"),
    };
});
<commit_msg>fix an overflowing division in the fuzz testcase<commit_after>#![no_main]
use libfuzzer_sys::fuzz_target;
use std::str;

extern crate nom;

use nom::{
  branch::alt,
  bytes::complete::tag,
  character::complete::char,
  character::complete::{digit1 as digit, space0 as space},
  combinator::{map_res, verify},
  multi::fold_many0,
  sequence::{delimited, pair},
  IResult,
};

use std::str::FromStr;

fn parens(i: &str) -> IResult<&str, i64> {
      delimited(space, delimited(tag("("), expr, tag(")")), space)(i)
}

fn factor(i: &str) -> IResult<&str, i64> {
  alt((
    map_res(delimited(space, digit, space), FromStr::from_str),
    parens,
  ))(i)
}

fn term(i: &str) -> IResult<&str, i64> {
  let (i, init) = factor(i)?;

  fold_many0(
    alt((
        pair(char('*'), factor),
        pair(char('/'), verify(factor, |i| *i != 0)),
    )),
    init,
    |acc, (op, val): (char, i64)| {
      if op == '*' {
        acc.saturating_mul(val)
      } else {
        match acc.checked_div(val) {
            Some(v) => v,
            // we get a division with overflow because we can get acc = i64::MIN and val = -1
            // the division by zero is already checked earlier by verify
            None => i64::MAX,
        }
      }
    },
  )(i)
}

fn expr(i: &str) -> IResult<&str, i64> {
  let (i, init) = term(i)?;

  fold_many0(
    pair(alt((char('+'), char('-'))), term),
    init,
    |acc, (op, val): (char, i64)| {
      if op == '+' {
        acc.saturating_add(val)
      } else {
        acc.saturating_sub(val)
      }
    },
  )(i)
}

fuzz_target!(|data: &[u8]| {
    // fuzzed code goes here
    let temp = match str::from_utf8(data) {
        Ok(v) => {
            //println!("v: {}", v);
            factor(v)
        },
        Err(e) => factor("2"),
    };
});
<|endoftext|>