Skip to content

Commit 6cf9f8c

Browse files
Merge #983
983: Parse proper cfg values r=CohenArthur a=CohenArthur Closes #936 Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
2 parents e82b59d + f7ff602 commit 6cf9f8c

File tree

7 files changed

+154
-86
lines changed

7 files changed

+154
-86
lines changed

gcc/rust/lex/rust-lex.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ Lexer::Lexer (const char *filename, RAIIFile file_input, Linemap *linemap)
128128
token_queue (TokenSource (this))
129129
{
130130
// inform line_table that file is being entered and is in line 1
131-
line_map->start_file (filename, current_line);
131+
if (linemap)
132+
line_map->start_file (filename, current_line);
132133
}
133134

134135
Lexer::~Lexer ()
@@ -152,7 +153,11 @@ Lexer::~Lexer ()
152153
Location
153154
Lexer::get_current_location ()
154155
{
155-
return line_map->get_location (current_column);
156+
if (line_map)
157+
return line_map->get_location (current_column);
158+
else
159+
// If we have no linemap, we're lexing something without proper locations
160+
return Location ();
156161
}
157162

158163
int

gcc/rust/lex/rust-lex.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "rust-buffered-queue.h"
2424
#include "rust-token.h"
2525

26+
#include <cstdio>
2627
#include <utility>
2728
#include <tuple>
2829

@@ -49,6 +50,13 @@ struct RAIIFile
4950
file = fopen (filename, "r");
5051
}
5152

53+
/**
54+
* Create a RAIIFile from an existing instance of FILE*
55+
*/
56+
RAIIFile (FILE *raw, const char *filename = nullptr)
57+
: file (raw), filename (filename)
58+
{}
59+
5260
RAIIFile (const RAIIFile &other) = delete;
5361
RAIIFile &operator= (const RAIIFile &other) = delete;
5462

@@ -57,6 +65,7 @@ struct RAIIFile
5765
{
5866
other.file = nullptr;
5967
}
68+
6069
RAIIFile &operator= (RAIIFile &&other)
6170
{
6271
close ();
@@ -132,6 +141,19 @@ class Lexer
132141
Lexer (const char *filename, RAIIFile input, Linemap *linemap);
133142
~Lexer ();
134143

144+
/**
145+
* Lex the contents of a string instead of a file
146+
*/
147+
static Lexer lex_string (std::string input)
148+
{
149+
// We can perform this ugly cast to a non-const char* since we're only
150+
// *reading* the string. This would not be valid if we were doing any
151+
// modification to it.
152+
auto string_file = fmemopen (&input[0], input.length (), "r");
153+
154+
return Lexer (nullptr, RAIIFile (string_file), nullptr);
155+
}
156+
135157
// don't allow copy semantics (for now, at least)
136158
Lexer (const Lexer &other) = delete;
137159
Lexer &operator= (const Lexer &other) = delete;

gcc/rust/parse/rust-cfg-parser.cc

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,55 @@
11
#include "rust-cfg-parser.h"
2+
#include "rust-lex.h"
3+
#include "rust-parse.h"
4+
#include "rust-session-manager.h"
25
#include "selftest.h"
36

47
namespace Rust {
58
bool
6-
parse_cfg_option (const std::string &input, std::string &key,
7-
std::string &value)
9+
parse_cfg_option (std::string &input, std::string &key, std::string &value)
810
{
911
key.clear ();
1012
value.clear ();
1113

12-
auto equal = input.find ('=');
14+
auto lexer = Lexer::lex_string (input);
15+
auto parser = Parser<Lexer> (std::move (lexer));
1316

14-
// If there is no equal sign, it means there is no value. Clean up the key
15-
// and return
16-
if (equal == std::string::npos)
17+
auto token = parser.peek_current_token ();
18+
if (token->get_id () != IDENTIFIER)
1719
{
18-
key = input;
19-
20-
// FIXME: Make sure key is a proper identifier
21-
22-
return true;
20+
return false;
2321
}
2422

25-
key = input.substr (0, equal);
26-
27-
auto remaining_input = input.substr (equal + 1);
28-
if (remaining_input[0] != '"' || remaining_input.back () != '"')
29-
return false;
30-
31-
// Remove the quotes around the value, by advancing one character
32-
value = remaining_input.substr (1);
33-
// And trimming the rightmost character. This is fine since we've already
34-
// checked that both the first and last characters were quotes.
35-
value.resize (value.size () - 1);
23+
key = token->get_str ();
3624

37-
// FIXME: We need to sanitize here and make sure that both key and value
38-
// are proper identifiers
25+
rust_assert (parser.skip_token (IDENTIFIER));
26+
token = parser.peek_current_token ();
3927

40-
return true;
28+
switch (token->get_id ())
29+
{
30+
case END_OF_FILE:
31+
// we're done parsing, we had a valid key, return happily
32+
return true;
33+
case EQUAL:
34+
// We have an equal sign: Skip the token and parse an identifier
35+
{
36+
rust_assert (parser.skip_token (EQUAL));
37+
38+
auto value_expr = parser.parse_literal_expr ();
39+
// We had an equal sign but no value, error out
40+
if (!value_expr)
41+
return false;
42+
43+
if (value_expr->get_lit_type () != AST::Literal::LitType::STRING)
44+
return false;
45+
46+
value = value_expr->get_literal ().as_string ();
47+
return true;
48+
}
49+
default:
50+
return false;
51+
}
4152
}
42-
4353
} // namespace Rust
4454

4555
#if CHECKING_P
@@ -52,23 +62,49 @@ rust_cfg_parser_test (void)
5262
std::string key;
5363
std::string value;
5464

55-
ASSERT_TRUE (Rust::parse_cfg_option ("key-no-value", key, value));
56-
ASSERT_EQ (key, "key-no-value");
65+
auto input = std::string ("key_no_value");
66+
67+
ASSERT_TRUE (Rust::parse_cfg_option (input, key, value));
68+
ASSERT_EQ (key, "key_no_value");
5769
ASSERT_TRUE (value.empty ());
5870

59-
ASSERT_TRUE (Rust::parse_cfg_option ("k=\"v\"", key, value));
71+
input = std::string ("k=\"v\"");
72+
73+
ASSERT_TRUE (Rust::parse_cfg_option (input, key, value));
6074
ASSERT_EQ (key, "k");
6175
ASSERT_EQ (value, "v");
6276

6377
// values should be between double quotes
64-
ASSERT_FALSE (Rust::parse_cfg_option ("k=v", key, value));
78+
input = std::string ("k=v");
79+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
6580

6681
// No value is an error if there is an equal sign
67-
ASSERT_FALSE (Rust::parse_cfg_option ("k=", key, value));
82+
input = std::string ("k=");
83+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
6884

6985
// No key is an error
70-
ASSERT_FALSE (Rust::parse_cfg_option ("=", key, value));
71-
ASSERT_FALSE (Rust::parse_cfg_option ("=value", key, value));
86+
input = std::string ("=");
87+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
88+
89+
input = std::string ("=value");
90+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
91+
92+
// values that are not string literals are an error
93+
input = std::string ("key=b\"a\"");
94+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
95+
96+
input = std::string ("key='v'");
97+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
98+
99+
input = std::string ("key=155");
100+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
101+
102+
input = std::string ("key=3.14");
103+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
104+
105+
// kebab case is not valid for an identifier
106+
input = std::string ("key-no-value");
107+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
72108
}
73109
} // namespace selftest
74110

gcc/rust/parse/rust-cfg-parser.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ namespace Rust {
4141
* @return false if the given input was invalid, true otherwise
4242
*/
4343
bool
44-
parse_cfg_option (const std::string &input, std::string &key,
45-
std::string &value);
44+
parse_cfg_option (std::string &input, std::string &key, std::string &value);
4645
} // namespace Rust
4746

4847
#if CHECKING_P

0 commit comments

Comments
 (0)