wsgl parser: Add ParserImpl::Expect<T>

And use it for the ParserImpl::expect_xxx() methods.

This is the first step towards supporting multiple error messages, as
the caller can now test to see if the specific call errored, instead of
using a global error state.

Also cleans up a bunch of code.

Bug: tint:282

Change-Id: I5e39fc33bd1e16620cee80d27fa728bc2af3387e
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32101
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
Ben Clayton 2020-11-09 19:39:34 +00:00 committed by Commit Bot service account
parent f2e91857e1
commit 653c4042e2
15 changed files with 966 additions and 788 deletions

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,7 @@
#ifndef SRC_READER_WGSL_PARSER_IMPL_H_ #ifndef SRC_READER_WGSL_PARSER_IMPL_H_
#define SRC_READER_WGSL_PARSER_IMPL_H_ #define SRC_READER_WGSL_PARSER_IMPL_H_
#include <cassert>
#include <deque> #include <deque>
#include <memory> #include <memory>
#include <string> #include <string>
@ -79,7 +80,61 @@ struct ForHeader {
/// ParserImpl for WGSL source data /// ParserImpl for WGSL source data
class ParserImpl { class ParserImpl {
/// Failure holds enumerator values used for the constructing an Expect in the
/// errored state.
struct Failure {
enum Errored { kErrored };
};
public: public:
/// Expect is the return type of the parser methods that are expected to
/// return a parsed value of type T, unless there was an parse error.
/// In the case of a parse error the called method will have called
/// |add_error()| and the Expect will have |errored| set to true.
template <typename T>
struct Expect {
/// An alias to the templated type T.
using type = T;
/// Don't allow an Expect to take a nullptr.
inline Expect(std::nullptr_t) = delete; // NOLINT
/// Constructor for a successful parse.
/// @param val the result value of the parse
/// @param s the optional source of the value
template <typename U>
inline Expect(U&& val, const Source& s = {}) // NOLINT
: value(std::forward<U>(val)), source(s) {}
/// Constructor for parse error.
inline Expect(Failure::Errored) : errored(true) {} // NOLINT
/// Copy constructor
inline Expect(const Expect&) = default;
/// Move constructor
inline Expect(Expect&&) = default;
/// Assignment operator
/// @return this Expect
inline Expect& operator=(const Expect&) = default;
/// Assignment move operator
/// @return this Expect
inline Expect& operator=(Expect&&) = default;
/// @return a pointer to |value|. |errored| must be false to call.
inline T* operator->() {
assert(!errored);
return &value;
}
/// The expected value of a successful parse.
/// Zero-initialized when there was a parse error.
T value{};
/// Optional source of the value.
Source source;
/// True if there was a error parsing.
bool errored = false;
};
/// TypedIdentifier holds a parsed identifier and type. Returned by /// TypedIdentifier holds a parsed identifier and type. Returned by
/// variable_ident_decl(). /// variable_ident_decl().
struct TypedIdentifier { struct TypedIdentifier {
@ -130,19 +185,25 @@ class ParserImpl {
/// Appends an error at |t| with the message |msg| /// Appends an error at |t| with the message |msg|
/// @param t the token to associate the error with /// @param t the token to associate the error with
/// @param msg the error message /// @param msg the error message
void add_error(const Token& t, const std::string& msg); /// @return |errored| so that you can combine an add_error call and return on
/// the same line.
Failure::Errored add_error(const Token& t, const std::string& msg);
/// Appends an error raised when parsing |use| at |t| with the message |msg| /// Appends an error raised when parsing |use| at |t| with the message |msg|
/// @param source the source to associate the error with /// @param source the source to associate the error with
/// @param msg the error message /// @param msg the error message
/// @param use a description of what was being parsed when the error was /// @param use a description of what was being parsed when the error was
/// raised. /// raised.
void add_error(const Source& source, /// @return |errored| so that you can combine an add_error call and return on
const std::string& msg, /// the same line.
const std::string& use); Failure::Errored add_error(const Source& source,
const std::string& msg,
const std::string& use);
/// Appends an error at |source| with the message |msg| /// Appends an error at |source| with the message |msg|
/// @param source the source to associate the error with /// @param source the source to associate the error with
/// @param msg the error message /// @param msg the error message
void add_error(const Source& source, const std::string& msg); /// @return |errored| so that you can combine an add_error call and return on
/// the same line.
Failure::Errored add_error(const Source& source, const std::string& msg);
/// Registers a constructed type into the parser /// Registers a constructed type into the parser
/// @param name the constructed name /// @param name the constructed name
@ -156,7 +217,8 @@ class ParserImpl {
/// Parses the `translation_unit` grammar element /// Parses the `translation_unit` grammar element
void translation_unit(); void translation_unit();
/// Parses the `global_decl` grammar element, erroring on parse failure. /// Parses the `global_decl` grammar element, erroring on parse failure.
void expect_global_decl(); /// @return true on parse success, otherwise an error.
Expect<bool> expect_global_decl();
/// Parses a `global_variable_decl` grammar element with the initial /// Parses a `global_variable_decl` grammar element with the initial
/// `variable_decoration_list*` provided as |decos|. /// `variable_decoration_list*` provided as |decos|.
/// @returns the variable parsed or nullptr /// @returns the variable parsed or nullptr
@ -173,7 +235,7 @@ class ParserImpl {
/// failure. /// failure.
/// @param use a description of what was being parsed if an error was raised. /// @param use a description of what was being parsed if an error was raised.
/// @returns the identifier and type parsed or empty otherwise /// @returns the identifier and type parsed or empty otherwise
TypedIdentifier expect_variable_ident_decl(const std::string& use); Expect<TypedIdentifier> expect_variable_ident_decl(const std::string& use);
/// Parses a `variable_storage_decoration` grammar element /// Parses a `variable_storage_decoration` grammar element
/// @returns the storage class or StorageClass::kNone if none matched /// @returns the storage class or StorageClass::kNone if none matched
ast::StorageClass variable_storage_decoration(); ast::StorageClass variable_storage_decoration();
@ -183,10 +245,10 @@ class ParserImpl {
/// Parses a `type_decl` grammar element /// Parses a `type_decl` grammar element
/// @returns the parsed Type or nullptr if none matched. /// @returns the parsed Type or nullptr if none matched.
ast::type::Type* type_decl(); ast::type::Type* type_decl();
/// Parses a `storage_class` grammar element /// Parses a `storage_class` grammar element, erroring on parse failure.
/// @param use a description of what was being parsed if an error was raised /// @param use a description of what was being parsed if an error was raised.
/// @returns the storage class or StorageClass::kNone if none matched /// @returns the storage class or StorageClass::kNone if none matched
ast::StorageClass expect_storage_class(const std::string& use); Expect<ast::StorageClass> expect_storage_class(const std::string& use);
/// Parses a `struct_decl` grammar element with the initial /// Parses a `struct_decl` grammar element with the initial
/// `struct_decoration_decl*` provided as |decos|. /// `struct_decoration_decl*` provided as |decos|.
/// @returns the struct type or nullptr on error /// @returns the struct type or nullptr on error
@ -195,13 +257,13 @@ class ParserImpl {
ast::DecorationList& decos); ast::DecorationList& decos);
/// Parses a `struct_body_decl` grammar element, erroring on parse failure. /// Parses a `struct_body_decl` grammar element, erroring on parse failure.
/// @returns the struct members /// @returns the struct members
ast::StructMemberList expect_struct_body_decl(); Expect<ast::StructMemberList> expect_struct_body_decl();
/// Parses a `struct_member` grammar element with the initial /// Parses a `struct_member` grammar element with the initial
/// `struct_member_decoration_decl+` provided as |decos|, erroring on parse /// `struct_member_decoration_decl+` provided as |decos|, erroring on parse
/// failure. /// failure.
/// @param decos the list of decorations for the struct member. /// @param decos the list of decorations for the struct member.
/// @returns the struct member or nullptr /// @returns the struct member or nullptr
std::unique_ptr<ast::StructMember> expect_struct_member( Expect<std::unique_ptr<ast::StructMember>> expect_struct_member(
ast::DecorationList& decos); ast::DecorationList& decos);
/// Parses a `function_decl` grammar element with the initial /// Parses a `function_decl` grammar element with the initial
/// `function_decoration_decl*` provided as |decos|. /// `function_decoration_decl*` provided as |decos|.
@ -230,8 +292,10 @@ class ParserImpl {
/// @returns the parsed Type or nullptr if none matched. /// @returns the parsed Type or nullptr if none matched.
ast::type::Type* depth_texture_type(); ast::type::Type* depth_texture_type();
/// Parses a `image_storage_type` grammar element /// Parses a `image_storage_type` grammar element
/// @param use a description of what was being parsed if an error was raised.
/// @returns returns the image format or kNone if none matched. /// @returns returns the image format or kNone if none matched.
ast::type::ImageFormat image_storage_type(); Expect<ast::type::ImageFormat> expect_image_storage_type(
const std::string& use);
/// Parses a `function_type_decl` grammar element /// Parses a `function_type_decl` grammar element
/// @returns the parsed type or nullptr otherwise /// @returns the parsed type or nullptr otherwise
ast::type::Type* function_type_decl(); ast::type::Type* function_type_decl();
@ -240,26 +304,24 @@ class ParserImpl {
std::unique_ptr<ast::Function> function_header(); std::unique_ptr<ast::Function> function_header();
/// Parses a `param_list` grammar element, erroring on parse failure. /// Parses a `param_list` grammar element, erroring on parse failure.
/// @returns the parsed variables /// @returns the parsed variables
ast::VariableList expect_param_list(); Expect<ast::VariableList> expect_param_list();
/// Parses a `pipeline_stage` grammar element, erroring if the next token does /// Parses a `pipeline_stage` grammar element, erroring if the next token does
/// not match a stage name. /// not match a stage name.
/// @returns the pipeline stage or PipelineStage::kNone if none matched, along /// @returns the pipeline stage.
/// with the source location for the stage. Expect<ast::PipelineStage> expect_pipeline_stage();
std::pair<ast::PipelineStage, Source> expect_pipeline_stage();
/// Parses a builtin identifier, erroring if the next token does not match a /// Parses a builtin identifier, erroring if the next token does not match a
/// valid builtin name. /// valid builtin name.
/// @returns the builtin or Builtin::kNone if none matched, along with the /// @returns the parsed builtin.
/// source location for the stage. Expect<ast::Builtin> expect_builtin();
std::pair<ast::Builtin, Source> expect_builtin();
/// Parses a `body_stmt` grammar element, erroring on parse failure. /// Parses a `body_stmt` grammar element, erroring on parse failure.
/// @returns the parsed statements /// @returns the parsed statements
std::unique_ptr<ast::BlockStatement> expect_body_stmt(); Expect<std::unique_ptr<ast::BlockStatement>> expect_body_stmt();
/// Parses a `paren_rhs_stmt` grammar element, erroring on parse failure. /// Parses a `paren_rhs_stmt` grammar element, erroring on parse failure.
/// @returns the parsed element or nullptr /// @returns the parsed element or nullptr
std::unique_ptr<ast::Expression> expect_paren_rhs_stmt(); Expect<std::unique_ptr<ast::Expression>> expect_paren_rhs_stmt();
/// Parses a `statements` grammar element /// Parses a `statements` grammar element
/// @returns the statements parsed /// @returns the statements parsed
std::unique_ptr<ast::BlockStatement> statements(); Expect<std::unique_ptr<ast::BlockStatement>> expect_statements();
/// Parses a `statement` grammar element /// Parses a `statement` grammar element
/// @returns the parsed statement or nullptr /// @returns the parsed statement or nullptr
std::unique_ptr<ast::Statement> statement(); std::unique_ptr<ast::Statement> statement();
@ -292,7 +354,7 @@ class ParserImpl {
std::unique_ptr<ast::CaseStatement> switch_body(); std::unique_ptr<ast::CaseStatement> switch_body();
/// Parses a `case_selectors` grammar element /// Parses a `case_selectors` grammar element
/// @returns the list of literals /// @returns the list of literals
ast::CaseSelectorList case_selectors(); Expect<ast::CaseSelectorList> expect_case_selectors();
/// Parses a `case_body` grammar element /// Parses a `case_body` grammar element
/// @returns the parsed statements /// @returns the parsed statements
std::unique_ptr<ast::BlockStatement> case_body(); std::unique_ptr<ast::BlockStatement> case_body();
@ -304,7 +366,7 @@ class ParserImpl {
std::unique_ptr<ast::LoopStatement> loop_stmt(); std::unique_ptr<ast::LoopStatement> loop_stmt();
/// Parses a `for_header` grammar element, erroring on parse failure. /// Parses a `for_header` grammar element, erroring on parse failure.
/// @returns the parsed for header or nullptr /// @returns the parsed for header or nullptr
std::unique_ptr<ForHeader> expect_for_header(); Expect<std::unique_ptr<ForHeader>> expect_for_header();
/// Parses a `for_stmt` grammar element /// Parses a `for_stmt` grammar element
/// @returns the parsed for loop or nullptr /// @returns the parsed for loop or nullptr
std::unique_ptr<ast::Statement> for_stmt(); std::unique_ptr<ast::Statement> for_stmt();
@ -316,14 +378,14 @@ class ParserImpl {
std::unique_ptr<ast::Literal> const_literal(); std::unique_ptr<ast::Literal> const_literal();
/// Parses a `const_expr` grammar element, erroring on parse failure. /// Parses a `const_expr` grammar element, erroring on parse failure.
/// @returns the parsed constructor expression or nullptr on error /// @returns the parsed constructor expression or nullptr on error
std::unique_ptr<ast::ConstructorExpression> expect_const_expr(); Expect<std::unique_ptr<ast::ConstructorExpression>> expect_const_expr();
/// Parses a `primary_expression` grammar element /// Parses a `primary_expression` grammar element
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> primary_expression(); std::unique_ptr<ast::Expression> primary_expression();
/// Parses a `argument_expression_list` grammar element, erroring on parse /// Parses a `argument_expression_list` grammar element, erroring on parse
/// failure. /// failure.
/// @returns the list of arguments /// @returns the list of arguments
ast::ExpressionList expect_argument_expression_list(); Expect<ast::ExpressionList> expect_argument_expression_list();
/// Parses the recursive portion of the postfix_expression /// Parses the recursive portion of the postfix_expression
/// @param prefix the left side of the expression /// @param prefix the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -339,7 +401,7 @@ class ParserImpl {
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> expect_multiplicative_expr( Expect<std::unique_ptr<ast::Expression>> expect_multiplicative_expr(
std::unique_ptr<ast::Expression> lhs); std::unique_ptr<ast::Expression> lhs);
/// Parses the `multiplicative_expression` grammar element /// Parses the `multiplicative_expression` grammar element
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -348,7 +410,7 @@ class ParserImpl {
/// failure. /// failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> expect_additive_expr( Expect<std::unique_ptr<ast::Expression>> expect_additive_expr(
std::unique_ptr<ast::Expression> lhs); std::unique_ptr<ast::Expression> lhs);
/// Parses the `additive_expression` grammar element /// Parses the `additive_expression` grammar element
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -357,7 +419,7 @@ class ParserImpl {
/// failure. /// failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> expect_shift_expr( Expect<std::unique_ptr<ast::Expression>> expect_shift_expr(
std::unique_ptr<ast::Expression> lhs); std::unique_ptr<ast::Expression> lhs);
/// Parses the `shift_expression` grammar element /// Parses the `shift_expression` grammar element
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -366,7 +428,7 @@ class ParserImpl {
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> expect_relational_expr( Expect<std::unique_ptr<ast::Expression>> expect_relational_expr(
std::unique_ptr<ast::Expression> lhs); std::unique_ptr<ast::Expression> lhs);
/// Parses the `relational_expression` grammar element /// Parses the `relational_expression` grammar element
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -375,7 +437,7 @@ class ParserImpl {
/// failure. /// failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> expect_equality_expr( Expect<std::unique_ptr<ast::Expression>> expect_equality_expr(
std::unique_ptr<ast::Expression> lhs); std::unique_ptr<ast::Expression> lhs);
/// Parses the `equality_expression` grammar element /// Parses the `equality_expression` grammar element
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -384,7 +446,7 @@ class ParserImpl {
/// failure. /// failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> expect_and_expr( Expect<std::unique_ptr<ast::Expression>> expect_and_expr(
std::unique_ptr<ast::Expression> lhs); std::unique_ptr<ast::Expression> lhs);
/// Parses the `and_expression` grammar element /// Parses the `and_expression` grammar element
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -393,7 +455,7 @@ class ParserImpl {
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> expect_exclusive_or_expr( Expect<std::unique_ptr<ast::Expression>> expect_exclusive_or_expr(
std::unique_ptr<ast::Expression> lhs); std::unique_ptr<ast::Expression> lhs);
/// Parses the `exclusive_or_expression` grammar elememnt /// Parses the `exclusive_or_expression` grammar elememnt
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -402,7 +464,7 @@ class ParserImpl {
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> expect_inclusive_or_expr( Expect<std::unique_ptr<ast::Expression>> expect_inclusive_or_expr(
std::unique_ptr<ast::Expression> lhs); std::unique_ptr<ast::Expression> lhs);
/// Parses the `inclusive_or_expression` grammar element /// Parses the `inclusive_or_expression` grammar element
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -411,7 +473,7 @@ class ParserImpl {
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> expect_logical_and_expr( Expect<std::unique_ptr<ast::Expression>> expect_logical_and_expr(
std::unique_ptr<ast::Expression> lhs); std::unique_ptr<ast::Expression> lhs);
/// Parses a `logical_and_expression` grammar element /// Parses a `logical_and_expression` grammar element
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -420,7 +482,7 @@ class ParserImpl {
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> expect_logical_or_expr( Expect<std::unique_ptr<ast::Expression>> expect_logical_or_expr(
std::unique_ptr<ast::Expression> lhs); std::unique_ptr<ast::Expression> lhs);
/// Parses a `logical_or_expression` grammar element /// Parses a `logical_or_expression` grammar element
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
@ -449,12 +511,16 @@ class ParserImpl {
/// represent a decoration. /// represent a decoration.
/// @see #decoration for the full list of decorations this method parses. /// @see #decoration for the full list of decorations this method parses.
/// @return the parsed decoration, or nullptr on error. /// @return the parsed decoration, or nullptr on error.
std::unique_ptr<ast::Decoration> expect_decoration(); Expect<std::unique_ptr<ast::Decoration>> expect_decoration();
private: private:
/// ResultType resolves to the return type for the function or lambda F. /// ReturnType resolves to the return type for the function or lambda F.
template <typename F> template <typename F>
using ResultType = typename std::result_of<F()>::type; using ReturnType = typename std::result_of<F()>::type;
/// ResultType resolves to |T| for a |RESULT| of type Expect<T>.
template <typename RESULT>
using ResultType = typename RESULT::type;
/// @returns true and consumes the next token if it equals |tok|. /// @returns true and consumes the next token if it equals |tok|.
/// @param source if not nullptr, the next token's source is written to this /// @param source if not nullptr, the next token's source is written to this
@ -470,33 +536,25 @@ class ParserImpl {
/// next token is not a signed integer. /// next token is not a signed integer.
/// Always consumes the next token. /// Always consumes the next token.
/// @param use a description of what was being parsed if an error was raised /// @param use a description of what was being parsed if an error was raised
/// @param out the pointer to write the parsed integer to /// @returns the parsed integer.
/// @returns true if the signed integer was parsed without error Expect<int32_t> expect_sint(const std::string& use);
bool expect_sint(const std::string& use, int32_t* out);
/// Parses a signed integer from the next token in the stream, erroring if /// Parses a signed integer from the next token in the stream, erroring if
/// the next token is not a signed integer or is negative. /// the next token is not a signed integer or is negative.
/// Always consumes the next token. /// Always consumes the next token.
/// @param use a description of what was being parsed if an error was raised /// @param use a description of what was being parsed if an error was raised
/// @param out the pointer to write the parsed integer to /// @returns the parsed integer.
/// @returns true if the signed integer was parsed without error Expect<uint32_t> expect_positive_sint(const std::string& use);
bool expect_positive_sint(const std::string& use, uint32_t* out);
/// Parses a non-zero signed integer from the next token in the stream, /// Parses a non-zero signed integer from the next token in the stream,
/// erroring if the next token is not a signed integer or is less than 1. /// erroring if the next token is not a signed integer or is less than 1.
/// Always consumes the next token. /// Always consumes the next token.
/// @param use a description of what was being parsed if an error was raised /// @param use a description of what was being parsed if an error was raised
/// @param out the pointer to write the parsed integer to /// @returns the parsed integer.
/// @returns true if the signed integer was parsed without error Expect<uint32_t> expect_nonzero_positive_sint(const std::string& use);
bool expect_nonzero_positive_sint(const std::string& use, uint32_t* out);
/// Errors if the next token is not an identifier. /// Errors if the next token is not an identifier.
/// Always consumes the next token. /// Always consumes the next token.
/// @param use a description of what was being parsed if an error was raised /// @param use a description of what was being parsed if an error was raised
/// @param out the pointer to write the parsed identifier to /// @returns the parsed identifier.
/// @param source if not nullptr, the next token's source is written to this Expect<std::string> expect_ident(const std::string& use);
/// pointer, regardless of success or error
/// @returns true if the identifier was parsed without error
bool expect_ident(const std::string& use,
std::string* out,
Source* source = nullptr);
/// Parses a lexical block starting with the token |start| and ending with /// Parses a lexical block starting with the token |start| and ending with
/// the token |end|. |body| is called to parse the lexical block body between /// the token |end|. |body| is called to parse the lexical block body between
/// the |start| and |end| tokens. /// the |start| and |end| tokens.
@ -508,10 +566,10 @@ class ParserImpl {
/// @param end the token that ends the lexical block /// @param end the token that ends the lexical block
/// @param use a description of what was being parsed if an error was raised /// @param use a description of what was being parsed if an error was raised
/// @param body a function or lambda that is called to parse the lexical block /// @param body a function or lambda that is called to parse the lexical block
/// body, with the signature T(). /// body, with the signature: `Expect<Result>()`.
/// @return the value returned by |body| if no errors are raised, otherwise /// @return the value returned by |body| if no errors are raised, otherwise
/// a zero-initialized |T|. /// a zero-initialized |T|.
template <typename F, typename T = ResultType<F>> template <typename F, typename T = ReturnType<F>>
T expect_block(Token::Type start, T expect_block(Token::Type start,
Token::Type end, Token::Type end,
const std::string& use, const std::string& use,
@ -521,36 +579,53 @@ class ParserImpl {
/// and |end| arguments, respectively. /// and |end| arguments, respectively.
/// @param use a description of what was being parsed if an error was raised /// @param use a description of what was being parsed if an error was raised
/// @param body a function or lambda that is called to parse the lexical block /// @param body a function or lambda that is called to parse the lexical block
/// body, with the signature T(). /// body, with the signature: `Expect<Result>()`.
/// @return the value returned by |body| if no errors are raised, otherwise /// @return the value returned by |body| if no errors are raised, otherwise
/// a zero-initialized |T|. /// a zero-initialized |T|.
template <typename F, typename T = ResultType<F>> template <typename F, typename T = ReturnType<F>>
T expect_paren_block(const std::string& use, F&& body); T expect_paren_block(const std::string& use, F&& body);
/// A convenience function that calls |expect_block| passing /// A convenience function that calls |expect_block| passing
/// |Token::Type::kBraceLeft| and |Token::Type::kBraceRight| for the |start| /// |Token::Type::kBraceLeft| and |Token::Type::kBraceRight| for the |start|
/// and |end| arguments, respectively. /// and |end| arguments, respectively.
/// @param use a description of what was being parsed if an error was raised /// @param use a description of what was being parsed if an error was raised
/// @param body a function or lambda that is called to parse the lexical block /// @param body a function or lambda that is called to parse the lexical block
/// body, with the signature T(). /// body, with the signature: `Expect<Result>()`.
/// @return the value returned by |body| if no errors are raised, otherwise /// @return the value returned by |body| if no errors are raised, otherwise
/// a zero-initialized |T|. /// a zero-initialized |T|.
template <typename F, typename T = ResultType<F>> template <typename F, typename T = ReturnType<F>>
T expect_brace_block(const std::string& use, F&& body); T expect_brace_block(const std::string& use, F&& body);
// Versions of expect_block(), expect_paren_block_old(),
// expect_brace_block_old() that do not take an Expect for T.
// These will be removed in the near future.
// TODO(ben-clayton) - migrate remaining uses of these.
template <typename F, typename T = ReturnType<F>>
T expect_block_old(Token::Type start,
Token::Type end,
const std::string& use,
F&& body);
template <typename F, typename T = ReturnType<F>>
T expect_paren_block_old(const std::string& use, F&& body);
template <typename F, typename T = ReturnType<F>>
T expect_brace_block_old(const std::string& use, F&& body);
/// Downcasts all the decorations in |list| to the type |T|, raising a parser /// Downcasts all the decorations in |list| to the type |T|, raising a parser
/// error if any of the decorations aren't of the type |T|. /// error if any of the decorations aren't of the type |T|.
template <typename T> template <typename T>
std::vector<std::unique_ptr<T>> cast_decorations(ast::DecorationList& in); Expect<std::vector<std::unique_ptr<T>>> cast_decorations(
ast::DecorationList& in);
/// Reports an error if the decoration list |list| is not empty. /// Reports an error if the decoration list |list| is not empty.
/// Used to ensure that all decorations are consumed. /// Used to ensure that all decorations are consumed.
bool expect_decorations_consumed(const ast::DecorationList& list); bool expect_decorations_consumed(const ast::DecorationList& list);
ast::type::Type* expect_type_decl_pointer(); Expect<ast::type::Type*> expect_type_decl_pointer();
ast::type::Type* expect_type_decl_vector(Token t); Expect<ast::type::Type*> expect_type_decl_vector(Token t);
ast::type::Type* expect_type_decl_array(ast::ArrayDecorationList decos); Expect<ast::type::Type*> expect_type_decl_array(
ast::type::Type* expect_type_decl_matrix(Token t); ast::ArrayDecorationList decos);
Expect<ast::type::Type*> expect_type_decl_matrix(Token t);
std::unique_ptr<ast::ConstructorExpression> expect_const_expr_internal( Expect<std::unique_ptr<ast::ConstructorExpression>>
uint32_t depth); expect_const_expr_internal(uint32_t depth);
Context& ctx_; Context& ctx_;
diag::List diags_; diag::List diags_;

View File

@ -30,26 +30,29 @@ TEST_F(ParserImplTest, ArgumentExpressionList_Parses) {
auto* p = parser("a"); auto* p = parser("a");
auto e = p->expect_argument_expression_list(); auto e = p->expect_argument_expression_list();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
ASSERT_EQ(e.size(), 1u); ASSERT_EQ(e.value.size(), 1u);
ASSERT_TRUE(e[0]->IsIdentifier()); ASSERT_TRUE(e.value[0]->IsIdentifier());
} }
TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) { TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) {
auto* p = parser("a, -33, 1+2"); auto* p = parser("a, -33, 1+2");
auto e = p->expect_argument_expression_list(); auto e = p->expect_argument_expression_list();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
ASSERT_EQ(e.size(), 3u); ASSERT_EQ(e.value.size(), 3u);
ASSERT_TRUE(e[0]->IsIdentifier()); ASSERT_TRUE(e.value[0]->IsIdentifier());
ASSERT_TRUE(e[1]->IsConstructor()); ASSERT_TRUE(e.value[1]->IsConstructor());
ASSERT_TRUE(e[2]->IsBinary()); ASSERT_TRUE(e.value[2]->IsBinary());
} }
TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingExpression) { TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingExpression) {
auto* p = parser("a, "); auto* p = parser("a, ");
auto e = p->expect_argument_expression_list(); auto e = p->expect_argument_expression_list();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
EXPECT_EQ(p->error(), "1:4: unable to parse argument expression after comma"); EXPECT_EQ(p->error(), "1:4: unable to parse argument expression after comma");
} }
@ -57,6 +60,7 @@ TEST_F(ParserImplTest, ArgumentExpressionList_HandlesInvalidExpression) {
auto* p = parser("if(a) {}"); auto* p = parser("if(a) {}");
auto e = p->expect_argument_expression_list(); auto e = p->expect_argument_expression_list();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
EXPECT_EQ(p->error(), "1:1: unable to parse argument expression"); EXPECT_EQ(p->error(), "1:1: unable to parse argument expression");
} }

View File

@ -28,22 +28,25 @@ TEST_F(ParserImplTest, BodyStmt) {
})"); })");
auto e = p->expect_body_stmt(); auto e = p->expect_body_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e->size(), 2u); ASSERT_FALSE(e.errored);
EXPECT_TRUE(e->get(0)->IsDiscard()); ASSERT_EQ(e.value->size(), 2u);
EXPECT_TRUE(e->get(1)->IsReturn()); EXPECT_TRUE(e.value->get(0)->IsDiscard());
EXPECT_TRUE(e.value->get(1)->IsReturn());
} }
TEST_F(ParserImplTest, BodyStmt_Empty) { TEST_F(ParserImplTest, BodyStmt_Empty) {
auto* p = parser("{}"); auto* p = parser("{}");
auto e = p->expect_body_stmt(); auto e = p->expect_body_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e->size(), 0u); ASSERT_FALSE(e.errored);
EXPECT_EQ(e.value->size(), 0u);
} }
TEST_F(ParserImplTest, BodyStmt_InvalidStmt) { TEST_F(ParserImplTest, BodyStmt_InvalidStmt) {
auto* p = parser("{fn main() -> void {}}"); auto* p = parser("{fn main() -> void {}}");
auto e = p->expect_body_stmt(); auto e = p->expect_body_stmt();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
EXPECT_EQ(p->error(), "1:2: expected '}'"); EXPECT_EQ(p->error(), "1:2: expected '}'");
} }
@ -51,6 +54,7 @@ TEST_F(ParserImplTest, BodyStmt_MissingRightParen) {
auto* p = parser("{return;"); auto* p = parser("{return;");
auto e = p->expect_body_stmt(); auto e = p->expect_body_stmt();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
EXPECT_EQ(p->error(), "1:9: expected '}'"); EXPECT_EQ(p->error(), "1:9: expected '}'");
} }

View File

@ -30,11 +30,11 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl) {
auto* p = parser("vec2<f32>(1., 2.)"); auto* p = parser("vec2<f32>(1., 2.)");
auto e = p->expect_const_expr(); auto e = p->expect_const_expr();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_FALSE(e.errored);
ASSERT_TRUE(e->IsConstructor()); ASSERT_TRUE(e.value->IsConstructor());
ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor()); ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor());
auto* t = e->AsConstructor()->AsTypeConstructor(); auto* t = e.value->AsConstructor()->AsTypeConstructor();
ASSERT_TRUE(t->type()->IsVector()); ASSERT_TRUE(t->type()->IsVector());
EXPECT_EQ(t->type()->AsVector()->size(), 2u); EXPECT_EQ(t->type()->AsVector()->size(), 2u);
@ -58,7 +58,8 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingRightParen) {
auto* p = parser("vec2<f32>(1., 2."); auto* p = parser("vec2<f32>(1., 2.");
auto e = p->expect_const_expr(); auto e = p->expect_const_expr();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:17: expected ')' for type constructor"); EXPECT_EQ(p->error(), "1:17: expected ')' for type constructor");
} }
@ -66,7 +67,8 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingLeftParen) {
auto* p = parser("vec2<f32> 1., 2.)"); auto* p = parser("vec2<f32> 1., 2.)");
auto e = p->expect_const_expr(); auto e = p->expect_const_expr();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor"); EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor");
} }
@ -74,7 +76,8 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_HangingComma) {
auto* p = parser("vec2<f32>(1.,)"); auto* p = parser("vec2<f32>(1.,)");
auto e = p->expect_const_expr(); auto e = p->expect_const_expr();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:14: unable to parse const literal"); EXPECT_EQ(p->error(), "1:14: unable to parse const literal");
} }
@ -82,7 +85,8 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingComma) {
auto* p = parser("vec2<f32>(1. 2."); auto* p = parser("vec2<f32>(1. 2.");
auto e = p->expect_const_expr(); auto e = p->expect_const_expr();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:14: expected ')' for type constructor"); EXPECT_EQ(p->error(), "1:14: expected ')' for type constructor");
} }
@ -90,7 +94,8 @@ TEST_F(ParserImplTest, ConstExpr_MissingExpr) {
auto* p = parser("vec2<f32>()"); auto* p = parser("vec2<f32>()");
auto e = p->expect_const_expr(); auto e = p->expect_const_expr();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:11: unable to parse const literal"); EXPECT_EQ(p->error(), "1:11: unable to parse const literal");
} }
@ -98,7 +103,8 @@ TEST_F(ParserImplTest, ConstExpr_InvalidExpr) {
auto* p = parser("vec2<f32>(1., if(a) {})"); auto* p = parser("vec2<f32>(1., if(a) {})");
auto e = p->expect_const_expr(); auto e = p->expect_const_expr();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:15: unable to parse const literal"); EXPECT_EQ(p->error(), "1:15: unable to parse const literal");
} }
@ -106,10 +112,11 @@ TEST_F(ParserImplTest, ConstExpr_ConstLiteral) {
auto* p = parser("true"); auto* p = parser("true");
auto e = p->expect_const_expr(); auto e = p->expect_const_expr();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_FALSE(e.errored);
ASSERT_TRUE(e->IsConstructor()); ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->AsConstructor()->IsScalarConstructor()); ASSERT_TRUE(e.value->IsConstructor());
auto* c = e->AsConstructor()->AsScalarConstructor(); ASSERT_TRUE(e.value->AsConstructor()->IsScalarConstructor());
auto* c = e.value->AsConstructor()->AsScalarConstructor();
ASSERT_TRUE(c->literal()->IsBool()); ASSERT_TRUE(c->literal()->IsBool());
EXPECT_TRUE(c->literal()->AsBool()->IsTrue()); EXPECT_TRUE(c->literal()->AsBool()->IsTrue());
} }
@ -118,7 +125,8 @@ TEST_F(ParserImplTest, ConstExpr_ConstLiteral_Invalid) {
auto* p = parser("invalid"); auto* p = parser("invalid");
auto e = p->expect_const_expr(); auto e = p->expect_const_expr();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:1: unknown constructed type 'invalid'"); EXPECT_EQ(p->error(), "1:1: unknown constructed type 'invalid'");
} }
@ -134,7 +142,8 @@ TEST_F(ParserImplTest, ConstExpr_Recursion) {
auto* p = parser(out.str()); auto* p = parser(out.str());
auto e = p->expect_const_expr(); auto e = p->expect_const_expr();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:517: max const_expr depth reached"); EXPECT_EQ(p->error(), "1:517: max const_expr depth reached");
} }

View File

@ -27,16 +27,18 @@ class ForStmtTest : public ParserImplTest {
public: public:
void TestForLoop(std::string loop_str, std::string for_str) { void TestForLoop(std::string loop_str, std::string for_str) {
auto* p_loop = parser(loop_str); auto* p_loop = parser(loop_str);
auto e_loop = p_loop->statements(); auto e_loop = p_loop->expect_statements();
ASSERT_FALSE(p_loop->has_error()) << p_loop->error(); EXPECT_FALSE(e_loop.errored);
ASSERT_NE(e_loop, nullptr); EXPECT_FALSE(p_loop->has_error()) << p_loop->error();
ASSERT_NE(e_loop.value, nullptr);
auto* p_for = parser(for_str); auto* p_for = parser(for_str);
auto e_for = p_for->statements(); auto e_for = p_for->expect_statements();
ASSERT_FALSE(p_for->has_error()) << p_for->error(); EXPECT_FALSE(e_for.errored);
ASSERT_NE(e_for, nullptr); EXPECT_FALSE(p_for->has_error()) << p_for->error();
ASSERT_NE(e_for.value, nullptr);
EXPECT_EQ(e_loop->str(), e_for->str()); EXPECT_EQ(e_loop.value->str(), e_for.value->str());
} }
}; };

View File

@ -24,253 +24,289 @@ namespace {
TEST_F(ParserImplTest, ImageStorageType_Invalid) { TEST_F(ParserImplTest, ImageStorageType_Invalid) {
auto* p = parser("1234"); auto* p = parser("1234");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kNone); EXPECT_TRUE(t.errored);
EXPECT_FALSE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:1: invalid format for test");
} }
TEST_F(ParserImplTest, ImageStorageType_R8Unorm) { TEST_F(ParserImplTest, ImageStorageType_R8Unorm) {
auto* p = parser("r8unorm"); auto* p = parser("r8unorm");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kR8Unorm); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kR8Unorm);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_R8Snorm) { TEST_F(ParserImplTest, ImageStorageType_R8Snorm) {
auto* p = parser("r8snorm"); auto* p = parser("r8snorm");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kR8Snorm); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kR8Snorm);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_R8Uint) { TEST_F(ParserImplTest, ImageStorageType_R8Uint) {
auto* p = parser("r8uint"); auto* p = parser("r8uint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kR8Uint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kR8Uint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_R8Sint) { TEST_F(ParserImplTest, ImageStorageType_R8Sint) {
auto* p = parser("r8sint"); auto* p = parser("r8sint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kR8Sint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kR8Sint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_R16Uint) { TEST_F(ParserImplTest, ImageStorageType_R16Uint) {
auto* p = parser("r16uint"); auto* p = parser("r16uint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kR16Uint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kR16Uint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_R16Sint) { TEST_F(ParserImplTest, ImageStorageType_R16Sint) {
auto* p = parser("r16sint"); auto* p = parser("r16sint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kR16Sint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kR16Sint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_R16Float) { TEST_F(ParserImplTest, ImageStorageType_R16Float) {
auto* p = parser("r16float"); auto* p = parser("r16float");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kR16Float); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kR16Float);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rg8Unorm) { TEST_F(ParserImplTest, ImageStorageType_Rg8Unorm) {
auto* p = parser("rg8unorm"); auto* p = parser("rg8unorm");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRg8Unorm); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRg8Unorm);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rg8Snorm) { TEST_F(ParserImplTest, ImageStorageType_Rg8Snorm) {
auto* p = parser("rg8snorm"); auto* p = parser("rg8snorm");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRg8Snorm); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRg8Snorm);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rg8Uint) { TEST_F(ParserImplTest, ImageStorageType_Rg8Uint) {
auto* p = parser("rg8uint"); auto* p = parser("rg8uint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRg8Uint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRg8Uint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rg8Sint) { TEST_F(ParserImplTest, ImageStorageType_Rg8Sint) {
auto* p = parser("rg8sint"); auto* p = parser("rg8sint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRg8Sint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRg8Sint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_R32Uint) { TEST_F(ParserImplTest, ImageStorageType_R32Uint) {
auto* p = parser("r32uint"); auto* p = parser("r32uint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kR32Uint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kR32Uint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_R32Sint) { TEST_F(ParserImplTest, ImageStorageType_R32Sint) {
auto* p = parser("r32sint"); auto* p = parser("r32sint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kR32Sint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kR32Sint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_R32Float) { TEST_F(ParserImplTest, ImageStorageType_R32Float) {
auto* p = parser("r32float"); auto* p = parser("r32float");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kR32Float); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kR32Float);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rg16Uint) { TEST_F(ParserImplTest, ImageStorageType_Rg16Uint) {
auto* p = parser("rg16uint"); auto* p = parser("rg16uint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRg16Uint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRg16Uint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rg16Sint) { TEST_F(ParserImplTest, ImageStorageType_Rg16Sint) {
auto* p = parser("rg16sint"); auto* p = parser("rg16sint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRg16Sint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRg16Sint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rg16Float) { TEST_F(ParserImplTest, ImageStorageType_Rg16Float) {
auto* p = parser("rg16float"); auto* p = parser("rg16float");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRg16Float); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRg16Float);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgba8Unorm) { TEST_F(ParserImplTest, ImageStorageType_Rgba8Unorm) {
auto* p = parser("rgba8unorm"); auto* p = parser("rgba8unorm");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgba8Unorm); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba8Unorm);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgba8UnormSrgb) { TEST_F(ParserImplTest, ImageStorageType_Rgba8UnormSrgb) {
auto* p = parser("rgba8unorm_srgb"); auto* p = parser("rgba8unorm_srgb");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgba8UnormSrgb); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba8UnormSrgb);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgba8Snorm) { TEST_F(ParserImplTest, ImageStorageType_Rgba8Snorm) {
auto* p = parser("rgba8snorm"); auto* p = parser("rgba8snorm");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgba8Snorm); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba8Snorm);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgba8Uint) { TEST_F(ParserImplTest, ImageStorageType_Rgba8Uint) {
auto* p = parser("rgba8uint"); auto* p = parser("rgba8uint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgba8Uint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba8Uint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgba8Sint) { TEST_F(ParserImplTest, ImageStorageType_Rgba8Sint) {
auto* p = parser("rgba8sint"); auto* p = parser("rgba8sint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgba8Sint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba8Sint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Bgra8Unorm) { TEST_F(ParserImplTest, ImageStorageType_Bgra8Unorm) {
auto* p = parser("bgra8unorm"); auto* p = parser("bgra8unorm");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kBgra8Unorm); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kBgra8Unorm);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Bgra8UnormSrgb) { TEST_F(ParserImplTest, ImageStorageType_Bgra8UnormSrgb) {
auto* p = parser("bgra8unorm_srgb"); auto* p = parser("bgra8unorm_srgb");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kBgra8UnormSrgb); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kBgra8UnormSrgb);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgb10A2Unorm) { TEST_F(ParserImplTest, ImageStorageType_Rgb10A2Unorm) {
auto* p = parser("rgb10a2unorm"); auto* p = parser("rgb10a2unorm");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgb10A2Unorm); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgb10A2Unorm);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rg11B10Float) { TEST_F(ParserImplTest, ImageStorageType_Rg11B10Float) {
auto* p = parser("rg11b10float"); auto* p = parser("rg11b10float");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRg11B10Float); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRg11B10Float);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rg32Uint) { TEST_F(ParserImplTest, ImageStorageType_Rg32Uint) {
auto* p = parser("rg32uint"); auto* p = parser("rg32uint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRg32Uint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRg32Uint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rg32Sint) { TEST_F(ParserImplTest, ImageStorageType_Rg32Sint) {
auto* p = parser("rg32sint"); auto* p = parser("rg32sint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRg32Sint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRg32Sint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rg32Float) { TEST_F(ParserImplTest, ImageStorageType_Rg32Float) {
auto* p = parser("rg32float"); auto* p = parser("rg32float");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRg32Float); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRg32Float);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgba16Uint) { TEST_F(ParserImplTest, ImageStorageType_Rgba16Uint) {
auto* p = parser("rgba16uint"); auto* p = parser("rgba16uint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgba16Uint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba16Uint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgba16Sint) { TEST_F(ParserImplTest, ImageStorageType_Rgba16Sint) {
auto* p = parser("rgba16sint"); auto* p = parser("rgba16sint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgba16Sint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba16Sint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgba16Float) { TEST_F(ParserImplTest, ImageStorageType_Rgba16Float) {
auto* p = parser("rgba16float"); auto* p = parser("rgba16float");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgba16Float); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba16Float);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgba32Uint) { TEST_F(ParserImplTest, ImageStorageType_Rgba32Uint) {
auto* p = parser("rgba32uint"); auto* p = parser("rgba32uint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgba32Uint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba32Uint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgba32Sint) { TEST_F(ParserImplTest, ImageStorageType_Rgba32Sint) {
auto* p = parser("rgba32sint"); auto* p = parser("rgba32sint");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgba32Sint); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba32Sint);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, ImageStorageType_Rgba32Float) { TEST_F(ParserImplTest, ImageStorageType_Rgba32Float) {
auto* p = parser("rgba32float"); auto* p = parser("rgba32float");
auto t = p->image_storage_type(); auto t = p->expect_image_storage_type("test");
EXPECT_EQ(t, ast::type::ImageFormat::kRgba32Float); EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::ImageFormat::kRgba32Float);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }

View File

@ -34,16 +34,17 @@ TEST_F(ParserImplTest, ParamList_Single) {
auto* p = parser("a : i32"); auto* p = parser("a : i32");
auto e = p->expect_param_list(); auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.size(), 1u); ASSERT_FALSE(e.errored);
EXPECT_EQ(e.value.size(), 1u);
EXPECT_EQ(e[0]->name(), "a"); EXPECT_EQ(e.value[0]->name(), "a");
EXPECT_EQ(e[0]->type(), i32); EXPECT_EQ(e.value[0]->type(), i32);
EXPECT_TRUE(e[0]->is_const()); EXPECT_TRUE(e.value[0]->is_const());
ASSERT_EQ(e[0]->source().range.begin.line, 1u); ASSERT_EQ(e.value[0]->source().range.begin.line, 1u);
ASSERT_EQ(e[0]->source().range.begin.column, 1u); ASSERT_EQ(e.value[0]->source().range.begin.column, 1u);
ASSERT_EQ(e[0]->source().range.end.line, 1u); ASSERT_EQ(e.value[0]->source().range.end.line, 1u);
ASSERT_EQ(e[0]->source().range.end.column, 2u); ASSERT_EQ(e.value[0]->source().range.end.column, 2u);
} }
TEST_F(ParserImplTest, ParamList_Multiple) { TEST_F(ParserImplTest, ParamList_Multiple) {
@ -54,47 +55,50 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
auto* p = parser("a : i32, b: f32, c: vec2<f32>"); auto* p = parser("a : i32, b: f32, c: vec2<f32>");
auto e = p->expect_param_list(); auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.size(), 3u); ASSERT_FALSE(e.errored);
EXPECT_EQ(e.value.size(), 3u);
EXPECT_EQ(e[0]->name(), "a"); EXPECT_EQ(e.value[0]->name(), "a");
EXPECT_EQ(e[0]->type(), i32); EXPECT_EQ(e.value[0]->type(), i32);
EXPECT_TRUE(e[0]->is_const()); EXPECT_TRUE(e.value[0]->is_const());
ASSERT_EQ(e[0]->source().range.begin.line, 1u); ASSERT_EQ(e.value[0]->source().range.begin.line, 1u);
ASSERT_EQ(e[0]->source().range.begin.column, 1u); ASSERT_EQ(e.value[0]->source().range.begin.column, 1u);
ASSERT_EQ(e[0]->source().range.end.line, 1u); ASSERT_EQ(e.value[0]->source().range.end.line, 1u);
ASSERT_EQ(e[0]->source().range.end.column, 2u); ASSERT_EQ(e.value[0]->source().range.end.column, 2u);
EXPECT_EQ(e[1]->name(), "b"); EXPECT_EQ(e.value[1]->name(), "b");
EXPECT_EQ(e[1]->type(), f32); EXPECT_EQ(e.value[1]->type(), f32);
EXPECT_TRUE(e[1]->is_const()); EXPECT_TRUE(e.value[1]->is_const());
ASSERT_EQ(e[1]->source().range.begin.line, 1u); ASSERT_EQ(e.value[1]->source().range.begin.line, 1u);
ASSERT_EQ(e[1]->source().range.begin.column, 10u); ASSERT_EQ(e.value[1]->source().range.begin.column, 10u);
ASSERT_EQ(e[1]->source().range.end.line, 1u); ASSERT_EQ(e.value[1]->source().range.end.line, 1u);
ASSERT_EQ(e[1]->source().range.end.column, 11u); ASSERT_EQ(e.value[1]->source().range.end.column, 11u);
EXPECT_EQ(e[2]->name(), "c"); EXPECT_EQ(e.value[2]->name(), "c");
EXPECT_EQ(e[2]->type(), vec2); EXPECT_EQ(e.value[2]->type(), vec2);
EXPECT_TRUE(e[2]->is_const()); EXPECT_TRUE(e.value[2]->is_const());
ASSERT_EQ(e[2]->source().range.begin.line, 1u); ASSERT_EQ(e.value[2]->source().range.begin.line, 1u);
ASSERT_EQ(e[2]->source().range.begin.column, 18u); ASSERT_EQ(e.value[2]->source().range.begin.column, 18u);
ASSERT_EQ(e[2]->source().range.end.line, 1u); ASSERT_EQ(e.value[2]->source().range.end.line, 1u);
ASSERT_EQ(e[2]->source().range.end.column, 19u); ASSERT_EQ(e.value[2]->source().range.end.column, 19u);
} }
TEST_F(ParserImplTest, ParamList_Empty) { TEST_F(ParserImplTest, ParamList_Empty) {
auto* p = parser(""); auto* p = parser("");
auto e = p->expect_param_list(); auto e = p->expect_param_list();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
EXPECT_EQ(e.size(), 0u); ASSERT_FALSE(e.errored);
EXPECT_EQ(e.value.size(), 0u);
} }
TEST_F(ParserImplTest, ParamList_HangingComma) { TEST_F(ParserImplTest, ParamList_HangingComma) {
auto* p = parser("a : i32,"); auto* p = parser("a : i32,");
auto e = p->expect_param_list(); auto e = p->expect_param_list();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
EXPECT_EQ(p->error(), "1:9: expected identifier for parameter"); EXPECT_EQ(p->error(), "1:9: expected identifier for parameter");
} }

View File

@ -25,15 +25,17 @@ TEST_F(ParserImplTest, ParenRhsStmt) {
auto* p = parser("(a + b)"); auto* p = parser("(a + b)");
auto e = p->expect_paren_rhs_stmt(); auto e = p->expect_paren_rhs_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_FALSE(e.errored);
ASSERT_TRUE(e->IsBinary()); ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsBinary());
} }
TEST_F(ParserImplTest, ParenRhsStmt_MissingLeftParen) { TEST_F(ParserImplTest, ParenRhsStmt_MissingLeftParen) {
auto* p = parser("true)"); auto* p = parser("true)");
auto e = p->expect_paren_rhs_stmt(); auto e = p->expect_paren_rhs_stmt();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:1: expected '('"); EXPECT_EQ(p->error(), "1:1: expected '('");
} }
@ -41,7 +43,8 @@ TEST_F(ParserImplTest, ParenRhsStmt_MissingRightParen) {
auto* p = parser("(true"); auto* p = parser("(true");
auto e = p->expect_paren_rhs_stmt(); auto e = p->expect_paren_rhs_stmt();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:6: expected ')'"); EXPECT_EQ(p->error(), "1:6: expected ')'");
} }
@ -49,7 +52,8 @@ TEST_F(ParserImplTest, ParenRhsStmt_InvalidExpression) {
auto* p = parser("(if (a() {})"); auto* p = parser("(if (a() {})");
auto e = p->expect_paren_rhs_stmt(); auto e = p->expect_paren_rhs_stmt();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:2: unable to parse expression"); EXPECT_EQ(p->error(), "1:2: unable to parse expression");
} }
@ -57,7 +61,8 @@ TEST_F(ParserImplTest, ParenRhsStmt_MissingExpression) {
auto* p = parser("()"); auto* p = parser("()");
auto e = p->expect_paren_rhs_stmt(); auto e = p->expect_paren_rhs_stmt();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); ASSERT_TRUE(e.errored);
ASSERT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:2: unable to parse expression"); EXPECT_EQ(p->error(), "1:2: unable to parse expression");
} }

View File

@ -36,15 +36,14 @@ TEST_P(PipelineStageTest, Parses) {
auto params = GetParam(); auto params = GetParam();
auto* p = parser(params.input); auto* p = parser(params.input);
ast::PipelineStage stage; auto stage = p->expect_pipeline_stage();
Source source;
std::tie(stage, source) = p->expect_pipeline_stage();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(stage, params.result); ASSERT_FALSE(stage.errored);
EXPECT_EQ(source.range.begin.line, 1u); EXPECT_EQ(stage.value, params.result);
EXPECT_EQ(source.range.begin.column, 1u); EXPECT_EQ(stage.source.range.begin.line, 1u);
EXPECT_EQ(source.range.end.line, 1u); EXPECT_EQ(stage.source.range.begin.column, 1u);
EXPECT_EQ(source.range.end.column, 1u + params.input.size()); EXPECT_EQ(stage.source.range.end.line, 1u);
EXPECT_EQ(stage.source.range.end.column, 1u + params.input.size());
auto t = p->next(); auto t = p->next();
EXPECT_TRUE(t.IsEof()); EXPECT_TRUE(t.IsEof());
@ -59,16 +58,10 @@ INSTANTIATE_TEST_SUITE_P(
TEST_F(ParserImplTest, PipelineStage_NoMatch) { TEST_F(ParserImplTest, PipelineStage_NoMatch) {
auto* p = parser("not-a-stage"); auto* p = parser("not-a-stage");
ast::PipelineStage stage; auto stage = p->expect_pipeline_stage();
Source source;
std::tie(stage, source) = p->expect_pipeline_stage();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(stage.errored);
ASSERT_EQ(p->error(), "1:1: invalid value for stage decoration"); ASSERT_EQ(p->error(), "1:1: invalid value for stage decoration");
ASSERT_EQ(stage, ast::PipelineStage::kNone);
EXPECT_EQ(source.range.begin.line, 1u);
EXPECT_EQ(source.range.begin.column, 1u);
EXPECT_EQ(source.range.end.line, 1u);
EXPECT_EQ(source.range.end.column, 4u);
} }
} // namespace } // namespace

View File

@ -24,18 +24,20 @@ namespace {
TEST_F(ParserImplTest, Statements) { TEST_F(ParserImplTest, Statements) {
auto* p = parser("discard; return;"); auto* p = parser("discard; return;");
auto e = p->statements(); auto e = p->expect_statements();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.errored);
ASSERT_EQ(e->size(), 2u); EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_TRUE(e->get(0)->IsDiscard()); ASSERT_EQ(e.value->size(), 2u);
EXPECT_TRUE(e->get(1)->IsReturn()); EXPECT_TRUE(e.value->get(0)->IsDiscard());
EXPECT_TRUE(e.value->get(1)->IsReturn());
} }
TEST_F(ParserImplTest, Statements_Empty) { TEST_F(ParserImplTest, Statements_Empty) {
auto* p = parser(""); auto* p = parser("");
auto e = p->statements(); auto e = p->expect_statements();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.errored);
ASSERT_EQ(e->size(), 0u); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.value->size(), 0u);
} }
} // namespace } // namespace

View File

@ -38,8 +38,9 @@ TEST_P(StorageClassTest, Parses) {
auto* p = parser(params.input); auto* p = parser(params.input);
auto sc = p->expect_storage_class("test"); auto sc = p->expect_storage_class("test");
ASSERT_FALSE(p->has_error()); EXPECT_FALSE(sc.errored);
EXPECT_EQ(sc, params.result); EXPECT_FALSE(p->has_error());
EXPECT_EQ(sc.value, params.result);
auto t = p->next(); auto t = p->next();
EXPECT_TRUE(t.IsEof()); EXPECT_TRUE(t.IsEof());
@ -62,8 +63,8 @@ INSTANTIATE_TEST_SUITE_P(
TEST_F(ParserImplTest, StorageClass_NoMatch) { TEST_F(ParserImplTest, StorageClass_NoMatch) {
auto* p = parser("not-a-storage-class"); auto* p = parser("not-a-storage-class");
auto sc = p->expect_storage_class("test"); auto sc = p->expect_storage_class("test");
ASSERT_EQ(sc, ast::StorageClass::kNone); EXPECT_EQ(sc.errored, true);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:1: invalid storage class for test"); EXPECT_EQ(p->error(), "1:1: invalid storage class for test");
auto t = p->next(); auto t = p->next();

View File

@ -29,9 +29,10 @@ TEST_F(ParserImplTest, StructBodyDecl_Parses) {
auto* p = parser("{a : i32;}"); auto* p = parser("{a : i32;}");
auto m = p->expect_struct_body_decl(); auto m = p->expect_struct_body_decl();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(m.size(), 1u); ASSERT_FALSE(m.errored);
ASSERT_EQ(m.value.size(), 1u);
const auto& mem = m[0]; const auto& mem = m.value[0];
EXPECT_EQ(mem->name(), "a"); EXPECT_EQ(mem->name(), "a");
EXPECT_EQ(mem->type(), i32); EXPECT_EQ(mem->type(), i32);
EXPECT_EQ(mem->decorations().size(), 0u); EXPECT_EQ(mem->decorations().size(), 0u);
@ -41,7 +42,8 @@ TEST_F(ParserImplTest, StructBodyDecl_ParsesEmpty) {
auto* p = parser("{}"); auto* p = parser("{}");
auto m = p->expect_struct_body_decl(); auto m = p->expect_struct_body_decl();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(m.size(), 0u); ASSERT_FALSE(m.errored);
ASSERT_EQ(m.value.size(), 0u);
} }
TEST_F(ParserImplTest, StructBodyDecl_InvalidMember) { TEST_F(ParserImplTest, StructBodyDecl_InvalidMember) {
@ -51,6 +53,7 @@ TEST_F(ParserImplTest, StructBodyDecl_InvalidMember) {
})"); })");
auto m = p->expect_struct_body_decl(); auto m = p->expect_struct_body_decl();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(m.errored);
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"3:12: expected signed integer literal for offset decoration"); "3:12: expected signed integer literal for offset decoration");
} }
@ -59,6 +62,7 @@ TEST_F(ParserImplTest, StructBodyDecl_MissingClosingBracket) {
auto* p = parser("{a : i32;"); auto* p = parser("{a : i32;");
auto m = p->expect_struct_body_decl(); auto m = p->expect_struct_body_decl();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(m.errored);
EXPECT_EQ(p->error(), "1:10: expected '}' for struct declaration"); EXPECT_EQ(p->error(), "1:10: expected '}' for struct declaration");
} }
@ -70,6 +74,7 @@ TEST_F(ParserImplTest, StructBodyDecl_InvalidToken) {
} )"); } )");
auto m = p->expect_struct_body_decl(); auto m = p->expect_struct_body_decl();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(m.errored);
EXPECT_EQ(p->error(), "4:3: expected identifier for struct member"); EXPECT_EQ(p->error(), "4:3: expected identifier for struct member");
} }

View File

@ -32,16 +32,17 @@ TEST_F(ParserImplTest, StructMember_Parses) {
EXPECT_EQ(decos.size(), 0u); EXPECT_EQ(decos.size(), 0u);
auto m = p->expect_struct_member(decos); auto m = p->expect_struct_member(decos);
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(m, nullptr); ASSERT_FALSE(m.errored);
ASSERT_NE(m.value, nullptr);
EXPECT_EQ(m->name(), "a"); EXPECT_EQ(m.value->name(), "a");
EXPECT_EQ(m->type(), i32); EXPECT_EQ(m.value->type(), i32);
EXPECT_EQ(m->decorations().size(), 0u); EXPECT_EQ(m.value->decorations().size(), 0u);
ASSERT_EQ(m->source().range.begin.line, 1u); ASSERT_EQ(m.value->source().range.begin.line, 1u);
ASSERT_EQ(m->source().range.begin.column, 1u); ASSERT_EQ(m.value->source().range.begin.column, 1u);
ASSERT_EQ(m->source().range.end.line, 1u); ASSERT_EQ(m.value->source().range.end.line, 1u);
ASSERT_EQ(m->source().range.end.column, 2u); ASSERT_EQ(m.value->source().range.end.column, 2u);
} }
TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) { TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
@ -52,18 +53,19 @@ TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
EXPECT_EQ(decos.size(), 1u); EXPECT_EQ(decos.size(), 1u);
auto m = p->expect_struct_member(decos); auto m = p->expect_struct_member(decos);
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(m, nullptr); ASSERT_FALSE(m.errored);
ASSERT_NE(m.value, nullptr);
EXPECT_EQ(m->name(), "a"); EXPECT_EQ(m.value->name(), "a");
EXPECT_EQ(m->type(), i32); EXPECT_EQ(m.value->type(), i32);
EXPECT_EQ(m->decorations().size(), 1u); EXPECT_EQ(m.value->decorations().size(), 1u);
EXPECT_TRUE(m->decorations()[0]->IsOffset()); EXPECT_TRUE(m.value->decorations()[0]->IsOffset());
EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2u); EXPECT_EQ(m.value->decorations()[0]->AsOffset()->offset(), 2u);
ASSERT_EQ(m->source().range.begin.line, 1u); ASSERT_EQ(m.value->source().range.begin.line, 1u);
ASSERT_EQ(m->source().range.begin.column, 15u); ASSERT_EQ(m.value->source().range.begin.column, 15u);
ASSERT_EQ(m->source().range.end.line, 1u); ASSERT_EQ(m.value->source().range.end.line, 1u);
ASSERT_EQ(m->source().range.end.column, 16u); ASSERT_EQ(m.value->source().range.end.column, 16u);
} }
TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) { TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
@ -75,20 +77,21 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
EXPECT_EQ(decos.size(), 2u); EXPECT_EQ(decos.size(), 2u);
auto m = p->expect_struct_member(decos); auto m = p->expect_struct_member(decos);
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(m, nullptr); ASSERT_FALSE(m.errored);
ASSERT_NE(m.value, nullptr);
EXPECT_EQ(m->name(), "a"); EXPECT_EQ(m.value->name(), "a");
EXPECT_EQ(m->type(), i32); EXPECT_EQ(m.value->type(), i32);
EXPECT_EQ(m->decorations().size(), 2u); EXPECT_EQ(m.value->decorations().size(), 2u);
EXPECT_TRUE(m->decorations()[0]->IsOffset()); EXPECT_TRUE(m.value->decorations()[0]->IsOffset());
EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2u); EXPECT_EQ(m.value->decorations()[0]->AsOffset()->offset(), 2u);
EXPECT_TRUE(m->decorations()[1]->IsOffset()); EXPECT_TRUE(m.value->decorations()[1]->IsOffset());
EXPECT_EQ(m->decorations()[1]->AsOffset()->offset(), 4u); EXPECT_EQ(m.value->decorations()[1]->AsOffset()->offset(), 4u);
ASSERT_EQ(m->source().range.begin.line, 2u); ASSERT_EQ(m.value->source().range.begin.line, 2u);
ASSERT_EQ(m->source().range.begin.column, 15u); ASSERT_EQ(m.value->source().range.begin.column, 15u);
ASSERT_EQ(m->source().range.end.line, 2u); ASSERT_EQ(m.value->source().range.end.line, 2u);
ASSERT_EQ(m->source().range.end.column, 16u); ASSERT_EQ(m.value->source().range.end.column, 16u);
} }
TEST_F(ParserImplTest, StructMember_InvalidDecoration) { TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
@ -96,7 +99,8 @@ TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
auto decos = p->decoration_list(); auto decos = p->decoration_list();
auto m = p->expect_struct_member(decos); auto m = p->expect_struct_member(decos);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(m, nullptr); ASSERT_TRUE(m.errored);
ASSERT_EQ(m.value, nullptr);
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:10: expected signed integer literal for offset decoration"); "1:10: expected signed integer literal for offset decoration");
} }
@ -106,7 +110,8 @@ TEST_F(ParserImplTest, StructMember_InvalidVariable) {
auto decos = p->decoration_list(); auto decos = p->decoration_list();
auto m = p->expect_struct_member(decos); auto m = p->expect_struct_member(decos);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(m, nullptr); ASSERT_TRUE(m.errored);
ASSERT_EQ(m.value, nullptr);
EXPECT_EQ(p->error(), "1:19: unknown constructed type 'B'"); EXPECT_EQ(p->error(), "1:19: unknown constructed type 'B'");
} }
@ -115,7 +120,8 @@ TEST_F(ParserImplTest, StructMember_MissingSemicolon) {
auto decos = p->decoration_list(); auto decos = p->decoration_list();
auto m = p->expect_struct_member(decos); auto m = p->expect_struct_member(decos);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(m, nullptr); ASSERT_TRUE(m.errored);
ASSERT_EQ(m.value, nullptr);
EXPECT_EQ(p->error(), "1:8: expected ';' for struct member"); EXPECT_EQ(p->error(), "1:8: expected ';' for struct member");
} }

View File

@ -25,34 +25,38 @@ TEST_F(ParserImplTest, VariableIdentDecl_Parses) {
auto* p = parser("my_var : f32"); auto* p = parser("my_var : f32");
auto decl = p->expect_variable_ident_decl("test"); auto decl = p->expect_variable_ident_decl("test");
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(decl.name, "my_var"); ASSERT_FALSE(decl.errored);
ASSERT_NE(decl.type, nullptr); ASSERT_EQ(decl->name, "my_var");
ASSERT_TRUE(decl.type->IsF32()); ASSERT_NE(decl->type, nullptr);
ASSERT_TRUE(decl->type->IsF32());
ASSERT_EQ(decl.source.range.begin.line, 1u); ASSERT_EQ(decl->source.range.begin.line, 1u);
ASSERT_EQ(decl.source.range.begin.column, 1u); ASSERT_EQ(decl->source.range.begin.column, 1u);
ASSERT_EQ(decl.source.range.end.line, 1u); ASSERT_EQ(decl->source.range.end.line, 1u);
ASSERT_EQ(decl.source.range.end.column, 7u); ASSERT_EQ(decl->source.range.end.column, 7u);
} }
TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) { TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) {
auto* p = parser(": f32"); auto* p = parser(": f32");
auto decl = p->expect_variable_ident_decl("test"); auto decl = p->expect_variable_ident_decl("test");
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
ASSERT_EQ(p->error(), "1:1: expected identifier for test"); ASSERT_EQ(p->error(), "1:1: expected identifier for test");
} }
TEST_F(ParserImplTest, VariableIdentDecl_MissingColon) { TEST_F(ParserImplTest, VariableIdentDecl_MissingColon) {
auto* p = parser("my_var f32"); auto* p = parser("my_var f32");
auto r = p->expect_variable_ident_decl("test"); auto decl = p->expect_variable_ident_decl("test");
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
ASSERT_EQ(p->error(), "1:8: expected ':' for test"); ASSERT_EQ(p->error(), "1:8: expected ':' for test");
} }
TEST_F(ParserImplTest, VariableIdentDecl_MissingType) { TEST_F(ParserImplTest, VariableIdentDecl_MissingType) {
auto* p = parser("my_var :"); auto* p = parser("my_var :");
auto r = p->expect_variable_ident_decl("test"); auto decl = p->expect_variable_ident_decl("test");
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
ASSERT_EQ(p->error(), "1:9: invalid type for test"); ASSERT_EQ(p->error(), "1:9: invalid type for test");
} }
@ -60,13 +64,15 @@ TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) {
auto* p = parser("123 : f32"); auto* p = parser("123 : f32");
auto decl = p->expect_variable_ident_decl("test"); auto decl = p->expect_variable_ident_decl("test");
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
ASSERT_EQ(p->error(), "1:1: expected identifier for test"); ASSERT_EQ(p->error(), "1:1: expected identifier for test");
} }
TEST_F(ParserImplTest, VariableIdentDecl_InvalidType) { TEST_F(ParserImplTest, VariableIdentDecl_InvalidType) {
auto* p = parser("my_var : invalid"); auto* p = parser("my_var : invalid");
auto r = p->expect_variable_ident_decl("test"); auto decl = p->expect_variable_ident_decl("test");
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(decl.errored);
ASSERT_EQ(p->error(), "1:10: unknown constructed type 'invalid'"); ASSERT_EQ(p->error(), "1:10: unknown constructed type 'invalid'");
} }