[fidl][errors] Parse method error syntax
This adds support for the syntax introduced in FTP-014. The error type
information is carried up through to the flat AST but is not used when
compiling types to IR.
TEST=added compiler test and example
Change-Id: Iaf71052d2f3493a44a3917121ad3dfd21f61691e
diff --git a/system/host/fidl/examples/errors.fidl b/system/host/fidl/examples/errors.fidl
new file mode 100644
index 0000000..6958d19
--- /dev/null
+++ b/system/host/fidl/examples/errors.fidl
@@ -0,0 +1,18 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library fidl.examples.errors;
+
+enum ErrorCode : int32 {
+ kBad = 1;
+ kReallyBad = 2;
+ kOMGSoTerrible = 3;
+};
+
+interface EpicFail {
+ 1: IntegerError(string x) -> (string y) error int32;
+ 2: UnsignedError(string x) -> (string y) error uint32;
+ 3: EnumError(string x) -> (string y) error ErrorCode;
+ 4: EmptyResult(string x) -> () error ErrorCode;
+};
\ No newline at end of file
diff --git a/system/host/fidl/include/fidl/flat_ast.h b/system/host/fidl/include/fidl/flat_ast.h
index d33c990..c4740ab 100644
--- a/system/host/fidl/include/fidl/flat_ast.h
+++ b/system/host/fidl/include/fidl/flat_ast.h
@@ -773,10 +773,14 @@
Method(std::unique_ptr<raw::AttributeList> attributes,
std::unique_ptr<raw::Ordinal> ordinal, SourceLocation name,
Struct* maybe_request,
- Struct* maybe_response)
+ Struct* maybe_response,
+ std::unique_ptr<Type> maybe_error)
: attributes(std::move(attributes)), ordinal(std::move(ordinal)), name(std::move(name)),
- maybe_request(maybe_request), maybe_response(maybe_response) {
+ maybe_request(maybe_request), maybe_response(maybe_response), maybe_error(std::move(maybe_error)) {
assert(this->maybe_request != nullptr || this->maybe_response != nullptr);
+ if (maybe_error) {
+ assert(this->maybe_request != nullptr && this->maybe_response != nullptr);
+ }
}
std::unique_ptr<raw::AttributeList> attributes;
@@ -784,6 +788,7 @@
SourceLocation name;
Struct* maybe_request;
Struct* maybe_response;
+ std::unique_ptr<Type> maybe_error;
};
Interface(std::unique_ptr<raw::AttributeList> attributes, Name name,
diff --git a/system/host/fidl/include/fidl/raw_ast.h b/system/host/fidl/include/fidl/raw_ast.h
index b845646..4e74554 100644
--- a/system/host/fidl/include/fidl/raw_ast.h
+++ b/system/host/fidl/include/fidl/raw_ast.h
@@ -396,10 +396,12 @@
std::unique_ptr<Ordinal> ordinal,
std::unique_ptr<Identifier> identifier,
std::unique_ptr<ParameterList> maybe_request,
- std::unique_ptr<ParameterList> maybe_response)
+ std::unique_ptr<ParameterList> maybe_response,
+ std::unique_ptr<Type> maybe_error)
: SourceElement(element), attributes(std::move(attributes)),
ordinal(std::move(ordinal)), identifier(std::move(identifier)),
- maybe_request(std::move(maybe_request)), maybe_response(std::move(maybe_response)) {}
+ maybe_request(std::move(maybe_request)), maybe_response(std::move(maybe_response)),
+ maybe_error(std::move(maybe_error)) { }
void Accept(TreeVisitor& visitor);
@@ -408,6 +410,7 @@
std::unique_ptr<Identifier> identifier;
std::unique_ptr<ParameterList> maybe_request;
std::unique_ptr<ParameterList> maybe_response;
+ std::unique_ptr<Type> maybe_error;
};
class InterfaceDeclaration : public SourceElement {
diff --git a/system/host/fidl/include/fidl/token_definitions.inc b/system/host/fidl/include/fidl/token_definitions.inc
index 910666f..5ac14c7 100644
--- a/system/host/fidl/include/fidl/token_definitions.inc
+++ b/system/host/fidl/include/fidl/token_definitions.inc
@@ -62,6 +62,8 @@
KEYWORD(Table, "table")
KEYWORD(Union, "union")
+KEYWORD(Error, "error")
+
KEYWORD(True, "true")
KEYWORD(False, "false")
diff --git a/system/host/fidl/lib/flat_ast.cpp b/system/host/fidl/lib/flat_ast.cpp
index 9a53aa7..6fca0aa 100644
--- a/system/host/fidl/lib/flat_ast.cpp
+++ b/system/host/fidl/lib/flat_ast.cpp
@@ -1123,11 +1123,18 @@
return false;
}
+ std::unique_ptr<Type> maybe_error = nullptr;
+ if (method->maybe_error != nullptr) {
+ auto location = method->maybe_error->location();
+ if (!ConsumeType(std::move(method->maybe_error), location, &maybe_error))
+ return false;
+ }
+
assert(maybe_request != nullptr || maybe_response != nullptr);
methods.emplace_back(std::move(attributes),
std::move(ordinal_literal),
std::move(method_name), std::move(maybe_request),
- std::move(maybe_response));
+ std::move(maybe_response), std::move(maybe_error));
}
interface_declarations_.push_back(
diff --git a/system/host/fidl/lib/parser.cpp b/system/host/fidl/lib/parser.cpp
index eabed11..533813a 100644
--- a/system/host/fidl/lib/parser.cpp
+++ b/system/host/fidl/lib/parser.cpp
@@ -690,6 +690,7 @@
std::unique_ptr<raw::Identifier> method_name;
std::unique_ptr<raw::ParameterList> maybe_request;
std::unique_ptr<raw::ParameterList> maybe_response;
+ std::unique_ptr<raw::Type> maybe_error;
auto parse_params = [this](std::unique_ptr<raw::ParameterList>* params_out) {
ConsumeToken(OfKind(Token::Kind::kLeftParen));
@@ -722,6 +723,11 @@
return Fail();
if (!parse_params(&maybe_response))
return Fail();
+ if (MaybeConsumeToken(IdentifierOfSubkind(Token::Subkind::kError))) {
+ maybe_error = ParseType();
+ if (!Ok())
+ return Fail();
+ }
}
}
@@ -733,7 +739,8 @@
std::move(ordinal),
std::move(method_name),
std::move(maybe_request),
- std::move(maybe_response));
+ std::move(maybe_response),
+ std::move(maybe_error));
}
std::unique_ptr<raw::InterfaceDeclaration>
diff --git a/system/utest/fidl-compiler/errors_tests.cpp b/system/utest/fidl-compiler/errors_tests.cpp
new file mode 100644
index 0000000..202a46f
--- /dev/null
+++ b/system/utest/fidl-compiler/errors_tests.cpp
@@ -0,0 +1,87 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <unittest/unittest.h>
+
+#include "test_library.h"
+
+namespace {
+
+bool GoodError() {
+ BEGIN_TEST;
+
+ TestLibrary library(R"FIDL(
+library example;
+interface Example {
+ Method() -> (int32 flub) error int32;
+};
+)FIDL");
+ ASSERT_TRUE(library.Compile());
+
+ auto methods = &library.LookupInterface("Example")->methods;
+ ASSERT_EQ(methods->size(), 1);
+ auto method = &methods->at(0);
+ auto error_type = method->maybe_error.get();
+ ASSERT_NE(error_type, nullptr);
+ ASSERT_EQ(error_type->kind, fidl::flat::Type::Kind::kPrimitive);
+ auto primitive_type = static_cast<fidl::flat::PrimitiveType*>(error_type);
+ ASSERT_EQ(primitive_type->subtype, fidl::types::PrimitiveSubtype::kInt32);
+
+ END_TEST;
+}
+
+bool BadErrorMissingType() {
+ BEGIN_TEST;
+
+ TestLibrary library(R"FIDL(
+library example;
+interface Example {
+ Method() -> (int32 flub) error;
+};
+)FIDL");
+ ASSERT_FALSE(library.Compile());
+ auto errors = library.errors();
+ ASSERT_EQ(errors.size(), 1);
+ END_TEST;
+}
+
+bool BadErrorNotAType() {
+ BEGIN_TEST;
+
+ TestLibrary library(R"FIDL(
+library example;
+interface Example {
+ Method() -> (int32 flub) error "hello";
+};
+)FIDL");
+ ASSERT_FALSE(library.Compile());
+ auto errors = library.errors();
+ ASSERT_EQ(errors.size(), 1);
+ END_TEST;
+}
+
+bool BadErrorNoResponse() {
+ BEGIN_TEST;
+
+ TestLibrary library(R"FIDL(
+library example;
+interface Example {
+ Method() -> error int32;
+};
+)FIDL");
+ ASSERT_FALSE(library.Compile());
+ auto errors = library.errors();
+ ASSERT_EQ(errors.size(), 1);
+ END_TEST;
+}
+} // namespace
+
+BEGIN_TEST_CASE(errors_tests);
+
+RUN_TEST(GoodError);
+RUN_TEST(BadErrorMissingType);
+RUN_TEST(BadErrorNotAType);
+RUN_TEST(BadErrorNoResponse);
+
+END_TEST_CASE(errors_tests);
diff --git a/system/utest/fidl-compiler/rules.mk b/system/utest/fidl-compiler/rules.mk
index e8c92d3..2696fee 100644
--- a/system/utest/fidl-compiler/rules.mk
+++ b/system/utest/fidl-compiler/rules.mk
@@ -21,6 +21,7 @@
$(EXAMPLE_DIR)/empty.fidl \
$(EXAMPLE_DIR)/enums.fidl \
$(EXAMPLE_DIR)/events.fidl \
+ $(EXAMPLE_DIR)/errors.fidl \
$(EXAMPLE_DIR)/example-0.fidl \
$(EXAMPLE_DIR)/example-1.fidl \
$(EXAMPLE_DIR)/example-2.fidl \
@@ -65,6 +66,7 @@
$(LOCAL_DIR)/attributes_tests.cpp \
$(LOCAL_DIR)/consts_tests.cpp \
$(LOCAL_DIR)/enums_tests.cpp \
+ $(LOCAL_DIR)/errors_tests.cpp \
$(LOCAL_DIR)/flat_ast_tests.cpp \
$(LOCAL_DIR)/formatter_unittests.cpp \
$(LOCAL_DIR)/json_generator_tests.cpp \