From cc4b5bd811f176c43328cc900c29b2b773a7827e Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Mon, 27 Nov 2023 08:03:12 -0800 Subject: [PATCH] [Yunq] Add support for empty requests and responses. --- yunq/client.cpp.jinja | 13 ++++++++++++ yunq/client.h.jinja | 6 ++++++ yunq/example/example.yunq.client.cpp | 7 +++++++ yunq/example/example.yunq.client.h | 2 ++ yunq/example/example.yunq.cpp | 4 ++-- yunq/example/example.yunq.h | 8 +++---- yunq/example/example.yunq.server.cpp | 13 +++++++++--- yunq/example/example.yunq.server.h | 4 +++- yunq/parser.py | 31 +++++++++++++++++++--------- yunq/server.cpp.jinja | 19 +++++++++++++++-- yunq/server.h.jinja | 6 ++++++ 11 files changed, 91 insertions(+), 22 deletions(-) diff --git a/yunq/client.cpp.jinja b/yunq/client.cpp.jinja index 1364e62..7a88c90 100644 --- a/yunq/client.cpp.jinja +++ b/yunq/client.cpp.jinja @@ -8,7 +8,13 @@ {% for interface in interfaces %} {% for method in interface.methods %} +{% if method.request == None %} +glcr::ErrorCode {{interface.name}}Client::{{method.name}}({{method.response}}& response) { +{% elif method.response == None %} +glcr::ErrorCode {{interface.name}}Client::{{method.name}}(const {{method.request}}& request) { +{% else %} glcr::ErrorCode {{interface.name}}Client::{{method.name}}(const {{method.request}}& request, {{method.response}}& response) { +{% endif %} uint64_t buffer_size = kBufferSize; uint64_t cap_size = kCapBufferSize; @@ -17,7 +23,12 @@ glcr::ErrorCode {{interface.name}}Client::{{method.name}}(const {{method.request buffer_.WriteAt(8, {{loop.index0}}); cap_buffer_.Reset(); +{% if method.request == None %} + uint64_t length = 0; +{% else %} uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); +{% endif %} + buffer_.WriteAt(4, 16 + length); z_cap_t reply_port_cap; @@ -33,7 +44,9 @@ glcr::ErrorCode {{interface.name}}Client::{{method.name}}(const {{method.request // Check Response Code. RET_ERR(buffer_.At(8)); +{% if method.response != None %} response.ParseFromBytes(buffer_, 16, cap_buffer_); +{% endif %} return glcr::OK; } diff --git a/yunq/client.h.jinja b/yunq/client.h.jinja index 178210e..a1c2936 100644 --- a/yunq/client.h.jinja +++ b/yunq/client.h.jinja @@ -18,7 +18,13 @@ class {{interface.name}}Client { z_cap_t Capability() { return endpoint_; } {% for method in interface.methods %} + {% if method.request == None %} + [[nodiscard]] glcr::ErrorCode {{method.name}}({{method.response}}& response); + {% elif method.response == None %} + [[nodiscard]] glcr::ErrorCode {{method.name}}(const {{method.request}}& request); + {% else %} [[nodiscard]] glcr::ErrorCode {{method.name}}(const {{method.request}}& request, {{method.response}}& response); + {% endif %} {% endfor %} private: z_cap_t endpoint_; diff --git a/yunq/example/example.yunq.client.cpp b/yunq/example/example.yunq.client.cpp index 0189543..3c21e3b 100644 --- a/yunq/example/example.yunq.client.cpp +++ b/yunq/example/example.yunq.client.cpp @@ -8,7 +8,9 @@ + glcr::ErrorCode VFSClient::open(const OpenFileRequest& request, File& response) { + uint64_t buffer_size = kBufferSize; uint64_t cap_size = kCapBufferSize; @@ -17,7 +19,10 @@ glcr::ErrorCode VFSClient::open(const OpenFileRequest& request, File& response) buffer_.WriteAt(8, 0); cap_buffer_.Reset(); + uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); + + buffer_.WriteAt(4, 16 + length); z_cap_t reply_port_cap; @@ -33,8 +38,10 @@ glcr::ErrorCode VFSClient::open(const OpenFileRequest& request, File& response) // Check Response Code. RET_ERR(buffer_.At(8)); + response.ParseFromBytes(buffer_, 16, cap_buffer_); + return glcr::OK; } diff --git a/yunq/example/example.yunq.client.h b/yunq/example/example.yunq.client.h index 385ff66..b74cab5 100644 --- a/yunq/example/example.yunq.client.h +++ b/yunq/example/example.yunq.client.h @@ -17,7 +17,9 @@ class VFSClient { z_cap_t Capability() { return endpoint_; } + [[nodiscard]] glcr::ErrorCode open(const OpenFileRequest& request, File& response); + private: z_cap_t endpoint_; diff --git a/yunq/example/example.yunq.cpp b/yunq/example/example.yunq.cpp index 5e3fcff..eb8a025 100644 --- a/yunq/example/example.yunq.cpp +++ b/yunq/example/example.yunq.cpp @@ -44,9 +44,9 @@ void OpenFileRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint // Parse options. auto options_pointer = bytes.At(offset + header_size + (8 * 1)); - options_.Resize(options_pointer.length); + options_.Resize(options_pointer.length / sizeof(uint64_t)); for (uint64_t i = offset + options_pointer.offset; - i < offset + options_pointer.offset + (sizeof(uint64_t) * options_pointer.length); + i < offset + options_pointer.offset + options_pointer.length; i += sizeof(uint64_t)) { options_.PushBack(bytes.At(i)); } diff --git a/yunq/example/example.yunq.h b/yunq/example/example.yunq.h index 3c162f0..2c79cdb 100644 --- a/yunq/example/example.yunq.h +++ b/yunq/example/example.yunq.h @@ -17,7 +17,7 @@ class OpenFileRequest { void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const; uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; - glcr::String path() const { return path_; } + const glcr::String& path() const { return path_; } void set_path(const glcr::String& value) { path_ = value; } const glcr::Vector& options() const { return options_; } void add_options(const uint64_t& value) { options_.PushBack(value); } @@ -40,11 +40,11 @@ class File { void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const; uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; - glcr::String path() const { return path_; } + const glcr::String& path() const { return path_; } void set_path(const glcr::String& value) { path_ = value; } - uint64_t attrs() const { return attrs_; } + const uint64_t& attrs() const { return attrs_; } void set_attrs(const uint64_t& value) { attrs_ = value; } - z_cap_t mem_cap() const { return mem_cap_; } + const z_cap_t& mem_cap() const { return mem_cap_; } void set_mem_cap(const z_cap_t& value) { mem_cap_ = value; } private: diff --git a/yunq/example/example.yunq.server.cpp b/yunq/example/example.yunq.server.cpp index 8262388..51a592f 100644 --- a/yunq/example/example.yunq.server.cpp +++ b/yunq/example/example.yunq.server.cpp @@ -1,7 +1,7 @@ // Generated file -- DO NOT MODIFY. #include "example.yunq.server.h" -#include +#include #include namespace { @@ -87,12 +87,19 @@ glcr::ErrorCode VFSServerBase::HandleRequest(const glcr::ByteBuffer& request, switch(method_select) { case 0: { + + OpenFileRequest yunq_request; - File yunq_response; - yunq_request.ParseFromBytes(request, kHeaderSize, req_caps); + + + File yunq_response; + + + RET_ERR(Handleopen(yunq_request, yunq_response)); + resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps); break; diff --git a/yunq/example/example.yunq.server.h b/yunq/example/example.yunq.server.h index 71c9bab..e17a6f9 100644 --- a/yunq/example/example.yunq.server.h +++ b/yunq/example/example.yunq.server.h @@ -2,7 +2,7 @@ #pragma once #include -#include +#include #include #include "example.yunq.h" @@ -21,9 +21,11 @@ class VFSServerBase { [[nodiscard]] Thread RunServer(); + [[nodiscard]] virtual glcr::ErrorCode Handleopen(const OpenFileRequest&, File&) = 0; + private: z_cap_t endpoint_; diff --git a/yunq/parser.py b/yunq/parser.py index ef923bb..4e94fff 100644 --- a/yunq/parser.py +++ b/yunq/parser.py @@ -211,13 +211,20 @@ class Parser(): self.consume_check(LexemeType.LEFT_PAREN) - request = self.consume_identifier() + request = None + # FIXME: Fix error handling here (and for response). We want to show + # "expected rparen or identifier" if type is wrong rather than just + # "expected rparen". + if self.peektype() == LexemeType.NAME: + request = self.consume_identifier() self.consume_check(LexemeType.RIGHT_PAREN) self.consume_check(LexemeType.ARROW) self.consume_check(LexemeType.LEFT_PAREN) - response = self.consume_identifier() + response = None + if self.peektype() == LexemeType.NAME: + response = self.consume_identifier() self.consume_check(LexemeType.RIGHT_PAREN) self.consume_check(LexemeType.SEMICOLON) @@ -269,14 +276,18 @@ def type_check(decls: list[Decl]): for decl in decls: if type(decl) is Interface: for method in decl.methods: - if method.request not in name_dict.keys(): - sys.exit("Request type '%s' for '%s.%s' does not exist" % (method.request, decl.name, method.name)) - if type(name_dict[method.request]) is not Message: - sys.exit("Request type '%s' for '%s.%s' should be a message" % (method.request, decl.name, method.name)) - if method.response not in name_dict.keys(): - sys.exit("Response type '%s' for '%s.%s' does not exist" % (method.response, decl.name, method.name)) - if type(name_dict[method.response]) is not Message: - sys.exit("Response type '%s' for '%s.%s' should be a message" % (method.response, decl.name, method.name)) + if method.request is None and method.response is None: + sys.exit("Method '%s.%s' cannot have empty request and response" % (decl.name, method.name)) + if method.request is not None: + if method.request not in name_dict.keys(): + sys.exit("Request type '%s' for '%s.%s' does not exist" % (method.request, decl.name, method.name)) + if type(name_dict[method.request]) is not Message: + sys.exit("Request type '%s' for '%s.%s' should be a message" % (method.request, decl.name, method.name)) + if method.response is not None: + if method.response not in name_dict.keys(): + sys.exit("Response type '%s' for '%s.%s' does not exist" % (method.response, decl.name, method.name)) + if type(name_dict[method.response]) is not Message: + sys.exit("Response type '%s' for '%s.%s' should be a message" % (method.response, decl.name, method.name)) def print_ast(decls: list[Decl]): for decl in decls: diff --git a/yunq/server.cpp.jinja b/yunq/server.cpp.jinja index 6f215d4..66763e9 100644 --- a/yunq/server.cpp.jinja +++ b/yunq/server.cpp.jinja @@ -88,14 +88,29 @@ glcr::ErrorCode {{interface.name}}ServerBase::HandleRequest(const glcr::ByteBuff switch(method_select) { {%- for method in interface.methods %} case {{loop.index0}}: { + + {% if method.request != None %} {{method.request}} yunq_request; - {{method.response}} yunq_response; - yunq_request.ParseFromBytes(request, kHeaderSize, req_caps); + {% endif %} + {% if method.response != None %} + {{method.response}} yunq_response; + {% endif %} + + {% if method.request == None %} + RET_ERR(Handle{{method.name}}(yunq_response)); + {% elif method.response == None %} + RET_ERR(Handle{{method.name}}(yunq_request)); + {% else %} RET_ERR(Handle{{method.name}}(yunq_request, yunq_response)); + {% endif %} + {% if method.response != None %} resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps); + {% else %} + resp_length = 0; + {% endif %} break; } {%- endfor %} diff --git a/yunq/server.h.jinja b/yunq/server.h.jinja index 58e9232..74d0de7 100644 --- a/yunq/server.h.jinja +++ b/yunq/server.h.jinja @@ -21,7 +21,13 @@ class {{interface.name}}ServerBase { [[nodiscard]] Thread RunServer(); {% for method in interface.methods %} +{% if method.request == None %} + [[nodiscard]] virtual glcr::ErrorCode Handle{{method.name}}({{method.response}}&) = 0; +{% elif method.response == None %} + [[nodiscard]] virtual glcr::ErrorCode Handle{{method.name}}(const {{method.request}}&) = 0; +{% else %} [[nodiscard]] virtual glcr::ErrorCode Handle{{method.name}}(const {{method.request}}&, {{method.response}}&) = 0; +{% endif %} {% endfor %} private: