wsgl parser: Add ParserImpl::Expect<T>

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

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

Also cleans up a bunch of code.

Bug: tint:282

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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