wsgl parser: Add ParserImpl::Maybe<T>

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

Another step towards supporting multiple error messages, as the caller can now test to see if the specific call errored, or didn't match, instead of using a global error state.

Makes reading the control flow conditionals a bit easier too.

Change-Id: Ie8627b8499ec9079167965da2a566401cd6bd903
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32102
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:52:24 +00:00 committed by Commit Bot service account
parent 653c4042e2
commit ab5dfee240
56 changed files with 3224 additions and 2238 deletions

File diff suppressed because it is too large Load Diff

View File

@ -80,10 +80,11 @@ 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 /// Failure holds enumerator values used for the constructing an Expect and
/// errored state. /// Match in an errored state.
struct Failure { struct Failure {
enum Errored { kErrored }; enum Errored { kErrored };
enum NoMatch { kNoMatch };
}; };
public: public:
@ -135,6 +136,74 @@ class ParserImpl {
bool errored = false; bool errored = false;
}; };
/// Maybe is the return type of the parser methods that attempts to match a
/// grammar and return a parsed value of type T, or may parse part of the
/// grammar and then hit a parse error.
/// In the case of a successful grammar match, the Maybe will have |matched|
/// set to true.
/// In the case of a parse error the called method will have called
/// |add_error()| and the Maybe will have |errored| set to true.
template <typename T>
struct Maybe {
inline Maybe(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 Maybe(U&& val, const Source& s = {}) // NOLINT
: value(std::forward<U>(val)), source(s), matched(true) {}
/// Constructor for parse error state.
inline Maybe(Failure::Errored) : errored(true) {} // NOLINT
/// Constructor for the no-match state.
inline Maybe(Failure::NoMatch) {} // NOLINT
/// Constructor from an Expect.
template <typename U>
inline Maybe(const Expect<U>& e) // NOLINT
: value(e.value),
source(e.value),
errored(e.errored),
matched(!e.errored) {}
/// Move from an Expect.
template <typename U>
inline Maybe(Expect<U>&& e) // NOLINT
: value(std::move(e.value)),
source(std::move(e.source)),
errored(e.errored),
matched(!e.errored) {}
/// Copy constructor
inline Maybe(const Maybe&) = default;
/// Move constructor
inline Maybe(Maybe&&) = default;
/// Assignment operator
/// @return this Maybe
inline Maybe& operator=(const Maybe&) = default;
/// Assignment move operator
/// @return this Maybe
inline Maybe& operator=(Maybe&&) = default;
/// @return a pointer to |value|. |errored| must be false to call.
inline T* operator->() {
assert(!errored);
return &value;
}
/// The 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;
/// True if there was a error parsing.
bool matched = 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 {
@ -223,14 +292,14 @@ class ParserImpl {
/// `variable_decoration_list*` provided as |decos|. /// `variable_decoration_list*` provided as |decos|.
/// @returns the variable parsed or nullptr /// @returns the variable parsed or nullptr
/// @param decos the list of decorations for the variable declaration. /// @param decos the list of decorations for the variable declaration.
std::unique_ptr<ast::Variable> global_variable_decl( Maybe<std::unique_ptr<ast::Variable>> global_variable_decl(
ast::DecorationList& decos); ast::DecorationList& decos);
/// Parses a `global_constant_decl` grammar element /// Parses a `global_constant_decl` grammar element
/// @returns the const object or nullptr /// @returns the const object or nullptr
std::unique_ptr<ast::Variable> global_constant_decl(); Maybe<std::unique_ptr<ast::Variable>> global_constant_decl();
/// Parses a `variable_decl` grammar element /// Parses a `variable_decl` grammar element
/// @returns the parsed variable or nullptr otherwise /// @returns the parsed variable or nullptr otherwise
std::unique_ptr<ast::Variable> variable_decl(); Maybe<std::unique_ptr<ast::Variable>> variable_decl();
/// Parses a `variable_ident_decl` grammar element, erroring on parse /// Parses a `variable_ident_decl` grammar element, erroring on parse
/// 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.
@ -238,13 +307,13 @@ class ParserImpl {
Expect<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(); Maybe<ast::StorageClass> variable_storage_decoration();
/// Parses a `type_alias` grammar element /// Parses a `type_alias` grammar element
/// @returns the type alias or nullptr on error /// @returns the type alias or nullptr on error
ast::type::Type* type_alias(); Maybe<ast::type::Type*> type_alias();
/// 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(); Maybe<ast::type::Type*> type_decl();
/// Parses a `storage_class` grammar element, erroring on parse failure. /// 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
@ -253,7 +322,7 @@ class ParserImpl {
/// `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
/// @param decos the list of decorations for the struct declaration. /// @param decos the list of decorations for the struct declaration.
std::unique_ptr<ast::type::StructType> struct_decl( Maybe<std::unique_ptr<ast::type::StructType>> struct_decl(
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
@ -269,39 +338,40 @@ class ParserImpl {
/// `function_decoration_decl*` provided as |decos|. /// `function_decoration_decl*` provided as |decos|.
/// @param decos the list of decorations for the function declaration. /// @param decos the list of decorations for the function declaration.
/// @returns the parsed function, nullptr otherwise /// @returns the parsed function, nullptr otherwise
std::unique_ptr<ast::Function> function_decl(ast::DecorationList& decos); Maybe<std::unique_ptr<ast::Function>> function_decl(
ast::DecorationList& decos);
/// Parses a `texture_sampler_types` grammar element /// Parses a `texture_sampler_types` grammar element
/// @returns the parsed Type or nullptr if none matched. /// @returns the parsed Type or nullptr if none matched.
ast::type::Type* texture_sampler_types(); Maybe<ast::type::Type*> texture_sampler_types();
/// Parses a `sampler_type` grammar element /// Parses a `sampler_type` grammar element
/// @returns the parsed Type or nullptr if none matched. /// @returns the parsed Type or nullptr if none matched.
ast::type::Type* sampler_type(); Maybe<ast::type::Type*> sampler_type();
/// Parses a `multisampled_texture_type` grammar element /// Parses a `multisampled_texture_type` grammar element
/// @returns returns the multisample texture dimension or kNone if none /// @returns returns the multisample texture dimension or kNone if none
/// matched. /// matched.
ast::type::TextureDimension multisampled_texture_type(); Maybe<ast::type::TextureDimension> multisampled_texture_type();
/// Parses a `sampled_texture_type` grammar element /// Parses a `sampled_texture_type` grammar element
/// @returns returns the sample texture dimension or kNone if none matched. /// @returns returns the sample texture dimension or kNone if none matched.
ast::type::TextureDimension sampled_texture_type(); Maybe<ast::type::TextureDimension> sampled_texture_type();
/// Parses a `storage_texture_type` grammar element /// Parses a `storage_texture_type` grammar element
/// @returns returns the storage texture dimension and the storage access. /// @returns returns the storage texture dimension and the storage access.
/// Returns kNone and kRead if none matched. /// Returns kNone and kRead if none matched.
std::pair<ast::type::TextureDimension, ast::AccessControl> Maybe<std::pair<ast::type::TextureDimension, ast::AccessControl>>
storage_texture_type(); storage_texture_type();
/// Parses a `depth_texture_type` grammar element /// Parses a `depth_texture_type` grammar element
/// @returns the parsed Type or nullptr if none matched. /// @returns the parsed Type or nullptr if none matched.
ast::type::Type* depth_texture_type(); Maybe<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. /// @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.
Expect<ast::type::ImageFormat> expect_image_storage_type( Expect<ast::type::ImageFormat> expect_image_storage_type(
const std::string& use); 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(); Maybe<ast::type::Type*> function_type_decl();
/// Parses a `function_header` grammar element /// Parses a `function_header` grammar element
/// @returns the parsed function nullptr otherwise /// @returns the parsed function nullptr otherwise
std::unique_ptr<ast::Function> function_header(); Maybe<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
Expect<ast::VariableList> expect_param_list(); Expect<ast::VariableList> expect_param_list();
@ -324,64 +394,64 @@ class ParserImpl {
Expect<std::unique_ptr<ast::BlockStatement>> expect_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(); Maybe<std::unique_ptr<ast::Statement>> statement();
/// Parses a `break_stmt` grammar element /// Parses a `break_stmt` grammar element
/// @returns the parsed statement or nullptr /// @returns the parsed statement or nullptr
std::unique_ptr<ast::BreakStatement> break_stmt(); Maybe<std::unique_ptr<ast::BreakStatement>> break_stmt();
/// Parses a `return_stmt` grammar element /// Parses a `return_stmt` grammar element
/// @returns the parsed statement or nullptr /// @returns the parsed statement or nullptr
std::unique_ptr<ast::ReturnStatement> return_stmt(); Maybe<std::unique_ptr<ast::ReturnStatement>> return_stmt();
/// Parses a `continue_stmt` grammar element /// Parses a `continue_stmt` grammar element
/// @returns the parsed statement or nullptr /// @returns the parsed statement or nullptr
std::unique_ptr<ast::ContinueStatement> continue_stmt(); Maybe<std::unique_ptr<ast::ContinueStatement>> continue_stmt();
/// Parses a `variable_stmt` grammar element /// Parses a `variable_stmt` grammar element
/// @returns the parsed variable or nullptr /// @returns the parsed variable or nullptr
std::unique_ptr<ast::VariableDeclStatement> variable_stmt(); Maybe<std::unique_ptr<ast::VariableDeclStatement>> variable_stmt();
/// Parses a `if_stmt` grammar element /// Parses a `if_stmt` grammar element
/// @returns the parsed statement or nullptr /// @returns the parsed statement or nullptr
std::unique_ptr<ast::IfStatement> if_stmt(); Maybe<std::unique_ptr<ast::IfStatement>> if_stmt();
/// Parses a `elseif_stmt` grammar element /// Parses a `elseif_stmt` grammar element
/// @returns the parsed elements /// @returns the parsed elements
ast::ElseStatementList elseif_stmt(); Maybe<ast::ElseStatementList> elseif_stmt();
/// Parses a `else_stmt` grammar element /// Parses a `else_stmt` grammar element
/// @returns the parsed statement or nullptr /// @returns the parsed statement or nullptr
std::unique_ptr<ast::ElseStatement> else_stmt(); Maybe<std::unique_ptr<ast::ElseStatement>> else_stmt();
/// Parses a `switch_stmt` grammar element /// Parses a `switch_stmt` grammar element
/// @returns the parsed statement or nullptr /// @returns the parsed statement or nullptr
std::unique_ptr<ast::SwitchStatement> switch_stmt(); Maybe<std::unique_ptr<ast::SwitchStatement>> switch_stmt();
/// Parses a `switch_body` grammar element /// Parses a `switch_body` grammar element
/// @returns the parsed statement or nullptr /// @returns the parsed statement or nullptr
std::unique_ptr<ast::CaseStatement> switch_body(); Maybe<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
Expect<ast::CaseSelectorList> expect_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(); Maybe<std::unique_ptr<ast::BlockStatement>> case_body();
/// Parses a `func_call_stmt` grammar element /// Parses a `func_call_stmt` grammar element
/// @returns the parsed function call or nullptr /// @returns the parsed function call or nullptr
std::unique_ptr<ast::CallStatement> func_call_stmt(); Maybe<std::unique_ptr<ast::CallStatement>> func_call_stmt();
/// Parses a `loop_stmt` grammar element /// Parses a `loop_stmt` grammar element
/// @returns the parsed loop or nullptr /// @returns the parsed loop or nullptr
std::unique_ptr<ast::LoopStatement> loop_stmt(); Maybe<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
Expect<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(); Maybe<std::unique_ptr<ast::Statement>> for_stmt();
/// Parses a `continuing_stmt` grammar element /// Parses a `continuing_stmt` grammar element
/// @returns the parsed statements /// @returns the parsed statements
std::unique_ptr<ast::BlockStatement> continuing_stmt(); Maybe<std::unique_ptr<ast::BlockStatement>> continuing_stmt();
/// Parses a `const_literal` grammar element /// Parses a `const_literal` grammar element
/// @returns the const literal parsed or nullptr if none found /// @returns the const literal parsed or nullptr if none found
std::unique_ptr<ast::Literal> const_literal(); Maybe<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
Expect<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(); Maybe<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
@ -389,14 +459,14 @@ class ParserImpl {
/// 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
std::unique_ptr<ast::Expression> postfix_expr( Maybe<std::unique_ptr<ast::Expression>> postfix_expr(
std::unique_ptr<ast::Expression> prefix); std::unique_ptr<ast::Expression> prefix);
/// Parses a `postfix_expression` grammar elment /// Parses a `postfix_expression` grammar elment
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> postfix_expression(); Maybe<std::unique_ptr<ast::Expression>> postfix_expression();
/// Parses a `unary_expression` grammar element /// Parses a `unary_expression` grammar element
/// @returns the parsed expression or nullptr /// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> unary_expression(); Maybe<std::unique_ptr<ast::Expression>> unary_expression();
/// Parses the recursive part of the `multiplicative_expression`, erroring on /// Parses the recursive part of the `multiplicative_expression`, erroring on
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
@ -405,7 +475,7 @@ class ParserImpl {
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
std::unique_ptr<ast::Expression> multiplicative_expression(); Maybe<std::unique_ptr<ast::Expression>> multiplicative_expression();
/// Parses the recursive part of the `additive_expression`, erroring on parse /// Parses the recursive part of the `additive_expression`, erroring on parse
/// failure. /// failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
@ -414,7 +484,7 @@ class ParserImpl {
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
std::unique_ptr<ast::Expression> additive_expression(); Maybe<std::unique_ptr<ast::Expression>> additive_expression();
/// Parses the recursive part of the `shift_expression`, erroring on parse /// Parses the recursive part of the `shift_expression`, erroring on parse
/// failure. /// failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
@ -423,7 +493,7 @@ class ParserImpl {
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
std::unique_ptr<ast::Expression> shift_expression(); Maybe<std::unique_ptr<ast::Expression>> shift_expression();
/// Parses the recursive part of the `relational_expression`, erroring on /// Parses the recursive part of the `relational_expression`, erroring on
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
@ -432,7 +502,7 @@ class ParserImpl {
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
std::unique_ptr<ast::Expression> relational_expression(); Maybe<std::unique_ptr<ast::Expression>> relational_expression();
/// Parses the recursive part of the `equality_expression`, erroring on parse /// Parses the recursive part of the `equality_expression`, erroring on parse
/// failure. /// failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
@ -441,7 +511,7 @@ class ParserImpl {
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
std::unique_ptr<ast::Expression> equality_expression(); Maybe<std::unique_ptr<ast::Expression>> equality_expression();
/// Parses the recursive part of the `and_expression`, erroring on parse /// Parses the recursive part of the `and_expression`, erroring on parse
/// failure. /// failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
@ -450,7 +520,7 @@ class ParserImpl {
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
std::unique_ptr<ast::Expression> and_expression(); Maybe<std::unique_ptr<ast::Expression>> and_expression();
/// Parses the recursive part of the `exclusive_or_expression`, erroring on /// Parses the recursive part of the `exclusive_or_expression`, erroring on
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
@ -459,7 +529,7 @@ class ParserImpl {
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
std::unique_ptr<ast::Expression> exclusive_or_expression(); Maybe<std::unique_ptr<ast::Expression>> exclusive_or_expression();
/// Parses the recursive part of the `inclusive_or_expression`, erroring on /// Parses the recursive part of the `inclusive_or_expression`, erroring on
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
@ -468,7 +538,7 @@ class ParserImpl {
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
std::unique_ptr<ast::Expression> inclusive_or_expression(); Maybe<std::unique_ptr<ast::Expression>> inclusive_or_expression();
/// Parses the recursive part of the `logical_and_expression`, erroring on /// Parses the recursive part of the `logical_and_expression`, erroring on
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
@ -477,7 +547,7 @@ class ParserImpl {
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
std::unique_ptr<ast::Expression> logical_and_expression(); Maybe<std::unique_ptr<ast::Expression>> logical_and_expression();
/// Parses the recursive part of the `logical_or_expression`, erroring on /// Parses the recursive part of the `logical_or_expression`, erroring on
/// parse failure. /// parse failure.
/// @param lhs the left side of the expression /// @param lhs the left side of the expression
@ -486,18 +556,18 @@ class ParserImpl {
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
std::unique_ptr<ast::Expression> logical_or_expression(); Maybe<std::unique_ptr<ast::Expression>> logical_or_expression();
/// Parses a `assignment_stmt` grammar element /// Parses a `assignment_stmt` grammar element
/// @returns the parsed assignment or nullptr /// @returns the parsed assignment or nullptr
std::unique_ptr<ast::AssignmentStatement> assignment_stmt(); Maybe<std::unique_ptr<ast::AssignmentStatement>> assignment_stmt();
/// Parses one or more bracketed decoration lists. /// Parses one or more bracketed decoration lists.
/// @return the parsed decoration list, or an empty list on error. /// @return the parsed decoration list, or an empty list on error.
ast::DecorationList decoration_list(); Maybe<ast::DecorationList> decoration_list();
/// Parses a list of decorations between `ATTR_LEFT` and `ATTR_RIGHT` /// Parses a list of decorations between `ATTR_LEFT` and `ATTR_RIGHT`
/// brackets. /// brackets.
/// @param decos the list to append newly parsed decorations to. /// @param decos the list to append newly parsed decorations to.
/// @return true if any decorations were be parsed, otherwise false. /// @return true if any decorations were be parsed, otherwise false.
bool decoration_bracketed_list(ast::DecorationList& decos); Maybe<bool> decoration_bracketed_list(ast::DecorationList& decos);
/// Parses a single decoration of the following types: /// Parses a single decoration of the following types:
/// * `struct_decoration` /// * `struct_decoration`
/// * `struct_member_decoration` /// * `struct_member_decoration`
@ -506,7 +576,7 @@ class ParserImpl {
/// * `global_const_decoration` /// * `global_const_decoration`
/// * `function_decoration` /// * `function_decoration`
/// @return the parsed decoration, or nullptr. /// @return the parsed decoration, or nullptr.
std::unique_ptr<ast::Decoration> decoration(); Maybe<std::unique_ptr<ast::Decoration>> decoration();
/// Parses a single decoration, reporting an error if the next token does not /// Parses a single decoration, reporting an error if the next token does not
/// 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.
@ -568,7 +638,7 @@ class ParserImpl {
/// @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: `Expect<Result>()`. /// 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|. /// an Expect with error state.
template <typename F, typename T = ReturnType<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,
@ -581,7 +651,7 @@ class ParserImpl {
/// @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: `Expect<Result>()`. /// 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|. /// an Expect with error state.
template <typename F, typename T = ReturnType<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
@ -591,24 +661,10 @@ class ParserImpl {
/// @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: `Expect<Result>()`. /// 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|. /// an Expect with error state.
template <typename F, typename T = ReturnType<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>
@ -627,6 +683,9 @@ class ParserImpl {
Expect<std::unique_ptr<ast::ConstructorExpression>> Expect<std::unique_ptr<ast::ConstructorExpression>>
expect_const_expr_internal(uint32_t depth); expect_const_expr_internal(uint32_t depth);
Maybe<std::unique_ptr<ast::Statement>> for_header_initializer();
Maybe<std::unique_ptr<ast::Statement>> for_header_continuing();
Context& ctx_; Context& ctx_;
diag::List diags_; diag::List diags_;
std::unique_ptr<Lexer> lexer_; std::unique_ptr<Lexer> lexer_;

View File

@ -28,11 +28,13 @@ namespace {
TEST_F(ParserImplTest, AdditiveExpression_Parses_Plus) { TEST_F(ParserImplTest, AdditiveExpression_Parses_Plus) {
auto* p = parser("a + true"); auto* p = parser("a + true");
auto e = p->additive_expression(); auto e = p->additive_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kAdd, rel->op()); EXPECT_EQ(ast::BinaryOp::kAdd, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -49,11 +51,13 @@ TEST_F(ParserImplTest, AdditiveExpression_Parses_Plus) {
TEST_F(ParserImplTest, AdditiveExpression_Parses_Minus) { TEST_F(ParserImplTest, AdditiveExpression_Parses_Minus) {
auto* p = parser("a - true"); auto* p = parser("a - true");
auto e = p->additive_expression(); auto e = p->additive_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kSubtract, rel->op()); EXPECT_EQ(ast::BinaryOp::kSubtract, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -70,24 +74,30 @@ TEST_F(ParserImplTest, AdditiveExpression_Parses_Minus) {
TEST_F(ParserImplTest, AdditiveExpression_InvalidLHS) { TEST_F(ParserImplTest, AdditiveExpression_InvalidLHS) {
auto* p = parser("if (a) {} + true"); auto* p = parser("if (a) {} + true");
auto e = p->additive_expression(); auto e = p->additive_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, AdditiveExpression_InvalidRHS) { TEST_F(ParserImplTest, AdditiveExpression_InvalidRHS) {
auto* p = parser("true + if (a) {}"); auto* p = parser("true + if (a) {}");
auto e = p->additive_expression(); auto e = p->additive_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:8: unable to parse right side of + expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of + expression");
} }
TEST_F(ParserImplTest, AdditiveExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, AdditiveExpression_NoOr_ReturnsLHS) {
auto* p = parser("a true"); auto* p = parser("a true");
auto e = p->additive_expression(); auto e = p->additive_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
} }
} // namespace } // namespace

View File

@ -28,11 +28,13 @@ namespace {
TEST_F(ParserImplTest, AndExpression_Parses) { TEST_F(ParserImplTest, AndExpression_Parses) {
auto* p = parser("a & true"); auto* p = parser("a & true");
auto e = p->and_expression(); auto e = p->and_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kAnd, rel->op()); EXPECT_EQ(ast::BinaryOp::kAnd, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -49,24 +51,30 @@ TEST_F(ParserImplTest, AndExpression_Parses) {
TEST_F(ParserImplTest, AndExpression_InvalidLHS) { TEST_F(ParserImplTest, AndExpression_InvalidLHS) {
auto* p = parser("if (a) {} & true"); auto* p = parser("if (a) {} & true");
auto e = p->and_expression(); auto e = p->and_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, AndExpression_InvalidRHS) { TEST_F(ParserImplTest, AndExpression_InvalidRHS) {
auto* p = parser("true & if (a) {}"); auto* p = parser("true & if (a) {}");
auto e = p->and_expression(); auto e = p->and_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:8: unable to parse right side of & expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of & expression");
} }
TEST_F(ParserImplTest, AndExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, AndExpression_NoOr_ReturnsLHS) {
auto* p = parser("a true"); auto* p = parser("a true");
auto e = p->and_expression(); auto e = p->and_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
} }
} // namespace } // namespace

View File

@ -31,21 +31,23 @@ namespace {
TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) { TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) {
auto* p = parser("a = 123"); auto* p = parser("a = 123");
auto e = p->assignment_stmt(); auto e = p->assignment_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsAssign()); ASSERT_TRUE(e.value->IsAssign());
ASSERT_NE(e->lhs(), nullptr); ASSERT_NE(e.value->lhs(), nullptr);
ASSERT_NE(e->rhs(), nullptr); ASSERT_NE(e.value->rhs(), nullptr);
ASSERT_TRUE(e->lhs()->IsIdentifier()); ASSERT_TRUE(e.value->lhs()->IsIdentifier());
auto* ident = e->lhs()->AsIdentifier(); auto* ident = e.value->lhs()->AsIdentifier();
EXPECT_EQ(ident->name(), "a"); EXPECT_EQ(ident->name(), "a");
ASSERT_TRUE(e->rhs()->IsConstructor()); ASSERT_TRUE(e.value->rhs()->IsConstructor());
ASSERT_TRUE(e->rhs()->AsConstructor()->IsScalarConstructor()); ASSERT_TRUE(e.value->rhs()->AsConstructor()->IsScalarConstructor());
auto* init = e->rhs()->AsConstructor()->AsScalarConstructor(); auto* init = e.value->rhs()->AsConstructor()->AsScalarConstructor();
ASSERT_NE(init->literal(), nullptr); ASSERT_NE(init->literal(), nullptr);
ASSERT_TRUE(init->literal()->IsSint()); ASSERT_TRUE(init->literal()->IsSint());
EXPECT_EQ(init->literal()->AsSint()->value(), 123); EXPECT_EQ(init->literal()->AsSint()->value(), 123);
@ -54,22 +56,24 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) {
TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) { TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) {
auto* p = parser("a.b.c[2].d = 123"); auto* p = parser("a.b.c[2].d = 123");
auto e = p->assignment_stmt(); auto e = p->assignment_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsAssign()); ASSERT_TRUE(e.value->IsAssign());
ASSERT_NE(e->lhs(), nullptr); ASSERT_NE(e.value->lhs(), nullptr);
ASSERT_NE(e->rhs(), nullptr); ASSERT_NE(e.value->rhs(), nullptr);
ASSERT_TRUE(e->rhs()->IsConstructor()); ASSERT_TRUE(e.value->rhs()->IsConstructor());
ASSERT_TRUE(e->rhs()->AsConstructor()->IsScalarConstructor()); ASSERT_TRUE(e.value->rhs()->AsConstructor()->IsScalarConstructor());
auto* init = e->rhs()->AsConstructor()->AsScalarConstructor(); auto* init = e.value->rhs()->AsConstructor()->AsScalarConstructor();
ASSERT_NE(init->literal(), nullptr); ASSERT_NE(init->literal(), nullptr);
ASSERT_TRUE(init->literal()->IsSint()); ASSERT_TRUE(init->literal()->IsSint());
EXPECT_EQ(init->literal()->AsSint()->value(), 123); EXPECT_EQ(init->literal()->AsSint()->value(), 123);
ASSERT_TRUE(e->lhs()->IsMemberAccessor()); ASSERT_TRUE(e.value->lhs()->IsMemberAccessor());
auto* mem = e->lhs()->AsMemberAccessor(); auto* mem = e.value->lhs()->AsMemberAccessor();
ASSERT_TRUE(mem->member()->IsIdentifier()); ASSERT_TRUE(mem->member()->IsIdentifier());
auto* ident = mem->member()->AsIdentifier(); auto* ident = mem->member()->AsIdentifier();
@ -106,23 +110,29 @@ TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) {
TEST_F(ParserImplTest, AssignmentStmt_MissingEqual) { TEST_F(ParserImplTest, AssignmentStmt_MissingEqual) {
auto* p = parser("a.b.c[2].d 123"); auto* p = parser("a.b.c[2].d 123");
auto e = p->assignment_stmt(); auto e = p->assignment_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(p->error(), "1:12: missing = for assignment"); EXPECT_TRUE(p->has_error());
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:12: expected '=' for assignment");
} }
TEST_F(ParserImplTest, AssignmentStmt_InvalidLHS) { TEST_F(ParserImplTest, AssignmentStmt_InvalidLHS) {
auto* p = parser("if (true) {} = 123"); auto* p = parser("if (true) {} = 123");
auto e = p->assignment_stmt(); auto e = p->assignment_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, AssignmentStmt_InvalidRHS) { TEST_F(ParserImplTest, AssignmentStmt_InvalidRHS) {
auto* p = parser("a.b.c[2].d = if (true) {}"); auto* p = parser("a.b.c[2].d = if (true) {}");
auto e = p->assignment_stmt(); auto e = p->assignment_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:14: unable to parse right side of assignment"); EXPECT_EQ(p->error(), "1:14: unable to parse right side of assignment");
} }

View File

@ -25,9 +25,10 @@ namespace {
TEST_F(ParserImplTest, BreakStmt) { TEST_F(ParserImplTest, BreakStmt) {
auto* p = parser("break"); auto* p = parser("break");
auto e = p->break_stmt(); auto e = p->break_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.errored);
ASSERT_NE(e, nullptr); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_TRUE(e->IsBreak()); ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsBreak());
} }
} // namespace } // namespace

View File

@ -28,10 +28,12 @@ TEST_F(ParserImplTest, Statement_Call) {
auto* p = parser("a();"); auto* p = parser("a();");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e.value, nullptr);
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsCall()); ASSERT_TRUE(e.value->IsCall());
auto* c = e->AsCall()->expr(); auto* c = e.value->AsCall()->expr();
ASSERT_TRUE(c->func()->IsIdentifier()); ASSERT_TRUE(c->func()->IsIdentifier());
auto* func = c->func()->AsIdentifier(); auto* func = c->func()->AsIdentifier();
@ -44,10 +46,12 @@ TEST_F(ParserImplTest, Statement_Call_WithParams) {
auto* p = parser("a(1, b, 2 + 3 / b);"); auto* p = parser("a(1, b, 2 + 3 / b);");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e.value, nullptr);
EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsCall()); ASSERT_TRUE(e.value->IsCall());
auto* c = e->AsCall()->expr(); auto* c = e.value->AsCall()->expr();
ASSERT_TRUE(c->func()->IsIdentifier()); ASSERT_TRUE(c->func()->IsIdentifier());
auto* func = c->func()->AsIdentifier(); auto* func = c->func()->AsIdentifier();
@ -62,21 +66,27 @@ TEST_F(ParserImplTest, Statement_Call_WithParams) {
TEST_F(ParserImplTest, Statement_Call_Missing_RightParen) { TEST_F(ParserImplTest, Statement_Call_Missing_RightParen) {
auto* p = parser("a("); auto* p = parser("a(");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(p->error(), "1:3: expected ')' for call statement"); EXPECT_EQ(p->error(), "1:3: expected ')' for call statement");
} }
TEST_F(ParserImplTest, Statement_Call_Missing_Semi) { TEST_F(ParserImplTest, Statement_Call_Missing_Semi) {
auto* p = parser("a()"); auto* p = parser("a()");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(p->error(), "1:4: expected ';' for function call"); EXPECT_EQ(p->error(), "1:4: expected ';' for function call");
} }
TEST_F(ParserImplTest, Statement_Call_Bad_ArgList) { TEST_F(ParserImplTest, Statement_Call_Bad_ArgList) {
auto* p = parser("a(b c);"); auto* p = parser("a(b c);");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(p->error(), "1:5: expected ')' for call statement"); EXPECT_EQ(p->error(), "1:5: expected ')' for call statement");
} }

View File

@ -25,7 +25,9 @@ TEST_F(ParserImplTest, CaseBody_Empty) {
auto* p = parser(""); auto* p = parser("");
auto e = p->case_body(); auto e = p->case_body();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e->size(), 0u); EXPECT_FALSE(e.errored);
EXPECT_TRUE(e.matched);
EXPECT_EQ(e.value->size(), 0u);
} }
TEST_F(ParserImplTest, CaseBody_Statements) { TEST_F(ParserImplTest, CaseBody_Statements) {
@ -35,31 +37,39 @@ TEST_F(ParserImplTest, CaseBody_Statements) {
auto e = p->case_body(); auto e = p->case_body();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e->size(), 2u); EXPECT_FALSE(e.errored);
EXPECT_TRUE(e->get(0)->IsVariableDecl()); EXPECT_TRUE(e.matched);
EXPECT_TRUE(e->get(1)->IsAssign()); ASSERT_EQ(e.value->size(), 2u);
EXPECT_TRUE(e.value->get(0)->IsVariableDecl());
EXPECT_TRUE(e.value->get(1)->IsAssign());
} }
TEST_F(ParserImplTest, CaseBody_InvalidStatement) { TEST_F(ParserImplTest, CaseBody_InvalidStatement) {
auto* p = parser("a ="); auto* p = parser("a =");
auto e = p->case_body(); auto e = p->case_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, CaseBody_Fallthrough) { TEST_F(ParserImplTest, CaseBody_Fallthrough) {
auto* p = parser("fallthrough;"); auto* p = parser("fallthrough;");
auto e = p->case_body(); auto e = p->case_body();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e->size(), 1u); EXPECT_FALSE(e.errored);
EXPECT_TRUE(e->get(0)->IsFallthrough()); EXPECT_TRUE(e.matched);
ASSERT_EQ(e.value->size(), 1u);
EXPECT_TRUE(e.value->get(0)->IsFallthrough());
} }
TEST_F(ParserImplTest, CaseBody_Fallthrough_MissingSemicolon) { TEST_F(ParserImplTest, CaseBody_Fallthrough_MissingSemicolon) {
auto* p = parser("fallthrough"); auto* p = parser("fallthrough");
auto e = p->case_body(); auto e = p->case_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:12: expected ';' for fallthrough statement"); EXPECT_EQ(p->error(), "1:12: expected ';' for fallthrough statement");
} }

View File

@ -28,59 +28,73 @@ namespace {
TEST_F(ParserImplTest, ConstLiteral_Int) { TEST_F(ParserImplTest, ConstLiteral_Int) {
auto* p = parser("-234"); auto* p = parser("-234");
auto c = p->const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p->has_error()); EXPECT_TRUE(c.matched);
ASSERT_NE(c, nullptr); EXPECT_FALSE(c.errored);
ASSERT_TRUE(c->IsSint()); EXPECT_FALSE(p->has_error());
EXPECT_EQ(c->AsSint()->value(), -234); ASSERT_NE(c.value, nullptr);
ASSERT_TRUE(c.value->IsSint());
EXPECT_EQ(c.value->AsSint()->value(), -234);
} }
TEST_F(ParserImplTest, ConstLiteral_Uint) { TEST_F(ParserImplTest, ConstLiteral_Uint) {
auto* p = parser("234u"); auto* p = parser("234u");
auto c = p->const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p->has_error()); EXPECT_TRUE(c.matched);
ASSERT_NE(c, nullptr); EXPECT_FALSE(c.errored);
ASSERT_TRUE(c->IsUint()); EXPECT_FALSE(p->has_error());
EXPECT_EQ(c->AsUint()->value(), 234u); ASSERT_NE(c.value, nullptr);
ASSERT_TRUE(c.value->IsUint());
EXPECT_EQ(c.value->AsUint()->value(), 234u);
} }
TEST_F(ParserImplTest, ConstLiteral_Float) { TEST_F(ParserImplTest, ConstLiteral_Float) {
auto* p = parser("234.e12"); auto* p = parser("234.e12");
auto c = p->const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p->has_error()); EXPECT_TRUE(c.matched);
ASSERT_NE(c, nullptr); EXPECT_FALSE(c.errored);
ASSERT_TRUE(c->IsFloat()); EXPECT_FALSE(p->has_error());
EXPECT_FLOAT_EQ(c->AsFloat()->value(), 234e12f); ASSERT_NE(c.value, nullptr);
ASSERT_TRUE(c.value->IsFloat());
EXPECT_FLOAT_EQ(c.value->AsFloat()->value(), 234e12f);
} }
TEST_F(ParserImplTest, ConstLiteral_InvalidFloat) { TEST_F(ParserImplTest, ConstLiteral_InvalidFloat) {
auto* p = parser("1.2e+256"); auto* p = parser("1.2e+256");
auto c = p->const_literal(); auto c = p->const_literal();
ASSERT_EQ(c, nullptr); EXPECT_FALSE(c.matched);
EXPECT_FALSE(c.errored);
ASSERT_EQ(c.value, nullptr);
} }
TEST_F(ParserImplTest, ConstLiteral_True) { TEST_F(ParserImplTest, ConstLiteral_True) {
auto* p = parser("true"); auto* p = parser("true");
auto c = p->const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p->has_error()); EXPECT_TRUE(c.matched);
ASSERT_NE(c, nullptr); EXPECT_FALSE(c.errored);
ASSERT_TRUE(c->IsBool()); EXPECT_FALSE(p->has_error());
EXPECT_TRUE(c->AsBool()->IsTrue()); ASSERT_NE(c.value, nullptr);
ASSERT_TRUE(c.value->IsBool());
EXPECT_TRUE(c.value->AsBool()->IsTrue());
} }
TEST_F(ParserImplTest, ConstLiteral_False) { TEST_F(ParserImplTest, ConstLiteral_False) {
auto* p = parser("false"); auto* p = parser("false");
auto c = p->const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p->has_error()); EXPECT_TRUE(c.matched);
ASSERT_NE(c, nullptr); EXPECT_FALSE(c.errored);
ASSERT_TRUE(c->IsBool()); EXPECT_FALSE(p->has_error());
EXPECT_TRUE(c->AsBool()->IsFalse()); ASSERT_NE(c.value, nullptr);
ASSERT_TRUE(c.value->IsBool());
EXPECT_TRUE(c.value->AsBool()->IsFalse());
} }
TEST_F(ParserImplTest, ConstLiteral_NoMatch) { TEST_F(ParserImplTest, ConstLiteral_NoMatch) {
auto* p = parser("another-token"); auto* p = parser("another-token");
auto c = p->const_literal(); auto c = p->const_literal();
ASSERT_FALSE(p->has_error()); EXPECT_FALSE(c.matched);
ASSERT_EQ(c, nullptr); EXPECT_FALSE(c.errored);
EXPECT_FALSE(p->has_error());
ASSERT_EQ(c.value, nullptr);
} }
} // namespace } // namespace

View File

@ -25,9 +25,10 @@ namespace {
TEST_F(ParserImplTest, ContinueStmt) { TEST_F(ParserImplTest, ContinueStmt) {
auto* p = parser("continue"); auto* p = parser("continue");
auto e = p->continue_stmt(); auto e = p->continue_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.errored);
ASSERT_NE(e, nullptr); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_TRUE(e->IsContinue()); ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsContinue());
} }
} // namespace } // namespace

View File

@ -24,16 +24,20 @@ namespace {
TEST_F(ParserImplTest, ContinuingStmt) { TEST_F(ParserImplTest, ContinuingStmt) {
auto* p = parser("continuing { discard; }"); auto* p = parser("continuing { discard; }");
auto e = p->continuing_stmt(); auto e = p->continuing_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_EQ(e->size(), 1u); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->get(0)->IsDiscard()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.value->size(), 1u);
ASSERT_TRUE(e.value->get(0)->IsDiscard());
} }
TEST_F(ParserImplTest, ContinuingStmt_InvalidBody) { TEST_F(ParserImplTest, ContinuingStmt_InvalidBody) {
auto* p = parser("continuing { discard }"); auto* p = parser("continuing { discard }");
auto e = p->continuing_stmt(); auto e = p->continuing_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:22: expected ';' for discard statement"); EXPECT_EQ(p->error(), "1:22: expected ';' for discard statement");
} }

View File

@ -24,48 +24,58 @@ namespace {
TEST_F(ParserImplTest, DepthTextureType_Invalid) { TEST_F(ParserImplTest, DepthTextureType_Invalid) {
auto* p = parser("1234"); auto* p = parser("1234");
auto* t = p->depth_texture_type(); auto t = p->depth_texture_type();
EXPECT_EQ(t, nullptr); EXPECT_FALSE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, DepthTextureType_2d) { TEST_F(ParserImplTest, DepthTextureType_2d) {
auto* p = parser("texture_depth_2d"); auto* p = parser("texture_depth_2d");
auto* t = p->depth_texture_type(); auto t = p->depth_texture_type();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsDepth()); ASSERT_NE(t.value, nullptr);
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); ASSERT_TRUE(t.value->IsTexture());
ASSERT_TRUE(t.value->AsTexture()->IsDepth());
EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, DepthTextureType_2dArray) { TEST_F(ParserImplTest, DepthTextureType_2dArray) {
auto* p = parser("texture_depth_2d_array"); auto* p = parser("texture_depth_2d_array");
auto* t = p->depth_texture_type(); auto t = p->depth_texture_type();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsDepth()); ASSERT_NE(t.value, nullptr);
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2dArray); ASSERT_TRUE(t.value->IsTexture());
ASSERT_TRUE(t.value->AsTexture()->IsDepth());
EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2dArray);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, DepthTextureType_Cube) { TEST_F(ParserImplTest, DepthTextureType_Cube) {
auto* p = parser("texture_depth_cube"); auto* p = parser("texture_depth_cube");
auto* t = p->depth_texture_type(); auto t = p->depth_texture_type();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsDepth()); ASSERT_NE(t.value, nullptr);
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::kCube); ASSERT_TRUE(t.value->IsTexture());
ASSERT_TRUE(t.value->AsTexture()->IsDepth());
EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::kCube);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, DepthTextureType_CubeArray) { TEST_F(ParserImplTest, DepthTextureType_CubeArray) {
auto* p = parser("texture_depth_cube_array"); auto* p = parser("texture_depth_cube_array");
auto* t = p->depth_texture_type(); auto t = p->depth_texture_type();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsDepth()); ASSERT_NE(t.value, nullptr);
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::kCubeArray); ASSERT_TRUE(t.value->IsTexture());
ASSERT_TRUE(t.value->AsTexture()->IsDepth());
EXPECT_EQ(t.value->AsTexture()->dim(),
ast::type::TextureDimension::kCubeArray);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }

View File

@ -25,26 +25,32 @@ namespace {
TEST_F(ParserImplTest, ElseStmt) { TEST_F(ParserImplTest, ElseStmt) {
auto* p = parser("else { a = b; c = d; }"); auto* p = parser("else { a = b; c = d; }");
auto e = p->else_stmt(); auto e = p->else_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsElse()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e->condition(), nullptr); ASSERT_NE(e.value, nullptr);
EXPECT_EQ(e->body()->size(), 2u); ASSERT_TRUE(e.value->IsElse());
ASSERT_EQ(e.value->condition(), nullptr);
EXPECT_EQ(e.value->body()->size(), 2u);
} }
TEST_F(ParserImplTest, ElseStmt_InvalidBody) { TEST_F(ParserImplTest, ElseStmt_InvalidBody) {
auto* p = parser("else { fn main() -> void {}}"); auto* p = parser("else { fn main() -> void {}}");
auto e = p->else_stmt(); auto e = p->else_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:8: expected '}'"); EXPECT_EQ(p->error(), "1:8: expected '}'");
} }
TEST_F(ParserImplTest, ElseStmt_MissingBody) { TEST_F(ParserImplTest, ElseStmt_MissingBody) {
auto* p = parser("else"); auto* p = parser("else");
auto e = p->else_stmt(); auto e = p->else_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:5: expected '{'"); EXPECT_EQ(p->error(), "1:5: expected '{'");
} }

View File

@ -25,43 +25,51 @@ namespace {
TEST_F(ParserImplTest, ElseIfStmt) { TEST_F(ParserImplTest, ElseIfStmt) {
auto* p = parser("elseif (a == 4) { a = b; c = d; }"); auto* p = parser("elseif (a == 4) { a = b; c = d; }");
auto e = p->elseif_stmt(); auto e = p->elseif_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_EQ(e.size(), 1u); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.value.size(), 1u);
ASSERT_TRUE(e[0]->IsElse()); ASSERT_TRUE(e.value[0]->IsElse());
ASSERT_NE(e[0]->condition(), nullptr); ASSERT_NE(e.value[0]->condition(), nullptr);
ASSERT_TRUE(e[0]->condition()->IsBinary()); ASSERT_TRUE(e.value[0]->condition()->IsBinary());
EXPECT_EQ(e[0]->body()->size(), 2u); EXPECT_EQ(e.value[0]->body()->size(), 2u);
} }
TEST_F(ParserImplTest, ElseIfStmt_Multiple) { TEST_F(ParserImplTest, ElseIfStmt_Multiple) {
auto* p = parser("elseif (a == 4) { a = b; c = d; } elseif(c) { d = 2; }"); auto* p = parser("elseif (a == 4) { a = b; c = d; } elseif(c) { d = 2; }");
auto e = p->elseif_stmt(); auto e = p->elseif_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_EQ(e.size(), 2u); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.value.size(), 2u);
ASSERT_TRUE(e[0]->IsElse()); ASSERT_TRUE(e.value[0]->IsElse());
ASSERT_NE(e[0]->condition(), nullptr); ASSERT_NE(e.value[0]->condition(), nullptr);
ASSERT_TRUE(e[0]->condition()->IsBinary()); ASSERT_TRUE(e.value[0]->condition()->IsBinary());
EXPECT_EQ(e[0]->body()->size(), 2u); EXPECT_EQ(e.value[0]->body()->size(), 2u);
ASSERT_TRUE(e[1]->IsElse()); ASSERT_TRUE(e.value[1]->IsElse());
ASSERT_NE(e[1]->condition(), nullptr); ASSERT_NE(e.value[1]->condition(), nullptr);
ASSERT_TRUE(e[1]->condition()->IsIdentifier()); ASSERT_TRUE(e.value[1]->condition()->IsIdentifier());
EXPECT_EQ(e[1]->body()->size(), 1u); EXPECT_EQ(e.value[1]->body()->size(), 1u);
} }
TEST_F(ParserImplTest, ElseIfStmt_InvalidBody) { TEST_F(ParserImplTest, ElseIfStmt_InvalidBody) {
auto* p = parser("elseif (true) { fn main() -> void {}}"); auto* p = parser("elseif (true) { fn main() -> void {}}");
auto e = p->elseif_stmt(); auto e = p->elseif_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:17: expected '}'"); EXPECT_EQ(p->error(), "1:17: expected '}'");
} }
TEST_F(ParserImplTest, ElseIfStmt_MissingBody) { TEST_F(ParserImplTest, ElseIfStmt_MissingBody) {
auto* p = parser("elseif (true)"); auto* p = parser("elseif (true)");
auto e = p->elseif_stmt(); auto e = p->elseif_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:14: expected '{'"); EXPECT_EQ(p->error(), "1:14: expected '{'");
} }

View File

@ -28,11 +28,13 @@ namespace {
TEST_F(ParserImplTest, EqualityExpression_Parses_Equal) { TEST_F(ParserImplTest, EqualityExpression_Parses_Equal) {
auto* p = parser("a == true"); auto* p = parser("a == true");
auto e = p->equality_expression(); auto e = p->equality_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kEqual, rel->op()); EXPECT_EQ(ast::BinaryOp::kEqual, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -49,11 +51,13 @@ TEST_F(ParserImplTest, EqualityExpression_Parses_Equal) {
TEST_F(ParserImplTest, EqualityExpression_Parses_NotEqual) { TEST_F(ParserImplTest, EqualityExpression_Parses_NotEqual) {
auto* p = parser("a != true"); auto* p = parser("a != true");
auto e = p->equality_expression(); auto e = p->equality_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kNotEqual, rel->op()); EXPECT_EQ(ast::BinaryOp::kNotEqual, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -70,24 +74,30 @@ TEST_F(ParserImplTest, EqualityExpression_Parses_NotEqual) {
TEST_F(ParserImplTest, EqualityExpression_InvalidLHS) { TEST_F(ParserImplTest, EqualityExpression_InvalidLHS) {
auto* p = parser("if (a) {} == true"); auto* p = parser("if (a) {} == true");
auto e = p->equality_expression(); auto e = p->equality_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, EqualityExpression_InvalidRHS) { TEST_F(ParserImplTest, EqualityExpression_InvalidRHS) {
auto* p = parser("true == if (a) {}"); auto* p = parser("true == if (a) {}");
auto e = p->equality_expression(); auto e = p->equality_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: unable to parse right side of == expression"); EXPECT_EQ(p->error(), "1:9: unable to parse right side of == expression");
} }
TEST_F(ParserImplTest, EqualityExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, EqualityExpression_NoOr_ReturnsLHS) {
auto* p = parser("a true"); auto* p = parser("a true");
auto e = p->equality_expression(); auto e = p->equality_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
} }
} // namespace } // namespace

View File

@ -56,21 +56,21 @@ TEST_F(ParserImplErrorTest, ArrayIndexExprInvalidExpr) {
TEST_F(ParserImplErrorTest, ArrayIndexExprMissingRBracket) { TEST_F(ParserImplErrorTest, ArrayIndexExprMissingRBracket) {
EXPECT("fn f() -> void { x = y[1; }", EXPECT("fn f() -> void { x = y[1; }",
"test.wgsl:1:25 error: missing ] for array accessor\n" "test.wgsl:1:25 error: expected ']' for array accessor\n"
"fn f() -> void { x = y[1; }\n" "fn f() -> void { x = y[1; }\n"
" ^\n"); " ^\n");
} }
TEST_F(ParserImplErrorTest, AssignmentStmtMissingAssignment) { TEST_F(ParserImplErrorTest, AssignmentStmtMissingAssignment) {
EXPECT("fn f() -> void { a; }", EXPECT("fn f() -> void { a; }",
"test.wgsl:1:19 error: missing = for assignment\n" "test.wgsl:1:19 error: expected '=' for assignment\n"
"fn f() -> void { a; }\n" "fn f() -> void { a; }\n"
" ^\n"); " ^\n");
} }
TEST_F(ParserImplErrorTest, AssignmentStmtMissingAssignment2) { TEST_F(ParserImplErrorTest, AssignmentStmtMissingAssignment2) {
EXPECT("fn f() -> void { a : i32; }", EXPECT("fn f() -> void { a : i32; }",
"test.wgsl:1:20 error: missing = for assignment\n" "test.wgsl:1:20 error: expected '=' for assignment\n"
"fn f() -> void { a : i32; }\n" "fn f() -> void { a : i32; }\n"
" ^\n"); " ^\n");
} }
@ -91,14 +91,14 @@ TEST_F(ParserImplErrorTest, AssignmentStmtInvalidRHS) {
TEST_F(ParserImplErrorTest, BitcastExprMissingLessThan) { TEST_F(ParserImplErrorTest, BitcastExprMissingLessThan) {
EXPECT("fn f() -> void { x = bitcast(y); }", EXPECT("fn f() -> void { x = bitcast(y); }",
"test.wgsl:1:29 error: missing < for bitcast expression\n" "test.wgsl:1:29 error: expected '<' for bitcast expression\n"
"fn f() -> void { x = bitcast(y); }\n" "fn f() -> void { x = bitcast(y); }\n"
" ^\n"); " ^\n");
} }
TEST_F(ParserImplErrorTest, BitcastExprMissingGreaterThan) { TEST_F(ParserImplErrorTest, BitcastExprMissingGreaterThan) {
EXPECT("fn f() -> void { x = bitcast<u32(y); }", EXPECT("fn f() -> void { x = bitcast<u32(y); }",
"test.wgsl:1:33 error: missing > for bitcast expression\n" "test.wgsl:1:33 error: expected '>' for bitcast expression\n"
"fn f() -> void { x = bitcast<u32(y); }\n" "fn f() -> void { x = bitcast<u32(y); }\n"
" ^\n"); " ^\n");
} }
@ -402,7 +402,7 @@ TEST_F(ParserImplErrorTest, FunctionDeclMissingRParen) {
TEST_F(ParserImplErrorTest, FunctionDeclMissingArrow) { TEST_F(ParserImplErrorTest, FunctionDeclMissingArrow) {
EXPECT("fn f() void {}", EXPECT("fn f() void {}",
"test.wgsl:1:8 error: missing -> for function declaration\n" "test.wgsl:1:8 error: expected '->' for function declaration\n"
"fn f() void {}\n" "fn f() void {}\n"
" ^^^^\n"); " ^^^^\n");
} }
@ -995,14 +995,14 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarInvalidIdentifier) {
TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingLessThan) { TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingLessThan) {
EXPECT("var i : mat4x4;", EXPECT("var i : mat4x4;",
"test.wgsl:1:15 error: missing < for matrix\n" "test.wgsl:1:15 error: expected '<' for matrix\n"
"var i : mat4x4;\n" "var i : mat4x4;\n"
" ^\n"); " ^\n");
} }
TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingGreaterThan) { TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingGreaterThan) {
EXPECT("var i : mat4x4<u32;", EXPECT("var i : mat4x4<u32;",
"test.wgsl:1:19 error: missing > for matrix\n" "test.wgsl:1:19 error: expected '>' for matrix\n"
"var i : mat4x4<u32;\n" "var i : mat4x4<u32;\n"
" ^\n"); " ^\n");
} }

View File

@ -28,11 +28,13 @@ namespace {
TEST_F(ParserImplTest, ExclusiveOrExpression_Parses) { TEST_F(ParserImplTest, ExclusiveOrExpression_Parses) {
auto* p = parser("a ^ true"); auto* p = parser("a ^ true");
auto e = p->exclusive_or_expression(); auto e = p->exclusive_or_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kXor, rel->op()); EXPECT_EQ(ast::BinaryOp::kXor, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -49,24 +51,30 @@ TEST_F(ParserImplTest, ExclusiveOrExpression_Parses) {
TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidLHS) { TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidLHS) {
auto* p = parser("if (a) {} ^ true"); auto* p = parser("if (a) {} ^ true");
auto e = p->exclusive_or_expression(); auto e = p->exclusive_or_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidRHS) { TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidRHS) {
auto* p = parser("true ^ if (a) {}"); auto* p = parser("true ^ if (a) {}");
auto e = p->exclusive_or_expression(); auto e = p->exclusive_or_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: unable to parse right side of ^ expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of ^ expression");
} }
TEST_F(ParserImplTest, ExclusiveOrExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, ExclusiveOrExpression_NoOr_ReturnsLHS) {
auto* p = parser("a true"); auto* p = parser("a true");
auto e = p->exclusive_or_expression(); auto e = p->exclusive_or_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
} }
} // namespace } // namespace

View File

@ -161,8 +161,10 @@ class ForStmtErrorTest : public ParserImplTest {
auto* p_for = parser(for_str); auto* p_for = parser(for_str);
auto e_for = p_for->for_stmt(); auto e_for = p_for->for_stmt();
ASSERT_TRUE(p_for->has_error()); EXPECT_FALSE(e_for.matched);
ASSERT_EQ(e_for, nullptr); EXPECT_TRUE(e_for.errored);
EXPECT_TRUE(p_for->has_error());
ASSERT_EQ(e_for.value, nullptr);
EXPECT_EQ(p_for->error(), error_str); EXPECT_EQ(p_for->error(), error_str);
} }
}; };

View File

@ -26,56 +26,64 @@ namespace {
TEST_F(ParserImplTest, FunctionDecl) { TEST_F(ParserImplTest, FunctionDecl) {
auto* p = parser("fn main(a : i32, b : f32) -> void { return; }"); auto* p = parser("fn main(a : i32, b : f32) -> void { return; }");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
auto f = p->function_decl(decorations); ASSERT_FALSE(decos.errored);
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(decos.matched);
ASSERT_NE(f, nullptr); auto f = p->function_decl(decos.value);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(f.errored);
EXPECT_TRUE(f.matched);
ASSERT_NE(f.value, nullptr);
EXPECT_EQ(f->name(), "main"); EXPECT_EQ(f.value->name(), "main");
ASSERT_NE(f->return_type(), nullptr); ASSERT_NE(f.value->return_type(), nullptr);
EXPECT_TRUE(f->return_type()->IsVoid()); EXPECT_TRUE(f.value->return_type()->IsVoid());
ASSERT_EQ(f->params().size(), 2u); ASSERT_EQ(f.value->params().size(), 2u);
EXPECT_EQ(f->params()[0]->name(), "a"); EXPECT_EQ(f.value->params()[0]->name(), "a");
EXPECT_EQ(f->params()[1]->name(), "b"); EXPECT_EQ(f.value->params()[1]->name(), "b");
ASSERT_NE(f->return_type(), nullptr); ASSERT_NE(f.value->return_type(), nullptr);
EXPECT_TRUE(f->return_type()->IsVoid()); EXPECT_TRUE(f.value->return_type()->IsVoid());
auto* body = f->body(); auto* body = f.value->body();
ASSERT_EQ(body->size(), 1u); ASSERT_EQ(body->size(), 1u);
EXPECT_TRUE(body->get(0)->IsReturn()); EXPECT_TRUE(body->get(0)->IsReturn());
} }
TEST_F(ParserImplTest, FunctionDecl_DecorationList) { TEST_F(ParserImplTest, FunctionDecl_DecorationList) {
auto* p = parser("[[workgroup_size(2, 3, 4)]] fn main() -> void { return; }"); auto* p = parser("[[workgroup_size(2, 3, 4)]] fn main() -> void { return; }");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
auto f = p->function_decl(decorations); ASSERT_FALSE(decos.errored);
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_TRUE(decos.matched);
ASSERT_NE(f, nullptr); auto f = p->function_decl(decos.value);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(f.errored);
EXPECT_TRUE(f.matched);
ASSERT_NE(f.value, nullptr);
EXPECT_EQ(f->name(), "main"); EXPECT_EQ(f.value->name(), "main");
ASSERT_NE(f->return_type(), nullptr); ASSERT_NE(f.value->return_type(), nullptr);
EXPECT_TRUE(f->return_type()->IsVoid()); EXPECT_TRUE(f.value->return_type()->IsVoid());
ASSERT_EQ(f->params().size(), 0u); ASSERT_EQ(f.value->params().size(), 0u);
ASSERT_NE(f->return_type(), nullptr); ASSERT_NE(f.value->return_type(), nullptr);
EXPECT_TRUE(f->return_type()->IsVoid()); EXPECT_TRUE(f.value->return_type()->IsVoid());
auto& decos = f->decorations(); auto& decorations = f.value->decorations();
ASSERT_EQ(decos.size(), 1u); ASSERT_EQ(decorations.size(), 1u);
ASSERT_TRUE(decos[0]->IsWorkgroup()); ASSERT_TRUE(decorations[0]->IsWorkgroup());
uint32_t x = 0; uint32_t x = 0;
uint32_t y = 0; uint32_t y = 0;
uint32_t z = 0; uint32_t z = 0;
std::tie(x, y, z) = decos[0]->AsWorkgroup()->values(); std::tie(x, y, z) = decorations[0]->AsWorkgroup()->values();
EXPECT_EQ(x, 2u); EXPECT_EQ(x, 2u);
EXPECT_EQ(y, 3u); EXPECT_EQ(y, 3u);
EXPECT_EQ(z, 4u); EXPECT_EQ(z, 4u);
auto* body = f->body(); auto* body = f.value->body();
ASSERT_EQ(body->size(), 1u); ASSERT_EQ(body->size(), 1u);
EXPECT_TRUE(body->get(0)->IsReturn()); EXPECT_TRUE(body->get(0)->IsReturn());
} }
@ -84,38 +92,42 @@ TEST_F(ParserImplTest, FunctionDecl_DecorationList_MultipleEntries) {
auto* p = parser(R"( auto* p = parser(R"(
[[workgroup_size(2, 3, 4), workgroup_size(5, 6, 7)]] [[workgroup_size(2, 3, 4), workgroup_size(5, 6, 7)]]
fn main() -> void { return; })"); fn main() -> void { return; })");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
auto f = p->function_decl(decorations); ASSERT_FALSE(decos.errored);
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_TRUE(decos.matched);
ASSERT_NE(f, nullptr); auto f = p->function_decl(decos.value);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(f.errored);
EXPECT_TRUE(f.matched);
ASSERT_NE(f.value, nullptr);
EXPECT_EQ(f->name(), "main"); EXPECT_EQ(f.value->name(), "main");
ASSERT_NE(f->return_type(), nullptr); ASSERT_NE(f.value->return_type(), nullptr);
EXPECT_TRUE(f->return_type()->IsVoid()); EXPECT_TRUE(f.value->return_type()->IsVoid());
ASSERT_EQ(f->params().size(), 0u); ASSERT_EQ(f.value->params().size(), 0u);
ASSERT_NE(f->return_type(), nullptr); ASSERT_NE(f.value->return_type(), nullptr);
EXPECT_TRUE(f->return_type()->IsVoid()); EXPECT_TRUE(f.value->return_type()->IsVoid());
auto& decos = f->decorations(); auto& decorations = f.value->decorations();
ASSERT_EQ(decos.size(), 2u); ASSERT_EQ(decorations.size(), 2u);
uint32_t x = 0; uint32_t x = 0;
uint32_t y = 0; uint32_t y = 0;
uint32_t z = 0; uint32_t z = 0;
ASSERT_TRUE(decos[0]->IsWorkgroup()); ASSERT_TRUE(decorations[0]->IsWorkgroup());
std::tie(x, y, z) = decos[0]->AsWorkgroup()->values(); std::tie(x, y, z) = decorations[0]->AsWorkgroup()->values();
EXPECT_EQ(x, 2u); EXPECT_EQ(x, 2u);
EXPECT_EQ(y, 3u); EXPECT_EQ(y, 3u);
EXPECT_EQ(z, 4u); EXPECT_EQ(z, 4u);
ASSERT_TRUE(decos[1]->IsWorkgroup()); ASSERT_TRUE(decorations[1]->IsWorkgroup());
std::tie(x, y, z) = decos[1]->AsWorkgroup()->values(); std::tie(x, y, z) = decorations[1]->AsWorkgroup()->values();
EXPECT_EQ(x, 5u); EXPECT_EQ(x, 5u);
EXPECT_EQ(y, 6u); EXPECT_EQ(y, 6u);
EXPECT_EQ(z, 7u); EXPECT_EQ(z, 7u);
auto* body = f->body(); auto* body = f.value->body();
ASSERT_EQ(body->size(), 1u); ASSERT_EQ(body->size(), 1u);
EXPECT_TRUE(body->get(0)->IsReturn()); EXPECT_TRUE(body->get(0)->IsReturn());
} }
@ -126,19 +138,23 @@ TEST_F(ParserImplTest, FunctionDecl_DecorationList_MultipleLists) {
[[workgroup_size(5, 6, 7)]] [[workgroup_size(5, 6, 7)]]
fn main() -> void { return; })"); fn main() -> void { return; })");
auto decorations = p->decoration_list(); auto decorations = p->decoration_list();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
auto f = p->function_decl(decorations); ASSERT_FALSE(decorations.errored);
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_TRUE(decorations.matched);
ASSERT_NE(f, nullptr); auto f = p->function_decl(decorations.value);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_FALSE(f.errored);
EXPECT_TRUE(f.matched);
ASSERT_NE(f.value, nullptr);
EXPECT_EQ(f->name(), "main"); EXPECT_EQ(f.value->name(), "main");
ASSERT_NE(f->return_type(), nullptr); ASSERT_NE(f.value->return_type(), nullptr);
EXPECT_TRUE(f->return_type()->IsVoid()); EXPECT_TRUE(f.value->return_type()->IsVoid());
ASSERT_EQ(f->params().size(), 0u); ASSERT_EQ(f.value->params().size(), 0u);
ASSERT_NE(f->return_type(), nullptr); ASSERT_NE(f.value->return_type(), nullptr);
EXPECT_TRUE(f->return_type()->IsVoid()); EXPECT_TRUE(f.value->return_type()->IsVoid());
auto& decos = f->decorations(); auto& decos = f.value->decorations();
ASSERT_EQ(decos.size(), 2u); ASSERT_EQ(decos.size(), 2u);
uint32_t x = 0; uint32_t x = 0;
@ -156,38 +172,50 @@ fn main() -> void { return; })");
EXPECT_EQ(y, 6u); EXPECT_EQ(y, 6u);
EXPECT_EQ(z, 7u); EXPECT_EQ(z, 7u);
auto* body = f->body(); auto* body = f.value->body();
ASSERT_EQ(body->size(), 1u); ASSERT_EQ(body->size(), 1u);
EXPECT_TRUE(body->get(0)->IsReturn()); EXPECT_TRUE(body->get(0)->IsReturn());
} }
TEST_F(ParserImplTest, FunctionDecl_InvalidHeader) { TEST_F(ParserImplTest, FunctionDecl_InvalidHeader) {
auto* p = parser("fn main() -> { }"); auto* p = parser("fn main() -> { }");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
auto f = p->function_decl(decorations); ASSERT_FALSE(decos.errored);
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(decos.matched);
ASSERT_EQ(f, nullptr); auto f = p->function_decl(decos.value);
EXPECT_TRUE(f.errored);
EXPECT_FALSE(f.matched);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
EXPECT_EQ(p->error(), "1:14: unable to determine function return type"); EXPECT_EQ(p->error(), "1:14: unable to determine function return type");
} }
TEST_F(ParserImplTest, FunctionDecl_InvalidBody) { TEST_F(ParserImplTest, FunctionDecl_InvalidBody) {
auto* p = parser("fn main() -> void { return }"); auto* p = parser("fn main() -> void { return }");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
auto f = p->function_decl(decorations); ASSERT_FALSE(decos.errored);
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(decos.matched);
ASSERT_EQ(f, nullptr); auto f = p->function_decl(decos.value);
EXPECT_TRUE(f.errored);
EXPECT_FALSE(f.matched);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
EXPECT_EQ(p->error(), "1:28: expected ';' for return statement"); EXPECT_EQ(p->error(), "1:28: expected ';' for return statement");
} }
TEST_F(ParserImplTest, FunctionDecl_MissingLeftBrace) { TEST_F(ParserImplTest, FunctionDecl_MissingLeftBrace) {
auto* p = parser("fn main() -> void return; }"); auto* p = parser("fn main() -> void return; }");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
auto f = p->function_decl(decorations); ASSERT_FALSE(decos.errored);
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(decos.matched);
ASSERT_EQ(f, nullptr); auto f = p->function_decl(decos.value);
EXPECT_TRUE(f.errored);
EXPECT_FALSE(f.matched);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
EXPECT_EQ(p->error(), "1:19: expected '{'"); EXPECT_EQ(p->error(), "1:19: expected '{'");
} }

View File

@ -25,11 +25,13 @@ namespace {
TEST_F(ParserImplTest, FunctionDecorationList_Parses) { TEST_F(ParserImplTest, FunctionDecorationList_Parses) {
auto* p = parser("[[workgroup_size(2), workgroup_size(3, 4, 5)]]"); auto* p = parser("[[workgroup_size(2), workgroup_size(3, 4, 5)]]");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(decos.size(), 2u); EXPECT_FALSE(decos.errored);
EXPECT_TRUE(decos.matched);
ASSERT_EQ(decos.value.size(), 2u);
auto deco_0 = ast::As<ast::FunctionDecoration>(std::move(decos[0])); auto deco_0 = ast::As<ast::FunctionDecoration>(std::move(decos.value[0]));
auto deco_1 = ast::As<ast::FunctionDecoration>(std::move(decos[1])); auto deco_1 = ast::As<ast::FunctionDecoration>(std::move(decos.value[1]));
ASSERT_NE(deco_0, nullptr); ASSERT_NE(deco_0, nullptr);
ASSERT_NE(deco_1, nullptr); ASSERT_NE(deco_1, nullptr);
@ -49,47 +51,59 @@ TEST_F(ParserImplTest, FunctionDecorationList_Parses) {
TEST_F(ParserImplTest, FunctionDecorationList_Empty) { TEST_F(ParserImplTest, FunctionDecorationList_Empty) {
auto* p = parser("[[]]"); auto* p = parser("[[]]");
ast::DecorationList decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:3: empty decoration list"); EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_EQ(p->error(), "1:3: empty decoration list");
} }
TEST_F(ParserImplTest, FunctionDecorationList_Invalid) { TEST_F(ParserImplTest, FunctionDecorationList_Invalid) {
auto* p = parser("[[invalid]]"); auto* p = parser("[[invalid]]");
ast::DecorationList decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_TRUE(decos.empty()); EXPECT_TRUE(decos.errored);
ASSERT_EQ(p->error(), "1:3: expected decoration"); EXPECT_FALSE(decos.matched);
EXPECT_TRUE(decos.value.empty());
EXPECT_EQ(p->error(), "1:3: expected decoration");
} }
TEST_F(ParserImplTest, FunctionDecorationList_ExtraComma) { TEST_F(ParserImplTest, FunctionDecorationList_ExtraComma) {
auto* p = parser("[[workgroup_size(2), ]]"); auto* p = parser("[[workgroup_size(2), ]]");
ast::DecorationList decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:22: expected decoration"); EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_EQ(p->error(), "1:22: expected decoration");
} }
TEST_F(ParserImplTest, FunctionDecorationList_MissingComma) { TEST_F(ParserImplTest, FunctionDecorationList_MissingComma) {
auto* p = parser("[[workgroup_size(2) workgroup_size(2)]]"); auto* p = parser("[[workgroup_size(2) workgroup_size(2)]]");
ast::DecorationList decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:21: expected ',' for decoration list"); EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_EQ(p->error(), "1:21: expected ',' for decoration list");
} }
TEST_F(ParserImplTest, FunctionDecorationList_BadDecoration) { TEST_F(ParserImplTest, FunctionDecorationList_BadDecoration) {
auto* p = parser("[[workgroup_size()]]"); auto* p = parser("[[workgroup_size()]]");
ast::DecorationList decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ( EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_EQ(
p->error(), p->error(),
"1:18: expected signed integer literal for workgroup_size x parameter"); "1:18: expected signed integer literal for workgroup_size x parameter");
} }
TEST_F(ParserImplTest, FunctionDecorationList_MissingRightAttr) { TEST_F(ParserImplTest, FunctionDecorationList_MissingRightAttr) {
auto* p = parser("[[workgroup_size(2), workgroup_size(3, 4, 5)"); auto* p = parser("[[workgroup_size(2), workgroup_size(3, 4, 5)");
ast::DecorationList decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:45: expected ']]' for decoration list"); EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_EQ(p->error(), "1:45: expected ']]' for decoration list");
} }
} // namespace } // namespace

View File

@ -26,9 +26,11 @@ namespace {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup) {
auto* p = parser("workgroup_size(4)"); auto* p = parser("workgroup_size(4)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_NE(deco, nullptr) << p->error(); EXPECT_TRUE(deco.matched);
EXPECT_FALSE(deco.errored);
ASSERT_NE(deco.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
auto func_deco = ast::As<ast::FunctionDecoration>(std::move(deco)); auto func_deco = ast::As<ast::FunctionDecoration>(std::move(deco.value));
ASSERT_NE(func_deco, nullptr); ASSERT_NE(func_deco, nullptr);
ASSERT_TRUE(func_deco->IsWorkgroup()); ASSERT_TRUE(func_deco->IsWorkgroup());
@ -44,9 +46,11 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_2Param) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_2Param) {
auto* p = parser("workgroup_size(4, 5)"); auto* p = parser("workgroup_size(4, 5)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_NE(deco, nullptr) << p->error(); EXPECT_TRUE(deco.matched);
EXPECT_FALSE(deco.errored);
ASSERT_NE(deco.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
auto func_deco = ast::As<ast::FunctionDecoration>(std::move(deco)); auto func_deco = ast::As<ast::FunctionDecoration>(std::move(deco.value));
ASSERT_NE(func_deco, nullptr) << p->error(); ASSERT_NE(func_deco, nullptr) << p->error();
ASSERT_TRUE(func_deco->IsWorkgroup()); ASSERT_TRUE(func_deco->IsWorkgroup());
@ -62,9 +66,11 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_2Param) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_3Param) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_3Param) {
auto* p = parser("workgroup_size(4, 5, 6)"); auto* p = parser("workgroup_size(4, 5, 6)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_NE(deco, nullptr) << p->error(); EXPECT_TRUE(deco.matched);
EXPECT_FALSE(deco.errored);
ASSERT_NE(deco.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
auto func_deco = ast::As<ast::FunctionDecoration>(std::move(deco)); auto func_deco = ast::As<ast::FunctionDecoration>(std::move(deco.value));
ASSERT_NE(func_deco, nullptr); ASSERT_NE(func_deco, nullptr);
ASSERT_TRUE(func_deco->IsWorkgroup()); ASSERT_TRUE(func_deco->IsWorkgroup());
@ -80,16 +86,20 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_3Param) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_TooManyValues) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_TooManyValues) {
auto* p = parser("workgroup_size(1, 2, 3, 4)"); auto* p = parser("workgroup_size(1, 2, 3, 4)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size decoration"); EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size decoration");
} }
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_X_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_X_Value) {
auto* p = parser("workgroup_size(-2, 5, 6)"); auto* p = parser("workgroup_size(-2, 5, 6)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:16: workgroup_size x parameter must be greater than 0"); "1:16: workgroup_size x parameter must be greater than 0");
} }
@ -97,8 +107,10 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_X_Value) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Y_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Y_Value) {
auto* p = parser("workgroup_size(4, 0, 6)"); auto* p = parser("workgroup_size(4, 0, 6)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:19: workgroup_size y parameter must be greater than 0"); "1:19: workgroup_size y parameter must be greater than 0");
} }
@ -106,8 +118,10 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Y_Value) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Z_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Z_Value) {
auto* p = parser("workgroup_size(4, 5, -3)"); auto* p = parser("workgroup_size(4, 5, -3)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:22: workgroup_size z parameter must be greater than 0"); "1:22: workgroup_size z parameter must be greater than 0");
} }
@ -115,24 +129,30 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Invalid_Z_Value) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingLeftParam) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingLeftParam) {
auto* p = parser("workgroup_size 4, 5, 6)"); auto* p = parser("workgroup_size 4, 5, 6)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:16: expected '(' for workgroup_size decoration"); EXPECT_EQ(p->error(), "1:16: expected '(' for workgroup_size decoration");
} }
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingRightParam) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingRightParam) {
auto* p = parser("workgroup_size(4, 5, 6"); auto* p = parser("workgroup_size(4, 5, 6");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size decoration"); EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size decoration");
} }
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingValues) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingValues) {
auto* p = parser("workgroup_size()"); auto* p = parser("workgroup_size()");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ( EXPECT_EQ(
p->error(), p->error(),
"1:16: expected signed integer literal for workgroup_size x parameter"); "1:16: expected signed integer literal for workgroup_size x parameter");
@ -141,8 +161,10 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_MissingValues) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Value) {
auto* p = parser("workgroup_size(, 2, 3)"); auto* p = parser("workgroup_size(, 2, 3)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ( EXPECT_EQ(
p->error(), p->error(),
"1:16: expected signed integer literal for workgroup_size x parameter"); "1:16: expected signed integer literal for workgroup_size x parameter");
@ -151,16 +173,20 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Value) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Comma) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Comma) {
auto* p = parser("workgroup_size(1 2, 3)"); auto* p = parser("workgroup_size(1 2, 3)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:18: expected ')' for workgroup_size decoration"); EXPECT_EQ(p->error(), "1:18: expected ')' for workgroup_size decoration");
} }
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Value) {
auto* p = parser("workgroup_size(1, , 3)"); auto* p = parser("workgroup_size(1, , 3)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ( EXPECT_EQ(
p->error(), p->error(),
"1:19: expected signed integer literal for workgroup_size y parameter"); "1:19: expected signed integer literal for workgroup_size y parameter");
@ -169,16 +195,20 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Value) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Comma) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Comma) {
auto* p = parser("workgroup_size(1, 2 3)"); auto* p = parser("workgroup_size(1, 2 3)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:21: expected ')' for workgroup_size decoration"); EXPECT_EQ(p->error(), "1:21: expected ')' for workgroup_size decoration");
} }
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Value) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Value) {
auto* p = parser("workgroup_size(1, 2, )"); auto* p = parser("workgroup_size(1, 2, )");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ( EXPECT_EQ(
p->error(), p->error(),
"1:22: expected signed integer literal for workgroup_size z parameter"); "1:22: expected signed integer literal for workgroup_size z parameter");
@ -187,8 +217,10 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Value) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Invalid) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Invalid) {
auto* p = parser("workgroup_size(nan)"); auto* p = parser("workgroup_size(nan)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ( EXPECT_EQ(
p->error(), p->error(),
"1:16: expected signed integer literal for workgroup_size x parameter"); "1:16: expected signed integer literal for workgroup_size x parameter");
@ -197,8 +229,10 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_X_Invalid) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Invalid) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Invalid) {
auto* p = parser("workgroup_size(2, nan)"); auto* p = parser("workgroup_size(2, nan)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ( EXPECT_EQ(
p->error(), p->error(),
"1:19: expected signed integer literal for workgroup_size y parameter"); "1:19: expected signed integer literal for workgroup_size y parameter");
@ -207,8 +241,10 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Y_Invalid) {
TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Invalid) { TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Invalid) {
auto* p = parser("workgroup_size(2, 3, nan)"); auto* p = parser("workgroup_size(2, 3, nan)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ( EXPECT_EQ(
p->error(), p->error(),
"1:22: expected signed integer literal for workgroup_size z parameter"); "1:22: expected signed integer literal for workgroup_size z parameter");
@ -217,9 +253,11 @@ TEST_F(ParserImplTest, FunctionDecoration_Workgroup_Missing_Z_Invalid) {
TEST_F(ParserImplTest, FunctionDecoration_Stage) { TEST_F(ParserImplTest, FunctionDecoration_Stage) {
auto* p = parser("stage(compute)"); auto* p = parser("stage(compute)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_NE(deco, nullptr) << p->error(); EXPECT_TRUE(deco.matched);
EXPECT_FALSE(deco.errored);
ASSERT_NE(deco.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
auto func_deco = ast::As<ast::FunctionDecoration>(std::move(deco)); auto func_deco = ast::As<ast::FunctionDecoration>(std::move(deco.value));
ASSERT_NE(func_deco, nullptr); ASSERT_NE(func_deco, nullptr);
ASSERT_TRUE(func_deco->IsStage()); ASSERT_TRUE(func_deco->IsStage());
EXPECT_EQ(func_deco->AsStage()->value(), ast::PipelineStage::kCompute); EXPECT_EQ(func_deco->AsStage()->value(), ast::PipelineStage::kCompute);
@ -228,32 +266,40 @@ TEST_F(ParserImplTest, FunctionDecoration_Stage) {
TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingValue) { TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingValue) {
auto* p = parser("stage()"); auto* p = parser("stage()");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:7: invalid value for stage decoration"); EXPECT_EQ(p->error(), "1:7: invalid value for stage decoration");
} }
TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingInvalid) { TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingInvalid) {
auto* p = parser("stage(nan)"); auto* p = parser("stage(nan)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:7: invalid value for stage decoration"); EXPECT_EQ(p->error(), "1:7: invalid value for stage decoration");
} }
TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingLeftParen) { TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingLeftParen) {
auto* p = parser("stage compute)"); auto* p = parser("stage compute)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:7: expected '(' for stage decoration"); EXPECT_EQ(p->error(), "1:7: expected '(' for stage decoration");
} }
TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingRightParen) { TEST_F(ParserImplTest, FunctionDecoration_Stage_MissingRightParen) {
auto* p = parser("stage(compute"); auto* p = parser("stage(compute");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:14: expected ')' for stage decoration"); EXPECT_EQ(p->error(), "1:14: expected ')' for stage decoration");
} }

View File

@ -27,76 +27,94 @@ TEST_F(ParserImplTest, FunctionHeader) {
auto* p = parser("fn main(a : i32, b: f32) -> void"); auto* p = parser("fn main(a : i32, b: f32) -> void");
auto f = p->function_header(); auto f = p->function_header();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(f, nullptr); EXPECT_TRUE(f.matched);
EXPECT_FALSE(f.errored);
ASSERT_NE(f.value, nullptr);
EXPECT_EQ(f->name(), "main"); EXPECT_EQ(f.value->name(), "main");
ASSERT_EQ(f->params().size(), 2u); ASSERT_EQ(f.value->params().size(), 2u);
EXPECT_EQ(f->params()[0]->name(), "a"); EXPECT_EQ(f.value->params()[0]->name(), "a");
EXPECT_EQ(f->params()[1]->name(), "b"); EXPECT_EQ(f.value->params()[1]->name(), "b");
EXPECT_TRUE(f->return_type()->IsVoid()); EXPECT_TRUE(f.value->return_type()->IsVoid());
} }
TEST_F(ParserImplTest, FunctionHeader_MissingIdent) { TEST_F(ParserImplTest, FunctionHeader_MissingIdent) {
auto* p = parser("fn () ->"); auto* p = parser("fn () ->");
auto f = p->function_header(); auto f = p->function_header();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(f.matched);
ASSERT_EQ(f, nullptr); EXPECT_TRUE(f.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
EXPECT_EQ(p->error(), "1:4: expected identifier for function declaration"); EXPECT_EQ(p->error(), "1:4: expected identifier for function declaration");
} }
TEST_F(ParserImplTest, FunctionHeader_InvalidIdent) { TEST_F(ParserImplTest, FunctionHeader_InvalidIdent) {
auto* p = parser("fn 133main() -> i32"); auto* p = parser("fn 133main() -> i32");
auto f = p->function_header(); auto f = p->function_header();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(f.matched);
ASSERT_EQ(f, nullptr); EXPECT_TRUE(f.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
EXPECT_EQ(p->error(), "1:4: expected identifier for function declaration"); EXPECT_EQ(p->error(), "1:4: expected identifier for function declaration");
} }
TEST_F(ParserImplTest, FunctionHeader_MissingParenLeft) { TEST_F(ParserImplTest, FunctionHeader_MissingParenLeft) {
auto* p = parser("fn main) -> i32"); auto* p = parser("fn main) -> i32");
auto f = p->function_header(); auto f = p->function_header();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(f.matched);
ASSERT_EQ(f, nullptr); EXPECT_TRUE(f.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
EXPECT_EQ(p->error(), "1:8: expected '(' for function declaration"); EXPECT_EQ(p->error(), "1:8: expected '(' for function declaration");
} }
TEST_F(ParserImplTest, FunctionHeader_InvalidParamList) { TEST_F(ParserImplTest, FunctionHeader_InvalidParamList) {
auto* p = parser("fn main(a :i32,) -> i32"); auto* p = parser("fn main(a :i32,) -> i32");
auto f = p->function_header(); auto f = p->function_header();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(f.matched);
ASSERT_EQ(f, nullptr); EXPECT_TRUE(f.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
EXPECT_EQ(p->error(), "1:16: expected identifier for parameter"); EXPECT_EQ(p->error(), "1:16: expected identifier for parameter");
} }
TEST_F(ParserImplTest, FunctionHeader_MissingParenRight) { TEST_F(ParserImplTest, FunctionHeader_MissingParenRight) {
auto* p = parser("fn main( -> i32"); auto* p = parser("fn main( -> i32");
auto f = p->function_header(); auto f = p->function_header();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(f.matched);
ASSERT_EQ(f, nullptr); EXPECT_TRUE(f.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
EXPECT_EQ(p->error(), "1:10: expected ')' for function declaration"); EXPECT_EQ(p->error(), "1:10: expected ')' for function declaration");
} }
TEST_F(ParserImplTest, FunctionHeader_MissingArrow) { TEST_F(ParserImplTest, FunctionHeader_MissingArrow) {
auto* p = parser("fn main() i32"); auto* p = parser("fn main() i32");
auto f = p->function_header(); auto f = p->function_header();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(f.matched);
ASSERT_EQ(f, nullptr); EXPECT_TRUE(f.errored);
EXPECT_EQ(p->error(), "1:11: missing -> for function declaration"); EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
EXPECT_EQ(p->error(), "1:11: expected '->' for function declaration");
} }
TEST_F(ParserImplTest, FunctionHeader_InvalidReturnType) { TEST_F(ParserImplTest, FunctionHeader_InvalidReturnType) {
auto* p = parser("fn main() -> invalid"); auto* p = parser("fn main() -> invalid");
auto f = p->function_header(); auto f = p->function_header();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(f.matched);
ASSERT_EQ(f, nullptr); EXPECT_TRUE(f.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
EXPECT_EQ(p->error(), "1:14: unknown constructed type 'invalid'"); EXPECT_EQ(p->error(), "1:14: unknown constructed type 'invalid'");
} }
TEST_F(ParserImplTest, FunctionHeader_MissingReturnType) { TEST_F(ParserImplTest, FunctionHeader_MissingReturnType) {
auto* p = parser("fn main() ->"); auto* p = parser("fn main() ->");
auto f = p->function_header(); auto f = p->function_header();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(f.matched);
ASSERT_EQ(f, nullptr); EXPECT_TRUE(f.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
EXPECT_EQ(p->error(), "1:13: unable to determine function return type"); EXPECT_EQ(p->error(), "1:13: unable to determine function return type");
} }

View File

@ -31,9 +31,11 @@ TEST_F(ParserImplTest, FunctionTypeDecl_Void) {
auto* v = tm()->Get(std::make_unique<ast::type::VoidType>()); auto* v = tm()->Get(std::make_unique<ast::type::VoidType>());
auto* p = parser("void"); auto* p = parser("void");
auto* e = p->function_type_decl(); auto e = p->function_type_decl();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_EQ(e, v); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.value, v);
} }
TEST_F(ParserImplTest, FunctionTypeDecl_Type) { TEST_F(ParserImplTest, FunctionTypeDecl_Type) {
@ -41,16 +43,20 @@ TEST_F(ParserImplTest, FunctionTypeDecl_Type) {
auto* vec2 = tm()->Get(std::make_unique<ast::type::VectorType>(f32, 2)); auto* vec2 = tm()->Get(std::make_unique<ast::type::VectorType>(f32, 2));
auto* p = parser("vec2<f32>"); auto* p = parser("vec2<f32>");
auto* e = p->function_type_decl(); auto e = p->function_type_decl();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_EQ(e, vec2); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.value, vec2);
} }
TEST_F(ParserImplTest, FunctionTypeDecl_InvalidType) { TEST_F(ParserImplTest, FunctionTypeDecl_InvalidType) {
auto* p = parser("vec2<invalid>"); auto* p = parser("vec2<invalid>");
auto* e = p->function_type_decl(); auto e = p->function_type_decl();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:6: unknown constructed type 'invalid'"); EXPECT_EQ(p->error(), "1:6: unknown constructed type 'invalid'");
} }

View File

@ -26,52 +26,62 @@ namespace {
TEST_F(ParserImplTest, GlobalConstantDecl) { TEST_F(ParserImplTest, GlobalConstantDecl) {
auto* p = parser("const a : f32 = 1."); auto* p = parser("const a : f32 = 1.");
auto e = p->global_constant_decl(); auto e = p->global_constant_decl();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
EXPECT_TRUE(e->is_const()); EXPECT_TRUE(e.value->is_const());
EXPECT_EQ(e->name(), "a"); EXPECT_EQ(e.value->name(), "a");
ASSERT_NE(e->type(), nullptr); ASSERT_NE(e.value->type(), nullptr);
EXPECT_TRUE(e->type()->IsF32()); EXPECT_TRUE(e.value->type()->IsF32());
EXPECT_EQ(e->source().range.begin.line, 1u); EXPECT_EQ(e.value->source().range.begin.line, 1u);
EXPECT_EQ(e->source().range.begin.column, 7u); EXPECT_EQ(e.value->source().range.begin.column, 7u);
EXPECT_EQ(e->source().range.end.line, 1u); EXPECT_EQ(e.value->source().range.end.line, 1u);
EXPECT_EQ(e->source().range.end.column, 8u); EXPECT_EQ(e.value->source().range.end.column, 8u);
ASSERT_NE(e->constructor(), nullptr); ASSERT_NE(e.value->constructor(), nullptr);
EXPECT_TRUE(e->constructor()->IsConstructor()); EXPECT_TRUE(e.value->constructor()->IsConstructor());
} }
TEST_F(ParserImplTest, GlobalConstantDecl_MissingEqual) { TEST_F(ParserImplTest, GlobalConstantDecl_MissingEqual) {
auto* p = parser("const a: f32 1."); auto* p = parser("const a: f32 1.");
auto e = p->global_constant_decl(); auto e = p->global_constant_decl();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:14: expected '=' for constant declaration"); EXPECT_EQ(p->error(), "1:14: expected '=' for constant declaration");
} }
TEST_F(ParserImplTest, GlobalConstantDecl_InvalidVariable) { TEST_F(ParserImplTest, GlobalConstantDecl_InvalidVariable) {
auto* p = parser("const a: invalid = 1."); auto* p = parser("const a: invalid = 1.");
auto e = p->global_constant_decl(); auto e = p->global_constant_decl();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:10: unknown constructed type 'invalid'"); EXPECT_EQ(p->error(), "1:10: unknown constructed type 'invalid'");
} }
TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) { TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) {
auto* p = parser("const a: f32 = if (a) {}"); auto* p = parser("const a: f32 = if (a) {}");
auto e = p->global_constant_decl(); auto e = p->global_constant_decl();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:16: unable to parse const literal"); EXPECT_EQ(p->error(), "1:16: unable to parse const literal");
} }
TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) { TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
auto* p = parser("const a: f32 ="); auto* p = parser("const a: f32 =");
auto e = p->global_constant_decl(); auto e = p->global_constant_decl();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_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");
} }

View File

@ -25,130 +25,161 @@ namespace {
TEST_F(ParserImplTest, GlobalVariableDecl_WithoutConstructor) { TEST_F(ParserImplTest, GlobalVariableDecl_WithoutConstructor) {
auto* p = parser("var<out> a : f32"); auto* p = parser("var<out> a : f32");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
auto e = p->global_variable_decl(decorations); EXPECT_FALSE(decos.errored);
EXPECT_FALSE(decos.matched);
auto e = p->global_variable_decl(decos.value);
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
EXPECT_EQ(e->name(), "a"); EXPECT_EQ(e.value->name(), "a");
EXPECT_TRUE(e->type()->IsF32()); EXPECT_TRUE(e.value->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput);
EXPECT_EQ(e->source().range.begin.line, 1u); EXPECT_EQ(e.value->source().range.begin.line, 1u);
EXPECT_EQ(e->source().range.begin.column, 10u); EXPECT_EQ(e.value->source().range.begin.column, 10u);
EXPECT_EQ(e->source().range.end.line, 1u); EXPECT_EQ(e.value->source().range.end.line, 1u);
EXPECT_EQ(e->source().range.end.column, 11u); EXPECT_EQ(e.value->source().range.end.column, 11u);
ASSERT_EQ(e->constructor(), nullptr); ASSERT_EQ(e.value->constructor(), nullptr);
ASSERT_FALSE(e->IsDecorated()); ASSERT_FALSE(e.value->IsDecorated());
} }
TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) { TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) {
auto* p = parser("var<out> a : f32 = 1."); auto* p = parser("var<out> a : f32 = 1.");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
auto e = p->global_variable_decl(decorations); EXPECT_FALSE(decos.errored);
EXPECT_FALSE(decos.matched);
auto e = p->global_variable_decl(decos.value);
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
EXPECT_EQ(e->name(), "a"); EXPECT_EQ(e.value->name(), "a");
EXPECT_TRUE(e->type()->IsF32()); EXPECT_TRUE(e.value->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput);
EXPECT_EQ(e->source().range.begin.line, 1u); EXPECT_EQ(e.value->source().range.begin.line, 1u);
EXPECT_EQ(e->source().range.begin.column, 10u); EXPECT_EQ(e.value->source().range.begin.column, 10u);
EXPECT_EQ(e->source().range.end.line, 1u); EXPECT_EQ(e.value->source().range.end.line, 1u);
EXPECT_EQ(e->source().range.end.column, 11u); EXPECT_EQ(e.value->source().range.end.column, 11u);
ASSERT_NE(e->constructor(), nullptr); ASSERT_NE(e.value->constructor(), nullptr);
ASSERT_TRUE(e->constructor()->IsConstructor()); ASSERT_TRUE(e.value->constructor()->IsConstructor());
ASSERT_TRUE(e->constructor()->AsConstructor()->IsScalarConstructor()); ASSERT_TRUE(e.value->constructor()->AsConstructor()->IsScalarConstructor());
ASSERT_FALSE(e->IsDecorated()); ASSERT_FALSE(e.value->IsDecorated());
} }
TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) { TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
auto* p = parser("[[binding(2), set(1)]] var<out> a : f32"); auto* p = parser("[[binding(2), set(1)]] var<out> a : f32");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
auto e = p->global_variable_decl(decorations); EXPECT_FALSE(decos.errored);
EXPECT_TRUE(decos.matched);
auto e = p->global_variable_decl(decos.value);
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
ASSERT_TRUE(e->IsDecorated()); EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsDecorated());
EXPECT_EQ(e->name(), "a"); EXPECT_EQ(e.value->name(), "a");
ASSERT_NE(e->type(), nullptr); ASSERT_NE(e.value->type(), nullptr);
EXPECT_TRUE(e->type()->IsF32()); EXPECT_TRUE(e.value->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput);
EXPECT_EQ(e->source().range.begin.line, 1u); EXPECT_EQ(e.value->source().range.begin.line, 1u);
EXPECT_EQ(e->source().range.begin.column, 33u); EXPECT_EQ(e.value->source().range.begin.column, 33u);
EXPECT_EQ(e->source().range.end.line, 1u); EXPECT_EQ(e.value->source().range.end.line, 1u);
EXPECT_EQ(e->source().range.end.column, 34u); EXPECT_EQ(e.value->source().range.end.column, 34u);
ASSERT_EQ(e->constructor(), nullptr); ASSERT_EQ(e.value->constructor(), nullptr);
ASSERT_TRUE(e->IsDecorated()); ASSERT_TRUE(e.value->IsDecorated());
auto* v = e->AsDecorated(); auto* v = e.value->AsDecorated();
auto& decos = v->decorations(); auto& decorations = v->decorations();
ASSERT_EQ(decos.size(), 2u); ASSERT_EQ(decorations.size(), 2u);
ASSERT_TRUE(decos[0]->IsBinding()); ASSERT_TRUE(decorations[0]->IsBinding());
ASSERT_TRUE(decos[1]->IsSet()); ASSERT_TRUE(decorations[1]->IsSet());
} }
TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration_MulitpleGroups) { TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration_MulitpleGroups) {
auto* p = parser("[[binding(2)]] [[set(1)]] var<out> a : f32"); auto* p = parser("[[binding(2)]] [[set(1)]] var<out> a : f32");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
auto e = p->global_variable_decl(decorations); EXPECT_FALSE(decos.errored);
EXPECT_TRUE(decos.matched);
auto e = p->global_variable_decl(decos.value);
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
ASSERT_TRUE(e->IsDecorated()); EXPECT_FALSE(e.errored);
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsDecorated());
EXPECT_EQ(e->name(), "a"); EXPECT_EQ(e.value->name(), "a");
ASSERT_NE(e->type(), nullptr); ASSERT_NE(e.value->type(), nullptr);
EXPECT_TRUE(e->type()->IsF32()); EXPECT_TRUE(e.value->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); EXPECT_EQ(e.value->storage_class(), ast::StorageClass::kOutput);
EXPECT_EQ(e->source().range.begin.line, 1u); EXPECT_EQ(e.value->source().range.begin.line, 1u);
EXPECT_EQ(e->source().range.begin.column, 36u); EXPECT_EQ(e.value->source().range.begin.column, 36u);
EXPECT_EQ(e->source().range.end.line, 1u); EXPECT_EQ(e.value->source().range.end.line, 1u);
EXPECT_EQ(e->source().range.end.column, 37u); EXPECT_EQ(e.value->source().range.end.column, 37u);
ASSERT_EQ(e->constructor(), nullptr); ASSERT_EQ(e.value->constructor(), nullptr);
ASSERT_TRUE(e->IsDecorated()); ASSERT_TRUE(e.value->IsDecorated());
auto* v = e->AsDecorated(); auto* v = e.value->AsDecorated();
auto& decos = v->decorations(); auto& decorations = v->decorations();
ASSERT_EQ(decos.size(), 2u); ASSERT_EQ(decorations.size(), 2u);
ASSERT_TRUE(decos[0]->IsBinding()); ASSERT_TRUE(decorations[0]->IsBinding());
ASSERT_TRUE(decos[1]->IsSet()); ASSERT_TRUE(decorations[1]->IsSet());
} }
TEST_F(ParserImplTest, GlobalVariableDecl_InvalidDecoration) { TEST_F(ParserImplTest, GlobalVariableDecl_InvalidDecoration) {
auto* p = parser("[[binding()]] var<out> a : f32"); auto* p = parser("[[binding()]] var<out> a : f32");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
auto e = p->global_variable_decl(decorations); EXPECT_TRUE(decos.errored);
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(decos.matched);
ASSERT_EQ(e, nullptr);
auto e = p->global_variable_decl(decos.value);
EXPECT_FALSE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:11: expected signed integer literal for binding decoration"); "1:11: expected signed integer literal for binding decoration");
} }
TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) { TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) {
auto* p = parser("var<out> a : f32 = if (a) {}"); auto* p = parser("var<out> a : f32 = if (a) {}");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
auto e = p->global_variable_decl(decorations); EXPECT_FALSE(decos.errored);
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(decos.matched);
ASSERT_EQ(e, nullptr); auto e = p->global_variable_decl(decos.value);
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:20: unable to parse const literal"); EXPECT_EQ(p->error(), "1:20: unable to parse const literal");
} }
TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) { TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) {
auto* p = parser("var<invalid> a : f32;"); auto* p = parser("var<invalid> a : f32;");
auto decorations = p->decoration_list(); auto decos = p->decoration_list();
auto e = p->global_variable_decl(decorations); EXPECT_FALSE(decos.errored);
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(decos.matched);
ASSERT_EQ(e, nullptr); auto e = p->global_variable_decl(decos.value);
EXPECT_TRUE(p->has_error());
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration"); EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration");
} }

View File

@ -26,82 +26,98 @@ namespace {
TEST_F(ParserImplTest, IfStmt) { TEST_F(ParserImplTest, IfStmt) {
auto* p = parser("if (a == 4) { a = b; c = d; }"); auto* p = parser("if (a == 4) { a = b; c = d; }");
auto e = p->if_stmt(); auto e = p->if_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsIf()); ASSERT_TRUE(e.value->IsIf());
ASSERT_NE(e->condition(), nullptr); ASSERT_NE(e.value->condition(), nullptr);
ASSERT_TRUE(e->condition()->IsBinary()); ASSERT_TRUE(e.value->condition()->IsBinary());
EXPECT_EQ(e->body()->size(), 2u); EXPECT_EQ(e.value->body()->size(), 2u);
EXPECT_EQ(e->else_statements().size(), 0u); EXPECT_EQ(e.value->else_statements().size(), 0u);
} }
TEST_F(ParserImplTest, IfStmt_WithElse) { TEST_F(ParserImplTest, IfStmt_WithElse) {
auto* p = auto* p =
parser("if (a == 4) { a = b; c = d; } elseif(c) { d = 2; } else {}"); parser("if (a == 4) { a = b; c = d; } elseif(c) { d = 2; } else {}");
auto e = p->if_stmt(); auto e = p->if_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsIf()); ASSERT_TRUE(e.value->IsIf());
ASSERT_NE(e->condition(), nullptr); ASSERT_NE(e.value->condition(), nullptr);
ASSERT_TRUE(e->condition()->IsBinary()); ASSERT_TRUE(e.value->condition()->IsBinary());
EXPECT_EQ(e->body()->size(), 2u); EXPECT_EQ(e.value->body()->size(), 2u);
ASSERT_EQ(e->else_statements().size(), 2u); ASSERT_EQ(e.value->else_statements().size(), 2u);
ASSERT_NE(e->else_statements()[0]->condition(), nullptr); ASSERT_NE(e.value->else_statements()[0]->condition(), nullptr);
ASSERT_TRUE(e->else_statements()[0]->condition()->IsIdentifier()); ASSERT_TRUE(e.value->else_statements()[0]->condition()->IsIdentifier());
EXPECT_EQ(e->else_statements()[0]->body()->size(), 1u); EXPECT_EQ(e.value->else_statements()[0]->body()->size(), 1u);
ASSERT_EQ(e->else_statements()[1]->condition(), nullptr); ASSERT_EQ(e.value->else_statements()[1]->condition(), nullptr);
EXPECT_EQ(e->else_statements()[1]->body()->size(), 0u); EXPECT_EQ(e.value->else_statements()[1]->body()->size(), 0u);
} }
TEST_F(ParserImplTest, IfStmt_InvalidCondition) { TEST_F(ParserImplTest, IfStmt_InvalidCondition) {
auto* p = parser("if (a = 3) {}"); auto* p = parser("if (a = 3) {}");
auto e = p->if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:7: expected ')'"); EXPECT_EQ(p->error(), "1:7: expected ')'");
} }
TEST_F(ParserImplTest, IfStmt_MissingCondition) { TEST_F(ParserImplTest, IfStmt_MissingCondition) {
auto* p = parser("if {}"); auto* p = parser("if {}");
auto e = p->if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:4: expected '('"); EXPECT_EQ(p->error(), "1:4: expected '('");
} }
TEST_F(ParserImplTest, IfStmt_InvalidBody) { TEST_F(ParserImplTest, IfStmt_InvalidBody) {
auto* p = parser("if (a) { fn main() -> void {}}"); auto* p = parser("if (a) { fn main() -> void {}}");
auto e = p->if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:10: expected '}'"); EXPECT_EQ(p->error(), "1:10: expected '}'");
} }
TEST_F(ParserImplTest, IfStmt_MissingBody) { TEST_F(ParserImplTest, IfStmt_MissingBody) {
auto* p = parser("if (a)"); auto* p = parser("if (a)");
auto e = p->if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:7: expected '{'"); EXPECT_EQ(p->error(), "1:7: expected '{'");
} }
TEST_F(ParserImplTest, IfStmt_InvalidElseif) { TEST_F(ParserImplTest, IfStmt_InvalidElseif) {
auto* p = parser("if (a) {} elseif (a) { fn main() -> a{}}"); auto* p = parser("if (a) {} elseif (a) { fn main() -> a{}}");
auto e = p->if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:24: expected '}'"); EXPECT_EQ(p->error(), "1:24: expected '}'");
} }
TEST_F(ParserImplTest, IfStmt_InvalidElse) { TEST_F(ParserImplTest, IfStmt_InvalidElse) {
auto* p = parser("if (a) {} else { fn main() -> a{}}"); auto* p = parser("if (a) {} else { fn main() -> a{}}");
auto e = p->if_stmt(); auto e = p->if_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:18: expected '}'"); EXPECT_EQ(p->error(), "1:18: expected '}'");
} }

View File

@ -28,11 +28,13 @@ namespace {
TEST_F(ParserImplTest, InclusiveOrExpression_Parses) { TEST_F(ParserImplTest, InclusiveOrExpression_Parses) {
auto* p = parser("a | true"); auto* p = parser("a | true");
auto e = p->inclusive_or_expression(); auto e = p->inclusive_or_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kOr, rel->op()); EXPECT_EQ(ast::BinaryOp::kOr, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -49,24 +51,30 @@ TEST_F(ParserImplTest, InclusiveOrExpression_Parses) {
TEST_F(ParserImplTest, InclusiveOrExpression_InvalidLHS) { TEST_F(ParserImplTest, InclusiveOrExpression_InvalidLHS) {
auto* p = parser("if (a) {} | true"); auto* p = parser("if (a) {} | true");
auto e = p->inclusive_or_expression(); auto e = p->inclusive_or_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, InclusiveOrExpression_InvalidRHS) { TEST_F(ParserImplTest, InclusiveOrExpression_InvalidRHS) {
auto* p = parser("true | if (a) {}"); auto* p = parser("true | if (a) {}");
auto e = p->inclusive_or_expression(); auto e = p->inclusive_or_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:8: unable to parse right side of | expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of | expression");
} }
TEST_F(ParserImplTest, InclusiveOrExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, InclusiveOrExpression_NoOr_ReturnsLHS) {
auto* p = parser("a true"); auto* p = parser("a true");
auto e = p->inclusive_or_expression(); auto e = p->inclusive_or_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
} }
} // namespace } // namespace

View File

@ -28,11 +28,13 @@ namespace {
TEST_F(ParserImplTest, LogicalAndExpression_Parses) { TEST_F(ParserImplTest, LogicalAndExpression_Parses) {
auto* p = parser("a && true"); auto* p = parser("a && true");
auto e = p->logical_and_expression(); auto e = p->logical_and_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kLogicalAnd, rel->op()); EXPECT_EQ(ast::BinaryOp::kLogicalAnd, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -49,24 +51,30 @@ TEST_F(ParserImplTest, LogicalAndExpression_Parses) {
TEST_F(ParserImplTest, LogicalAndExpression_InvalidLHS) { TEST_F(ParserImplTest, LogicalAndExpression_InvalidLHS) {
auto* p = parser("if (a) {} && true"); auto* p = parser("if (a) {} && true");
auto e = p->logical_and_expression(); auto e = p->logical_and_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, LogicalAndExpression_InvalidRHS) { TEST_F(ParserImplTest, LogicalAndExpression_InvalidRHS) {
auto* p = parser("true && if (a) {}"); auto* p = parser("true && if (a) {}");
auto e = p->logical_and_expression(); auto e = p->logical_and_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: unable to parse right side of && expression"); EXPECT_EQ(p->error(), "1:9: unable to parse right side of && expression");
} }
TEST_F(ParserImplTest, LogicalAndExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, LogicalAndExpression_NoOr_ReturnsLHS) {
auto* p = parser("a true"); auto* p = parser("a true");
auto e = p->logical_and_expression(); auto e = p->logical_and_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
} }
} // namespace } // namespace

View File

@ -28,11 +28,13 @@ namespace {
TEST_F(ParserImplTest, LogicalOrExpression_Parses) { TEST_F(ParserImplTest, LogicalOrExpression_Parses) {
auto* p = parser("a || true"); auto* p = parser("a || true");
auto e = p->logical_or_expression(); auto e = p->logical_or_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kLogicalOr, rel->op()); EXPECT_EQ(ast::BinaryOp::kLogicalOr, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -49,24 +51,30 @@ TEST_F(ParserImplTest, LogicalOrExpression_Parses) {
TEST_F(ParserImplTest, LogicalOrExpression_InvalidLHS) { TEST_F(ParserImplTest, LogicalOrExpression_InvalidLHS) {
auto* p = parser("if (a) {} || true"); auto* p = parser("if (a) {} || true");
auto e = p->logical_or_expression(); auto e = p->logical_or_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, LogicalOrExpression_InvalidRHS) { TEST_F(ParserImplTest, LogicalOrExpression_InvalidRHS) {
auto* p = parser("true || if (a) {}"); auto* p = parser("true || if (a) {}");
auto e = p->logical_or_expression(); auto e = p->logical_or_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: unable to parse right side of || expression"); EXPECT_EQ(p->error(), "1:9: unable to parse right side of || expression");
} }
TEST_F(ParserImplTest, LogicalOrExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, LogicalOrExpression_NoOr_ReturnsLHS) {
auto* p = parser("a true"); auto* p = parser("a true");
auto e = p->logical_or_expression(); auto e = p->logical_or_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
} }
} // namespace } // namespace

View File

@ -24,76 +24,92 @@ namespace {
TEST_F(ParserImplTest, LoopStmt_BodyNoContinuing) { TEST_F(ParserImplTest, LoopStmt_BodyNoContinuing) {
auto* p = parser("loop { discard; }"); auto* p = parser("loop { discard; }");
auto e = p->loop_stmt(); auto e = p->loop_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_EQ(e->body()->size(), 1u); ASSERT_EQ(e.value->body()->size(), 1u);
EXPECT_TRUE(e->body()->get(0)->IsDiscard()); EXPECT_TRUE(e.value->body()->get(0)->IsDiscard());
EXPECT_EQ(e->continuing()->size(), 0u); EXPECT_EQ(e.value->continuing()->size(), 0u);
} }
TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) { TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) {
auto* p = parser("loop { discard; continuing { discard; }}"); auto* p = parser("loop { discard; continuing { discard; }}");
auto e = p->loop_stmt(); auto e = p->loop_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_EQ(e->body()->size(), 1u); ASSERT_EQ(e.value->body()->size(), 1u);
EXPECT_TRUE(e->body()->get(0)->IsDiscard()); EXPECT_TRUE(e.value->body()->get(0)->IsDiscard());
EXPECT_EQ(e->continuing()->size(), 1u); EXPECT_EQ(e.value->continuing()->size(), 1u);
EXPECT_TRUE(e->continuing()->get(0)->IsDiscard()); EXPECT_TRUE(e.value->continuing()->get(0)->IsDiscard());
} }
TEST_F(ParserImplTest, LoopStmt_NoBodyNoContinuing) { TEST_F(ParserImplTest, LoopStmt_NoBodyNoContinuing) {
auto* p = parser("loop { }"); auto* p = parser("loop { }");
auto e = p->loop_stmt(); auto e = p->loop_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_EQ(e->body()->size(), 0u); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e->continuing()->size(), 0u); ASSERT_NE(e.value, nullptr);
ASSERT_EQ(e.value->body()->size(), 0u);
ASSERT_EQ(e.value->continuing()->size(), 0u);
} }
TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) { TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) {
auto* p = parser("loop { continuing { discard; }}"); auto* p = parser("loop { continuing { discard; }}");
auto e = p->loop_stmt(); auto e = p->loop_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_EQ(e->body()->size(), 0u); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e->continuing()->size(), 1u); ASSERT_NE(e.value, nullptr);
EXPECT_TRUE(e->continuing()->get(0)->IsDiscard()); ASSERT_EQ(e.value->body()->size(), 0u);
ASSERT_EQ(e.value->continuing()->size(), 1u);
EXPECT_TRUE(e.value->continuing()->get(0)->IsDiscard());
} }
TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) { TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) {
auto* p = parser("loop discard; }"); auto* p = parser("loop discard; }");
auto e = p->loop_stmt(); auto e = p->loop_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:6: expected '{' for loop"); EXPECT_EQ(p->error(), "1:6: expected '{' for loop");
} }
TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) { TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) {
auto* p = parser("loop { discard; "); auto* p = parser("loop { discard; ");
auto e = p->loop_stmt(); auto e = p->loop_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:17: expected '}' for loop"); EXPECT_EQ(p->error(), "1:17: expected '}' for loop");
} }
TEST_F(ParserImplTest, LoopStmt_InvalidStatements) { TEST_F(ParserImplTest, LoopStmt_InvalidStatements) {
auto* p = parser("loop { discard }"); auto* p = parser("loop { discard }");
auto e = p->loop_stmt(); auto e = p->loop_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:16: expected ';' for discard statement"); EXPECT_EQ(p->error(), "1:16: expected ';' for discard statement");
} }
TEST_F(ParserImplTest, LoopStmt_InvalidContinuing) { TEST_F(ParserImplTest, LoopStmt_InvalidContinuing) {
auto* p = parser("loop { continuing { discard }}"); auto* p = parser("loop { continuing { discard }}");
auto e = p->loop_stmt(); auto e = p->loop_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:29: expected ';' for discard statement"); EXPECT_EQ(p->error(), "1:29: expected ';' for discard statement");
} }

View File

@ -28,11 +28,13 @@ namespace {
TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Multiply) { TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Multiply) {
auto* p = parser("a * true"); auto* p = parser("a * true");
auto e = p->multiplicative_expression(); auto e = p->multiplicative_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kMultiply, rel->op()); EXPECT_EQ(ast::BinaryOp::kMultiply, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -49,11 +51,13 @@ TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Multiply) {
TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Divide) { TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Divide) {
auto* p = parser("a / true"); auto* p = parser("a / true");
auto e = p->multiplicative_expression(); auto e = p->multiplicative_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kDivide, rel->op()); EXPECT_EQ(ast::BinaryOp::kDivide, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -70,11 +74,13 @@ TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Divide) {
TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Modulo) { TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Modulo) {
auto* p = parser("a % true"); auto* p = parser("a % true");
auto e = p->multiplicative_expression(); auto e = p->multiplicative_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kModulo, rel->op()); EXPECT_EQ(ast::BinaryOp::kModulo, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -91,24 +97,30 @@ TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Modulo) {
TEST_F(ParserImplTest, MultiplicativeExpression_InvalidLHS) { TEST_F(ParserImplTest, MultiplicativeExpression_InvalidLHS) {
auto* p = parser("if (a) {} * true"); auto* p = parser("if (a) {} * true");
auto e = p->multiplicative_expression(); auto e = p->multiplicative_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, MultiplicativeExpression_InvalidRHS) { TEST_F(ParserImplTest, MultiplicativeExpression_InvalidRHS) {
auto* p = parser("true * if (a) {}"); auto* p = parser("true * if (a) {}");
auto e = p->multiplicative_expression(); auto e = p->multiplicative_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: unable to parse right side of * expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of * expression");
} }
TEST_F(ParserImplTest, MultiplicativeExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, MultiplicativeExpression_NoOr_ReturnsLHS) {
auto* p = parser("a true"); auto* p = parser("a true");
auto e = p->multiplicative_expression(); auto e = p->multiplicative_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
} }
} // namespace } // namespace

View File

@ -31,11 +31,13 @@ namespace {
TEST_F(ParserImplTest, PostfixExpression_Array_ConstantIndex) { TEST_F(ParserImplTest, PostfixExpression_Array_ConstantIndex) {
auto* p = parser("a[1]"); auto* p = parser("a[1]");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsArrayAccessor()); ASSERT_TRUE(e.value->IsArrayAccessor());
auto* ary = e->AsArrayAccessor(); auto* ary = e.value->AsArrayAccessor();
ASSERT_TRUE(ary->array()->IsIdentifier()); ASSERT_TRUE(ary->array()->IsIdentifier());
auto* ident = ary->array()->AsIdentifier(); auto* ident = ary->array()->AsIdentifier();
@ -51,11 +53,13 @@ TEST_F(ParserImplTest, PostfixExpression_Array_ConstantIndex) {
TEST_F(ParserImplTest, PostfixExpression_Array_ExpressionIndex) { TEST_F(ParserImplTest, PostfixExpression_Array_ExpressionIndex) {
auto* p = parser("a[1 + b / 4]"); auto* p = parser("a[1 + b / 4]");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsArrayAccessor()); ASSERT_TRUE(e.value->IsArrayAccessor());
auto* ary = e->AsArrayAccessor(); auto* ary = e.value->AsArrayAccessor();
ASSERT_TRUE(ary->array()->IsIdentifier()); ASSERT_TRUE(ary->array()->IsIdentifier());
auto* ident = ary->array()->AsIdentifier(); auto* ident = ary->array()->AsIdentifier();
@ -67,35 +71,43 @@ TEST_F(ParserImplTest, PostfixExpression_Array_ExpressionIndex) {
TEST_F(ParserImplTest, PostfixExpression_Array_MissingIndex) { TEST_F(ParserImplTest, PostfixExpression_Array_MissingIndex) {
auto* p = parser("a[]"); auto* p = parser("a[]");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []"); EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []");
} }
TEST_F(ParserImplTest, PostfixExpression_Array_MissingRightBrace) { TEST_F(ParserImplTest, PostfixExpression_Array_MissingRightBrace) {
auto* p = parser("a[1"); auto* p = parser("a[1");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(p->error(), "1:4: missing ] for array accessor"); EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:4: expected ']' for array accessor");
} }
TEST_F(ParserImplTest, PostfixExpression_Array_InvalidIndex) { TEST_F(ParserImplTest, PostfixExpression_Array_InvalidIndex) {
auto* p = parser("a[if(a() {})]"); auto* p = parser("a[if(a() {})]");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []"); EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []");
} }
TEST_F(ParserImplTest, PostfixExpression_Call_Empty) { TEST_F(ParserImplTest, PostfixExpression_Call_Empty) {
auto* p = parser("a()"); auto* p = parser("a()");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsCall()); ASSERT_TRUE(e.value->IsCall());
auto* c = e->AsCall(); auto* c = e.value->AsCall();
ASSERT_TRUE(c->func()->IsIdentifier()); ASSERT_TRUE(c->func()->IsIdentifier());
auto* func = c->func()->AsIdentifier(); auto* func = c->func()->AsIdentifier();
@ -107,11 +119,13 @@ TEST_F(ParserImplTest, PostfixExpression_Call_Empty) {
TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) { TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) {
auto* p = parser("test(1, b, 2 + 3 / b)"); auto* p = parser("test(1, b, 2 + 3 / b)");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsCall()); ASSERT_TRUE(e.value->IsCall());
auto* c = e->AsCall(); auto* c = e.value->AsCall();
ASSERT_TRUE(c->func()->IsIdentifier()); ASSERT_TRUE(c->func()->IsIdentifier());
auto* func = c->func()->AsIdentifier(); auto* func = c->func()->AsIdentifier();
@ -126,35 +140,43 @@ TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) {
TEST_F(ParserImplTest, PostfixExpression_Call_InvalidArg) { TEST_F(ParserImplTest, PostfixExpression_Call_InvalidArg) {
auto* p = parser("a(if(a) {})"); auto* p = parser("a(if(a) {})");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:3: unable to parse argument expression"); EXPECT_EQ(p->error(), "1:3: unable to parse argument expression");
} }
TEST_F(ParserImplTest, PostfixExpression_Call_HangingComma) { TEST_F(ParserImplTest, PostfixExpression_Call_HangingComma) {
auto* p = parser("a(b, )"); auto* p = parser("a(b, )");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:6: unable to parse argument expression after comma"); EXPECT_EQ(p->error(), "1:6: unable to parse argument expression after comma");
} }
TEST_F(ParserImplTest, PostfixExpression_Call_MissingRightParen) { TEST_F(ParserImplTest, PostfixExpression_Call_MissingRightParen) {
auto* p = parser("a("); auto* p = parser("a(");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:3: expected ')' for call expression"); EXPECT_EQ(p->error(), "1:3: expected ')' for call expression");
} }
TEST_F(ParserImplTest, PostfixExpression_MemberAccessor) { TEST_F(ParserImplTest, PostfixExpression_MemberAccessor) {
auto* p = parser("a.b"); auto* p = parser("a.b");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsMemberAccessor()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsMemberAccessor());
auto* m = e->AsMemberAccessor(); auto* m = e.value->AsMemberAccessor();
ASSERT_TRUE(m->structure()->IsIdentifier()); ASSERT_TRUE(m->structure()->IsIdentifier());
EXPECT_EQ(m->structure()->AsIdentifier()->name(), "a"); EXPECT_EQ(m->structure()->AsIdentifier()->name(), "a");
@ -165,25 +187,31 @@ TEST_F(ParserImplTest, PostfixExpression_MemberAccessor) {
TEST_F(ParserImplTest, PostfixExpression_MemberAccesssor_InvalidIdent) { TEST_F(ParserImplTest, PostfixExpression_MemberAccesssor_InvalidIdent) {
auto* p = parser("a.if"); auto* p = parser("a.if");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:3: expected identifier for member accessor"); EXPECT_EQ(p->error(), "1:3: expected identifier for member accessor");
} }
TEST_F(ParserImplTest, PostfixExpression_MemberAccessor_MissingIdent) { TEST_F(ParserImplTest, PostfixExpression_MemberAccessor_MissingIdent) {
auto* p = parser("a."); auto* p = parser("a.");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:3: expected identifier for member accessor"); EXPECT_EQ(p->error(), "1:3: expected identifier for member accessor");
} }
TEST_F(ParserImplTest, PostfixExpression_NonMatch_returnLHS) { TEST_F(ParserImplTest, PostfixExpression_NonMatch_returnLHS) {
auto* p = parser("a b"); auto* p = parser("a b");
auto e = p->postfix_expression(); auto e = p->postfix_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
} }
} // namespace } // namespace

View File

@ -35,21 +35,25 @@ namespace {
TEST_F(ParserImplTest, PrimaryExpression_Ident) { TEST_F(ParserImplTest, PrimaryExpression_Ident) {
auto* p = parser("a"); auto* p = parser("a");
auto e = p->primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
auto* ident = e->AsIdentifier(); ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
auto* ident = e.value->AsIdentifier();
EXPECT_EQ(ident->name(), "a"); EXPECT_EQ(ident->name(), "a");
} }
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) {
auto* p = parser("vec4<i32>(1, 2, 3, 4))"); auto* p = parser("vec4<i32>(1, 2, 3, 4))");
auto e = p->primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsConstructor()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor()); ASSERT_NE(e.value, nullptr);
auto* ty = e->AsConstructor()->AsTypeConstructor(); ASSERT_TRUE(e.value->IsConstructor());
ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor());
auto* ty = e.value->AsConstructor()->AsTypeConstructor();
ASSERT_EQ(ty->values().size(), 4u); ASSERT_EQ(ty->values().size(), 4u);
const auto& val = ty->values(); const auto& val = ty->values();
@ -81,11 +85,13 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) {
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_ZeroConstructor) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_ZeroConstructor) {
auto* p = parser("vec4<i32>()"); auto* p = parser("vec4<i32>()");
auto e = p->primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsConstructor()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor()); ASSERT_NE(e.value, nullptr);
auto* ty = e->AsConstructor()->AsTypeConstructor(); ASSERT_TRUE(e.value->IsConstructor());
ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor());
auto* ty = e.value->AsConstructor()->AsTypeConstructor();
ASSERT_EQ(ty->values().size(), 0u); ASSERT_EQ(ty->values().size(), 0u);
} }
@ -93,43 +99,53 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_ZeroConstructor) {
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) {
auto* p = parser("vec4<if>(2., 3., 4., 5.)"); auto* p = parser("vec4<if>(2., 3., 4., 5.)");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: unable to determine subtype for vector"); EXPECT_EQ(p->error(), "1:6: unable to determine subtype for vector");
} }
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingLeftParen) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingLeftParen) {
auto* p = parser("vec4<f32> 2., 3., 4., 5.)"); auto* p = parser("vec4<f32> 2., 3., 4., 5.)");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor"); EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor");
} }
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingRightParen) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingRightParen) {
auto* p = parser("vec4<f32>(2., 3., 4., 5."); auto* p = parser("vec4<f32>(2., 3., 4., 5.");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:25: expected ')' for type constructor"); EXPECT_EQ(p->error(), "1:25: expected ')' for type constructor");
} }
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidValue) { TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidValue) {
auto* p = parser("i32(if(a) {})"); auto* p = parser("i32(if(a) {})");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:5: unable to parse argument expression"); EXPECT_EQ(p->error(), "1:5: unable to parse argument expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_ConstLiteral_True) { TEST_F(ParserImplTest, PrimaryExpression_ConstLiteral_True) {
auto* p = parser("true"); auto* p = parser("true");
auto e = p->primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsConstructor()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_TRUE(e->AsConstructor()->IsScalarConstructor()); ASSERT_NE(e.value, nullptr);
auto* init = e->AsConstructor()->AsScalarConstructor(); ASSERT_TRUE(e.value->IsConstructor());
ASSERT_TRUE(e.value->AsConstructor()->IsScalarConstructor());
auto* init = e.value->AsConstructor()->AsScalarConstructor();
ASSERT_TRUE(init->literal()->IsBool()); ASSERT_TRUE(init->literal()->IsBool());
EXPECT_TRUE(init->literal()->AsBool()->IsTrue()); EXPECT_TRUE(init->literal()->AsBool()->IsTrue());
} }
@ -137,32 +153,40 @@ TEST_F(ParserImplTest, PrimaryExpression_ConstLiteral_True) {
TEST_F(ParserImplTest, PrimaryExpression_ParenExpr) { TEST_F(ParserImplTest, PrimaryExpression_ParenExpr) {
auto* p = parser("(a == b)"); auto* p = parser("(a == b)");
auto e = p->primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsBinary()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsBinary());
} }
TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingRightParen) { TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingRightParen) {
auto* p = parser("(a == b"); auto* p = parser("(a == b");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: expected ')'"); EXPECT_EQ(p->error(), "1:8: expected ')'");
} }
TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingExpr) { TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingExpr) {
auto* p = parser("()"); auto* p = parser("()");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:2: unable to parse expression"); EXPECT_EQ(p->error(), "1:2: unable to parse expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_InvalidExpr) { TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_InvalidExpr) {
auto* p = parser("(if (a) {})"); auto* p = parser("(if (a) {})");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:2: unable to parse expression"); EXPECT_EQ(p->error(), "1:2: unable to parse expression");
} }
@ -171,12 +195,14 @@ TEST_F(ParserImplTest, PrimaryExpression_Cast) {
auto* p = parser("f32(1)"); auto* p = parser("f32(1)");
auto e = p->primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsConstructor()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor()); ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsConstructor());
ASSERT_TRUE(e.value->AsConstructor()->IsTypeConstructor());
auto* c = e->AsConstructor()->AsTypeConstructor(); auto* c = e.value->AsConstructor()->AsTypeConstructor();
ASSERT_EQ(c->type(), f32_type); ASSERT_EQ(c->type(), f32_type);
ASSERT_EQ(c->values().size(), 1u); ASSERT_EQ(c->values().size(), 1u);
@ -189,11 +215,13 @@ TEST_F(ParserImplTest, PrimaryExpression_Bitcast) {
auto* p = parser("bitcast<f32>(1)"); auto* p = parser("bitcast<f32>(1)");
auto e = p->primary_expression(); auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsBitcast()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsBitcast());
auto* c = e->AsBitcast(); auto* c = e.value->AsBitcast();
ASSERT_EQ(c->type(), f32_type); ASSERT_EQ(c->type(), f32_type);
ASSERT_TRUE(c->expr()->IsConstructor()); ASSERT_TRUE(c->expr()->IsConstructor());
@ -203,56 +231,70 @@ TEST_F(ParserImplTest, PrimaryExpression_Bitcast) {
TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingGreaterThan) { TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingGreaterThan) {
auto* p = parser("bitcast<f32(1)"); auto* p = parser("bitcast<f32(1)");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_EQ(p->error(), "1:12: expected '>' for bitcast expression");
EXPECT_EQ(p->error(), "1:12: missing > for bitcast expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingType) { TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingType) {
auto* p = parser("bitcast<>(1)"); auto* p = parser("bitcast<>(1)");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:9: missing type for bitcast expression"); EXPECT_EQ(p->error(), "1:9: missing type for bitcast expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_Bitcast_InvalidType) { TEST_F(ParserImplTest, PrimaryExpression_Bitcast_InvalidType) {
auto* p = parser("bitcast<invalid>(1)"); auto* p = parser("bitcast<invalid>(1)");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:9: unknown constructed type 'invalid'"); EXPECT_EQ(p->error(), "1:9: unknown constructed type 'invalid'");
} }
TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingLeftParen) { TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingLeftParen) {
auto* p = parser("bitcast<f32>1)"); auto* p = parser("bitcast<f32>1)");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:13: expected '('"); EXPECT_EQ(p->error(), "1:13: expected '('");
} }
TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingRightParen) { TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingRightParen) {
auto* p = parser("bitcast<f32>(1"); auto* p = parser("bitcast<f32>(1");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:15: expected ')'"); EXPECT_EQ(p->error(), "1:15: expected ')'");
} }
TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingExpression) { TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingExpression) {
auto* p = parser("bitcast<f32>()"); auto* p = parser("bitcast<f32>()");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:14: unable to parse expression"); EXPECT_EQ(p->error(), "1:14: unable to parse expression");
} }
TEST_F(ParserImplTest, PrimaryExpression_bitcast_InvalidExpression) { TEST_F(ParserImplTest, PrimaryExpression_bitcast_InvalidExpression) {
auto* p = parser("bitcast<f32>(if (a) {})"); auto* p = parser("bitcast<f32>(if (a) {})");
auto e = p->primary_expression(); auto e = p->primary_expression();
EXPECT_FALSE(e.matched);
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:14: unable to parse expression"); EXPECT_EQ(p->error(), "1:14: unable to parse expression");
} }

View File

@ -28,11 +28,13 @@ namespace {
TEST_F(ParserImplTest, RelationalExpression_Parses_LessThan) { TEST_F(ParserImplTest, RelationalExpression_Parses_LessThan) {
auto* p = parser("a < true"); auto* p = parser("a < true");
auto e = p->relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kLessThan, rel->op()); EXPECT_EQ(ast::BinaryOp::kLessThan, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -49,11 +51,13 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_LessThan) {
TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) { TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) {
auto* p = parser("a > true"); auto* p = parser("a > true");
auto e = p->relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kGreaterThan, rel->op()); EXPECT_EQ(ast::BinaryOp::kGreaterThan, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -70,11 +74,13 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) {
TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) { TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) {
auto* p = parser("a <= true"); auto* p = parser("a <= true");
auto e = p->relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kLessThanEqual, rel->op()); EXPECT_EQ(ast::BinaryOp::kLessThanEqual, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -91,11 +97,13 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) {
TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) { TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) {
auto* p = parser("a >= true"); auto* p = parser("a >= true");
auto e = p->relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kGreaterThanEqual, rel->op()); EXPECT_EQ(ast::BinaryOp::kGreaterThanEqual, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -112,24 +120,28 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) {
TEST_F(ParserImplTest, RelationalExpression_InvalidLHS) { TEST_F(ParserImplTest, RelationalExpression_InvalidLHS) {
auto* p = parser("if (a) {} < true"); auto* p = parser("if (a) {} < true");
auto e = p->relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, RelationalExpression_InvalidRHS) { TEST_F(ParserImplTest, RelationalExpression_InvalidRHS) {
auto* p = parser("true < if (a) {}"); auto* p = parser("true < if (a) {}");
auto e = p->relational_expression(); auto e = p->relational_expression();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:8: unable to parse right side of < expression"); EXPECT_EQ(p->error(), "1:8: unable to parse right side of < expression");
} }
TEST_F(ParserImplTest, RelationalExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, RelationalExpression_NoOr_ReturnsLHS) {
auto* p = parser("a true"); auto* p = parser("a true");
auto e = p->relational_expression(); auto e = p->relational_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
} }
} // namespace } // namespace

View File

@ -25,105 +25,134 @@ namespace {
TEST_F(ParserImplTest, SampledTextureType_Invalid) { TEST_F(ParserImplTest, SampledTextureType_Invalid) {
auto* p = parser("1234"); auto* p = parser("1234");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::kNone); EXPECT_FALSE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_1d_Old) { TEST_F(ParserImplTest, SampledTextureType_1d_Old) {
auto* p = parser("texture_sampled_1d"); auto* p = parser("texture_sampled_1d");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::k1d); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::k1d);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_1dArray_Old) { TEST_F(ParserImplTest, SampledTextureType_1dArray_Old) {
auto* p = parser("texture_sampled_1d_array"); auto* p = parser("texture_sampled_1d_array");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::k1dArray); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::k1dArray);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_2d_Old) { TEST_F(ParserImplTest, SampledTextureType_2d_Old) {
auto* p = parser("texture_sampled_2d"); auto* p = parser("texture_sampled_2d");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::k2d); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::k2d);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_2dArray_Old) { TEST_F(ParserImplTest, SampledTextureType_2dArray_Old) {
auto* p = parser("texture_sampled_2d_array"); auto* p = parser("texture_sampled_2d_array");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::k2dArray); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::k2dArray);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_3d_Old) { TEST_F(ParserImplTest, SampledTextureType_3d_Old) {
auto* p = parser("texture_sampled_3d"); auto* p = parser("texture_sampled_3d");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::k3d); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::k3d);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_Cube_Old) { TEST_F(ParserImplTest, SampledTextureType_Cube_Old) {
auto* p = parser("texture_sampled_cube"); auto* p = parser("texture_sampled_cube");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::kCube); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::kCube);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_kCubeArray_Old) { TEST_F(ParserImplTest, SampledTextureType_kCubeArray_Old) {
auto* p = parser("texture_sampled_cube_array"); auto* p = parser("texture_sampled_cube_array");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::kCubeArray); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::kCubeArray);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_1d) { TEST_F(ParserImplTest, SampledTextureType_1d) {
auto* p = parser("texture_1d"); auto* p = parser("texture_1d");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::k1d); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::k1d);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_1dArray) { TEST_F(ParserImplTest, SampledTextureType_1dArray) {
auto* p = parser("texture_1d_array"); auto* p = parser("texture_1d_array");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::k1dArray); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::k1dArray);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_2d) { TEST_F(ParserImplTest, SampledTextureType_2d) {
auto* p = parser("texture_2d"); auto* p = parser("texture_2d");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::k2d); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::k2d);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_2dArray) { TEST_F(ParserImplTest, SampledTextureType_2dArray) {
auto* p = parser("texture_2d_array"); auto* p = parser("texture_2d_array");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::k2dArray); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::k2dArray);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_3d) { TEST_F(ParserImplTest, SampledTextureType_3d) {
auto* p = parser("texture_3d"); auto* p = parser("texture_3d");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::k3d); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::k3d);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_Cube) { TEST_F(ParserImplTest, SampledTextureType_Cube) {
auto* p = parser("texture_cube"); auto* p = parser("texture_cube");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::kCube); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::kCube);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SampledTextureType_kCubeArray) { TEST_F(ParserImplTest, SampledTextureType_kCubeArray) {
auto* p = parser("texture_cube_array"); auto* p = parser("texture_cube_array");
auto t = p->sampled_texture_type(); auto t = p->sampled_texture_type();
EXPECT_EQ(t, ast::type::TextureDimension::kCubeArray); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, ast::type::TextureDimension::kCubeArray);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }

View File

@ -24,26 +24,32 @@ namespace {
TEST_F(ParserImplTest, SamplerType_Invalid) { TEST_F(ParserImplTest, SamplerType_Invalid) {
auto* p = parser("1234"); auto* p = parser("1234");
auto* t = p->sampler_type(); auto t = p->sampler_type();
EXPECT_EQ(t, nullptr); EXPECT_FALSE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SamplerType_Sampler) { TEST_F(ParserImplTest, SamplerType_Sampler) {
auto* p = parser("sampler"); auto* p = parser("sampler");
auto* t = p->sampler_type(); auto t = p->sampler_type();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsSampler()); EXPECT_FALSE(t.errored);
EXPECT_FALSE(t->AsSampler()->IsComparison()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t.value->IsSampler());
EXPECT_FALSE(t.value->AsSampler()->IsComparison());
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, SamplerType_ComparisonSampler) { TEST_F(ParserImplTest, SamplerType_ComparisonSampler) {
auto* p = parser("sampler_comparison"); auto* p = parser("sampler_comparison");
auto* t = p->sampler_type(); auto t = p->sampler_type();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsSampler()); EXPECT_FALSE(t.errored);
EXPECT_TRUE(t->AsSampler()->IsComparison()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t.value->IsSampler());
EXPECT_TRUE(t.value->AsSampler()->IsComparison());
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }

View File

@ -28,11 +28,13 @@ namespace {
TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) { TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) {
auto* p = parser("a << true"); auto* p = parser("a << true");
auto e = p->shift_expression(); auto e = p->shift_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kShiftLeft, rel->op()); EXPECT_EQ(ast::BinaryOp::kShiftLeft, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -49,11 +51,13 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) {
TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) { TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) {
auto* p = parser("a >> true"); auto* p = parser("a >> true");
auto e = p->shift_expression(); auto e = p->shift_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsBinary()); ASSERT_TRUE(e.value->IsBinary());
auto* rel = e->AsBinary(); auto* rel = e.value->AsBinary();
EXPECT_EQ(ast::BinaryOp::kShiftRight, rel->op()); EXPECT_EQ(ast::BinaryOp::kShiftRight, rel->op());
ASSERT_TRUE(rel->lhs()->IsIdentifier()); ASSERT_TRUE(rel->lhs()->IsIdentifier());
@ -70,24 +74,30 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) {
TEST_F(ParserImplTest, ShiftExpression_InvalidLHS) { TEST_F(ParserImplTest, ShiftExpression_InvalidLHS) {
auto* p = parser("if (a) {} << true"); auto* p = parser("if (a) {} << true");
auto e = p->shift_expression(); auto e = p->shift_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
EXPECT_EQ(e.value, nullptr);
} }
TEST_F(ParserImplTest, ShiftExpression_InvalidRHS) { TEST_F(ParserImplTest, ShiftExpression_InvalidRHS) {
auto* p = parser("true << if (a) {}"); auto* p = parser("true << if (a) {}");
auto e = p->shift_expression(); auto e = p->shift_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:9: unable to parse right side of << expression"); EXPECT_EQ(p->error(), "1:9: unable to parse right side of << expression");
} }
TEST_F(ParserImplTest, ShiftExpression_NoOr_ReturnsLHS) { TEST_F(ParserImplTest, ShiftExpression_NoOr_ReturnsLHS) {
auto* p = parser("a true"); auto* p = parser("a true");
auto e = p->shift_expression(); auto e = p->shift_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsIdentifier()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsIdentifier());
} }
} // namespace } // namespace

View File

@ -27,25 +27,25 @@ TEST_F(ParserImplTest, Statement) {
auto* p = parser("return;"); auto* p = parser("return;");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
EXPECT_TRUE(e->IsReturn()); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e.value->IsReturn());
} }
TEST_F(ParserImplTest, Statement_Semicolon) { TEST_F(ParserImplTest, Statement_Semicolon) {
auto* p = parser(";"); auto* p = parser(";");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e, nullptr);
} }
TEST_F(ParserImplTest, Statement_Return_NoValue) { TEST_F(ParserImplTest, Statement_Return_NoValue) {
auto* p = parser("return;"); auto* p = parser("return;");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsReturn()); ASSERT_TRUE(e.value->IsReturn());
auto* ret = e->AsReturn(); auto* ret = e.value->AsReturn();
ASSERT_EQ(ret->value(), nullptr); ASSERT_EQ(ret->value(), nullptr);
} }
@ -53,10 +53,11 @@ TEST_F(ParserImplTest, Statement_Return_Value) {
auto* p = parser("return a + b * (.1 - .2);"); auto* p = parser("return a + b * (.1 - .2);");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsReturn()); EXPECT_TRUE(e.matched);
auto* ret = e->AsReturn(); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e.value->IsReturn());
auto* ret = e.value->AsReturn();
ASSERT_NE(ret->value(), nullptr); ASSERT_NE(ret->value(), nullptr);
EXPECT_TRUE(ret->value()->IsBinary()); EXPECT_TRUE(ret->value()->IsBinary());
} }
@ -64,16 +65,20 @@ TEST_F(ParserImplTest, Statement_Return_Value) {
TEST_F(ParserImplTest, Statement_Return_MissingSemi) { TEST_F(ParserImplTest, Statement_Return_MissingSemi) {
auto* p = parser("return"); auto* p = parser("return");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:7: expected ';' for return statement"); EXPECT_EQ(p->error(), "1:7: expected ';' for return statement");
} }
TEST_F(ParserImplTest, Statement_Return_Invalid) { TEST_F(ParserImplTest, Statement_Return_Invalid) {
auto* p = parser("return if(a) {};"); auto* p = parser("return if(a) {};");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:8: expected ';' for return statement"); EXPECT_EQ(p->error(), "1:8: expected ';' for return statement");
} }
@ -81,15 +86,18 @@ TEST_F(ParserImplTest, Statement_If) {
auto* p = parser("if (a) {}"); auto* p = parser("if (a) {}");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
ASSERT_TRUE(e->IsIf()); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e.value->IsIf());
} }
TEST_F(ParserImplTest, Statement_If_Invalid) { TEST_F(ParserImplTest, Statement_If_Invalid) {
auto* p = parser("if (a) { fn main() -> {}}"); auto* p = parser("if (a) { fn main() -> {}}");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:10: expected '}'"); EXPECT_EQ(p->error(), "1:10: expected '}'");
} }
@ -97,23 +105,28 @@ TEST_F(ParserImplTest, Statement_Variable) {
auto* p = parser("var a : i32 = 1;"); auto* p = parser("var a : i32 = 1;");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
ASSERT_TRUE(e->IsVariableDecl()); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e.value->IsVariableDecl());
} }
TEST_F(ParserImplTest, Statement_Variable_Invalid) { TEST_F(ParserImplTest, Statement_Variable_Invalid) {
auto* p = parser("var a : i32 =;"); auto* p = parser("var a : i32 =;");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:14: missing constructor for variable declaration"); EXPECT_EQ(p->error(), "1:14: missing constructor for variable declaration");
} }
TEST_F(ParserImplTest, Statement_Variable_MissingSemicolon) { TEST_F(ParserImplTest, Statement_Variable_MissingSemicolon) {
auto* p = parser("var a : i32"); auto* p = parser("var a : i32");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:12: expected ';' for variable declaration"); EXPECT_EQ(p->error(), "1:12: expected ';' for variable declaration");
} }
@ -121,15 +134,18 @@ TEST_F(ParserImplTest, Statement_Switch) {
auto* p = parser("switch (a) {}"); auto* p = parser("switch (a) {}");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
ASSERT_TRUE(e->IsSwitch()); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e.value->IsSwitch());
} }
TEST_F(ParserImplTest, Statement_Switch_Invalid) { TEST_F(ParserImplTest, Statement_Switch_Invalid) {
auto* p = parser("switch (a) { case: {}}"); auto* p = parser("switch (a) { case: {}}");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:18: unable to parse case selectors"); EXPECT_EQ(p->error(), "1:18: unable to parse case selectors");
} }
@ -137,15 +153,18 @@ TEST_F(ParserImplTest, Statement_Loop) {
auto* p = parser("loop {}"); auto* p = parser("loop {}");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
ASSERT_TRUE(e->IsLoop()); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e.value->IsLoop());
} }
TEST_F(ParserImplTest, Statement_Loop_Invalid) { TEST_F(ParserImplTest, Statement_Loop_Invalid) {
auto* p = parser("loop discard; }"); auto* p = parser("loop discard; }");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:6: expected '{' for loop"); EXPECT_EQ(p->error(), "1:6: expected '{' for loop");
} }
@ -153,23 +172,28 @@ TEST_F(ParserImplTest, Statement_Assignment) {
auto* p = parser("a = b;"); auto* p = parser("a = b;");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
EXPECT_TRUE(e->IsAssign()); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e.value->IsAssign());
} }
TEST_F(ParserImplTest, Statement_Assignment_Invalid) { TEST_F(ParserImplTest, Statement_Assignment_Invalid) {
auto* p = parser("a = if(b) {};"); auto* p = parser("a = if(b) {};");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:5: unable to parse right side of assignment"); EXPECT_EQ(p->error(), "1:5: unable to parse right side of assignment");
} }
TEST_F(ParserImplTest, Statement_Assignment_MissingSemicolon) { TEST_F(ParserImplTest, Statement_Assignment_MissingSemicolon) {
auto* p = parser("a = b"); auto* p = parser("a = b");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:6: expected ';' for assignment statement"); EXPECT_EQ(p->error(), "1:6: expected ';' for assignment statement");
} }
@ -177,15 +201,18 @@ TEST_F(ParserImplTest, Statement_Break) {
auto* p = parser("break;"); auto* p = parser("break;");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
EXPECT_TRUE(e->IsBreak()); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e.value->IsBreak());
} }
TEST_F(ParserImplTest, Statement_Break_MissingSemicolon) { TEST_F(ParserImplTest, Statement_Break_MissingSemicolon) {
auto* p = parser("break"); auto* p = parser("break");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:6: expected ';' for break statement"); EXPECT_EQ(p->error(), "1:6: expected ';' for break statement");
} }
@ -193,15 +220,18 @@ TEST_F(ParserImplTest, Statement_Continue) {
auto* p = parser("continue;"); auto* p = parser("continue;");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
EXPECT_TRUE(e->IsContinue()); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e.value->IsContinue());
} }
TEST_F(ParserImplTest, Statement_Continue_MissingSemicolon) { TEST_F(ParserImplTest, Statement_Continue_MissingSemicolon) {
auto* p = parser("continue"); auto* p = parser("continue");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:9: expected ';' for continue statement"); EXPECT_EQ(p->error(), "1:9: expected ';' for continue statement");
} }
@ -209,15 +239,19 @@ TEST_F(ParserImplTest, Statement_Discard) {
auto* p = parser("discard;"); auto* p = parser("discard;");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
EXPECT_NE(e, nullptr); ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsDiscard()); EXPECT_TRUE(e.matched);
EXPECT_FALSE(e.errored);
ASSERT_TRUE(e.value->IsDiscard());
} }
TEST_F(ParserImplTest, Statement_Discard_MissingSemicolon) { TEST_F(ParserImplTest, Statement_Discard_MissingSemicolon) {
auto* p = parser("discard"); auto* p = parser("discard");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(e, nullptr); EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(p->error(), "1:8: expected ';' for discard statement"); EXPECT_EQ(p->error(), "1:8: expected ';' for discard statement");
} }
@ -225,16 +259,19 @@ TEST_F(ParserImplTest, Statement_Body) {
auto* p = parser("{ var i: i32; }"); auto* p = parser("{ var i: i32; }");
auto e = p->statement(); auto e = p->statement();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
ASSERT_TRUE(e->IsBlock()); EXPECT_FALSE(e.errored);
EXPECT_TRUE(e->AsBlock()->get(0)->IsVariableDecl()); ASSERT_TRUE(e.value->IsBlock());
EXPECT_TRUE(e.value->AsBlock()->get(0)->IsVariableDecl());
} }
TEST_F(ParserImplTest, Statement_Body_Invalid) { TEST_F(ParserImplTest, Statement_Body_Invalid) {
auto* p = parser("{ fn main() -> {}}"); auto* p = parser("{ fn main() -> {}}");
auto e = p->statement(); auto e = p->statement();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:3: expected '}'"); EXPECT_EQ(p->error(), "1:3: expected '}'");
} }

View File

@ -25,168 +25,208 @@ namespace {
TEST_F(ParserImplTest, StorageTextureType_Invalid) { TEST_F(ParserImplTest, StorageTextureType_Invalid) {
auto* p = parser("abc"); auto* p = parser("abc");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::kNone); EXPECT_FALSE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); EXPECT_FALSE(t.errored);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_Readonly1d_Old) { TEST_F(ParserImplTest, StorageTextureType_Readonly1d_Old) {
auto* p = parser("texture_ro_1d"); auto* p = parser("texture_ro_1d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_Readonly1dArray_Old) { TEST_F(ParserImplTest, StorageTextureType_Readonly1dArray_Old) {
auto* p = parser("texture_ro_1d_array"); auto* p = parser("texture_ro_1d_array");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1dArray); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1dArray);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_Readonly2d_Old) { TEST_F(ParserImplTest, StorageTextureType_Readonly2d_Old) {
auto* p = parser("texture_ro_2d"); auto* p = parser("texture_ro_2d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_Readonly2dArray_Old) { TEST_F(ParserImplTest, StorageTextureType_Readonly2dArray_Old) {
auto* p = parser("texture_ro_2d_array"); auto* p = parser("texture_ro_2d_array");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2dArray); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2dArray);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_Readonly3d_Old) { TEST_F(ParserImplTest, StorageTextureType_Readonly3d_Old) {
auto* p = parser("texture_ro_3d"); auto* p = parser("texture_ro_3d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k3d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k3d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_Writeonly1d_Old) { TEST_F(ParserImplTest, StorageTextureType_Writeonly1d_Old) {
auto* p = parser("texture_wo_1d"); auto* p = parser("texture_wo_1d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_Writeonly1dArray_Old) { TEST_F(ParserImplTest, StorageTextureType_Writeonly1dArray_Old) {
auto* p = parser("texture_wo_1d_array"); auto* p = parser("texture_wo_1d_array");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1dArray); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1dArray);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_Writeonly2d_Old) { TEST_F(ParserImplTest, StorageTextureType_Writeonly2d_Old) {
auto* p = parser("texture_wo_2d"); auto* p = parser("texture_wo_2d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_Writeonly2dArray_Old) { TEST_F(ParserImplTest, StorageTextureType_Writeonly2dArray_Old) {
auto* p = parser("texture_wo_2d_array"); auto* p = parser("texture_wo_2d_array");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2dArray); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2dArray);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_Writeonly3d_Old) { TEST_F(ParserImplTest, StorageTextureType_Writeonly3d_Old) {
auto* p = parser("texture_wo_3d"); auto* p = parser("texture_wo_3d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k3d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k3d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_ro_1d) { TEST_F(ParserImplTest, StorageTextureType_ro_1d) {
auto* p = parser("texture_storage_ro_1d"); auto* p = parser("texture_storage_ro_1d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_ro_1dArray) { TEST_F(ParserImplTest, StorageTextureType_ro_1dArray) {
auto* p = parser("texture_storage_ro_1d_array"); auto* p = parser("texture_storage_ro_1d_array");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1dArray); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1dArray);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_ro_2d) { TEST_F(ParserImplTest, StorageTextureType_ro_2d) {
auto* p = parser("texture_storage_ro_2d"); auto* p = parser("texture_storage_ro_2d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_ro_2dArray) { TEST_F(ParserImplTest, StorageTextureType_ro_2dArray) {
auto* p = parser("texture_storage_ro_2d_array"); auto* p = parser("texture_storage_ro_2d_array");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2dArray); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2dArray);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_ro_3d) { TEST_F(ParserImplTest, StorageTextureType_ro_3d) {
auto* p = parser("texture_storage_ro_3d"); auto* p = parser("texture_storage_ro_3d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k3d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kReadOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k3d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kReadOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_wo_1d) { TEST_F(ParserImplTest, StorageTextureType_wo_1d) {
auto* p = parser("texture_storage_wo_1d"); auto* p = parser("texture_storage_wo_1d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_wo_1dArray) { TEST_F(ParserImplTest, StorageTextureType_wo_1dArray) {
auto* p = parser("texture_storage_wo_1d_array"); auto* p = parser("texture_storage_wo_1d_array");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k1dArray); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k1dArray);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_wo_2d) { TEST_F(ParserImplTest, StorageTextureType_wo_2d) {
auto* p = parser("texture_storage_wo_2d"); auto* p = parser("texture_storage_wo_2d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_wo_2dArray) { TEST_F(ParserImplTest, StorageTextureType_wo_2dArray) {
auto* p = parser("texture_storage_wo_2d_array"); auto* p = parser("texture_storage_wo_2d_array");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k2dArray); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k2dArray);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, StorageTextureType_wo_3d) { TEST_F(ParserImplTest, StorageTextureType_wo_3d) {
auto* p = parser("texture_storage_wo_3d"); auto* p = parser("texture_storage_wo_3d");
auto t = p->storage_texture_type(); auto t = p->storage_texture_type();
EXPECT_EQ(std::get<0>(t), ast::type::TextureDimension::k3d); EXPECT_TRUE(t.matched);
EXPECT_EQ(std::get<1>(t), ast::AccessControl::kWriteOnly); EXPECT_FALSE(t.errored);
EXPECT_EQ(std::get<0>(t.value), ast::type::TextureDimension::k3d);
EXPECT_EQ(std::get<1>(t.value), ast::AccessControl::kWriteOnly);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
} // namespace } // namespace

View File

@ -29,14 +29,19 @@ struct S {
[[offset(4)]] b : f32; [[offset(4)]] b : f32;
})"); })");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_EQ(decos.size(), 0u); EXPECT_FALSE(decos.errored);
auto s = p->struct_decl(decos); EXPECT_FALSE(decos.matched);
ASSERT_FALSE(p->has_error()); ASSERT_EQ(decos.value.size(), 0u);
ASSERT_NE(s, nullptr);
ASSERT_EQ(s->name(), "S"); auto s = p->struct_decl(decos.value);
ASSERT_EQ(s->impl()->members().size(), 2u); EXPECT_FALSE(p->has_error());
EXPECT_EQ(s->impl()->members()[0]->name(), "a"); EXPECT_FALSE(s.errored);
EXPECT_EQ(s->impl()->members()[1]->name(), "b"); EXPECT_TRUE(s.matched);
ASSERT_NE(s.value, nullptr);
ASSERT_EQ(s.value->name(), "S");
ASSERT_EQ(s.value->impl()->members().size(), 2u);
EXPECT_EQ(s.value->impl()->members()[0]->name(), "a");
EXPECT_EQ(s.value->impl()->members()[1]->name(), "b");
} }
TEST_F(ParserImplTest, StructDecl_ParsesWithDecoration) { TEST_F(ParserImplTest, StructDecl_ParsesWithDecoration) {
@ -46,16 +51,21 @@ TEST_F(ParserImplTest, StructDecl_ParsesWithDecoration) {
b : f32; b : f32;
})"); })");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_EQ(decos.size(), 1u); EXPECT_FALSE(decos.errored);
auto s = p->struct_decl(decos); EXPECT_TRUE(decos.matched);
ASSERT_FALSE(p->has_error()); ASSERT_EQ(decos.value.size(), 1u);
ASSERT_NE(s, nullptr);
ASSERT_EQ(s->name(), "B"); auto s = p->struct_decl(decos.value);
ASSERT_EQ(s->impl()->members().size(), 2u); EXPECT_FALSE(p->has_error());
EXPECT_EQ(s->impl()->members()[0]->name(), "a"); EXPECT_FALSE(s.errored);
EXPECT_EQ(s->impl()->members()[1]->name(), "b"); EXPECT_TRUE(s.matched);
ASSERT_EQ(s->impl()->decorations().size(), 1u); ASSERT_NE(s.value, nullptr);
EXPECT_TRUE(s->impl()->decorations()[0]->IsBlock()); ASSERT_EQ(s.value->name(), "B");
ASSERT_EQ(s.value->impl()->members().size(), 2u);
EXPECT_EQ(s.value->impl()->members()[0]->name(), "a");
EXPECT_EQ(s.value->impl()->members()[1]->name(), "b");
ASSERT_EQ(s.value->impl()->decorations().size(), 1u);
EXPECT_TRUE(s.value->impl()->decorations()[0]->IsBlock());
} }
TEST_F(ParserImplTest, StructDecl_ParsesWithMultipleDecoration) { TEST_F(ParserImplTest, StructDecl_ParsesWithMultipleDecoration) {
@ -66,75 +76,115 @@ TEST_F(ParserImplTest, StructDecl_ParsesWithMultipleDecoration) {
b : f32; b : f32;
})"); })");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_EQ(decos.size(), 2u); EXPECT_FALSE(decos.errored);
auto s = p->struct_decl(decos); EXPECT_TRUE(decos.matched);
ASSERT_FALSE(p->has_error()); ASSERT_EQ(decos.value.size(), 2u);
ASSERT_NE(s, nullptr);
ASSERT_EQ(s->name(), "S"); auto s = p->struct_decl(decos.value);
ASSERT_EQ(s->impl()->members().size(), 2u); EXPECT_FALSE(p->has_error());
EXPECT_EQ(s->impl()->members()[0]->name(), "a"); EXPECT_FALSE(s.errored);
EXPECT_EQ(s->impl()->members()[1]->name(), "b"); EXPECT_TRUE(s.matched);
ASSERT_EQ(s->impl()->decorations().size(), 2u); ASSERT_NE(s.value, nullptr);
EXPECT_TRUE(s->impl()->decorations()[0]->IsBlock()); ASSERT_EQ(s.value->name(), "S");
EXPECT_TRUE(s->impl()->decorations()[1]->IsBlock()); ASSERT_EQ(s.value->impl()->members().size(), 2u);
EXPECT_EQ(s.value->impl()->members()[0]->name(), "a");
EXPECT_EQ(s.value->impl()->members()[1]->name(), "b");
ASSERT_EQ(s.value->impl()->decorations().size(), 2u);
EXPECT_TRUE(s.value->impl()->decorations()[0]->IsBlock());
EXPECT_TRUE(s.value->impl()->decorations()[1]->IsBlock());
} }
TEST_F(ParserImplTest, StructDecl_EmptyMembers) { TEST_F(ParserImplTest, StructDecl_EmptyMembers) {
auto* p = parser("struct S {}"); auto* p = parser("struct S {}");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_EQ(decos.size(), 0u); EXPECT_FALSE(decos.errored);
auto s = p->struct_decl(decos); EXPECT_FALSE(decos.matched);
ASSERT_FALSE(p->has_error()); ASSERT_EQ(decos.value.size(), 0u);
ASSERT_NE(s, nullptr);
ASSERT_EQ(s->impl()->members().size(), 0u); auto s = p->struct_decl(decos.value);
EXPECT_FALSE(p->has_error());
EXPECT_FALSE(s.errored);
EXPECT_TRUE(s.matched);
ASSERT_NE(s.value, nullptr);
ASSERT_EQ(s.value->impl()->members().size(), 0u);
} }
TEST_F(ParserImplTest, StructDecl_MissingIdent) { TEST_F(ParserImplTest, StructDecl_MissingIdent) {
auto* p = parser("struct {}"); auto* p = parser("struct {}");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_EQ(decos.size(), 0u); EXPECT_FALSE(decos.errored);
auto s = p->struct_decl(decos); EXPECT_FALSE(decos.matched);
ASSERT_TRUE(p->has_error()); ASSERT_EQ(decos.value.size(), 0u);
ASSERT_EQ(s, nullptr);
auto s = p->struct_decl(decos.value);
EXPECT_TRUE(s.errored);
EXPECT_FALSE(s.matched);
EXPECT_EQ(s.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:8: expected identifier for struct declaration"); EXPECT_EQ(p->error(), "1:8: expected identifier for struct declaration");
} }
TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) { TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) {
auto* p = parser("struct S }"); auto* p = parser("struct S }");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_EQ(decos.size(), 0u); EXPECT_FALSE(decos.errored);
auto s = p->struct_decl(decos); EXPECT_FALSE(decos.matched);
ASSERT_TRUE(p->has_error()); ASSERT_EQ(decos.value.size(), 0u);
ASSERT_EQ(s, nullptr);
auto s = p->struct_decl(decos.value);
EXPECT_TRUE(s.errored);
EXPECT_FALSE(s.matched);
EXPECT_EQ(s.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:10: expected '{' for struct declaration"); EXPECT_EQ(p->error(), "1:10: expected '{' for struct declaration");
} }
TEST_F(ParserImplTest, StructDecl_InvalidStructBody) { TEST_F(ParserImplTest, StructDecl_InvalidStructBody) {
auto* p = parser("struct S { a : B; }"); auto* p = parser("struct S { a : B; }");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_EQ(decos.size(), 0u); EXPECT_FALSE(decos.errored);
auto s = p->struct_decl(decos); EXPECT_FALSE(decos.matched);
ASSERT_TRUE(p->has_error()); ASSERT_EQ(decos.value.size(), 0u);
ASSERT_EQ(s, nullptr);
auto s = p->struct_decl(decos.value);
EXPECT_TRUE(s.errored);
EXPECT_FALSE(s.matched);
EXPECT_EQ(s.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:16: unknown constructed type 'B'"); EXPECT_EQ(p->error(), "1:16: unknown constructed type 'B'");
} }
TEST_F(ParserImplTest, StructDecl_InvalidStructDecorationDecl) { TEST_F(ParserImplTest, StructDecl_InvalidStructDecorationDecl) {
auto* p = parser("[[block struct S { a : i32; }"); auto* p = parser("[[block struct S { a : i32; }");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
auto s = p->struct_decl(decos); EXPECT_TRUE(decos.errored);
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(decos.matched);
ASSERT_EQ(s, nullptr);
auto s = p->struct_decl(decos.value);
EXPECT_FALSE(s.errored);
EXPECT_FALSE(s.matched);
EXPECT_EQ(s.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: expected ']]' for decoration list"); EXPECT_EQ(p->error(), "1:9: expected ']]' for decoration list");
} }
TEST_F(ParserImplTest, StructDecl_MissingStruct) { TEST_F(ParserImplTest, StructDecl_MissingStruct) {
auto* p = parser("[[block]] S {}"); auto* p = parser("[[block]] S {}");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_EQ(decos.size(), 1u); EXPECT_FALSE(decos.errored);
auto s = p->struct_decl(decos); EXPECT_TRUE(decos.matched);
ASSERT_FALSE(p->has_error()); ASSERT_EQ(decos.value.size(), 1u);
ASSERT_EQ(s, nullptr);
auto s = p->struct_decl(decos.value);
EXPECT_FALSE(s.errored);
EXPECT_FALSE(s.matched);
EXPECT_EQ(s.value, nullptr);
EXPECT_FALSE(p->has_error());
} }
} // namespace } // namespace

View File

@ -24,25 +24,31 @@ namespace {
TEST_F(ParserImplTest, StructDecorationDecl_Parses) { TEST_F(ParserImplTest, StructDecorationDecl_Parses) {
auto* p = parser("[[block]]"); auto* p = parser("[[block]]");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
ASSERT_EQ(decos.size(), 1u); EXPECT_FALSE(decos.errored);
auto struct_deco = ast::As<ast::StructDecoration>(std::move(decos[0])); EXPECT_TRUE(decos.matched);
ASSERT_EQ(decos.value.size(), 1u);
auto struct_deco = ast::As<ast::StructDecoration>(std::move(decos.value[0]));
EXPECT_TRUE(struct_deco->IsBlock()); EXPECT_TRUE(struct_deco->IsBlock());
} }
TEST_F(ParserImplTest, StructDecorationDecl_MissingAttrRight) { TEST_F(ParserImplTest, StructDecorationDecl_MissingAttrRight) {
auto* p = parser("[[block"); auto* p = parser("[[block");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_TRUE(decos.value.empty());
EXPECT_EQ(p->error(), "1:8: expected ']]' for decoration list"); EXPECT_EQ(p->error(), "1:8: expected ']]' for decoration list");
} }
TEST_F(ParserImplTest, StructDecorationDecl_InvalidDecoration) { TEST_F(ParserImplTest, StructDecorationDecl_InvalidDecoration) {
auto* p = parser("[[invalid]]"); auto* p = parser("[[invalid]]");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(decos.size(), 0u); EXPECT_TRUE(decos.errored);
EXPECT_TRUE(decos.empty()); EXPECT_FALSE(decos.matched);
EXPECT_TRUE(decos.value.empty());
} }
} // namespace } // namespace

View File

@ -40,8 +40,10 @@ TEST_P(StructDecorationTest, Parses) {
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(deco, nullptr); EXPECT_TRUE(deco.matched);
auto struct_deco = ast::As<ast::StructDecoration>(std::move(deco)); EXPECT_FALSE(deco.errored);
ASSERT_NE(deco.value, nullptr);
auto struct_deco = ast::As<ast::StructDecoration>(std::move(deco.value));
ASSERT_NE(struct_deco, nullptr); ASSERT_NE(struct_deco, nullptr);
EXPECT_EQ(struct_deco->IsBlock(), params.is_block); EXPECT_EQ(struct_deco->IsBlock(), params.is_block);
} }
@ -52,7 +54,9 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
TEST_F(ParserImplTest, StructDecoration_NoMatch) { TEST_F(ParserImplTest, StructDecoration_NoMatch) {
auto* p = parser("not-a-stage"); auto* p = parser("not-a-stage");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
EXPECT_FALSE(deco.errored);
ASSERT_EQ(deco.value, nullptr);
} }
} // namespace } // namespace

View File

@ -25,40 +25,50 @@ namespace {
TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyStr) { TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyStr) {
auto* p = parser(""); auto* p = parser("");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
EXPECT_EQ(decos.size(), 0u); EXPECT_FALSE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_EQ(decos.value.size(), 0u);
} }
TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyBlock) { TEST_F(ParserImplTest, StructMemberDecorationDecl_EmptyBlock) {
auto* p = parser("[[]]"); auto* p = parser("[[]]");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(decos.size(), 0u); EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_EQ(decos.value.size(), 0u);
EXPECT_EQ(p->error(), "1:3: empty decoration list"); EXPECT_EQ(p->error(), "1:3: empty decoration list");
} }
TEST_F(ParserImplTest, StructMemberDecorationDecl_Single) { TEST_F(ParserImplTest, StructMemberDecorationDecl_Single) {
auto* p = parser("[[offset(4)]]"); auto* p = parser("[[offset(4)]]");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
ASSERT_EQ(decos.size(), 1u); EXPECT_FALSE(decos.errored);
auto deco = ast::As<ast::StructMemberDecoration>(std::move(decos[0])); EXPECT_TRUE(decos.matched);
ASSERT_EQ(decos.value.size(), 1u);
auto deco = ast::As<ast::StructMemberDecoration>(std::move(decos.value[0]));
ASSERT_NE(deco, nullptr); ASSERT_NE(deco, nullptr);
EXPECT_TRUE(deco->IsOffset()); EXPECT_TRUE(deco->IsOffset());
} }
TEST_F(ParserImplTest, StructMemberDecorationDecl_InvalidDecoration) { TEST_F(ParserImplTest, StructMemberDecorationDecl_InvalidDecoration) {
auto* p = parser("[[offset(nan)]]"); auto* p = parser("[[offset(nan)]]");
p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()) << p->error(); EXPECT_TRUE(p->has_error()) << p->error();
EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
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");
} }
TEST_F(ParserImplTest, StructMemberDecorationDecl_MissingClose) { TEST_F(ParserImplTest, StructMemberDecorationDecl_MissingClose) {
auto* p = parser("[[offset(4)"); auto* p = parser("[[offset(4)");
p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()) << p->error(); EXPECT_TRUE(p->has_error()) << p->error();
EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_EQ(p->error(), "1:12: expected ']]' for decoration list"); EXPECT_EQ(p->error(), "1:12: expected ']]' for decoration list");
} }

View File

@ -25,10 +25,13 @@ namespace {
TEST_F(ParserImplTest, StructMemberDecoration_Offset) { TEST_F(ParserImplTest, StructMemberDecoration_Offset) {
auto* p = parser("offset(4)"); auto* p = parser("offset(4)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_NE(deco, nullptr); EXPECT_TRUE(deco.matched);
EXPECT_FALSE(deco.errored);
ASSERT_NE(deco.value, nullptr);
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
auto member_deco = ast::As<ast::StructMemberDecoration>(std::move(deco)); auto member_deco =
ast::As<ast::StructMemberDecoration>(std::move(deco.value));
ASSERT_NE(member_deco, nullptr); ASSERT_NE(member_deco, nullptr);
ASSERT_TRUE(member_deco->IsOffset()); ASSERT_TRUE(member_deco->IsOffset());
@ -39,24 +42,30 @@ TEST_F(ParserImplTest, StructMemberDecoration_Offset) {
TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingLeftParen) { TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingLeftParen) {
auto* p = parser("offset 4)"); auto* p = parser("offset 4)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:8: expected '(' for offset decoration"); EXPECT_EQ(p->error(), "1:8: expected '(' for offset decoration");
} }
TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingRightParen) { TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingRightParen) {
auto* p = parser("offset(4"); auto* p = parser("offset(4");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: expected ')' for offset decoration"); EXPECT_EQ(p->error(), "1:9: expected ')' for offset decoration");
} }
TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingValue) { TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingValue) {
auto* p = parser("offset()"); auto* p = parser("offset()");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:8: expected signed integer literal for offset decoration"); "1:8: expected signed integer literal for offset decoration");
} }
@ -64,8 +73,10 @@ TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingValue) {
TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingInvalid) { TEST_F(ParserImplTest, StructMemberDecoration_Offset_MissingInvalid) {
auto* p = parser("offset(nan)"); auto* p = parser("offset(nan)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:8: expected signed integer literal for offset decoration"); "1:8: expected signed integer literal for offset decoration");
} }

View File

@ -29,8 +29,11 @@ TEST_F(ParserImplTest, StructMember_Parses) {
auto* p = parser("a : i32;"); auto* p = parser("a : i32;");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
EXPECT_EQ(decos.size(), 0u); EXPECT_FALSE(decos.errored);
auto m = p->expect_struct_member(decos); EXPECT_FALSE(decos.matched);
EXPECT_EQ(decos.value.size(), 0u);
auto m = p->expect_struct_member(decos.value);
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_FALSE(m.errored); ASSERT_FALSE(m.errored);
ASSERT_NE(m.value, nullptr); ASSERT_NE(m.value, nullptr);
@ -50,8 +53,11 @@ TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
auto* p = parser("[[offset(2)]] a : i32;"); auto* p = parser("[[offset(2)]] a : i32;");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
EXPECT_EQ(decos.size(), 1u); EXPECT_FALSE(decos.errored);
auto m = p->expect_struct_member(decos); EXPECT_TRUE(decos.matched);
EXPECT_EQ(decos.value.size(), 1u);
auto m = p->expect_struct_member(decos.value);
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_FALSE(m.errored); ASSERT_FALSE(m.errored);
ASSERT_NE(m.value, nullptr); ASSERT_NE(m.value, nullptr);
@ -74,8 +80,11 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
auto* p = parser(R"([[offset(2)]] auto* p = parser(R"([[offset(2)]]
[[offset(4)]] a : i32;)"); [[offset(4)]] a : i32;)");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
EXPECT_EQ(decos.size(), 2u); EXPECT_FALSE(decos.errored);
auto m = p->expect_struct_member(decos); EXPECT_TRUE(decos.matched);
EXPECT_EQ(decos.value.size(), 2u);
auto m = p->expect_struct_member(decos.value);
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_FALSE(m.errored); ASSERT_FALSE(m.errored);
ASSERT_NE(m.value, nullptr); ASSERT_NE(m.value, nullptr);
@ -97,7 +106,10 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
TEST_F(ParserImplTest, StructMember_InvalidDecoration) { TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
auto* p = parser("[[offset(nan)]] a : i32;"); auto* p = parser("[[offset(nan)]] a : i32;");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
auto m = p->expect_struct_member(decos); EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
auto m = p->expect_struct_member(decos.value);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(m.errored); ASSERT_TRUE(m.errored);
ASSERT_EQ(m.value, nullptr); ASSERT_EQ(m.value, nullptr);
@ -108,7 +120,10 @@ TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
TEST_F(ParserImplTest, StructMember_InvalidVariable) { TEST_F(ParserImplTest, StructMember_InvalidVariable) {
auto* p = parser("[[offset(4)]] a : B;"); auto* p = parser("[[offset(4)]] a : B;");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
auto m = p->expect_struct_member(decos); EXPECT_FALSE(decos.errored);
EXPECT_TRUE(decos.matched);
auto m = p->expect_struct_member(decos.value);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(m.errored); ASSERT_TRUE(m.errored);
ASSERT_EQ(m.value, nullptr); ASSERT_EQ(m.value, nullptr);
@ -118,7 +133,10 @@ TEST_F(ParserImplTest, StructMember_InvalidVariable) {
TEST_F(ParserImplTest, StructMember_MissingSemicolon) { TEST_F(ParserImplTest, StructMember_MissingSemicolon) {
auto* p = parser("a : i32"); auto* p = parser("a : i32");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
auto m = p->expect_struct_member(decos); EXPECT_FALSE(decos.errored);
EXPECT_FALSE(decos.matched);
auto m = p->expect_struct_member(decos.value);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_TRUE(m.errored); ASSERT_TRUE(m.errored);
ASSERT_EQ(m.value, nullptr); ASSERT_EQ(m.value, nullptr);

View File

@ -25,110 +25,136 @@ namespace {
TEST_F(ParserImplTest, SwitchBody_Case) { TEST_F(ParserImplTest, SwitchBody_Case) {
auto* p = parser("case 1: { a = 4; }"); auto* p = parser("case 1: { a = 4; }");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
ASSERT_TRUE(e->IsCase()); EXPECT_FALSE(e.errored);
EXPECT_FALSE(e->IsDefault()); ASSERT_NE(e.value, nullptr);
ASSERT_EQ(e->body()->size(), 1u); ASSERT_TRUE(e.value->IsCase());
EXPECT_TRUE(e->body()->get(0)->IsAssign()); EXPECT_FALSE(e.value->IsDefault());
ASSERT_EQ(e.value->body()->size(), 1u);
EXPECT_TRUE(e.value->body()->get(0)->IsAssign());
} }
TEST_F(ParserImplTest, SwitchBody_Case_InvalidConstLiteral) { TEST_F(ParserImplTest, SwitchBody_Case_InvalidConstLiteral) {
auto* p = parser("case a == 4: { a = 4; }"); auto* p = parser("case a == 4: { a = 4; }");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:6: unable to parse case selectors"); EXPECT_EQ(p->error(), "1:6: unable to parse case selectors");
} }
TEST_F(ParserImplTest, SwitchBody_Case_InvalidSelector_bool) { TEST_F(ParserImplTest, SwitchBody_Case_InvalidSelector_bool) {
auto* p = parser("case true: { a = 4; }"); auto* p = parser("case true: { a = 4; }");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:6: invalid case selector must be an integer value"); EXPECT_EQ(p->error(), "1:6: invalid case selector must be an integer value");
} }
TEST_F(ParserImplTest, SwitchBody_Case_MissingConstLiteral) { TEST_F(ParserImplTest, SwitchBody_Case_MissingConstLiteral) {
auto* p = parser("case: { a = 4; }"); auto* p = parser("case: { a = 4; }");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:5: unable to parse case selectors"); EXPECT_EQ(p->error(), "1:5: unable to parse case selectors");
} }
TEST_F(ParserImplTest, SwitchBody_Case_MissingColon) { TEST_F(ParserImplTest, SwitchBody_Case_MissingColon) {
auto* p = parser("case 1 { a = 4; }"); auto* p = parser("case 1 { a = 4; }");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:8: expected ':' for case statement"); EXPECT_EQ(p->error(), "1:8: expected ':' for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft) { TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft) {
auto* p = parser("case 1: a = 4; }"); auto* p = parser("case 1: a = 4; }");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:9: expected '{' for case statement"); EXPECT_EQ(p->error(), "1:9: expected '{' for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketRight) { TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketRight) {
auto* p = parser("case 1: { a = 4; "); auto* p = parser("case 1: { a = 4; ");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:18: expected '}' for case statement"); EXPECT_EQ(p->error(), "1:18: expected '}' for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Case_InvalidCaseBody) { TEST_F(ParserImplTest, SwitchBody_Case_InvalidCaseBody) {
auto* p = parser("case 1: { fn main() -> void {} }"); auto* p = parser("case 1: { fn main() -> void {} }");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:11: expected '}' for case statement"); EXPECT_EQ(p->error(), "1:11: expected '}' for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Default) { TEST_F(ParserImplTest, SwitchBody_Default) {
auto* p = parser("default: { a = 4; }"); auto* p = parser("default: { a = 4; }");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); EXPECT_TRUE(e.matched);
ASSERT_TRUE(e->IsCase()); EXPECT_FALSE(e.errored);
EXPECT_TRUE(e->IsDefault()); ASSERT_NE(e.value, nullptr);
ASSERT_EQ(e->body()->size(), 1u); ASSERT_TRUE(e.value->IsCase());
EXPECT_TRUE(e->body()->get(0)->IsAssign()); EXPECT_TRUE(e.value->IsDefault());
ASSERT_EQ(e.value->body()->size(), 1u);
EXPECT_TRUE(e.value->body()->get(0)->IsAssign());
} }
TEST_F(ParserImplTest, SwitchBody_Default_MissingColon) { TEST_F(ParserImplTest, SwitchBody_Default_MissingColon) {
auto* p = parser("default { a = 4; }"); auto* p = parser("default { a = 4; }");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:9: expected ':' for case statement"); EXPECT_EQ(p->error(), "1:9: expected ':' for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketLeft) { TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketLeft) {
auto* p = parser("default: a = 4; }"); auto* p = parser("default: a = 4; }");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:10: expected '{' for case statement"); EXPECT_EQ(p->error(), "1:10: expected '{' for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketRight) { TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketRight) {
auto* p = parser("default: { a = 4; "); auto* p = parser("default: { a = 4; ");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:19: expected '}' for case statement"); EXPECT_EQ(p->error(), "1:19: expected '}' for case statement");
} }
TEST_F(ParserImplTest, SwitchBody_Default_InvalidCaseBody) { TEST_F(ParserImplTest, SwitchBody_Default_InvalidCaseBody) {
auto* p = parser("default: { fn main() -> void {} }"); auto* p = parser("default: { fn main() -> void {} }");
auto e = p->switch_body(); auto e = p->switch_body();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
EXPECT_EQ(p->error(), "1:12: expected '}' for case statement"); EXPECT_EQ(p->error(), "1:12: expected '}' for case statement");
} }

View File

@ -29,21 +29,25 @@ TEST_F(ParserImplTest, SwitchStmt_WithoutDefault) {
case 2: {} case 2: {}
})"); })");
auto e = p->switch_stmt(); auto e = p->switch_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsSwitch()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e->body().size(), 2u); ASSERT_NE(e.value, nullptr);
EXPECT_FALSE(e->body()[0]->IsDefault()); ASSERT_TRUE(e.value->IsSwitch());
EXPECT_FALSE(e->body()[1]->IsDefault()); ASSERT_EQ(e.value->body().size(), 2u);
EXPECT_FALSE(e.value->body()[0]->IsDefault());
EXPECT_FALSE(e.value->body()[1]->IsDefault());
} }
TEST_F(ParserImplTest, SwitchStmt_Empty) { TEST_F(ParserImplTest, SwitchStmt_Empty) {
auto* p = parser("switch(a) { }"); auto* p = parser("switch(a) { }");
auto e = p->switch_stmt(); auto e = p->switch_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsSwitch()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(e->body().size(), 0u); ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsSwitch());
ASSERT_EQ(e.value->body().size(), 0u);
} }
TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) { TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) {
@ -53,45 +57,55 @@ TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) {
case 2: {} case 2: {}
})"); })");
auto e = p->switch_stmt(); auto e = p->switch_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsSwitch()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsSwitch());
ASSERT_EQ(e->body().size(), 3u); ASSERT_EQ(e.value->body().size(), 3u);
ASSERT_FALSE(e->body()[0]->IsDefault()); ASSERT_FALSE(e.value->body()[0]->IsDefault());
ASSERT_TRUE(e->body()[1]->IsDefault()); ASSERT_TRUE(e.value->body()[1]->IsDefault());
ASSERT_FALSE(e->body()[2]->IsDefault()); ASSERT_FALSE(e.value->body()[2]->IsDefault());
} }
TEST_F(ParserImplTest, SwitchStmt_InvalidExpression) { TEST_F(ParserImplTest, SwitchStmt_InvalidExpression) {
auto* p = parser("switch(a=b) {}"); auto* p = parser("switch(a=b) {}");
auto e = p->switch_stmt(); auto e = p->switch_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: expected ')'"); EXPECT_EQ(p->error(), "1:9: expected ')'");
} }
TEST_F(ParserImplTest, SwitchStmt_MissingExpression) { TEST_F(ParserImplTest, SwitchStmt_MissingExpression) {
auto* p = parser("switch {}"); auto* p = parser("switch {}");
auto e = p->switch_stmt(); auto e = p->switch_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:8: expected '('"); EXPECT_EQ(p->error(), "1:8: expected '('");
} }
TEST_F(ParserImplTest, SwitchStmt_MissingBracketLeft) { TEST_F(ParserImplTest, SwitchStmt_MissingBracketLeft) {
auto* p = parser("switch(a) }"); auto* p = parser("switch(a) }");
auto e = p->switch_stmt(); auto e = p->switch_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:11: expected '{' for switch statement"); EXPECT_EQ(p->error(), "1:11: expected '{' for switch statement");
} }
TEST_F(ParserImplTest, SwitchStmt_MissingBracketRight) { TEST_F(ParserImplTest, SwitchStmt_MissingBracketRight) {
auto* p = parser("switch(a) {"); auto* p = parser("switch(a) {");
auto e = p->switch_stmt(); auto e = p->switch_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:12: expected '}' for switch statement"); EXPECT_EQ(p->error(), "1:12: expected '}' for switch statement");
} }
@ -100,8 +114,10 @@ TEST_F(ParserImplTest, SwitchStmt_InvalidBody) {
case: {} case: {}
})"); })");
auto e = p->switch_stmt(); auto e = p->switch_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "2:7: unable to parse case selectors"); EXPECT_EQ(p->error(), "2:7: unable to parse case selectors");
} }

View File

@ -26,325 +26,395 @@ namespace {
TEST_F(ParserImplTest, TextureSamplerTypes_Invalid) { TEST_F(ParserImplTest, TextureSamplerTypes_Invalid) {
auto* p = parser("1234"); auto* p = parser("1234");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_FALSE(t.errored);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
TEST_F(ParserImplTest, TextureSamplerTypes_Sampler) { TEST_F(ParserImplTest, TextureSamplerTypes_Sampler) {
auto* p = parser("sampler"); auto* p = parser("sampler");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsSampler()); EXPECT_FALSE(t.errored);
ASSERT_FALSE(t->AsSampler()->IsComparison()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t.value->IsSampler());
ASSERT_FALSE(t.value->AsSampler()->IsComparison());
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) { TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) {
auto* p = parser("sampler_comparison"); auto* p = parser("sampler_comparison");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsSampler()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsSampler()->IsComparison()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t.value->IsSampler());
ASSERT_TRUE(t.value->AsSampler()->IsComparison());
} }
TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) { TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) {
auto* p = parser("texture_depth_2d"); auto* p = parser("texture_depth_2d");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsDepth()); ASSERT_NE(t.value, nullptr);
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); ASSERT_TRUE(t.value->IsTexture());
ASSERT_TRUE(t.value->AsTexture()->IsDepth());
EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32_Old) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32_Old) {
auto* p = parser("texture_sampled_1d<f32>"); auto* p = parser("texture_sampled_1d<f32>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsSampled()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32()); ASSERT_TRUE(t.value->IsTexture());
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d); ASSERT_TRUE(t.value->AsTexture()->IsSampled());
ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32());
EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d);
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32_Old) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32_Old) {
auto* p = parser("texture_sampled_2d<i32>"); auto* p = parser("texture_sampled_2d<i32>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsSampled()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsI32()); ASSERT_TRUE(t.value->IsTexture());
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); ASSERT_TRUE(t.value->AsTexture()->IsSampled());
ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsI32());
EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32_Old) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32_Old) {
auto* p = parser("texture_sampled_3d<u32>"); auto* p = parser("texture_sampled_3d<u32>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsSampled()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsU32()); ASSERT_TRUE(t.value->IsTexture());
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k3d); ASSERT_TRUE(t.value->AsTexture()->IsSampled());
ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsU32());
EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k3d);
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_Invalid_Old) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_Invalid_Old) {
auto* p = parser("texture_sampled_1d<abc>"); auto* p = parser("texture_sampled_1d<abc>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:20: unknown constructed type 'abc'"); EXPECT_EQ(p->error(), "1:20: unknown constructed type 'abc'");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType_Old) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType_Old) {
auto* p = parser("texture_sampled_1d<>"); auto* p = parser("texture_sampled_1d<>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:20: invalid subtype for sampled texture type"); EXPECT_EQ(p->error(), "1:20: invalid subtype for sampled texture type");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan_Old) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan_Old) {
auto* p = parser("texture_sampled_1d"); auto* p = parser("texture_sampled_1d");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:19: expected '<' for sampled texture type"); EXPECT_EQ(p->error(), "1:19: expected '<' for sampled texture type");
} }
TEST_F(ParserImplTest, TEST_F(ParserImplTest,
TextureSamplerTypes_SampledTexture_MissingGreaterThan_Old) { TextureSamplerTypes_SampledTexture_MissingGreaterThan_Old) {
auto* p = parser("texture_sampled_1d<u32"); auto* p = parser("texture_sampled_1d<u32");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:23: expected '>' for sampled texture type"); EXPECT_EQ(p->error(), "1:23: expected '>' for sampled texture type");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) {
auto* p = parser("texture_1d<f32>"); auto* p = parser("texture_1d<f32>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsSampled()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32()); ASSERT_TRUE(t.value->IsTexture());
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d); ASSERT_TRUE(t.value->AsTexture()->IsSampled());
ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32());
EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d);
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) {
auto* p = parser("texture_2d<i32>"); auto* p = parser("texture_2d<i32>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsSampled()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsI32()); ASSERT_TRUE(t.value->IsTexture());
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); ASSERT_TRUE(t.value->AsTexture()->IsSampled());
ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsI32());
EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) {
auto* p = parser("texture_3d<u32>"); auto* p = parser("texture_3d<u32>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsSampled()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsU32()); ASSERT_TRUE(t.value->IsTexture());
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k3d); ASSERT_TRUE(t.value->AsTexture()->IsSampled());
ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsU32());
EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k3d);
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_Invalid) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_Invalid) {
auto* p = parser("texture_1d<abc>"); auto* p = parser("texture_1d<abc>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:12: unknown constructed type 'abc'"); EXPECT_EQ(p->error(), "1:12: unknown constructed type 'abc'");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType) {
auto* p = parser("texture_1d<>"); auto* p = parser("texture_1d<>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:12: invalid subtype for sampled texture type"); EXPECT_EQ(p->error(), "1:12: invalid subtype for sampled texture type");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan) {
auto* p = parser("texture_1d"); auto* p = parser("texture_1d");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:11: expected '<' for sampled texture type"); EXPECT_EQ(p->error(), "1:11: expected '<' for sampled texture type");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingGreaterThan) { TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingGreaterThan) {
auto* p = parser("texture_1d<u32"); auto* p = parser("texture_1d<u32");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:15: expected '>' for sampled texture type"); EXPECT_EQ(p->error(), "1:15: expected '>' for sampled texture type");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_I32) { TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_I32) {
auto* p = parser("texture_multisampled_2d<i32>"); auto* p = parser("texture_multisampled_2d<i32>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsMultisampled()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->AsTexture()->AsMultisampled()->type()->IsI32()); ASSERT_TRUE(t.value->IsTexture());
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); ASSERT_TRUE(t.value->AsTexture()->IsMultisampled());
ASSERT_TRUE(t.value->AsTexture()->AsMultisampled()->type()->IsI32());
EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
} }
TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_Invalid) { TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_Invalid) {
auto* p = parser("texture_multisampled_2d<abc>"); auto* p = parser("texture_multisampled_2d<abc>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:25: unknown constructed type 'abc'"); EXPECT_EQ(p->error(), "1:25: unknown constructed type 'abc'");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingType) { TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingType) {
auto* p = parser("texture_multisampled_2d<>"); auto* p = parser("texture_multisampled_2d<>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:25: invalid subtype for multisampled texture type"); EXPECT_EQ(p->error(), "1:25: invalid subtype for multisampled texture type");
} }
TEST_F(ParserImplTest, TEST_F(ParserImplTest,
TextureSamplerTypes_MultisampledTexture_MissingLessThan) { TextureSamplerTypes_MultisampledTexture_MissingLessThan) {
auto* p = parser("texture_multisampled_2d"); auto* p = parser("texture_multisampled_2d");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:24: expected '<' for multisampled texture type"); EXPECT_EQ(p->error(), "1:24: expected '<' for multisampled texture type");
} }
TEST_F(ParserImplTest, TEST_F(ParserImplTest,
TextureSamplerTypes_MultisampledTexture_MissingGreaterThan) { TextureSamplerTypes_MultisampledTexture_MissingGreaterThan) {
auto* p = parser("texture_multisampled_2d<u32"); auto* p = parser("texture_multisampled_2d<u32");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:28: expected '>' for multisampled texture type"); EXPECT_EQ(p->error(), "1:28: expected '>' for multisampled texture type");
} }
TEST_F(ParserImplTest, TEST_F(ParserImplTest,
TextureSamplerTypes_StorageTexture_Readonly1dR8Unorm_Old) { TextureSamplerTypes_StorageTexture_Readonly1dR8Unorm_Old) {
auto* p = parser("texture_ro_1d<r8unorm>"); auto* p = parser("texture_ro_1d<r8unorm>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsStorage()); ASSERT_NE(t.value, nullptr);
EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(), ASSERT_TRUE(t.value->IsTexture());
ASSERT_TRUE(t.value->AsTexture()->IsStorage());
EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(),
ast::type::ImageFormat::kR8Unorm); ast::type::ImageFormat::kR8Unorm);
EXPECT_EQ(t->AsTexture()->AsStorage()->access(), EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(),
ast::AccessControl::kReadOnly); ast::AccessControl::kReadOnly);
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d); EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d);
} }
TEST_F(ParserImplTest, TEST_F(ParserImplTest,
TextureSamplerTypes_StorageTexture_Writeonly2dR16Float_Old) { TextureSamplerTypes_StorageTexture_Writeonly2dR16Float_Old) {
auto* p = parser("texture_wo_2d<r16float>"); auto* p = parser("texture_wo_2d<r16float>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsStorage()); ASSERT_NE(t.value, nullptr);
EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(), ASSERT_TRUE(t.value->IsTexture());
ASSERT_TRUE(t.value->AsTexture()->IsStorage());
EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(),
ast::type::ImageFormat::kR16Float); ast::type::ImageFormat::kR16Float);
EXPECT_EQ(t->AsTexture()->AsStorage()->access(), EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(),
ast::AccessControl::kWriteOnly); ast::AccessControl::kWriteOnly);
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
} }
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType_Old) { TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType_Old) {
auto* p = parser("texture_ro_1d<abc>"); auto* p = parser("texture_ro_1d<abc>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:15: invalid format for storage texture type"); EXPECT_EQ(p->error(), "1:15: invalid format for storage texture type");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType_Old) { TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType_Old) {
auto* p = parser("texture_wo_1d<>"); auto* p = parser("texture_wo_1d<>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:15: invalid format for storage texture type"); EXPECT_EQ(p->error(), "1:15: invalid format for storage texture type");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan_Old) { TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan_Old) {
auto* p = parser("texture_ro_1d"); auto* p = parser("texture_ro_1d");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:14: expected '<' for storage texture type"); EXPECT_EQ(p->error(), "1:14: expected '<' for storage texture type");
} }
TEST_F(ParserImplTest, TEST_F(ParserImplTest,
TextureSamplerTypes_StorageTexture_MissingGreaterThan_Old) { TextureSamplerTypes_StorageTexture_MissingGreaterThan_Old) {
auto* p = parser("texture_wo_1d<r8unorm"); auto* p = parser("texture_wo_1d<r8unorm");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:22: expected '>' for storage texture type"); EXPECT_EQ(p->error(), "1:22: expected '>' for storage texture type");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dR8Unorm) { TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dR8Unorm) {
auto* p = parser("texture_storage_ro_1d<r8unorm>"); auto* p = parser("texture_storage_ro_1d<r8unorm>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsStorage()); ASSERT_NE(t.value, nullptr);
EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(), ASSERT_TRUE(t.value->IsTexture());
ASSERT_TRUE(t.value->AsTexture()->IsStorage());
EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(),
ast::type::ImageFormat::kR8Unorm); ast::type::ImageFormat::kR8Unorm);
EXPECT_EQ(t->AsTexture()->AsStorage()->access(), EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(),
ast::AccessControl::kReadOnly); ast::AccessControl::kReadOnly);
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k1d); EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k1d);
} }
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR16Float) { TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR16Float) {
auto* p = parser("texture_storage_wo_2d<r16float>"); auto* p = parser("texture_storage_wo_2d<r16float>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
ASSERT_TRUE(t->IsTexture()); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->AsTexture()->IsStorage()); ASSERT_NE(t.value, nullptr);
EXPECT_EQ(t->AsTexture()->AsStorage()->image_format(), ASSERT_TRUE(t.value->IsTexture());
ASSERT_TRUE(t.value->AsTexture()->IsStorage());
EXPECT_EQ(t.value->AsTexture()->AsStorage()->image_format(),
ast::type::ImageFormat::kR16Float); ast::type::ImageFormat::kR16Float);
EXPECT_EQ(t->AsTexture()->AsStorage()->access(), EXPECT_EQ(t.value->AsTexture()->AsStorage()->access(),
ast::AccessControl::kWriteOnly); ast::AccessControl::kWriteOnly);
EXPECT_EQ(t->AsTexture()->dim(), ast::type::TextureDimension::k2d); EXPECT_EQ(t.value->AsTexture()->dim(), ast::type::TextureDimension::k2d);
} }
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) { TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) {
auto* p = parser("texture_storage_ro_1d<abc>"); auto* p = parser("texture_storage_ro_1d<abc>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:23: invalid format for storage texture type"); EXPECT_EQ(p->error(), "1:23: invalid format for storage texture type");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType) { TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType) {
auto* p = parser("texture_storage_ro_1d<>"); auto* p = parser("texture_storage_ro_1d<>");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:23: invalid format for storage texture type"); EXPECT_EQ(p->error(), "1:23: invalid format for storage texture type");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan) { TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan) {
auto* p = parser("texture_storage_ro_1d"); auto* p = parser("texture_storage_ro_1d");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:22: expected '<' for storage texture type"); EXPECT_EQ(p->error(), "1:22: expected '<' for storage texture type");
} }
TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingGreaterThan) { TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingGreaterThan) {
auto* p = parser("texture_storage_ro_1d<r8unorm"); auto* p = parser("texture_storage_ro_1d<r8unorm");
auto* t = p->texture_sampler_types(); auto t = p->texture_sampler_types();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(t.matched);
EXPECT_TRUE(t.errored);
EXPECT_EQ(p->error(), "1:30: expected '>' for storage texture type"); EXPECT_EQ(p->error(), "1:30: expected '>' for storage texture type");
} }

View File

@ -30,11 +30,13 @@ TEST_F(ParserImplTest, TypeDecl_ParsesType) {
auto* i32 = tm()->Get(std::make_unique<ast::type::I32Type>()); auto* i32 = tm()->Get(std::make_unique<ast::type::I32Type>());
auto* p = parser("type a = i32"); auto* p = parser("type a = i32");
auto* t = p->type_alias(); auto t = p->type_alias();
ASSERT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
ASSERT_NE(t, nullptr); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->IsAlias()); EXPECT_TRUE(t.matched);
auto* alias = t->AsAlias(); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t.value->IsAlias());
auto* alias = t.value->AsAlias();
ASSERT_TRUE(alias->type()->IsI32()); ASSERT_TRUE(alias->type()->IsI32());
ASSERT_EQ(alias->type(), i32); ASSERT_EQ(alias->type(), i32);
} }
@ -45,11 +47,13 @@ TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) {
auto* p = parser("type a = B"); auto* p = parser("type a = B");
p->register_constructed("B", &str); p->register_constructed("B", &str);
auto* t = p->type_alias(); auto t = p->type_alias();
ASSERT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
ASSERT_NE(t, nullptr); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->IsAlias()); EXPECT_TRUE(t.matched);
auto* alias = t->AsAlias(); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t.value->IsAlias());
auto* alias = t.value->AsAlias();
EXPECT_EQ(alias->name(), "a"); EXPECT_EQ(alias->name(), "a");
ASSERT_TRUE(alias->type()->IsStruct()); ASSERT_TRUE(alias->type()->IsStruct());
@ -59,33 +63,41 @@ TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) {
TEST_F(ParserImplTest, TypeDecl_MissingIdent) { TEST_F(ParserImplTest, TypeDecl_MissingIdent) {
auto* p = parser("type = i32"); auto* p = parser("type = i32");
auto* t = p->type_alias(); auto t = p->type_alias();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(t.errored);
ASSERT_EQ(t, nullptr); EXPECT_FALSE(t.matched);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(t.value, nullptr);
EXPECT_EQ(p->error(), "1:6: expected identifier for type alias"); EXPECT_EQ(p->error(), "1:6: expected identifier for type alias");
} }
TEST_F(ParserImplTest, TypeDecl_InvalidIdent) { TEST_F(ParserImplTest, TypeDecl_InvalidIdent) {
auto* p = parser("type 123 = i32"); auto* p = parser("type 123 = i32");
auto* t = p->type_alias(); auto t = p->type_alias();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(t.errored);
ASSERT_EQ(t, nullptr); EXPECT_FALSE(t.matched);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(t.value, nullptr);
EXPECT_EQ(p->error(), "1:6: expected identifier for type alias"); EXPECT_EQ(p->error(), "1:6: expected identifier for type alias");
} }
TEST_F(ParserImplTest, TypeDecl_MissingEqual) { TEST_F(ParserImplTest, TypeDecl_MissingEqual) {
auto* p = parser("type a i32"); auto* p = parser("type a i32");
auto* t = p->type_alias(); auto t = p->type_alias();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(t.errored);
ASSERT_EQ(t, nullptr); EXPECT_FALSE(t.matched);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(t.value, nullptr);
EXPECT_EQ(p->error(), "1:8: expected '=' for type alias"); EXPECT_EQ(p->error(), "1:8: expected '=' for type alias");
} }
TEST_F(ParserImplTest, TypeDecl_InvalidType) { TEST_F(ParserImplTest, TypeDecl_InvalidType) {
auto* p = parser("type a = B"); auto* p = parser("type a = B");
auto* t = p->type_alias(); auto t = p->type_alias();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(t.errored);
ASSERT_EQ(t, nullptr); EXPECT_FALSE(t.matched);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(t.value, nullptr);
EXPECT_EQ(p->error(), "1:10: unknown constructed type 'B'"); EXPECT_EQ(p->error(), "1:10: unknown constructed type 'B'");
} }

View File

@ -37,8 +37,10 @@ namespace {
TEST_F(ParserImplTest, TypeDecl_Invalid) { TEST_F(ParserImplTest, TypeDecl_Invalid) {
auto* p = parser("1234"); auto* p = parser("1234");
auto* t = p->type_decl(); auto t = p->type_decl();
EXPECT_EQ(t, nullptr); EXPECT_EQ(t.errored, false);
EXPECT_EQ(t.matched, false);
EXPECT_EQ(t.value, nullptr);
EXPECT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
} }
@ -52,12 +54,14 @@ TEST_F(ParserImplTest, TypeDecl_Identifier) {
p->register_constructed("A", alias_type); p->register_constructed("A", alias_type);
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_EQ(t, alias_type); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->IsAlias()); ASSERT_NE(t.value, nullptr) << p->error();
EXPECT_EQ(t.value, alias_type);
ASSERT_TRUE(t.value->IsAlias());
auto* alias = t->AsAlias(); auto* alias = t.value->AsAlias();
EXPECT_EQ(alias->name(), "A"); EXPECT_EQ(alias->name(), "A");
EXPECT_EQ(alias->type(), int_type); EXPECT_EQ(alias->type(), int_type);
} }
@ -65,8 +69,10 @@ TEST_F(ParserImplTest, TypeDecl_Identifier) {
TEST_F(ParserImplTest, TypeDecl_Identifier_NotFound) { TEST_F(ParserImplTest, TypeDecl_Identifier_NotFound) {
auto* p = parser("B"); auto* p = parser("B");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
EXPECT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:1: unknown constructed type 'B'"); EXPECT_EQ(p->error(), "1:1: unknown constructed type 'B'");
} }
@ -76,10 +82,12 @@ TEST_F(ParserImplTest, TypeDecl_Bool) {
auto* bool_type = tm()->Get(std::make_unique<ast::type::BoolType>()); auto* bool_type = tm()->Get(std::make_unique<ast::type::BoolType>());
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_EQ(t, bool_type); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->IsBool()); ASSERT_NE(t.value, nullptr) << p->error();
EXPECT_EQ(t.value, bool_type);
ASSERT_TRUE(t.value->IsBool());
} }
TEST_F(ParserImplTest, TypeDecl_F32) { TEST_F(ParserImplTest, TypeDecl_F32) {
@ -87,10 +95,12 @@ TEST_F(ParserImplTest, TypeDecl_F32) {
auto* float_type = tm()->Get(std::make_unique<ast::type::F32Type>()); auto* float_type = tm()->Get(std::make_unique<ast::type::F32Type>());
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_EQ(t, float_type); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->IsF32()); ASSERT_NE(t.value, nullptr) << p->error();
EXPECT_EQ(t.value, float_type);
ASSERT_TRUE(t.value->IsF32());
} }
TEST_F(ParserImplTest, TypeDecl_I32) { TEST_F(ParserImplTest, TypeDecl_I32) {
@ -98,10 +108,12 @@ TEST_F(ParserImplTest, TypeDecl_I32) {
auto* int_type = tm()->Get(std::make_unique<ast::type::I32Type>()); auto* int_type = tm()->Get(std::make_unique<ast::type::I32Type>());
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_EQ(t, int_type); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->IsI32()); ASSERT_NE(t.value, nullptr) << p->error();
EXPECT_EQ(t.value, int_type);
ASSERT_TRUE(t.value->IsI32());
} }
TEST_F(ParserImplTest, TypeDecl_U32) { TEST_F(ParserImplTest, TypeDecl_U32) {
@ -109,10 +121,12 @@ TEST_F(ParserImplTest, TypeDecl_U32) {
auto* uint_type = tm()->Get(std::make_unique<ast::type::U32Type>()); auto* uint_type = tm()->Get(std::make_unique<ast::type::U32Type>());
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_EQ(t, uint_type); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->IsU32()); ASSERT_NE(t.value, nullptr) << p->error();
EXPECT_EQ(t.value, uint_type);
ASSERT_TRUE(t.value->IsU32());
} }
struct VecData { struct VecData {
@ -129,11 +143,13 @@ class VecTest : public ParserImplTestWithParam<VecData> {};
TEST_P(VecTest, Parse) { TEST_P(VecTest, Parse) {
auto params = GetParam(); auto params = GetParam();
auto* p = parser(params.input); auto* p = parser(params.input);
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
EXPECT_TRUE(t->IsVector()); EXPECT_TRUE(t.value->IsVector());
EXPECT_EQ(t->AsVector()->size(), params.count); EXPECT_EQ(t.value->AsVector()->size(), params.count);
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecTest, VecTest,
@ -146,8 +162,10 @@ class VecMissingGreaterThanTest : public ParserImplTestWithParam<VecData> {};
TEST_P(VecMissingGreaterThanTest, Handles_Missing_GreaterThan) { TEST_P(VecMissingGreaterThanTest, Handles_Missing_GreaterThan) {
auto params = GetParam(); auto params = GetParam();
auto* p = parser(params.input); auto* p = parser(params.input);
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:9: expected '>' for vector"); ASSERT_EQ(p->error(), "1:9: expected '>' for vector");
} }
@ -162,8 +180,10 @@ class VecMissingLessThanTest : public ParserImplTestWithParam<VecData> {};
TEST_P(VecMissingLessThanTest, Handles_Missing_GreaterThan) { TEST_P(VecMissingLessThanTest, Handles_Missing_GreaterThan) {
auto params = GetParam(); auto params = GetParam();
auto* p = parser(params.input); auto* p = parser(params.input);
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:5: expected '<' for vector"); ASSERT_EQ(p->error(), "1:5: expected '<' for vector");
} }
@ -178,8 +198,10 @@ class VecBadType : public ParserImplTestWithParam<VecData> {};
TEST_P(VecBadType, Handles_Unknown_Type) { TEST_P(VecBadType, Handles_Unknown_Type) {
auto params = GetParam(); auto params = GetParam();
auto* p = parser(params.input); auto* p = parser(params.input);
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:6: unknown constructed type 'unknown'"); ASSERT_EQ(p->error(), "1:6: unknown constructed type 'unknown'");
} }
@ -194,8 +216,10 @@ class VecMissingType : public ParserImplTestWithParam<VecData> {};
TEST_P(VecMissingType, Handles_Missing_Type) { TEST_P(VecMissingType, Handles_Missing_Type) {
auto params = GetParam(); auto params = GetParam();
auto* p = parser(params.input); auto* p = parser(params.input);
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:6: unable to determine subtype for vector"); ASSERT_EQ(p->error(), "1:6: unable to determine subtype for vector");
} }
@ -207,24 +231,28 @@ INSTANTIATE_TEST_SUITE_P(ParserImplTest,
TEST_F(ParserImplTest, TypeDecl_Ptr) { TEST_F(ParserImplTest, TypeDecl_Ptr) {
auto* p = parser("ptr<function, f32>"); auto* p = parser("ptr<function, f32>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsPointer()); ASSERT_TRUE(t.value->IsPointer());
auto* ptr = t->AsPointer(); auto* ptr = t.value->AsPointer();
ASSERT_TRUE(ptr->type()->IsF32()); ASSERT_TRUE(ptr->type()->IsF32());
ASSERT_EQ(ptr->storage_class(), ast::StorageClass::kFunction); ASSERT_EQ(ptr->storage_class(), ast::StorageClass::kFunction);
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) { TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) {
auto* p = parser("ptr<function, vec2<f32>>"); auto* p = parser("ptr<function, vec2<f32>>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsPointer()); ASSERT_TRUE(t.value->IsPointer());
auto* ptr = t->AsPointer(); auto* ptr = t.value->AsPointer();
ASSERT_TRUE(ptr->type()->IsVector()); ASSERT_TRUE(ptr->type()->IsVector());
ASSERT_EQ(ptr->storage_class(), ast::StorageClass::kFunction); ASSERT_EQ(ptr->storage_class(), ast::StorageClass::kFunction);
@ -235,76 +263,94 @@ TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) {
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingLessThan) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingLessThan) {
auto* p = parser("ptr private, f32>"); auto* p = parser("ptr private, f32>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:5: expected '<' for ptr declaration"); ASSERT_EQ(p->error(), "1:5: expected '<' for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThan) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThan) {
auto* p = parser("ptr<function, f32"); auto* p = parser("ptr<function, f32");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:18: expected '>' for ptr declaration"); ASSERT_EQ(p->error(), "1:18: expected '>' for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingComma) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingComma) {
auto* p = parser("ptr<function f32>"); auto* p = parser("ptr<function f32>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:14: expected ',' for ptr declaration"); ASSERT_EQ(p->error(), "1:14: expected ',' for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingStorageClass) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingStorageClass) {
auto* p = parser("ptr<, f32>"); auto* p = parser("ptr<, f32>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration"); ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) {
auto* p = parser("ptr<>"); auto* p = parser("ptr<>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration"); ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) { TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) {
auto* p = parser("ptr<function,>"); auto* p = parser("ptr<function,>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:14: missing type for ptr declaration"); ASSERT_EQ(p->error(), "1:14: missing type for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_BadStorageClass) { TEST_F(ParserImplTest, TypeDecl_Ptr_BadStorageClass) {
auto* p = parser("ptr<unknown, f32>"); auto* p = parser("ptr<unknown, f32>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration"); ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Ptr_BadType) { TEST_F(ParserImplTest, TypeDecl_Ptr_BadType) {
auto* p = parser("ptr<function, unknown>"); auto* p = parser("ptr<function, unknown>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:15: unknown constructed type 'unknown'"); ASSERT_EQ(p->error(), "1:15: unknown constructed type 'unknown'");
} }
TEST_F(ParserImplTest, TypeDecl_Array) { TEST_F(ParserImplTest, TypeDecl_Array) {
auto* p = parser("array<f32, 5>"); auto* p = parser("array<f32, 5>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsArray()); ASSERT_TRUE(t.value->IsArray());
auto* a = t->AsArray(); auto* a = t.value->AsArray();
ASSERT_FALSE(a->IsRuntimeArray()); ASSERT_FALSE(a->IsRuntimeArray());
ASSERT_EQ(a->size(), 5u); ASSERT_EQ(a->size(), 5u);
ASSERT_TRUE(a->type()->IsF32()); ASSERT_TRUE(a->type()->IsF32());
@ -313,12 +359,14 @@ TEST_F(ParserImplTest, TypeDecl_Array) {
TEST_F(ParserImplTest, TypeDecl_Array_Stride) { TEST_F(ParserImplTest, TypeDecl_Array_Stride) {
auto* p = parser("[[stride(16)]] array<f32, 5>"); auto* p = parser("[[stride(16)]] array<f32, 5>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsArray()); ASSERT_TRUE(t.value->IsArray());
auto* a = t->AsArray(); auto* a = t.value->AsArray();
ASSERT_FALSE(a->IsRuntimeArray()); ASSERT_FALSE(a->IsRuntimeArray());
ASSERT_EQ(a->size(), 5u); ASSERT_EQ(a->size(), 5u);
ASSERT_TRUE(a->type()->IsF32()); ASSERT_TRUE(a->type()->IsF32());
@ -328,12 +376,14 @@ TEST_F(ParserImplTest, TypeDecl_Array_Stride) {
TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Stride) { TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Stride) {
auto* p = parser("[[stride(16)]] array<f32>"); auto* p = parser("[[stride(16)]] array<f32>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsArray()); ASSERT_TRUE(t.value->IsArray());
auto* a = t->AsArray(); auto* a = t.value->AsArray();
ASSERT_TRUE(a->IsRuntimeArray()); ASSERT_TRUE(a->IsRuntimeArray());
ASSERT_TRUE(a->type()->IsF32()); ASSERT_TRUE(a->type()->IsF32());
ASSERT_TRUE(a->has_array_stride()); ASSERT_TRUE(a->has_array_stride());
@ -342,12 +392,14 @@ TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Stride) {
TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_OneBlock) { TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_OneBlock) {
auto* p = parser("[[stride(16), stride(32)]] array<f32>"); auto* p = parser("[[stride(16), stride(32)]] array<f32>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsArray()); ASSERT_TRUE(t.value->IsArray());
auto* a = t->AsArray(); auto* a = t.value->AsArray();
ASSERT_TRUE(a->IsRuntimeArray()); ASSERT_TRUE(a->IsRuntimeArray());
ASSERT_TRUE(a->type()->IsF32()); ASSERT_TRUE(a->type()->IsF32());
@ -361,12 +413,14 @@ TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_OneBlock) {
TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_MultipleBlocks) { TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_MultipleBlocks) {
auto* p = parser("[[stride(16)]] [[stride(32)]] array<f32>"); auto* p = parser("[[stride(16)]] [[stride(32)]] array<f32>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsArray()); ASSERT_TRUE(t.value->IsArray());
auto* a = t->AsArray(); auto* a = t.value->AsArray();
ASSERT_TRUE(a->IsRuntimeArray()); ASSERT_TRUE(a->IsRuntimeArray());
ASSERT_TRUE(a->type()->IsF32()); ASSERT_TRUE(a->type()->IsF32());
@ -380,48 +434,60 @@ TEST_F(ParserImplTest, TypeDecl_Array_MultipleDecorations_MultipleBlocks) {
TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingArray) { TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingArray) {
auto* p = parser("[[stride(16)]] f32"); auto* p = parser("[[stride(16)]] f32");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:3: unexpected decorations"); EXPECT_EQ(p->error(), "1:3: unexpected decorations");
} }
TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingClosingAttr) { TEST_F(ParserImplTest, TypeDecl_Array_Decoration_MissingClosingAttr) {
auto* p = parser("[[stride(16) array<f32, 5>"); auto* p = parser("[[stride(16) array<f32, 5>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:14: expected ']]' for decoration list"); EXPECT_EQ(p->error(), "1:14: expected ']]' for decoration list");
} }
TEST_F(ParserImplTest, TypeDecl_Array_Decoration_UnknownDecoration) { TEST_F(ParserImplTest, TypeDecl_Array_Decoration_UnknownDecoration) {
auto* p = parser("[[unknown 16]] array<f32, 5>"); auto* p = parser("[[unknown 16]] array<f32, 5>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:3: expected decoration"); EXPECT_EQ(p->error(), "1:3: expected decoration");
} }
TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingLeftParen) { TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingLeftParen) {
auto* p = parser("[[stride 4)]] array<f32, 5>"); auto* p = parser("[[stride 4)]] array<f32, 5>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:10: expected '(' for stride decoration"); EXPECT_EQ(p->error(), "1:10: expected '(' for stride decoration");
} }
TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingRightParen) { TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingRightParen) {
auto* p = parser("[[stride(4]] array<f32, 5>"); auto* p = parser("[[stride(4]] array<f32, 5>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:11: expected ')' for stride decoration"); EXPECT_EQ(p->error(), "1:11: expected ')' for stride decoration");
} }
TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingValue) { TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingValue) {
auto* p = parser("[[stride()]] array<f32, 5>"); auto* p = parser("[[stride()]] array<f32, 5>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:10: expected signed integer literal for stride decoration"); "1:10: expected signed integer literal for stride decoration");
@ -429,8 +495,10 @@ TEST_F(ParserImplTest, TypeDecl_Array_Stride_MissingValue) {
TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue) { TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue) {
auto* p = parser("[[stride(invalid)]] array<f32, 5>"); auto* p = parser("[[stride(invalid)]] array<f32, 5>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:10: expected signed integer literal for stride decoration"); "1:10: expected signed integer literal for stride decoration");
@ -438,76 +506,94 @@ TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue) {
TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue_Negative) { TEST_F(ParserImplTest, TypeDecl_Array_Stride_InvalidValue_Negative) {
auto* p = parser("[[stride(-1)]] array<f32, 5>"); auto* p = parser("[[stride(-1)]] array<f32, 5>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:10: stride decoration must be greater than 0"); EXPECT_EQ(p->error(), "1:10: stride decoration must be greater than 0");
} }
TEST_F(ParserImplTest, TypeDecl_Array_Runtime) { TEST_F(ParserImplTest, TypeDecl_Array_Runtime) {
auto* p = parser("array<u32>"); auto* p = parser("array<u32>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(t->IsArray()); ASSERT_TRUE(t.value->IsArray());
auto* a = t->AsArray(); auto* a = t.value->AsArray();
ASSERT_TRUE(a->IsRuntimeArray()); ASSERT_TRUE(a->IsRuntimeArray());
ASSERT_TRUE(a->type()->IsU32()); ASSERT_TRUE(a->type()->IsU32());
} }
TEST_F(ParserImplTest, TypeDecl_Array_BadType) { TEST_F(ParserImplTest, TypeDecl_Array_BadType) {
auto* p = parser("array<unknown, 3>"); auto* p = parser("array<unknown, 3>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:7: unknown constructed type 'unknown'"); ASSERT_EQ(p->error(), "1:7: unknown constructed type 'unknown'");
} }
TEST_F(ParserImplTest, TypeDecl_Array_ZeroSize) { TEST_F(ParserImplTest, TypeDecl_Array_ZeroSize) {
auto* p = parser("array<f32, 0>"); auto* p = parser("array<f32, 0>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:12: array size must be greater than 0"); ASSERT_EQ(p->error(), "1:12: array size must be greater than 0");
} }
TEST_F(ParserImplTest, TypeDecl_Array_NegativeSize) { TEST_F(ParserImplTest, TypeDecl_Array_NegativeSize) {
auto* p = parser("array<f32, -1>"); auto* p = parser("array<f32, -1>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:12: array size must be greater than 0"); ASSERT_EQ(p->error(), "1:12: array size must be greater than 0");
} }
TEST_F(ParserImplTest, TypeDecl_Array_BadSize) { TEST_F(ParserImplTest, TypeDecl_Array_BadSize) {
auto* p = parser("array<f32, invalid>"); auto* p = parser("array<f32, invalid>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:12: expected signed integer literal for array size"); ASSERT_EQ(p->error(), "1:12: expected signed integer literal for array size");
} }
TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) { TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) {
auto* p = parser("array f32>"); auto* p = parser("array f32>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:7: expected '<' for array declaration"); ASSERT_EQ(p->error(), "1:7: expected '<' for array declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Array_MissingGreaterThan) { TEST_F(ParserImplTest, TypeDecl_Array_MissingGreaterThan) {
auto* p = parser("array<f32"); auto* p = parser("array<f32");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:10: expected '>' for array declaration"); ASSERT_EQ(p->error(), "1:10: expected '>' for array declaration");
} }
TEST_F(ParserImplTest, TypeDecl_Array_MissingComma) { TEST_F(ParserImplTest, TypeDecl_Array_MissingComma) {
auto* p = parser("array<f32 3>"); auto* p = parser("array<f32 3>");
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:11: expected '>' for array declaration"); ASSERT_EQ(p->error(), "1:11: expected '>' for array declaration");
} }
@ -527,11 +613,13 @@ class MatrixTest : public ParserImplTestWithParam<MatrixData> {};
TEST_P(MatrixTest, Parse) { TEST_P(MatrixTest, Parse) {
auto params = GetParam(); auto params = GetParam();
auto* p = parser(params.input); auto* p = parser(params.input);
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_FALSE(t.errored);
ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
EXPECT_TRUE(t->IsMatrix()); EXPECT_TRUE(t.value->IsMatrix());
auto* mat = t->AsMatrix(); auto* mat = t.value->AsMatrix();
EXPECT_EQ(mat->rows(), params.rows); EXPECT_EQ(mat->rows(), params.rows);
EXPECT_EQ(mat->columns(), params.columns); EXPECT_EQ(mat->columns(), params.columns);
} }
@ -553,10 +641,12 @@ class MatrixMissingGreaterThanTest
TEST_P(MatrixMissingGreaterThanTest, Handles_Missing_GreaterThan) { TEST_P(MatrixMissingGreaterThanTest, Handles_Missing_GreaterThan) {
auto params = GetParam(); auto params = GetParam();
auto* p = parser(params.input); auto* p = parser(params.input);
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:11: missing > for matrix"); ASSERT_EQ(p->error(), "1:11: expected '>' for matrix");
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixMissingGreaterThanTest, MatrixMissingGreaterThanTest,
@ -575,10 +665,12 @@ class MatrixMissingLessThanTest : public ParserImplTestWithParam<MatrixData> {};
TEST_P(MatrixMissingLessThanTest, Handles_Missing_GreaterThan) { TEST_P(MatrixMissingLessThanTest, Handles_Missing_GreaterThan) {
auto params = GetParam(); auto params = GetParam();
auto* p = parser(params.input); auto* p = parser(params.input);
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:8: missing < for matrix"); ASSERT_EQ(p->error(), "1:8: expected '<' for matrix");
} }
INSTANTIATE_TEST_SUITE_P(ParserImplTest, INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixMissingLessThanTest, MatrixMissingLessThanTest,
@ -597,8 +689,10 @@ class MatrixBadType : public ParserImplTestWithParam<MatrixData> {};
TEST_P(MatrixBadType, Handles_Unknown_Type) { TEST_P(MatrixBadType, Handles_Unknown_Type) {
auto params = GetParam(); auto params = GetParam();
auto* p = parser(params.input); auto* p = parser(params.input);
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:8: unknown constructed type 'unknown'"); ASSERT_EQ(p->error(), "1:8: unknown constructed type 'unknown'");
} }
@ -619,8 +713,10 @@ class MatrixMissingType : public ParserImplTestWithParam<MatrixData> {};
TEST_P(MatrixMissingType, Handles_Missing_Type) { TEST_P(MatrixMissingType, Handles_Missing_Type) {
auto params = GetParam(); auto params = GetParam();
auto* p = parser(params.input); auto* p = parser(params.input);
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_EQ(t, nullptr); EXPECT_TRUE(t.errored);
EXPECT_FALSE(t.matched);
ASSERT_EQ(t.value, nullptr);
ASSERT_TRUE(p->has_error()); ASSERT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:8: unable to determine subtype for matrix"); ASSERT_EQ(p->error(), "1:8: unable to determine subtype for matrix");
} }
@ -642,11 +738,13 @@ TEST_F(ParserImplTest, TypeDecl_Sampler) {
auto* type = tm()->Get(std::make_unique<ast::type::SamplerType>( auto* type = tm()->Get(std::make_unique<ast::type::SamplerType>(
ast::type::SamplerKind::kSampler)); ast::type::SamplerKind::kSampler));
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_EQ(t, type); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->IsSampler()); ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_FALSE(t->AsSampler()->IsComparison()); EXPECT_EQ(t.value, type);
ASSERT_TRUE(t.value->IsSampler());
ASSERT_FALSE(t.value->AsSampler()->IsComparison());
} }
TEST_F(ParserImplTest, TypeDecl_Texture_Old) { TEST_F(ParserImplTest, TypeDecl_Texture_Old) {
@ -656,12 +754,14 @@ TEST_F(ParserImplTest, TypeDecl_Texture_Old) {
auto* type = tm()->Get(std::make_unique<ast::type::SampledTextureType>( auto* type = tm()->Get(std::make_unique<ast::type::SampledTextureType>(
ast::type::TextureDimension::kCube, &f32)); ast::type::TextureDimension::kCube, &f32));
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr) << p->error(); EXPECT_TRUE(t.matched);
EXPECT_EQ(t, type); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->IsTexture()); ASSERT_NE(t.value, nullptr) << p->error();
ASSERT_TRUE(t->AsTexture()->IsSampled()); EXPECT_EQ(t.value, type);
ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32()); ASSERT_TRUE(t.value->IsTexture());
ASSERT_TRUE(t.value->AsTexture()->IsSampled());
ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32());
} }
TEST_F(ParserImplTest, TypeDecl_Texture) { TEST_F(ParserImplTest, TypeDecl_Texture) {
@ -671,12 +771,14 @@ TEST_F(ParserImplTest, TypeDecl_Texture) {
auto* type = tm()->Get(std::make_unique<ast::type::SampledTextureType>( auto* type = tm()->Get(std::make_unique<ast::type::SampledTextureType>(
ast::type::TextureDimension::kCube, &f32)); ast::type::TextureDimension::kCube, &f32));
auto* t = p->type_decl(); auto t = p->type_decl();
ASSERT_NE(t, nullptr); EXPECT_TRUE(t.matched);
EXPECT_EQ(t, type); EXPECT_FALSE(t.errored);
ASSERT_TRUE(t->IsTexture()); ASSERT_NE(t.value, nullptr);
ASSERT_TRUE(t->AsTexture()->IsSampled()); EXPECT_EQ(t.value, type);
ASSERT_TRUE(t->AsTexture()->AsSampled()->type()->IsF32()); ASSERT_TRUE(t.value->IsTexture());
ASSERT_TRUE(t.value->AsTexture()->IsSampled());
ASSERT_TRUE(t.value->AsTexture()->AsSampled()->type()->IsF32());
} }
} // namespace } // namespace

View File

@ -29,11 +29,13 @@ namespace {
TEST_F(ParserImplTest, UnaryExpression_Postix) { TEST_F(ParserImplTest, UnaryExpression_Postix) {
auto* p = parser("a[2]"); auto* p = parser("a[2]");
auto e = p->unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e->IsArrayAccessor()); ASSERT_TRUE(e.value->IsArrayAccessor());
auto* ary = e->AsArrayAccessor(); auto* ary = e.value->AsArrayAccessor();
ASSERT_TRUE(ary->array()->IsIdentifier()); ASSERT_TRUE(ary->array()->IsIdentifier());
auto* ident = ary->array()->AsIdentifier(); auto* ident = ary->array()->AsIdentifier();
EXPECT_EQ(ident->name(), "a"); EXPECT_EQ(ident->name(), "a");
@ -48,11 +50,13 @@ TEST_F(ParserImplTest, UnaryExpression_Postix) {
TEST_F(ParserImplTest, UnaryExpression_Minus) { TEST_F(ParserImplTest, UnaryExpression_Minus) {
auto* p = parser("- 1"); auto* p = parser("- 1");
auto e = p->unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsUnaryOp()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsUnaryOp());
auto* u = e->AsUnaryOp(); auto* u = e.value->AsUnaryOp();
ASSERT_EQ(u->op(), ast::UnaryOp::kNegation); ASSERT_EQ(u->op(), ast::UnaryOp::kNegation);
ASSERT_TRUE(u->expr()->IsConstructor()); ASSERT_TRUE(u->expr()->IsConstructor());
@ -66,19 +70,23 @@ TEST_F(ParserImplTest, UnaryExpression_Minus) {
TEST_F(ParserImplTest, UnaryExpression_Minus_InvalidRHS) { TEST_F(ParserImplTest, UnaryExpression_Minus_InvalidRHS) {
auto* p = parser("-if(a) {}"); auto* p = parser("-if(a) {}");
auto e = p->unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:2: unable to parse right side of - expression"); EXPECT_EQ(p->error(), "1:2: unable to parse right side of - expression");
} }
TEST_F(ParserImplTest, UnaryExpression_Bang) { TEST_F(ParserImplTest, UnaryExpression_Bang) {
auto* p = parser("!1"); auto* p = parser("!1");
auto e = p->unary_expression(); auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsUnaryOp()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsUnaryOp());
auto* u = e->AsUnaryOp(); auto* u = e.value->AsUnaryOp();
ASSERT_EQ(u->op(), ast::UnaryOp::kNot); ASSERT_EQ(u->op(), ast::UnaryOp::kNot);
ASSERT_TRUE(u->expr()->IsConstructor()); ASSERT_TRUE(u->expr()->IsConstructor());
@ -92,8 +100,10 @@ TEST_F(ParserImplTest, UnaryExpression_Bang) {
TEST_F(ParserImplTest, UnaryExpression_Bang_InvalidRHS) { TEST_F(ParserImplTest, UnaryExpression_Bang_InvalidRHS) {
auto* p = parser("!if (a) {}"); auto* p = parser("!if (a) {}");
auto e = p->unary_expression(); auto e = p->unary_expression();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:2: unable to parse right side of ! expression"); EXPECT_EQ(p->error(), "1:2: unable to parse right side of ! expression");
} }

View File

@ -25,23 +25,27 @@ namespace {
TEST_F(ParserImplTest, VariableDecl_Parses) { TEST_F(ParserImplTest, VariableDecl_Parses) {
auto* p = parser("var my_var : f32"); auto* p = parser("var my_var : f32");
auto var = p->variable_decl(); auto var = p->variable_decl();
ASSERT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
ASSERT_NE(var, nullptr); EXPECT_TRUE(var.matched);
ASSERT_EQ(var->name(), "my_var"); EXPECT_FALSE(var.errored);
ASSERT_NE(var->type(), nullptr); ASSERT_NE(var.value, nullptr);
ASSERT_TRUE(var->type()->IsF32()); EXPECT_EQ(var.value->name(), "my_var");
EXPECT_NE(var.value->type(), nullptr);
EXPECT_TRUE(var.value->type()->IsF32());
ASSERT_EQ(var->source().range.begin.line, 1u); EXPECT_EQ(var.value->source().range.begin.line, 1u);
ASSERT_EQ(var->source().range.begin.column, 5u); EXPECT_EQ(var.value->source().range.begin.column, 5u);
ASSERT_EQ(var->source().range.end.line, 1u); EXPECT_EQ(var.value->source().range.end.line, 1u);
ASSERT_EQ(var->source().range.end.column, 11u); EXPECT_EQ(var.value->source().range.end.column, 11u);
} }
TEST_F(ParserImplTest, VariableDecl_MissingVar) { TEST_F(ParserImplTest, VariableDecl_MissingVar) {
auto* p = parser("my_var : f32"); auto* p = parser("my_var : f32");
auto v = p->variable_decl(); auto v = p->variable_decl();
ASSERT_EQ(v, nullptr); EXPECT_EQ(v.value, nullptr);
ASSERT_FALSE(p->has_error()); EXPECT_FALSE(v.matched);
EXPECT_FALSE(v.errored);
EXPECT_FALSE(p->has_error());
auto t = p->next(); auto t = p->next();
ASSERT_TRUE(t.IsIdentifier()); ASSERT_TRUE(t.IsIdentifier());
@ -50,31 +54,37 @@ TEST_F(ParserImplTest, VariableDecl_MissingVar) {
TEST_F(ParserImplTest, VariableDecl_InvalidIdentDecl) { TEST_F(ParserImplTest, VariableDecl_InvalidIdentDecl) {
auto* p = parser("var my_var f32"); auto* p = parser("var my_var f32");
auto v = p->variable_decl(); auto v = p->variable_decl();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(v.matched);
ASSERT_EQ(v, nullptr); EXPECT_TRUE(v.errored);
ASSERT_EQ(p->error(), "1:12: expected ':' for variable declaration"); EXPECT_TRUE(p->has_error());
EXPECT_EQ(v.value, nullptr);
EXPECT_EQ(p->error(), "1:12: expected ':' for variable declaration");
} }
TEST_F(ParserImplTest, VariableDecl_WithStorageClass) { TEST_F(ParserImplTest, VariableDecl_WithStorageClass) {
auto* p = parser("var<private> my_var : f32"); auto* p = parser("var<private> my_var : f32");
auto v = p->variable_decl(); auto v = p->variable_decl();
ASSERT_FALSE(p->has_error()); EXPECT_TRUE(v.matched);
ASSERT_NE(v, nullptr); EXPECT_FALSE(v.errored);
EXPECT_EQ(v->name(), "my_var"); EXPECT_FALSE(p->has_error());
EXPECT_TRUE(v->type()->IsF32()); ASSERT_NE(v.value, nullptr);
EXPECT_EQ(v->storage_class(), ast::StorageClass::kPrivate); EXPECT_EQ(v.value->name(), "my_var");
EXPECT_TRUE(v.value->type()->IsF32());
EXPECT_EQ(v.value->storage_class(), ast::StorageClass::kPrivate);
EXPECT_EQ(v->source().range.begin.line, 1u); EXPECT_EQ(v.value->source().range.begin.line, 1u);
EXPECT_EQ(v->source().range.begin.column, 14u); EXPECT_EQ(v.value->source().range.begin.column, 14u);
EXPECT_EQ(v->source().range.end.line, 1u); EXPECT_EQ(v.value->source().range.end.line, 1u);
EXPECT_EQ(v->source().range.end.column, 20u); EXPECT_EQ(v.value->source().range.end.column, 20u);
} }
TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) { TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) {
auto* p = parser("var<unknown> my_var : f32"); auto* p = parser("var<unknown> my_var : f32");
auto v = p->variable_decl(); auto v = p->variable_decl();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(v.matched);
ASSERT_EQ(v, nullptr); EXPECT_TRUE(v.errored);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(v.value, nullptr);
EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration"); EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration");
} }

View File

@ -27,10 +27,12 @@ TEST_F(ParserImplTest, VariableDecorationList_Parses) {
auto* p = parser(R"([[location(4), builtin(position)]])"); auto* p = parser(R"([[location(4), builtin(position)]])");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_EQ(decos.size(), 2u); ASSERT_FALSE(decos.errored);
ASSERT_TRUE(decos.matched);
ASSERT_EQ(decos.value.size(), 2u);
auto deco_0 = ast::As<ast::VariableDecoration>(std::move(decos[0])); auto deco_0 = ast::As<ast::VariableDecoration>(std::move(decos.value[0]));
auto deco_1 = ast::As<ast::VariableDecoration>(std::move(decos[1])); auto deco_1 = ast::As<ast::VariableDecoration>(std::move(decos.value[1]));
ASSERT_NE(deco_0, nullptr); ASSERT_NE(deco_0, nullptr);
ASSERT_NE(deco_1, nullptr); ASSERT_NE(deco_1, nullptr);
@ -43,44 +45,62 @@ TEST_F(ParserImplTest, VariableDecorationList_Parses) {
TEST_F(ParserImplTest, VariableDecorationList_Empty) { TEST_F(ParserImplTest, VariableDecorationList_Empty) {
auto* p = parser(R"([[]])"); auto* p = parser(R"([[]])");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:3: empty decoration list"); EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_TRUE(decos.value.empty());
EXPECT_EQ(p->error(), "1:3: empty decoration list");
} }
TEST_F(ParserImplTest, VariableDecorationList_Invalid) { TEST_F(ParserImplTest, VariableDecorationList_Invalid) {
auto* p = parser(R"([[invalid]])"); auto* p = parser(R"([[invalid]])");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_TRUE(decos.empty()); EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_TRUE(decos.value.empty());
EXPECT_EQ(p->error(), "1:3: expected decoration");
} }
TEST_F(ParserImplTest, VariableDecorationList_ExtraComma) { TEST_F(ParserImplTest, VariableDecorationList_ExtraComma) {
auto* p = parser(R"([[builtin(position), ]])"); auto* p = parser(R"([[builtin(position), ]])");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:22: expected decoration"); EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_TRUE(decos.value.empty());
EXPECT_EQ(p->error(), "1:22: expected decoration");
} }
TEST_F(ParserImplTest, VariableDecorationList_MissingComma) { TEST_F(ParserImplTest, VariableDecorationList_MissingComma) {
auto* p = parser(R"([[binding(4) location(5)]])"); auto* p = parser(R"([[binding(4) location(5)]])");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:14: expected ',' for decoration list"); EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_TRUE(decos.value.empty());
EXPECT_EQ(p->error(), "1:14: expected ',' for decoration list");
} }
TEST_F(ParserImplTest, VariableDecorationList_BadDecoration) { TEST_F(ParserImplTest, VariableDecorationList_BadDecoration) {
auto* p = parser(R"([[location(bad)]])"); auto* p = parser(R"([[location(bad)]])");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(p->error(), EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_TRUE(decos.value.empty());
EXPECT_EQ(p->error(),
"1:12: expected signed integer literal for location decoration"); "1:12: expected signed integer literal for location decoration");
} }
TEST_F(ParserImplTest, VariableDecorationList_InvalidBuiltin) { TEST_F(ParserImplTest, VariableDecorationList_InvalidBuiltin) {
auto* p = parser("[[builtin(invalid)]]"); auto* p = parser("[[builtin(invalid)]]");
auto decos = p->decoration_list(); auto decos = p->decoration_list();
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(p->has_error());
ASSERT_EQ(p->error(), "1:11: invalid value for builtin decoration"); EXPECT_TRUE(decos.errored);
EXPECT_FALSE(decos.matched);
EXPECT_TRUE(decos.value.empty());
EXPECT_EQ(p->error(), "1:11: invalid value for builtin decoration");
} }
} // namespace } // namespace

View File

@ -28,8 +28,10 @@ namespace {
TEST_F(ParserImplTest, VariableDecoration_Location) { TEST_F(ParserImplTest, VariableDecoration_Location) {
auto* p = parser("location(4)"); auto* p = parser("location(4)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_NE(deco, nullptr); EXPECT_TRUE(deco.matched);
auto var_deco = ast::As<ast::VariableDecoration>(std::move(deco)); EXPECT_FALSE(deco.errored);
ASSERT_NE(deco.value, nullptr);
auto var_deco = ast::As<ast::VariableDecoration>(std::move(deco.value));
ASSERT_NE(var_deco, nullptr); ASSERT_NE(var_deco, nullptr);
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(var_deco->IsLocation()); ASSERT_TRUE(var_deco->IsLocation());
@ -41,24 +43,30 @@ TEST_F(ParserImplTest, VariableDecoration_Location) {
TEST_F(ParserImplTest, VariableDecoration_Location_MissingLeftParen) { TEST_F(ParserImplTest, VariableDecoration_Location_MissingLeftParen) {
auto* p = parser("location 4)"); auto* p = parser("location 4)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:10: expected '(' for location decoration"); EXPECT_EQ(p->error(), "1:10: expected '(' for location decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Location_MissingRightParen) { TEST_F(ParserImplTest, VariableDecoration_Location_MissingRightParen) {
auto* p = parser("location(4"); auto* p = parser("location(4");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:11: expected ')' for location decoration"); EXPECT_EQ(p->error(), "1:11: expected ')' for location decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Location_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Location_MissingValue) {
auto* p = parser("location()"); auto* p = parser("location()");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:10: expected signed integer literal for location decoration"); "1:10: expected signed integer literal for location decoration");
} }
@ -66,8 +74,10 @@ TEST_F(ParserImplTest, VariableDecoration_Location_MissingValue) {
TEST_F(ParserImplTest, VariableDecoration_Location_MissingInvalid) { TEST_F(ParserImplTest, VariableDecoration_Location_MissingInvalid) {
auto* p = parser("location(nan)"); auto* p = parser("location(nan)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:10: expected signed integer literal for location decoration"); "1:10: expected signed integer literal for location decoration");
} }
@ -88,8 +98,10 @@ TEST_P(BuiltinTest, VariableDecoration_Builtin) {
auto* p = parser(std::string("builtin(") + params.input + ")"); auto* p = parser(std::string("builtin(") + params.input + ")");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_NE(deco, nullptr); EXPECT_TRUE(deco.matched);
auto var_deco = ast::As<ast::VariableDecoration>(std::move(deco)); EXPECT_FALSE(deco.errored);
ASSERT_NE(deco.value, nullptr);
auto var_deco = ast::As<ast::VariableDecoration>(std::move(deco.value));
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(var_deco, nullptr); ASSERT_NE(var_deco, nullptr);
ASSERT_TRUE(var_deco->IsBuiltin()); ASSERT_TRUE(var_deco->IsBuiltin());
@ -115,48 +127,60 @@ INSTANTIATE_TEST_SUITE_P(
TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingLeftParen) { TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingLeftParen) {
auto* p = parser("builtin position)"); auto* p = parser("builtin position)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: expected '(' for builtin decoration"); EXPECT_EQ(p->error(), "1:9: expected '(' for builtin decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingRightParen) { TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingRightParen) {
auto* p = parser("builtin(position"); auto* p = parser("builtin(position");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:17: expected ')' for builtin decoration"); EXPECT_EQ(p->error(), "1:17: expected ')' for builtin decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingValue) {
auto* p = parser("builtin()"); auto* p = parser("builtin()");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: expected identifier for builtin"); EXPECT_EQ(p->error(), "1:9: expected identifier for builtin");
} }
TEST_F(ParserImplTest, VariableDecoration_Builtin_InvalidValue) { TEST_F(ParserImplTest, VariableDecoration_Builtin_InvalidValue) {
auto* p = parser("builtin(other_thingy)"); auto* p = parser("builtin(other_thingy)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: invalid value for builtin decoration"); EXPECT_EQ(p->error(), "1:9: invalid value for builtin decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingInvalid) { TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingInvalid) {
auto* p = parser("builtin(3)"); auto* p = parser("builtin(3)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: expected identifier for builtin"); EXPECT_EQ(p->error(), "1:9: expected identifier for builtin");
} }
TEST_F(ParserImplTest, VariableDecoration_Binding) { TEST_F(ParserImplTest, VariableDecoration_Binding) {
auto* p = parser("binding(4)"); auto* p = parser("binding(4)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_NE(deco, nullptr); EXPECT_TRUE(deco.matched);
auto var_deco = ast::As<ast::VariableDecoration>(std::move(deco)); EXPECT_FALSE(deco.errored);
ASSERT_NE(deco.value, nullptr);
auto var_deco = ast::As<ast::VariableDecoration>(std::move(deco.value));
ASSERT_NE(var_deco, nullptr); ASSERT_NE(var_deco, nullptr);
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_TRUE(var_deco->IsBinding()); ASSERT_TRUE(var_deco->IsBinding());
@ -168,24 +192,30 @@ TEST_F(ParserImplTest, VariableDecoration_Binding) {
TEST_F(ParserImplTest, VariableDecoration_Binding_MissingLeftParen) { TEST_F(ParserImplTest, VariableDecoration_Binding_MissingLeftParen) {
auto* p = parser("binding 4)"); auto* p = parser("binding 4)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: expected '(' for binding decoration"); EXPECT_EQ(p->error(), "1:9: expected '(' for binding decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Binding_MissingRightParen) { TEST_F(ParserImplTest, VariableDecoration_Binding_MissingRightParen) {
auto* p = parser("binding(4"); auto* p = parser("binding(4");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:10: expected ')' for binding decoration"); EXPECT_EQ(p->error(), "1:10: expected ')' for binding decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Binding_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Binding_MissingValue) {
auto* p = parser("binding()"); auto* p = parser("binding()");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:9: expected signed integer literal for binding decoration"); "1:9: expected signed integer literal for binding decoration");
} }
@ -193,8 +223,10 @@ TEST_F(ParserImplTest, VariableDecoration_Binding_MissingValue) {
TEST_F(ParserImplTest, VariableDecoration_Binding_MissingInvalid) { TEST_F(ParserImplTest, VariableDecoration_Binding_MissingInvalid) {
auto* p = parser("binding(nan)"); auto* p = parser("binding(nan)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:9: expected signed integer literal for binding decoration"); "1:9: expected signed integer literal for binding decoration");
} }
@ -202,8 +234,10 @@ TEST_F(ParserImplTest, VariableDecoration_Binding_MissingInvalid) {
TEST_F(ParserImplTest, VariableDecoration_set) { TEST_F(ParserImplTest, VariableDecoration_set) {
auto* p = parser("set(4)"); auto* p = parser("set(4)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_NE(deco, nullptr); EXPECT_TRUE(deco.matched);
auto var_deco = ast::As<ast::VariableDecoration>(std::move(deco)); EXPECT_FALSE(deco.errored);
ASSERT_NE(deco.value, nullptr);
auto var_deco = ast::As<ast::VariableDecoration>(std::move(deco.value));
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_NE(var_deco.get(), nullptr); ASSERT_NE(var_deco.get(), nullptr);
ASSERT_TRUE(var_deco->IsSet()); ASSERT_TRUE(var_deco->IsSet());
@ -215,24 +249,30 @@ TEST_F(ParserImplTest, VariableDecoration_set) {
TEST_F(ParserImplTest, VariableDecoration_Set_MissingLeftParen) { TEST_F(ParserImplTest, VariableDecoration_Set_MissingLeftParen) {
auto* p = parser("set 2)"); auto* p = parser("set 2)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:5: expected '(' for set decoration"); EXPECT_EQ(p->error(), "1:5: expected '(' for set decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Set_MissingRightParen) { TEST_F(ParserImplTest, VariableDecoration_Set_MissingRightParen) {
auto* p = parser("set(2"); auto* p = parser("set(2");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:6: expected ')' for set decoration"); EXPECT_EQ(p->error(), "1:6: expected ')' for set decoration");
} }
TEST_F(ParserImplTest, VariableDecoration_Set_MissingValue) { TEST_F(ParserImplTest, VariableDecoration_Set_MissingValue) {
auto* p = parser("set()"); auto* p = parser("set()");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:5: expected signed integer literal for set decoration"); "1:5: expected signed integer literal for set decoration");
} }
@ -240,8 +280,10 @@ TEST_F(ParserImplTest, VariableDecoration_Set_MissingValue) {
TEST_F(ParserImplTest, VariableDecoration_Set_MissingInvalid) { TEST_F(ParserImplTest, VariableDecoration_Set_MissingInvalid) {
auto* p = parser("set(nan)"); auto* p = parser("set(nan)");
auto deco = p->decoration(); auto deco = p->decoration();
ASSERT_EQ(deco, nullptr); EXPECT_FALSE(deco.matched);
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(deco.errored);
EXPECT_EQ(deco.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), EXPECT_EQ(p->error(),
"1:5: expected signed integer literal for set decoration"); "1:5: expected signed integer literal for set decoration");
} }

View File

@ -26,96 +26,114 @@ namespace {
TEST_F(ParserImplTest, VariableStmt_VariableDecl) { TEST_F(ParserImplTest, VariableStmt_VariableDecl) {
auto* p = parser("var a : i32;"); auto* p = parser("var a : i32;");
auto e = p->variable_stmt(); auto e = p->variable_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsVariableDecl()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e->variable(), nullptr); ASSERT_NE(e.value, nullptr);
EXPECT_EQ(e->variable()->name(), "a"); ASSERT_TRUE(e.value->IsVariableDecl());
ASSERT_NE(e.value->variable(), nullptr);
EXPECT_EQ(e.value->variable()->name(), "a");
ASSERT_EQ(e->source().range.begin.line, 1u); ASSERT_EQ(e.value->source().range.begin.line, 1u);
ASSERT_EQ(e->source().range.begin.column, 5u); ASSERT_EQ(e.value->source().range.begin.column, 5u);
ASSERT_EQ(e->source().range.end.line, 1u); ASSERT_EQ(e.value->source().range.end.line, 1u);
ASSERT_EQ(e->source().range.end.column, 6u); ASSERT_EQ(e.value->source().range.end.column, 6u);
EXPECT_EQ(e->variable()->constructor(), nullptr); EXPECT_EQ(e.value->variable()->constructor(), nullptr);
} }
TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) { TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) {
auto* p = parser("var a : i32 = 1;"); auto* p = parser("var a : i32 = 1;");
auto e = p->variable_stmt(); auto e = p->variable_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsVariableDecl()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e->variable(), nullptr); ASSERT_NE(e.value, nullptr);
EXPECT_EQ(e->variable()->name(), "a"); ASSERT_TRUE(e.value->IsVariableDecl());
ASSERT_NE(e.value->variable(), nullptr);
EXPECT_EQ(e.value->variable()->name(), "a");
ASSERT_EQ(e->source().range.begin.line, 1u); ASSERT_EQ(e.value->source().range.begin.line, 1u);
ASSERT_EQ(e->source().range.begin.column, 5u); ASSERT_EQ(e.value->source().range.begin.column, 5u);
ASSERT_EQ(e->source().range.end.line, 1u); ASSERT_EQ(e.value->source().range.end.line, 1u);
ASSERT_EQ(e->source().range.end.column, 6u); ASSERT_EQ(e.value->source().range.end.column, 6u);
ASSERT_NE(e->variable()->constructor(), nullptr); ASSERT_NE(e.value->variable()->constructor(), nullptr);
EXPECT_TRUE(e->variable()->constructor()->IsConstructor()); EXPECT_TRUE(e.value->variable()->constructor()->IsConstructor());
} }
TEST_F(ParserImplTest, VariableStmt_VariableDecl_Invalid) { TEST_F(ParserImplTest, VariableStmt_VariableDecl_Invalid) {
auto* p = parser("var a : invalid;"); auto* p = parser("var a : invalid;");
auto e = p->variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: unknown constructed type 'invalid'"); EXPECT_EQ(p->error(), "1:9: unknown constructed type 'invalid'");
} }
TEST_F(ParserImplTest, VariableStmt_VariableDecl_ConstructorInvalid) { TEST_F(ParserImplTest, VariableStmt_VariableDecl_ConstructorInvalid) {
auto* p = parser("var a : i32 = if(a) {}"); auto* p = parser("var a : i32 = if(a) {}");
auto e = p->variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:15: missing constructor for variable declaration"); EXPECT_EQ(p->error(), "1:15: missing constructor for variable declaration");
} }
TEST_F(ParserImplTest, VariableStmt_Const) { TEST_F(ParserImplTest, VariableStmt_Const) {
auto* p = parser("const a : i32 = 1"); auto* p = parser("const a : i32 = 1");
auto e = p->variable_stmt(); auto e = p->variable_stmt();
ASSERT_FALSE(p->has_error()) << p->error(); EXPECT_TRUE(e.matched);
ASSERT_NE(e, nullptr); EXPECT_FALSE(e.errored);
ASSERT_TRUE(e->IsVariableDecl()); EXPECT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e.value, nullptr);
ASSERT_TRUE(e.value->IsVariableDecl());
ASSERT_EQ(e->source().range.begin.line, 1u); ASSERT_EQ(e.value->source().range.begin.line, 1u);
ASSERT_EQ(e->source().range.begin.column, 7u); ASSERT_EQ(e.value->source().range.begin.column, 7u);
ASSERT_EQ(e->source().range.end.line, 1u); ASSERT_EQ(e.value->source().range.end.line, 1u);
ASSERT_EQ(e->source().range.end.column, 8u); ASSERT_EQ(e.value->source().range.end.column, 8u);
} }
TEST_F(ParserImplTest, VariableStmt_Const_InvalidVarIdent) { TEST_F(ParserImplTest, VariableStmt_Const_InvalidVarIdent) {
auto* p = parser("const a : invalid = 1"); auto* p = parser("const a : invalid = 1");
auto e = p->variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:11: unknown constructed type 'invalid'"); EXPECT_EQ(p->error(), "1:11: unknown constructed type 'invalid'");
} }
TEST_F(ParserImplTest, VariableStmt_Const_MissingEqual) { TEST_F(ParserImplTest, VariableStmt_Const_MissingEqual) {
auto* p = parser("const a : i32 1"); auto* p = parser("const a : i32 1");
auto e = p->variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:15: expected '=' for constant declaration"); EXPECT_EQ(p->error(), "1:15: expected '=' for constant declaration");
} }
TEST_F(ParserImplTest, VariableStmt_Const_MissingConstructor) { TEST_F(ParserImplTest, VariableStmt_Const_MissingConstructor) {
auto* p = parser("const a : i32 ="); auto* p = parser("const a : i32 =");
auto e = p->variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:16: missing constructor for const declaration"); EXPECT_EQ(p->error(), "1:16: missing constructor for const declaration");
} }
TEST_F(ParserImplTest, VariableStmt_Const_InvalidConstructor) { TEST_F(ParserImplTest, VariableStmt_Const_InvalidConstructor) {
auto* p = parser("const a : i32 = if (a) {}"); auto* p = parser("const a : i32 = if (a) {}");
auto e = p->variable_stmt(); auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error()); EXPECT_FALSE(e.matched);
ASSERT_EQ(e, nullptr); EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:17: missing constructor for const declaration"); EXPECT_EQ(p->error(), "1:17: missing constructor for const declaration");
} }

View File

@ -39,8 +39,10 @@ TEST_P(VariableStorageTest, Parses) {
auto* p = parser(std::string("<") + params.input + ">"); auto* p = parser(std::string("<") + params.input + ">");
auto sc = p->variable_storage_decoration(); auto sc = p->variable_storage_decoration();
ASSERT_FALSE(p->has_error()); EXPECT_FALSE(p->has_error());
EXPECT_EQ(sc, params.result); EXPECT_FALSE(sc.errored);
EXPECT_TRUE(sc.matched);
EXPECT_EQ(sc.value, params.result);
auto t = p->next(); auto t = p->next();
EXPECT_TRUE(t.IsEof()); EXPECT_TRUE(t.IsEof());
@ -64,24 +66,27 @@ INSTANTIATE_TEST_SUITE_P(
TEST_F(ParserImplTest, VariableStorageDecoration_NoMatch) { TEST_F(ParserImplTest, VariableStorageDecoration_NoMatch) {
auto* p = parser("<not-a-storage-class>"); auto* p = parser("<not-a-storage-class>");
auto sc = p->variable_storage_decoration(); auto sc = p->variable_storage_decoration();
ASSERT_EQ(sc, ast::StorageClass::kNone); EXPECT_TRUE(p->has_error());
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(sc.errored);
ASSERT_EQ(p->error(), "1:2: invalid storage class for variable decoration"); EXPECT_FALSE(sc.matched);
EXPECT_EQ(p->error(), "1:2: invalid storage class for variable decoration");
} }
TEST_F(ParserImplTest, VariableStorageDecoration_Empty) { TEST_F(ParserImplTest, VariableStorageDecoration_Empty) {
auto* p = parser("<>"); auto* p = parser("<>");
auto sc = p->variable_storage_decoration(); auto sc = p->variable_storage_decoration();
ASSERT_EQ(sc, ast::StorageClass::kNone); EXPECT_TRUE(p->has_error());
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(sc.errored);
ASSERT_EQ(p->error(), "1:2: invalid storage class for variable decoration"); EXPECT_FALSE(sc.matched);
EXPECT_EQ(p->error(), "1:2: invalid storage class for variable decoration");
} }
TEST_F(ParserImplTest, VariableStorageDecoration_MissingLessThan) { TEST_F(ParserImplTest, VariableStorageDecoration_MissingLessThan) {
auto* p = parser("in>"); auto* p = parser("in>");
auto sc = p->variable_storage_decoration(); auto sc = p->variable_storage_decoration();
ASSERT_EQ(sc, ast::StorageClass::kNone); EXPECT_FALSE(p->has_error());
ASSERT_FALSE(p->has_error()); EXPECT_FALSE(sc.errored);
EXPECT_FALSE(sc.matched);
auto t = p->next(); auto t = p->next();
ASSERT_TRUE(t.IsIn()); ASSERT_TRUE(t.IsIn());
@ -90,9 +95,10 @@ TEST_F(ParserImplTest, VariableStorageDecoration_MissingLessThan) {
TEST_F(ParserImplTest, VariableStorageDecoration_MissingGreaterThan) { TEST_F(ParserImplTest, VariableStorageDecoration_MissingGreaterThan) {
auto* p = parser("<in"); auto* p = parser("<in");
auto sc = p->variable_storage_decoration(); auto sc = p->variable_storage_decoration();
ASSERT_EQ(sc, ast::StorageClass::kNone); EXPECT_TRUE(p->has_error());
ASSERT_TRUE(p->has_error()); EXPECT_TRUE(sc.errored);
ASSERT_EQ(p->error(), "1:4: expected '>' for variable decoration"); EXPECT_FALSE(sc.matched);
EXPECT_EQ(p->error(), "1:4: expected '>' for variable decoration");
} }
} // namespace } // namespace