diff --git a/src/front/glsl_new/ast.rs b/src/front/glsl_new/ast.rs index 1f06439121..61c1d18a1b 100644 --- a/src/front/glsl_new/ast.rs +++ b/src/front/glsl_new/ast.rs @@ -23,9 +23,7 @@ impl Program { #[derive(Debug)] pub enum Profile { - // Compatibility, Core, - // Es, } #[derive(Debug)] diff --git a/src/front/glsl_new/error.rs b/src/front/glsl_new/error.rs index c860960bac..bfb7d7c930 100644 --- a/src/front/glsl_new/error.rs +++ b/src/front/glsl_new/error.rs @@ -1,12 +1,15 @@ use super::parser::Token; +use super::token::TokenMetadata; use std::{fmt, io}; #[derive(Debug)] pub enum ErrorKind { - InvalidInput, - IoError(io::Error), - InvalidToken(Token), EndOfFile, + InvalidInput, + InvalidProfile(TokenMetadata, String), + InvalidToken(Token), + InvalidVersion(TokenMetadata, i64), + IoError(io::Error), ParserFail, ParserStackOverflow, } @@ -14,10 +17,16 @@ pub enum ErrorKind { impl fmt::Display for ErrorKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - ErrorKind::InvalidInput => write!(f, "InvalidInput"), - ErrorKind::IoError(error) => write!(f, "IO Error {}", error), - ErrorKind::InvalidToken(token) => write!(f, "Invalid Token {:?}", token), ErrorKind::EndOfFile => write!(f, "Unexpected end of file"), + ErrorKind::InvalidInput => write!(f, "InvalidInput"), + ErrorKind::InvalidProfile(meta, val) => { + write!(f, "Invalid profile {} at {:?}", val, meta) + } + ErrorKind::InvalidToken(token) => write!(f, "Invalid Token {:?}", token), + ErrorKind::InvalidVersion(meta, val) => { + write!(f, "Invalid version {} at {:?}", val, meta) + } + ErrorKind::IoError(error) => write!(f, "IO Error {}", error), ErrorKind::ParserFail => write!(f, "Parser failed"), ErrorKind::ParserStackOverflow => write!(f, "Parser stack overflow"), } diff --git a/src/front/glsl_new/lex.rs b/src/front/glsl_new/lex.rs index eb05603e24..1f46f23c79 100644 --- a/src/front/glsl_new/lex.rs +++ b/src/front/glsl_new/lex.rs @@ -206,7 +206,7 @@ pub fn consume_token(mut input: &str) -> (Option, &str) { '#' => { input = chars.as_str(); let (word, rest, pos) = consume_any(input, |c| c.is_alphanumeric() || c == '_'); - meta.chars.end = start + pos; + meta.chars.end = start + 1 + pos; match word { "version" => (Some(Token::Version(meta)), rest), _ => (None, input), diff --git a/src/front/glsl_new/lex_tests.rs b/src/front/glsl_new/lex_tests.rs index 1da89d80f3..5d260cae50 100644 --- a/src/front/glsl_new/lex_tests.rs +++ b/src/front/glsl_new/lex_tests.rs @@ -136,3 +136,25 @@ fn glsl_lex_identifier() { "Unknown((TokenMetadata { line: 0, chars: 25..26 }, \'好\'))" ); } + +#[test] +fn glsl_lex_version() { + let source = "#version 890 core"; + let lex = Lexer::new(source); + let tokens: Vec = lex.collect(); + assert_eq!(tokens.len(), 3); + + let mut iter = tokens.iter(); + assert_eq!( + format!("{:?}", iter.next().unwrap()), + "Version(TokenMetadata { line: 0, chars: 0..8 })" + ); + assert_eq!( + format!("{:?}", iter.next().unwrap()), + "IntConstant((TokenMetadata { line: 0, chars: 9..12 }, 890))" + ); + assert_eq!( + format!("{:?}", iter.next().unwrap()), + "Identifier((TokenMetadata { line: 0, chars: 13..17 }, \"core\"))" + ); +} diff --git a/src/front/glsl_new/mod.rs b/src/front/glsl_new/mod.rs index 6c1fb568fe..4836f5efb1 100644 --- a/src/front/glsl_new/mod.rs +++ b/src/front/glsl_new/mod.rs @@ -11,6 +11,8 @@ use lex::Lexer; mod error; use error::ParseError; mod parser; +#[cfg(test)] +mod parser_tests; mod token; pub fn parse_str(source: &str, entry: String, stage: ShaderStage) -> Result { diff --git a/src/front/glsl_new/parser.rs b/src/front/glsl_new/parser.rs index 9cba9a6b67..b0cca17ac3 100644 --- a/src/front/glsl_new/parser.rs +++ b/src/front/glsl_new/parser.rs @@ -41,7 +41,24 @@ pomelo! { %type function_definition Function; root ::= version_pragma translation_unit; - version_pragma ::= Version IntConstant Identifier?; + version_pragma ::= Version IntConstant(V) Identifier?(P) { + match V.1 { + 440 => (), + 450 => (), + 460 => (), + _ => return Err(ErrorKind::InvalidVersion(V.0, V.1)) + } + extra.version = V.1 as u16; + extra.profile = match P { + Some((meta, profile)) => { + match profile.as_str() { + "core" => Profile::Core, + _ => return Err(ErrorKind::InvalidProfile(meta, profile)) + } + }, + None => Profile::Core, + } + }; // expression variable_identifier ::= Identifier; diff --git a/src/front/glsl_new/parser_tests.rs b/src/front/glsl_new/parser_tests.rs new file mode 100644 index 0000000000..9da4677c6c --- /dev/null +++ b/src/front/glsl_new/parser_tests.rs @@ -0,0 +1,49 @@ +use super::ast::Program; +use super::error::ErrorKind; +use super::lex::Lexer; +use super::parser; + +fn parse_program(source: &str) -> Result { + let mut program = Program::new(); + let lex = Lexer::new(source); + let mut parser = parser::Parser::new(&mut program); + + for token in lex { + parser.parse(token)?; + } + parser.end_of_input()?; + Ok(program) +} + +#[test] +fn glsl_parser_version_invalid() { + assert_eq!( + format!("{:?}", parse_program("#version 99000").err().unwrap()), + "InvalidVersion(TokenMetadata { line: 0, chars: 9..14 }, 99000)" + ); + + assert_eq!( + format!("{:?}", parse_program("#version 449").err().unwrap()), + "InvalidVersion(TokenMetadata { line: 0, chars: 9..12 }, 449)" + ); + + assert_eq!( + format!("{:?}", parse_program("#version 450 smart").err().unwrap()), + "InvalidProfile(TokenMetadata { line: 0, chars: 13..18 }, \"smart\")" + ); +} + +#[test] +fn glsl_parser_version_valid() { + let program = parse_program("#version 450\nvoid main() {}").unwrap(); + assert_eq!( + format!("{:?}", (program.version, program.profile)), + "(450, Core)" + ); + + let program = parse_program("#version 450 core\nvoid main() {}").unwrap(); + assert_eq!( + format!("{:?}", (program.version, program.profile)), + "(450, Core)" + ); +}