1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! GLSL parsing.
//!
//! This module gives you several functions and types to deal with GLSL parsing, transforming an
//! input source into an AST. The AST is defined in the [`syntax`] module.
//!
//! You want to use the [`Parse`]’s methods to get starting with parsing and pattern match on
//! [`ParseResult`].
//!
//! [`Parse`]: parser::Parse
//! [`ParseResult`]: parser::ParseResult

use nom::{Err as NomErr, ErrorKind, IResult, Needed};
use std::fmt;
use std::str::{from_utf8_unchecked};

use syntax;

/// A parse error. It contains an [`ErrorKind`] along with a [`String`] giving information on the reason
/// why the parser failed.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ParseError {
  kind: ErrorKind,
  info: String
}

impl fmt::Display for ParseError {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    write!(f, "error ({:?}): {}", self.kind, self.info)
  }
}

/// Parse result. It can either be parsed, incomplete or errored.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ParseResult<T> {
  /// The source was successfully parsed.
  Ok(T),
  /// The parser failed with a [`ParseError`].
  Err(ParseError),
  /// More data is required to go on.
  Incomplete(Needed)
}

/// Run a parser over a byte slice.
fn run_parser<P, T>(source: &[u8], parser: P) -> ParseResult<T>
    where P: FnOnce(&[u8]) -> IResult<&[u8], T> {
  match parser(source) {
    IResult::Done(i, x) => {
      if i.is_empty() {
        ParseResult::Ok(x)
      } else {
        let kind = ErrorKind::Custom(0); // FIXME: use our own error kind
        let msg = unsafe { from_utf8_unchecked(i).to_owned() };
        let info = msg.lines().next().unwrap_or("").to_owned();
        ParseResult::Err(ParseError { kind, info })
      }
    },
    IResult::Error(err) => match err {
      NomErr::Code(k) => ParseResult::Err(ParseError { kind: k, info: String::new() }),
      NomErr::Node(kind, trace) => {
        let info = format!("{:#?}", trace);
        ParseResult::Err(ParseError { kind, info })
      },
      NomErr::Position(kind, p) => {
        let msg = unsafe { from_utf8_unchecked(p).to_owned() };
        let info = msg.lines().next().unwrap_or("").to_owned();

        ParseResult::Err(ParseError { kind, info })
      },
      NomErr::NodePosition(kind, p, trace) => {
        let p_msg = unsafe { from_utf8_unchecked(p) };
        let info = format!("{}: {:#?}", p_msg, trace);

        ParseResult::Err(ParseError { kind, info })
      }
    },
    IResult::Incomplete(n) => ParseResult::Incomplete(n)
  }
}

/// Class of types that can be parsed.
///
/// This trait exposes two methods:
/// 
///   - [`Parse::parse`], that runs on bytes.
///   - [`Parse::parse_str`], a convenient function that runs on strings.
///
/// If you want to implement [`Parse`], only [`Parse::parse`] is mandatory – [`Parse::parse_str`]
/// has a default implementation using [`Parse::parse`].
///
/// The methods from this trait are the standard way to parse data into GLSL ASTs.
pub trait Parse: Sized {
  /// Parse from a byte slice.
  fn parse<B>(source: B) -> ParseResult<Self> where B: AsRef<[u8]>;

  /// Parse from a string.
  fn parse_str<S>(source: S) -> ParseResult<Self> where S: AsRef<str> {
    let s = source.as_ref().as_bytes();
    Self::parse(s)
  }
}

/// Macro to implement Parse for a given type.
macro_rules! impl_parse {
  ($type_name:ty, $parser_name:ident) => {
    impl Parse for $type_name {
      fn parse<B>(source: B) -> ParseResult<Self> where B: AsRef<[u8]> {
        run_parser(source.as_ref(), $crate::parsers::$parser_name)
      }
    }
  }
}

impl_parse!(syntax::Identifier, identifier);
impl_parse!(syntax::TypeSpecifierNonArray, type_specifier_non_array);
impl_parse!(syntax::TypeSpecifier, type_specifier);
impl_parse!(syntax::UnaryOp, unary_op);
impl_parse!(syntax::StructFieldSpecifier, struct_field_specifier);
impl_parse!(syntax::StructSpecifier, struct_specifier);
impl_parse!(syntax::StorageQualifier, storage_qualifier);
impl_parse!(syntax::LayoutQualifier, layout_qualifier);
impl_parse!(syntax::PrecisionQualifier, precision_qualifier);
impl_parse!(syntax::InterpolationQualifier, interpolation_qualifier);
impl_parse!(syntax::TypeQualifier, type_qualifier);
impl_parse!(syntax::TypeQualifierSpec, type_qualifier_spec);
impl_parse!(syntax::FullySpecifiedType, fully_specified_type);
impl_parse!(syntax::ArraySpecifier, array_specifier);
impl_parse!(syntax::Expr, expr);
impl_parse!(syntax::Declaration, declaration);
impl_parse!(syntax::FunctionPrototype, function_prototype);
impl_parse!(syntax::InitDeclaratorList, init_declarator_list);
impl_parse!(syntax::SingleDeclaration, single_declaration);
impl_parse!(syntax::Initializer, initializer);
impl_parse!(syntax::FunIdentifier, function_identifier);
impl_parse!(syntax::AssignmentOp, assignment_op);
impl_parse!(syntax::SimpleStatement, simple_statement);
impl_parse!(syntax::ExprStatement, expr_statement);
impl_parse!(syntax::SelectionStatement, selection_statement);
impl_parse!(syntax::SwitchStatement, switch_statement);
impl_parse!(syntax::CaseLabel, case_label);
impl_parse!(syntax::IterationStatement, iteration_statement);
impl_parse!(syntax::JumpStatement, jump_statement);
impl_parse!(syntax::Condition, condition);
impl_parse!(syntax::Statement, statement);
impl_parse!(syntax::CompoundStatement, compound_statement);
impl_parse!(syntax::FunctionDefinition, function_definition);
impl_parse!(syntax::ExternalDeclaration, external_declaration);
impl_parse!(syntax::TranslationUnit, translation_unit);
impl_parse!(syntax::Preprocessor, preprocessor);
impl_parse!(syntax::PreprocessorVersion, pp_version);
impl_parse!(syntax::PreprocessorVersionProfile, pp_version_profile);
impl_parse!(syntax::PreprocessorExtensionName, pp_extension_name);
impl_parse!(syntax::PreprocessorExtensionBehavior, pp_extension_behavior);
impl_parse!(syntax::PreprocessorExtension, pp_extension);