use std::fmt;
use std::iter::{FromIterator, once};
use std::ops::{Deref, DerefMut};
#[derive(Clone, Debug, PartialEq)]
pub struct NonEmpty<T>(pub Vec<T>);
impl<T> NonEmpty<T> {
  
  
  
  
  
  pub fn from_iter<I>(iter: I) -> Option<Self> where I: IntoIterator<Item = T> {
    let vec: Vec<_> = iter.into_iter().collect();
    if vec.is_empty() {
      None
    } else {
      Some(NonEmpty(vec))
    }
  }
  
  pub fn push(&mut self, item: T) {
    self.0.push(item);
  }
  
  
  
  
  
  pub fn pop(&mut self) -> Option<T> {
    if self.0.len() == 1 {
      None
    } else {
      self.0.pop()
    }
  }
}
impl<T> IntoIterator for NonEmpty<T> {
  type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
  type Item = T;
  fn into_iter(self) -> Self::IntoIter {
    self.0.into_iter()
  }
}
impl<'a, T> IntoIterator for &'a NonEmpty<T> {
  type IntoIter = <&'a Vec<T> as IntoIterator>::IntoIter;
  type Item = &'a T;
  fn into_iter(self) -> Self::IntoIter {
    self.0.iter()
  }
}
impl<'a, T> IntoIterator for &'a mut NonEmpty<T> {
  type IntoIter = <&'a mut Vec<T> as IntoIterator>::IntoIter;
  type Item = &'a mut T;
  fn into_iter(self) -> Self::IntoIter {
    self.0.iter_mut()
  }
}
impl<T> Extend<T> for NonEmpty<T> {
  fn extend<I>(&mut self, iter: I) where I: IntoIterator<Item = T> {
    self.0.extend(iter);
  }
}
#[derive(Debug)]
pub enum IdentifierError {
  StartsWithDigit,
  ContainsNonASCIIAlphaNum
}
impl fmt::Display for IdentifierError {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    match *self {
      IdentifierError::StartsWithDigit =>
        f.write_str("starts starts with a digit"),
      IdentifierError::ContainsNonASCIIAlphaNum =>
        f.write_str("contains at least one non-alphanumeric ASCII character")
    }
  }
}
#[derive(Clone, Debug, PartialEq)]
pub struct Identifier(pub String);
impl Identifier {
  
  
  
  
  
  
  pub fn new<N>(name: N) -> Result<Self, IdentifierError> where N: Into<String> {
    let name = name.into();
    if name.chars().next().map(|c| c.is_ascii_alphabetic()) == Some(false) {
      
      Err(IdentifierError::StartsWithDigit)
    } else if name.contains(|c: char| !(c.is_ascii_alphanumeric() || c == '_')) {
      
      Err(IdentifierError::ContainsNonASCIIAlphaNum)
    } else {
      Ok(Identifier(name))
    }
  }
  
  pub fn as_str(&self) -> &str {
    &self.0
  }
}
impl<'a> From<&'a str> for Identifier {
  fn from(s: &str) -> Self {
    Identifier(s.to_owned())
  }
}
impl From<String> for Identifier {
  fn from(s: String) -> Self {
    Identifier(s)
  }
}
impl fmt::Display for Identifier {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    self.0.fmt(f)
  }
}
#[derive(Clone, Debug, PartialEq)]
pub struct TypeName(pub String);
impl TypeName {
  
  
  
  
  
  
  pub fn new<N>(name: N) -> Result<Self, IdentifierError> where N: Into<String> {
    
    let Identifier(tn) = Identifier::new(name)?;
    Ok(TypeName(tn))
  }
  
  pub fn as_str(&self) -> &str {
    &self.0
  }
}
impl<'a> From<&'a str> for TypeName {
  fn from(s: &str) -> Self {
    TypeName(s.to_owned())
  }
}
impl From<String> for TypeName {
  fn from(s: String) -> Self {
    TypeName(s)
  }
}
impl fmt::Display for TypeName {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    self.0.fmt(f)
  }
}
#[derive(Clone, Debug, PartialEq)]
pub enum TypeSpecifierNonArray {
  
  Void,
  Bool,
  Int,
  UInt,
  Float,
  Double,
  Vec2,
  Vec3,
  Vec4,
  DVec2,
  DVec3,
  DVec4,
  BVec2,
  BVec3,
  BVec4,
  IVec2,
  IVec3,
  IVec4,
  UVec2,
  UVec3,
  UVec4,
  Mat2,
  Mat3,
  Mat4,
  Mat23,
  Mat24,
  Mat32,
  Mat34,
  Mat42,
  Mat43,
  DMat2,
  DMat3,
  DMat4,
  DMat23,
  DMat24,
  DMat32,
  DMat34,
  DMat42,
  DMat43,
  
  Sampler1D,
  Image1D,
  Sampler2D,
  Image2D,
  Sampler3D,
  Image3D,
  SamplerCube,
  ImageCube,
  Sampler2DRect,
  Image2DRect,
  Sampler1DArray,
  Image1DArray,
  Sampler2DArray,
  Image2DArray,
  SamplerBuffer,
  ImageBuffer,
  Sampler2DMS,
  Image2DMS,
  Sampler2DMSArray,
  Image2DMSArray,
  SamplerCubeArray,
  ImageCubeArray,
  Sampler1DShadow,
  Sampler2DShadow,
  Sampler2DRectShadow,
  Sampler1DArrayShadow,
  Sampler2DArrayShadow,
  SamplerCubeShadow,
  SamplerCubeArrayShadow,
  
  ISampler1D,
  IImage1D,
  ISampler2D,
  IImage2D,
  ISampler3D,
  IImage3D,
  ISamplerCube,
  IImageCube,
  ISampler2DRect,
  IImage2DRect,
  ISampler1DArray,
  IImage1DArray,
  ISampler2DArray,
  IImage2DArray,
  ISamplerBuffer,
  IImageBuffer,
  ISampler2DMS,
  IImage2DMS,
  ISampler2DMSArray,
  IImage2DMSArray,
  ISamplerCubeArray,
  IImageCubeArray,
  
  AtomicUInt,
  USampler1D,
  UImage1D,
  USampler2D,
  UImage2D,
  USampler3D,
  UImage3D,
  USamplerCube,
  UImageCube,
  USampler2DRect,
  UImage2DRect,
  USampler1DArray,
  UImage1DArray,
  USampler2DArray,
  UImage2DArray,
  USamplerBuffer,
  UImageBuffer,
  USampler2DMS,
  UImage2DMS,
  USampler2DMSArray,
  UImage2DMSArray,
  USamplerCubeArray,
  UImageCubeArray,
  Struct(StructSpecifier),
  TypeName(TypeName)
}
#[derive(Clone, Debug, PartialEq)]
pub struct TypeSpecifier {
  pub ty: TypeSpecifierNonArray,
  pub array_specifier: Option<ArraySpecifier>
}
impl TypeSpecifier {
  pub fn new(ty: TypeSpecifierNonArray) -> Self {
    TypeSpecifier {
      ty,
      array_specifier: None
    }
  }
}
impl From<TypeSpecifierNonArray> for TypeSpecifier {
  fn from(ty: TypeSpecifierNonArray) -> Self {
    TypeSpecifier::new(ty)
  }
}
#[derive(Clone, Debug, PartialEq)]
pub struct StructSpecifier {
  pub name: Option<TypeName>,
  pub fields: NonEmpty<StructFieldSpecifier>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct StructFieldSpecifier {
  pub qualifier: Option<TypeQualifier>,
  pub ty: TypeSpecifier,
  pub identifiers: NonEmpty<ArrayedIdentifier> 
}
impl StructFieldSpecifier {
  
  pub fn new<A, T>(
    identifier: A,
    ty: T
  ) -> Self
  where A: Into<ArrayedIdentifier>,
        T: Into<TypeSpecifier> {
    StructFieldSpecifier {
      qualifier: None,
      ty: ty.into(),
      identifiers: NonEmpty(vec![identifier.into()])
    }
  }
  
  pub fn new_many<I>(
    identifiers: I,
    ty: TypeSpecifier
  ) -> Self
  where I: IntoIterator<Item = ArrayedIdentifier> {
    StructFieldSpecifier {
      qualifier: None,
      ty,
      identifiers: NonEmpty(identifiers.into_iter().collect())
    }
  }
}
#[derive(Clone, Debug, PartialEq)]
pub struct ArrayedIdentifier {
  pub ident: Identifier,
  pub array_spec: Option<ArraySpecifier>
}
impl ArrayedIdentifier {
  pub fn new<I, AS>(
    ident: I,
    array_spec: AS
  ) -> Self
  where I: Into<Identifier>,
        AS: Into<Option<ArraySpecifier>> {
    ArrayedIdentifier {
      ident: ident.into(),
      array_spec: array_spec.into()
    }
  }
}
impl<'a> From<&'a str> for ArrayedIdentifier {
  fn from(ident: &str) -> Self {
    ArrayedIdentifier {
      ident: Identifier(ident.to_owned()),
      array_spec: None
    }
  }
}
impl From<Identifier> for ArrayedIdentifier {
  fn from(ident: Identifier) -> Self {
    ArrayedIdentifier {
      ident,
      array_spec: None
    }
  }
}
#[derive(Clone, Debug, PartialEq)]
pub struct TypeQualifier {
  pub qualifiers: NonEmpty<TypeQualifierSpec>
}
#[derive(Clone, Debug, PartialEq)]
pub enum TypeQualifierSpec {
  Storage(StorageQualifier),
  Layout(LayoutQualifier),
  Precision(PrecisionQualifier),
  Interpolation(InterpolationQualifier),
  Invariant,
  Precise
}
#[derive(Clone, Debug, PartialEq)]
pub enum StorageQualifier {
  Const,
  InOut,
  In,
  Out,
  Centroid,
  Patch,
  Sample,
  Uniform,
  Buffer,
  Shared,
  Coherent,
  Volatile,
  Restrict,
  ReadOnly,
  WriteOnly,
  Subroutine(Vec<TypeName>),
}
#[derive(Clone, Debug, PartialEq)]
pub struct LayoutQualifier {
  pub ids: NonEmpty<LayoutQualifierSpec>
}
#[derive(Clone, Debug, PartialEq)]
pub enum LayoutQualifierSpec {
  Identifier(Identifier, Option<Box<Expr>>),
  Shared
}
#[derive(Clone, Debug, PartialEq)]
pub enum PrecisionQualifier {
  High,
  Medium,
  Low
}
#[derive(Clone, Debug, PartialEq)]
pub enum InterpolationQualifier {
  Smooth,
  Flat,
  NoPerspective
}
#[derive(Clone, Debug, PartialEq)]
pub struct FullySpecifiedType {
  pub qualifier: Option<TypeQualifier>,
  pub ty: TypeSpecifier
}
impl FullySpecifiedType {
  pub fn new(ty: TypeSpecifierNonArray) -> Self {
    FullySpecifiedType {
      qualifier: None,
      ty: TypeSpecifier {
        ty,
        array_specifier: None
      }
    }
  }
}
impl From<TypeSpecifierNonArray> for FullySpecifiedType {
  fn from(ty: TypeSpecifierNonArray) -> Self {
    FullySpecifiedType::new(ty)
  }
}
#[derive(Clone, Debug, PartialEq)]
pub enum ArraySpecifier {
  Unsized,
  ExplicitlySized(Box<Expr>)
}
#[derive(Clone, Debug, PartialEq)]
pub enum Declaration {
  FunctionPrototype(FunctionPrototype),
  InitDeclaratorList(InitDeclaratorList),
  Precision(PrecisionQualifier, TypeSpecifier),
  Block(Block),
  Global(TypeQualifier, Vec<Identifier>)
}
#[derive(Clone, Debug, PartialEq)]
pub struct Block {
  pub qualifier: TypeQualifier,
  pub name: Identifier,
  pub fields: Vec<StructFieldSpecifier>,
  pub identifier: Option<ArrayedIdentifier>
}
#[derive(Clone, Debug, PartialEq)]
pub enum FunIdentifier {
  Identifier(Identifier),
  Expr(Box<Expr>)
}
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionPrototype {
  pub ty: FullySpecifiedType,
  pub name: Identifier,
  pub parameters: Vec<FunctionParameterDeclaration>
}
#[derive(Clone, Debug, PartialEq)]
pub enum FunctionParameterDeclaration {
  Named(Option<TypeQualifier>, FunctionParameterDeclarator),
  Unnamed(Option<TypeQualifier>, TypeSpecifier)
}
impl FunctionParameterDeclaration {
  
  pub fn new_named<I, T>(
    ident: I,
    ty: T
  ) -> Self
  where I: Into<ArrayedIdentifier>,
        T: Into<TypeSpecifier> {
    let declator = FunctionParameterDeclarator {
      ty: ty.into(),
      ident: ident.into()
    };
    FunctionParameterDeclaration::Named(None, declator)
  }
  
  pub fn new_unnamed<T>(ty: T) -> Self where T: Into<TypeSpecifier> {
    FunctionParameterDeclaration::Unnamed(None, ty.into())
  }
}
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionParameterDeclarator {
  pub ty: TypeSpecifier,
  pub ident: ArrayedIdentifier
}
#[derive(Clone, Debug, PartialEq)]
pub struct InitDeclaratorList {
  pub head: SingleDeclaration,
  pub tail: Vec<SingleDeclarationNoType>
}
#[derive(Clone, Debug, PartialEq)]
pub struct SingleDeclaration {
  pub ty: FullySpecifiedType,
  pub name: Option<Identifier>,
  pub array_specifier: Option<ArraySpecifier>,
  pub initializer: Option<Initializer>
}
#[derive(Clone, Debug, PartialEq)]
pub struct SingleDeclarationNoType {
  pub ident: ArrayedIdentifier,
  pub initializer: Option<Initializer>
}
#[derive(Clone, Debug, PartialEq)]
pub enum Initializer {
  Simple(Box<Expr>),
  List(NonEmpty<Initializer>)
}
impl From<Expr> for Initializer {
  fn from(e: Expr) -> Self {
    Initializer::Simple(Box::new(e))
  }
}
#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
  
  Variable(Identifier),
  
  IntConst(i32),
  
  UIntConst(u32),
  
  BoolConst(bool),
  
  FloatConst(f32),
  
  DoubleConst(f64),
  
  Unary(UnaryOp, Box<Expr>),
  
  Binary(BinaryOp, Box<Expr>, Box<Expr>),
  
  Ternary(Box<Expr>, Box<Expr>, Box<Expr>),
  
  
  Assignment(Box<Expr>, AssignmentOp, Box<Expr>),
  
  Bracket(Box<Expr>, ArraySpecifier),
  
  FunCall(FunIdentifier, Vec<Expr>),
  
  Dot(Box<Expr>, Identifier),
  
  PostInc(Box<Expr>),
  
  PostDec(Box<Expr>),
  
  Comma(Box<Expr>, Box<Expr>)
}
impl From<i32> for Expr {
  fn from(x: i32) -> Expr {
    Expr::IntConst(x)
  }
}
impl From<u32> for Expr {
  fn from(x: u32) -> Expr {
    Expr::UIntConst(x)
  }
}
impl From<bool> for Expr {
  fn from(x: bool) -> Expr {
    Expr::BoolConst(x)
  }
}
impl From<f32> for Expr {
  fn from(x: f32) -> Expr {
    Expr::FloatConst(x)
  }
}
impl From<f64> for Expr {
  fn from(x: f64) -> Expr {
    Expr::DoubleConst(x)
  }
}
#[derive(Clone, Debug, PartialEq)]
pub enum UnaryOp {
  Inc,
  Dec,
  Add,
  Minus,
  Not,
  Complement
}
#[derive(Clone, Debug, PartialEq)]
pub enum BinaryOp {
  Or,
  Xor,
  And,
  BitOr,
  BitXor,
  BitAnd,
  Equal,
  NonEqual,
  LT,
  GT,
  LTE,
  GTE,
  LShift,
  RShift,
  Add,
  Sub,
  Mult,
  Div,
  Mod
}
#[derive(Clone, Debug, PartialEq)]
pub enum AssignmentOp {
  Equal,
  Mult,
  Div,
  Mod,
  Add,
  Sub,
  LShift,
  RShift,
  And,
  Xor,
  Or
}
#[derive(Clone, Debug, PartialEq)]
pub struct TranslationUnit(pub NonEmpty<ExternalDeclaration>);
impl TranslationUnit {
  
  
  
  
  
  pub fn from_iter<I>(iter: I) -> Option<Self> where I: IntoIterator<Item = ExternalDeclaration> {
    NonEmpty::from_iter(iter).map(TranslationUnit)
  }
}
impl Deref for TranslationUnit {
  type Target = NonEmpty<ExternalDeclaration>;
  fn deref(&self) -> &Self::Target {
    &self.0
  }
}
impl DerefMut for TranslationUnit {
  fn deref_mut(&mut self) -> &mut Self::Target {
    &mut self.0
  }
}
impl IntoIterator for TranslationUnit {
  type IntoIter = <NonEmpty<ExternalDeclaration> as IntoIterator>::IntoIter;
  type Item = ExternalDeclaration;
  fn into_iter(self) -> Self::IntoIter {
    self.0.into_iter()
  }
}
impl<'a> IntoIterator for &'a TranslationUnit {
  type IntoIter = <&'a NonEmpty<ExternalDeclaration> as IntoIterator>::IntoIter;
  type Item = &'a ExternalDeclaration;
  fn into_iter(self) -> Self::IntoIter {
    (&self.0).into_iter()
  }
}
impl<'a> IntoIterator for &'a mut TranslationUnit {
  type IntoIter = <&'a mut NonEmpty<ExternalDeclaration> as IntoIterator>::IntoIter;
  type Item = &'a mut ExternalDeclaration;
  fn into_iter(self) -> Self::IntoIter {
    (&mut self.0).into_iter()
  }
}
#[derive(Clone, Debug, PartialEq)]
pub enum ExternalDeclaration {
  Preprocessor(Preprocessor),
  FunctionDefinition(FunctionDefinition),
  Declaration(Declaration)
}
impl ExternalDeclaration {
  
  pub fn new_fn<T, N, A, S>(
    ret_ty: T,
    name: N,
    args: A,
    body: S
  ) -> Self
  where T: Into<FullySpecifiedType>,
        N: Into<Identifier>,
        A: IntoIterator<Item = FunctionParameterDeclaration>,
        S: IntoIterator<Item = Statement> {
    ExternalDeclaration::FunctionDefinition(
      FunctionDefinition {
        prototype: FunctionPrototype {
          ty: ret_ty.into(),
          name: name.into(),
          parameters: args.into_iter().collect()
        },
        statement: CompoundStatement {
          statement_list: body.into_iter().collect()
        }
      }
    )
  }
  
  
  
  
  
  pub fn new_struct<N, F>(name: N, fields: F) -> Option<Self>
  where N: Into<TypeName>,
        F: IntoIterator<Item = StructFieldSpecifier> {
    let fields: Vec<_> = fields.into_iter().collect();
    if fields.is_empty() {
      None
    } else {
      Some(ExternalDeclaration::Declaration(
        Declaration::InitDeclaratorList(
          InitDeclaratorList {
            head: SingleDeclaration {
              ty: FullySpecifiedType {
                qualifier: None,
                ty: TypeSpecifier {
                  ty: TypeSpecifierNonArray::Struct(
                        StructSpecifier {
                          name: Some(name.into()),
                          fields: NonEmpty(fields.into_iter().collect())
                        }
                  ),
                  array_specifier: None
                }
              },
              name: None,
              array_specifier: None,
              initializer: None
            },
            tail: vec![]
          }
        )
      ))
    }
  }
}
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionDefinition {
  pub prototype: FunctionPrototype,
  pub statement: CompoundStatement,
}
#[derive(Clone, Debug, PartialEq)]
pub struct CompoundStatement {
  pub statement_list: Vec<Statement>
}
impl FromIterator<Statement> for CompoundStatement {
  fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = Statement> {
    CompoundStatement {
      statement_list: iter.into_iter().collect()
    }
  }
}
#[derive(Clone, Debug, PartialEq)]
pub enum Statement {
  Compound(Box<CompoundStatement>),
  Simple(Box<SimpleStatement>)
}
impl Statement {
  
  pub fn new_case<C, S>(
    case: C,
    statements: S
  ) -> Self
  where C: Into<CaseLabel>,
        S: IntoIterator<Item = Statement> {
    let case_stmt = Statement::Simple(Box::new(SimpleStatement::CaseLabel(case.into())));
    Statement::Compound(
      Box::new(CompoundStatement {
        statement_list: once(case_stmt).chain(statements.into_iter()).collect()
      })
    )
  }
  
  
  
  
  
  pub fn declare_var<T, N, A, I>(
    ty: T,
    name: N,
    array_specifier: A,
    initializer: I
  ) -> Self
  where T: Into<FullySpecifiedType>,
        N: Into<Identifier>,
        A: Into<Option<ArraySpecifier>>,
        I: Into<Option<Initializer>> {
    Statement::Simple(
      Box::new(SimpleStatement::Declaration(
        Declaration::InitDeclaratorList(
          InitDeclaratorList {
            head: SingleDeclaration {
              ty: ty.into(),
              name: Some(name.into()),
              array_specifier: array_specifier.into(),
              initializer: initializer.into()
            },
            tail: Vec::new()
          }
        )
      ))
    )
  }
}
#[derive(Clone, Debug, PartialEq)]
pub enum SimpleStatement {
  Declaration(Declaration),
  Expression(ExprStatement),
  Selection(SelectionStatement),
  Switch(SwitchStatement),
  CaseLabel(CaseLabel),
  Iteration(IterationStatement),
  Jump(JumpStatement)
}
impl SimpleStatement {
  
  pub fn new_expr<E>(expr: E) -> Self where E: Into<Expr> {
    SimpleStatement::Expression(Some(expr.into()))
  }
  
  pub fn new_if_else<If, True, False>(
    ife: If,
    truee: True,
    falsee: False
  ) -> Self
  where If: Into<Expr>,
        True: Into<Statement>,
        False: Into<Statement> {
    SimpleStatement::Selection(
      SelectionStatement {
        cond: Box::new(ife.into()),
        rest: SelectionRestStatement::Else(Box::new(truee.into()), Box::new(falsee.into()))
      }
    )
  }
  
  
  
  
  pub fn new_switch<H, B>(
    head: H,
    body: B
  ) -> Self
  where H: Into<Expr>,
        B: IntoIterator<Item = Statement> {
    SimpleStatement::Switch(
      SwitchStatement {
        head: Box::new(head.into()),
        body: body.into_iter().collect()
      }
    )
  }
  
  pub fn new_while<C, S>(
    cond: C,
    body: S
  ) -> Self
  where C: Into<Condition>,
        S: Into<Statement> {
    SimpleStatement::Iteration(
      IterationStatement::While(cond.into(), Box::new(body.into()))
    )
  }
  
  pub fn new_do_while<C, S>(
    body: S,
    cond: C
  ) -> Self
  where S: Into<Statement>,
        C: Into<Expr> {
    SimpleStatement::Iteration(
      IterationStatement::DoWhile(Box::new(body.into()), Box::new(cond.into()))
    )
  }
}
pub type ExprStatement = Option<Expr>;
#[derive(Clone, Debug, PartialEq)]
pub struct SelectionStatement {
  pub cond: Box<Expr>,
  pub rest: SelectionRestStatement
}
#[derive(Clone, Debug, PartialEq)]
pub enum Condition {
  Expr(Box<Expr>),
  Assignment(FullySpecifiedType, Identifier, Initializer)
}
impl From<Expr> for Condition {
  fn from(expr: Expr) -> Self {
    Condition::Expr(Box::new(expr))
  }
}
#[derive(Clone, Debug, PartialEq)]
pub enum SelectionRestStatement {
  
  Statement(Box<Statement>),
  
  Else(Box<Statement>, Box<Statement>)
}
#[derive(Clone, Debug, PartialEq)]
pub struct SwitchStatement {
  pub head: Box<Expr>,
  pub body: Vec<Statement>
}
#[derive(Clone, Debug, PartialEq)]
pub enum CaseLabel {
  Case(Box<Expr>),
  Def
}
#[derive(Clone, Debug, PartialEq)]
pub enum IterationStatement {
  While(Condition, Box<Statement>),
  DoWhile(Box<Statement>, Box<Expr>),
  For(ForInitStatement, ForRestStatement, Box<Statement>)
}
#[derive(Clone, Debug, PartialEq)]
pub enum ForInitStatement {
  Expression(Option<Expr>),
  Declaration(Box<Declaration>)
}
#[derive(Clone, Debug, PartialEq)]
pub struct ForRestStatement {
  pub condition: Option<Condition>,
  pub post_expr: Option<Box<Expr>>
}
#[derive(Clone, Debug, PartialEq)]
pub enum JumpStatement {
  Continue,
  Break,
  Return(Box<Expr>),
  Discard
}
#[derive(Clone, Debug, PartialEq)]
pub enum Preprocessor {
  Define(PreprocessorDefine),
  Version(PreprocessorVersion),
  Extension(PreprocessorExtension)
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorDefine {
  pub name: Identifier,
  pub value: Expr,
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorVersion {
  pub version: u16,
  pub profile: Option<PreprocessorVersionProfile>
}
#[derive(Clone, Debug, PartialEq)]
pub enum PreprocessorVersionProfile {
  Core,
  Compatibility,
  ES
}
#[derive(Clone, Debug, PartialEq)]
pub struct PreprocessorExtension {
  pub name: PreprocessorExtensionName,
  pub behavior: Option<PreprocessorExtensionBehavior>
}
#[derive(Clone, Debug, PartialEq)]
pub enum PreprocessorExtensionName {
  
  All,
  
  Specific(String)
}
#[derive(Clone, Debug, PartialEq)]
pub enum PreprocessorExtensionBehavior {
  Require,
  Enable,
  Warn,
  Disable
}
#[cfg(test)]
mod tests {
  use super::*;
  #[test]
  fn create_new_identifier() {
    assert!(Identifier::new("foo_bar").is_ok());
    assert!(Identifier::new("3foo_bar").is_err());
    assert!(Identifier::new("FooBar").is_ok());
    assert!(Identifier::new("_FooBar").is_err());
    assert!(Identifier::new("foo3").is_ok());
    assert!(Identifier::new("foo3_").is_ok());
    assert!(Identifier::new("fδo3_").is_err());
  }
  #[test]
  fn create_new_type_name() {
    assert!(TypeName::new("foo_bar").is_ok());
    assert!(TypeName::new("FooBar").is_ok());
    assert!(TypeName::new("foo3").is_ok());
    assert!(TypeName::new("foo3_").is_ok());
    assert!(TypeName::new("_FooBar").is_err());
    assert!(TypeName::new("3foo_bar").is_err());
    assert!(TypeName::new("fδo3_").is_err());
  }
  
  
  #[test]
  fn declare_new_fn() {
    let _ =
      ExternalDeclaration::new_fn(TypeSpecifierNonArray::Bool,
                                  "predicate",
                                  vec![FunctionParameterDeclaration::new_named("x", TypeSpecifierNonArray::Float)],
                                  vec![]
      );
  }
  
  
  
  
  #[test]
  fn declare_struct() {
    let point =
      ExternalDeclaration::new_struct("Point2D",
                                      vec![
                                        StructFieldSpecifier::new("x", TypeSpecifierNonArray::Double),
                                        StructFieldSpecifier::new("y", TypeSpecifierNonArray::Double)
                                      ]
      );
    assert!(point.is_some());
  }
  
  #[test]
  fn declare_bad_struct() {
    let point = ExternalDeclaration::new_struct("Point2D", vec![]);
    assert!(point.is_none());
  }
  #[test]
  fn initializer_from_expr() {
    let _: Initializer = Expr::from(false).into();
  }
}