-#![allow(non_camel_case_types)]

use std;
use lex;
use lex::Token;
use lex::Token_Type;

pub enum Piece {
  None,
  Block,
  Statement,
  Nop,
  Assign_Or_Call,
  Label,
  Break,
  Goto,
  Sub_Block,
  While_Loop,
  Repeat_Loop,
  If_Chain,
  For_Loop,
  Global_Function,
  Local_Thing,

  Variable,
  Prefix_Expr,

  Assignment,
  Function_Call,
  For_Inc,
  For_Range,
  Local_Function,
  Local_Declaration,
}

// Each piece of code is made of sub pieces, down to the lowest layer which
// is made of tokens.

// There is a current context of pieces that can be created.
// To start, only a block can be created.
// To construct a piece, check whether the current token can be used to start
// the piece.  If it can, start constructing the piece, telling it what sub
// piece it starts with.  If the piece cannot be started by the current
// token, go to the next piece in the list of pieces that can be created in
// the current context.

// A piece continues until the current token cannot be used to continue it,
// or a token that ends it is found.
// A piece constructor can also have a custom end condition.

// As the piece is created, sub pieces are placed in a container in order.

// return type: can_start, sub_piece
fn token_can_start_piece(pie: Piece, kind: &Token_Type) -> (bool, Piece) {
  const block_contain: Vec<Piece> = vec!(Piece::Statement);
  const statement_contain: Vec<Piece> = vec!(
    Piece::Nop, Piece::Assign_Or_Call, Piece::Label,
    Piece::Break, Piece::Goto, Piece::Sub_Block, Piece::While_Loop,
    Piece::Repeat_Loop, Piece::If_Chain, Piece::For_Loop,
    Piece::Global_Function, Piece::Local_Function, Piece::Local_Variables);
  const assign_or_call_contain: Vec<Piece> = vec!(
    Piece::Assignment, Piece::Function_Call);
  const prefix_contain: Vec<Piece> = vec!(
    Piece::Variable, Piece::Function_Call, Piece::Sub_Expr);
  match pie {
    Piece::Block => {
      token_can_start_piece(Piece::Statement, kind)
    },
    Piece::Statement => {
      for con in statement_contain.iter() {
        let sub = token_can_start_piece(con, kind);
        if sub.0 {
          return sub
        }
      }
      (false, Piece::None)
    },
    Piece::Nop => {
      match kind {
        Token_Type::Element_Separator => (true, Piece::Nop),
        _ => (false, Piece::None),
      }
    },
    Piece::Assign_Or_Call => {
      
    },
    Piece::Assignment => {
      token_can_start_piece(Piece::Variable, kind)
    },
    Piece::Function_Call => {
      token_can_start_piece(Piece::Prefix_Expr, kind)
    },
    Piece::Label => {
      match kind {
        Token_Type::Label_Marker => (true, Piece::Label),
        _ => (false, Piece::None),
      }
    },
    Piece::Break => {
      match kind {
        Token_Type::Break => (true, Piece::Break),
        _ => (false, Piece::None),
      }
    },
    Piece::Goto => {
      match kind {
        Token_Type::Goto => (true, Piece::Goto),
        _ => (false, Piece::None),
      }
    },
    Piece::Sub_Block => {
      match kind {
        Token_Type::Do => (true, Piece::Sub_Block),
        _ => (false, Piece::None),
      }
    },
    Piece::While_Loop => {
      match kind {
        Token_Type::While => (true, Piece::While_Loop),
        _ => (false, Piece::None),
      }
    },
    Piece::Repeat_Loop => {
      match kind {
        Token_Type::Repeat => (true, Piece::Repeat_Loop),
        _ => (false, Piece::None),
      }
    },
    Piece::If_Chain => {
      match kind {
        Token_Type::If => (true, Piece::If_Chain),
        _ => (false, Piece::None),
      }
    },
    Piece::For_Loop => {
      match kind {
        Token_Type::For => (true, Piece::For_Loop),
        _ => (false, Piece::None),
      }
    },
    Piece::Global_Function => {
      match kind {
        Token_Type::Function => (true, Piece::Global_Function),
        _ => (false, Piece::None),
      }
    },
    Piece::Local_Thing => {
      match kind {
        Token_Type::Local => (true, Piece::Local_Thing),
        _ => (false, Piece::None),
      }
    },
    Piece::Prefix_Expr => {
      for con in prefix_contain.iter() {
        let sub = token_can_start_piece(con, kind);
        if sub.0 {
          return sub
        }
      }
      (false, Piece::None)
    },
  };
}

fn token_can_continue_piece(pie: Piece, kind: &Token_Type) -> bool {
}
