Skip to content

Commit c911686

Browse files
committed
Parse the entire program
1 parent d4c4366 commit c911686

File tree

9 files changed

+275
-4
lines changed

9 files changed

+275
-4
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ add_library(
126126
src/networkprotocoldsl/parser/grammar/traits.cpp
127127
src/networkprotocoldsl/parser/grammar/typeparameter.hpp
128128
src/networkprotocoldsl/parser/grammar/typeparameter.cpp
129+
src/networkprotocoldsl/parser/parse.hpp
130+
src/networkprotocoldsl/parser/parse.cpp
129131
src/networkprotocoldsl/parser/support/recursiveparser.cpp
130132
src/networkprotocoldsl/parser/support/recursiveparser.hpp
131133
src/networkprotocoldsl/parser/tree/booleanliteral.cpp

src/networkprotocoldsl/parser/grammar/message.hpp

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,52 @@ class Message
3131
return nullptr;
3232
}
3333
static MessageData *
34-
recurse_one(lexer::token::keyword::Message,
35-
std::shared_ptr<const tree::StringLiteral>,
36-
lexer::token::punctuation::CurlyBraceOpen,
37-
std::vector<std::shared_ptr<const tree::MessageDataPair>>) {
34+
recurse_maybe(lexer::token::keyword::Message,
35+
std::shared_ptr<const tree::StringLiteral>,
36+
lexer::token::punctuation::CurlyBraceOpen,
37+
std::vector<std::shared_ptr<const tree::MessageDataPair>>) {
3838
return nullptr;
3939
}
40+
static void
41+
partial_match(lexer::token::keyword::Message,
42+
std::shared_ptr<const tree::StringLiteral>,
43+
lexer::token::punctuation::CurlyBraceOpen,
44+
std::vector<std::shared_ptr<const tree::MessageDataPair>>,
45+
std::nullopt_t) {}
46+
47+
static ParseStateReturn
48+
match(TokenIterator begin, TokenIterator end, lexer::token::keyword::Message,
49+
std::shared_ptr<const tree::StringLiteral> messagename,
50+
lexer::token::punctuation::CurlyBraceOpen,
51+
std::vector<std::shared_ptr<const tree::MessageDataPair>> attributes,
52+
std::nullopt_t, lexer::token::punctuation::CurlyBraceClose) {
53+
auto message = std::make_shared<tree::Message>();
54+
message->name = messagename;
55+
message->data = std::make_shared<const tree::MessageData>();
56+
message->parts = std::make_shared<const tree::MessageSequence>();
57+
bool seen_when = false;
58+
bool seen_then = false;
59+
bool seen_agent = false;
60+
for (auto &attr : attributes) {
61+
if (attr->first == "when") {
62+
message->when = attr->second->name;
63+
seen_when = true;
64+
} else if (attr->first == "then") {
65+
message->then = attr->second->name;
66+
seen_then = true;
67+
} else if (attr->first == "agent") {
68+
message->agent = attr->second->name;
69+
seen_agent = true;
70+
}
71+
}
72+
if (!(seen_when && seen_then && seen_agent)) {
73+
return {std::nullopt, begin, end};
74+
} else {
75+
return {std::const_pointer_cast<const tree::Message>(message), begin,
76+
end};
77+
}
78+
}
79+
4080
static MessageParts *
4181
recurse_one(lexer::token::keyword::Message,
4282
std::shared_ptr<const tree::StringLiteral>,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#include <networkprotocoldsl/parser/grammar/protocoldescription.hpp>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef INCLUDED_NETWORKPROTOCOLDSL_PARSER_GRAMMAR_PROTOCOLDESCRIPTION_HPP
2+
#define INCLUDED_NETWORKPROTOCOLDSL_PARSER_GRAMMAR_PROTOCOLDESCRIPTION_HPP
3+
4+
#include <memory>
5+
#include <optional>
6+
#include <vector>
7+
8+
#include <networkprotocoldsl/parser/grammar/message.hpp>
9+
#include <networkprotocoldsl/parser/grammar/traits.hpp>
10+
#include <networkprotocoldsl/parser/support/recursiveparser.hpp>
11+
12+
#include <networkprotocoldsl/parser/tree/protocoldescription.hpp>
13+
14+
namespace networkprotocoldsl::parser::grammar {
15+
16+
class ProtocolDescription
17+
: public support::RecursiveParser<ProtocolDescription, ParseTraits,
18+
Tracer<ProtocolDescription>> {
19+
public:
20+
static constexpr const char *name = "ProtocolDescription";
21+
static Message *recurse_many() { return nullptr; };
22+
static ParseStateReturn
23+
match(TokenIterator begin, TokenIterator end,
24+
std::vector<std::shared_ptr<const tree::Message>> messages) {
25+
auto protocol_description = std::make_shared<tree::ProtocolDescription>();
26+
for (auto &message : messages) {
27+
protocol_description->emplace(message->name->value, message);
28+
}
29+
return {std::const_pointer_cast<const tree::ProtocolDescription>(
30+
protocol_description),
31+
begin, end};
32+
};
33+
};
34+
35+
} // namespace networkprotocoldsl::parser::grammar
36+
37+
#endif
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <networkprotocoldsl/parser/grammar/protocoldescription.hpp>
2+
#include <networkprotocoldsl/parser/parse.hpp>
3+
4+
namespace networkprotocoldsl::parser {
5+
6+
std::optional<std::shared_ptr<const tree::ProtocolDescription>>
7+
parse(const std::vector<lexer::Token> &tokens) {
8+
auto result =
9+
grammar::ProtocolDescription::parse(tokens.cbegin(), tokens.cend());
10+
if (result.begin != tokens.cend()) {
11+
return std::nullopt;
12+
}
13+
if (result.node.has_value()) {
14+
return std::get<std::shared_ptr<const tree::ProtocolDescription>>(
15+
result.node.value());
16+
} else {
17+
return std::nullopt;
18+
}
19+
}
20+
21+
} // namespace networkprotocoldsl::parser
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef INCLUDED_NETWORKPROTOCOLDSL_PARSER_PARSE_HPP
2+
#define INCLUDED_NETWORKPROTOCOLDSL_PARSER_PARSE_HPP
3+
4+
#include <memory>
5+
#include <optional>
6+
#include <vector>
7+
8+
#include <networkprotocoldsl/lexer/token.hpp>
9+
#include <networkprotocoldsl/parser/tree/protocoldescription.hpp>
10+
11+
namespace networkprotocoldsl::parser {
12+
13+
std::optional<std::shared_ptr<const tree::ProtocolDescription>>
14+
parse(const std::vector<lexer::Token> &tokens);
15+
16+
}
17+
18+
#endif

tests/023-grammar-complete.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <networkprotocoldsl/lexer/token.hpp>
2+
#include <networkprotocoldsl/lexer/tokenize.hpp>
3+
#include <networkprotocoldsl/parser/parse.hpp>
4+
5+
#include <fstream>
6+
#include <gtest/gtest.h>
7+
#include <iostream>
8+
#include <memory>
9+
#include <vector>
10+
11+
using namespace networkprotocoldsl;
12+
13+
TEST(MessageTest, Message) {
14+
std::string test_file =
15+
std::string(TEST_DATA_DIR) + "/023-source-code-http-client-server.txt";
16+
std::ifstream file(test_file);
17+
ASSERT_TRUE(file.is_open());
18+
std::string content((std::istreambuf_iterator<char>(file)),
19+
std::istreambuf_iterator<char>());
20+
file.close();
21+
auto maybe_tokens = lexer::tokenize(content);
22+
ASSERT_TRUE(maybe_tokens.has_value());
23+
std::vector<lexer::Token> &tokens = maybe_tokens.value();
24+
auto result = parser::parse(tokens);
25+
ASSERT_TRUE(result.has_value());
26+
auto protocol_description = result.value();
27+
ASSERT_EQ(3, protocol_description->size());
28+
29+
auto req = protocol_description->at("HTTP Request");
30+
ASSERT_EQ(8, req->parts->size());
31+
ASSERT_EQ(6, req->data->size());
32+
ASSERT_EQ("HTTP Request", req->name->value);
33+
ASSERT_EQ("Open", req->when->name);
34+
ASSERT_EQ("AwaitResponse", req->then->name);
35+
ASSERT_EQ("Client", req->agent->name);
36+
37+
auto res = protocol_description->at("HTTP Response");
38+
ASSERT_EQ(8, res->parts->size());
39+
ASSERT_EQ(6, res->data->size());
40+
ASSERT_EQ("HTTP Response", res->name->value);
41+
ASSERT_EQ("AwaitResponse", res->when->name);
42+
ASSERT_EQ("Open", res->then->name);
43+
ASSERT_EQ("Server", res->agent->name);
44+
45+
auto open = protocol_description->at("Client Closes Connection");
46+
ASSERT_EQ(0, open->parts->size());
47+
ASSERT_EQ(0, open->data->size());
48+
ASSERT_EQ("Client Closes Connection", open->name->value);
49+
ASSERT_EQ("Open", open->when->name);
50+
ASSERT_EQ("Closed", open->then->name);
51+
}

tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ foreach(
4040
020-grammar-tokenpart
4141
021-grammar-messagesequence
4242
022-grammar-message
43+
023-grammar-complete
4344
)
4445
add_executable(${TEST}.t ${TEST}.cpp)
46+
target_compile_definitions(${TEST}.t PRIVATE -DTEST_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data")
4547
target_link_libraries(
4648
${TEST}.t
4749
PUBLIC
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
message "HTTP Request" {
2+
when: Open;
3+
then: AwaitResponse;
4+
agent: Client;
5+
data: {
6+
method: str<encoding=Ascii7Bit,
7+
sizing=Dynamic,
8+
max_length=10>;
9+
request_target: str<encoding=Ascii7Bit,
10+
sizing=Dynamic,
11+
max_length=32768>;
12+
major_version: int<encoding=AsciiInt,
13+
unsigned=True,
14+
bits=8>;
15+
minor_version: int<encoding=AsciiInt,
16+
unsigned=True,
17+
bits=8>;
18+
headers: array<
19+
element_type=tuple<key=str<encoding=Ascii7Bit,
20+
sizing=Dynamic,
21+
max_length=32768>,
22+
value=str<encoding=Ascii7Bit,
23+
sizing=Dynamic,
24+
max_length=32768>>,
25+
sizing=Dynamic,
26+
max_length=100>;
27+
contents: stream;
28+
}
29+
parts {
30+
tokens { verb }
31+
terminator { " " }
32+
tokens { request_target }
33+
terminator { " " }
34+
tokens {
35+
"HTTP/" major_version "." minor_version
36+
}
37+
terminator { "\r\n" }
38+
for header in headers {
39+
tokens { header.key }
40+
terminator { ":" }
41+
tokens { header.value }
42+
terminator { "\r\n"}
43+
}
44+
terminator { "\r\n" }
45+
}
46+
}
47+
48+
message "HTTP Response" {
49+
when: AwaitResponse;
50+
then: Open;
51+
agent: Server;
52+
data: {
53+
major_version: int<encoding=AsciiInt,
54+
unsigned=True,
55+
bits=8>;
56+
minor_version: int<encoding=AsciiInt,
57+
unsigned=True,
58+
bits=8>;
59+
response_code: int<encoding=AsciiInt,
60+
unsigned=True,
61+
bits=16>;
62+
reason_phrase: str<encoding=Ascii7Bit,
63+
sizing=Dynamic,
64+
max_length=1024>;
65+
headers: array<
66+
element_type=tuple<key=str<encoding=Ascii7Bit,
67+
sizing=Dynamic,
68+
max_length=32768>,
69+
value=str<encoding=Ascii7Bit,
70+
sizing=Dynamic,
71+
max_length=32768>>,
72+
sizing=Dynamic,
73+
max_length=100>;
74+
contents: stream;
75+
}
76+
parts {
77+
tokens {
78+
"HTTP/" major_version "." minor_version
79+
}
80+
terminator { " " }
81+
tokens { response_code }
82+
terminator { " " }
83+
tokens { reason_phrase }
84+
terminator { "\r\n" }
85+
for header in headers {
86+
tokens { header.key }
87+
terminator { ":" }
88+
tokens { header.value }
89+
terminator { "\r\n"}
90+
}
91+
terminator { "\r\n" }
92+
}
93+
}
94+
95+
message "Client Closes Connection" {
96+
when: Open;
97+
then: Closed;
98+
agent: Client;
99+
}

0 commit comments

Comments
 (0)