Skip to content
This repository was archived by the owner on Oct 12, 2026. It is now read-only.

Commit 7851236

Browse files
committed
chore: refactor parser APIs
1 parent 375637b commit 7851236

5 files changed

Lines changed: 91 additions & 85 deletions

File tree

‎include/lbd/frontend/parser.h‎

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,36 @@
99

1010
namespace frontend {
1111
struct Parser {
12-
// TODO: Make this private
13-
Program program;
12+
Program parse();
1413

15-
explicit Parser(const std::vector<token::Token> &tokens, context::Options options_ = {});
14+
explicit Parser(const std::vector<token::Token> &tokens, context::Options options = {});
1615

1716
private:
17+
const context::Options options;
18+
const std::vector<token::Token> &tokens;
19+
size_t index;
20+
1821
// TODO: Add checks for T to be a variant of frontend::TokenType
1922
template<typename T>
20-
static void assertToken(const std::vector<token::Token> &tokens, size_t &index);
23+
void assertToken();
2124

2225
template<typename T>
23-
static void assertAndConsume(const std::vector<token::Token> &tokens, size_t &index);
26+
void assertAndConsume();
2427

25-
static IdentifierAstNode consumeIdentifier(const std::vector<token::Token> &tokens, size_t &index);
28+
IdentifierAstNode consumeIdentifier();
2629

27-
static interpreter::type::PrimitiveType consumePrimitiveTypeName(
28-
const std::vector<token::Token> &tokens, size_t &index);
30+
interpreter::type::PrimitiveType consumePrimitiveTypeName();
2931

30-
static interpreter::type::Type parseType(const std::vector<token::Token> &tokens, size_t &index);
32+
interpreter::type::Type parseType();
3133

32-
static Expression parseExpression(const std::vector<token::Token> &tokens, size_t &index);
34+
Expression parseExpression();
3335

34-
static LambdaExpression parseLambdaExpression(const std::vector<token::Token> &tokens, size_t &index);
36+
LambdaExpression parseLambdaExpression();
3537

36-
static FunctionApplication parseFunctionApplication(const std::vector<token::Token> &tokens, size_t &index);
38+
FunctionApplication parseFunctionApplication();
3739

38-
static DefinitionAstNode parseDefinitionAstNode(const std::vector<token::Token> &tokens, size_t &index);
40+
DefinitionAstNode parseDefinitionAstNode();
3941

40-
static std::vector<AstNode> build(const std::vector<token::Token> &tokens, size_t &index);
42+
std::vector<AstNode> build();
4143
};
4244
}

‎src/frontend/parser.cpp‎

Lines changed: 65 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -7,42 +7,44 @@
77

88
namespace frontend {
99
static std::unordered_set<std::string> loadedFiles;
10-
static context::Options optionsValue;
1110

12-
Parser::Parser(const std::vector<token::Token> &tokens, const context::Options options_) {
13-
optionsValue = options_;
14-
size_t index = 0;
15-
program = Program{build(tokens, index)};
11+
Parser::Parser(const std::vector<token::Token> &tokens,
12+
const context::Options options) : options(options), tokens(tokens), index(0) {
13+
}
14+
15+
Program Parser::parse() {
16+
return Program{build()};
1617
}
1718

1819
template<typename T>
19-
void Parser::assertToken(const std::vector<token::Token> &tokens, size_t &index) {
20+
void Parser::assertToken() {
2021
if (const token::Token &currentToken = tokens[index]; !std::holds_alternative<T>(currentToken.tokenType)) {
21-
optionsValue.logger.error(currentToken.location, "syntax error: expected ", token::toString<T>(), ", got ",
22-
currentToken.toString());
22+
options.logger.error(currentToken.location, "syntax error: expected ", token::toString<T>(), ", got ",
23+
currentToken.toString());
2324
}
2425
}
2526

2627
template<typename T>
27-
void Parser::assertAndConsume(const std::vector<token::Token> &tokens, size_t &index) {
28-
assertToken<T>(tokens, index);
28+
void Parser::assertAndConsume() {
29+
assertToken<T>();
2930
++index;
3031
}
3132

32-
IdentifierAstNode Parser::consumeIdentifier(const std::vector<token::Token> &tokens, size_t &index) {
33-
assertToken<token::Identifier>(tokens, index);
33+
IdentifierAstNode Parser::consumeIdentifier() {
34+
assertToken<token::Identifier>();
3435
auto [value] = std::get<token::Identifier>(tokens[index].tokenType);
3536
const Location location = tokens[index].location;
3637
++index;
3738
return IdentifierAstNode{value, location};
3839
}
3940

4041
interpreter::type::PrimitiveType
41-
Parser::consumePrimitiveTypeName(const std::vector<token::Token> &tokens, size_t &index) {
42-
assertToken<token::Identifier>(tokens, index);
42+
Parser::consumePrimitiveTypeName() {
43+
assertToken<token::Identifier>();
4344
auto [value] = std::get<token::Identifier>(tokens[index].tokenType);
4445
Location location = tokens[index].location;
4546
++index;
47+
// TODO: Perform this check through interpreter::type package.
4648
if (value == "Float") {
4749
return interpreter::type::PrimitiveType{interpreter::type::PrimitiveType::Type::Float};
4850
}
@@ -55,12 +57,12 @@ namespace frontend {
5557
return interpreter::type::PrimitiveType{interpreter::type::PrimitiveType::Type::Custom, std::move(value)};
5658
}
5759

58-
interpreter::type::Type Parser::parseType(const std::vector<token::Token> &tokens, size_t &index) {
59-
interpreter::type::PrimitiveType typ = consumePrimitiveTypeName(tokens, index);
60+
interpreter::type::Type Parser::parseType() {
61+
interpreter::type::PrimitiveType typ = consumePrimitiveTypeName();
6062
std::vector types{typ};
6163
while (std::holds_alternative<token::Arrow>(tokens[index].tokenType)) {
62-
assertAndConsume<token::Arrow>(tokens, index);
63-
types.push_back(consumePrimitiveTypeName(tokens, index));
64+
assertAndConsume<token::Arrow>();
65+
types.push_back(consumePrimitiveTypeName());
6466
}
6567
if (types.size() == 1) {
6668
return typ;
@@ -76,96 +78,97 @@ namespace frontend {
7678
return currentType;
7779
}
7880

79-
Expression Parser::parseExpression(const std::vector<token::Token> &tokens, size_t &index) {
80-
const auto &tok = tokens[index];
81-
const Location location = tok.location;
81+
Expression Parser::parseExpression() {
82+
const auto &token = tokens[index];
83+
const Location location = token.location;
8284
return std::visit([&]<typename T0>(T0 &&) {
8385
using T = std::decay_t<T0>;
8486
if (std::is_same_v<T, token::Identifier>) {
8587
++index;
86-
const auto value = std::get<token::Identifier>(tok.tokenType).value;
88+
const auto value = std::get<token::Identifier>(token.tokenType).value;
8789
return Expression(IdentifierAstNode{value, location});
8890
}
8991
if (std::is_same_v<T, token::String>) {
9092
++index;
91-
const auto value = unescapeString(std::get<token::String>(tok.tokenType).value);
93+
const auto value = unescapeString(std::get<token::String>(token.tokenType).value);
9294
return Expression(StringAstNode{value, location});
9395
}
9496
if (std::is_same_v<T, token::Float>) {
9597
++index;
96-
const auto value = std::get<token::Float>(tok.tokenType).value;
98+
const auto value = std::get<token::Float>(token.tokenType).value;
9799
return Expression(FloatAstNode{value, location});
98100
}
99101
if (std::is_same_v<T, token::BackwardSlash>) {
100-
return Expression(parseLambdaExpression(tokens, index));
102+
return Expression(parseLambdaExpression());
101103
}
102104
if (std::is_same_v<T, token::OpenParenthesis>) {
103-
return Expression(parseFunctionApplication(tokens, index));
105+
return Expression(parseFunctionApplication());
104106
}
105-
optionsValue.logger.error(location, "syntax error: unexpected token ", tok.toString());
106-
}, tok.tokenType);
107+
options.logger.error(location, "syntax error: unexpected token ", token.toString());
108+
}, token.tokenType);
107109
}
108110

109-
LambdaExpression Parser::parseLambdaExpression(const std::vector<token::Token> &tokens, size_t &index) {
111+
LambdaExpression Parser::parseLambdaExpression() {
110112
Location location = tokens[index].location;
111-
assertAndConsume<token::BackwardSlash>(tokens, index);
112-
IdentifierAstNode argument = consumeIdentifier(tokens, index);
113-
assertAndConsume<token::Colon>(tokens, index);
114-
interpreter::type::Type argumentType = parseType(tokens, index);
115-
assertAndConsume<token::Dot>(tokens, index);
116-
Expression expression = parseExpression(tokens, index);
113+
assertAndConsume<token::BackwardSlash>();
114+
IdentifierAstNode argument = consumeIdentifier();
115+
assertAndConsume<token::Colon>();
116+
interpreter::type::Type argumentType = parseType();
117+
assertAndConsume<token::Dot>();
118+
Expression expression = parseExpression();
117119
return LambdaExpression{
118120
argument, argumentType, std::make_unique<Expression>(std::move(expression)), location
119121
};
120122
}
121123

122-
FunctionApplication Parser::parseFunctionApplication(const std::vector<token::Token> &tokens, size_t &index) {
124+
FunctionApplication Parser::parseFunctionApplication() {
123125
const Location location = tokens[index].location;
124-
assertAndConsume<token::OpenParenthesis>(tokens, index);
125-
const IdentifierAstNode functionName = consumeIdentifier(tokens, index);
126+
assertAndConsume<token::OpenParenthesis>();
127+
const IdentifierAstNode functionName = consumeIdentifier();
126128
std::vector<std::unique_ptr<Expression> > arguments;
127129
while (!std::holds_alternative<token::CloseParenthesis>(tokens[index].tokenType)) {
128-
arguments.push_back(std::make_unique<Expression>(std::move(parseExpression(tokens, index))));
130+
arguments.push_back(std::make_unique<Expression>(std::move(parseExpression())));
129131
}
130-
assertAndConsume<token::CloseParenthesis>(tokens, index);
132+
assertAndConsume<token::CloseParenthesis>();
131133
return FunctionApplication{functionName, std::move(arguments), location};
132134
}
133135

134-
DefinitionAstNode Parser::parseDefinitionAstNode(const std::vector<token::Token> &tokens, size_t &index) {
136+
DefinitionAstNode Parser::parseDefinitionAstNode() {
135137
Location location = tokens[index].location;
136-
IdentifierAstNode definitionName = consumeIdentifier(tokens, index);
137-
assertAndConsume<token::Colon>(tokens, index);
138-
interpreter::type::Type definitionType = parseType(tokens, index);
139-
assertAndConsume<token::Equal>(tokens, index);
140-
Expression expression = parseExpression(tokens, index);
138+
IdentifierAstNode definitionName = consumeIdentifier();
139+
assertAndConsume<token::Colon>();
140+
interpreter::type::Type definitionType = parseType();
141+
assertAndConsume<token::Equal>();
142+
Expression expression = parseExpression();
141143
return DefinitionAstNode{definitionName, definitionType, std::move(expression), location};
142144
}
143145

144-
static std::string getAbsolutePath(const std::string &path) {
145-
return std::filesystem::absolute(path).string();
146+
static std::string getAbsolutePath(const std::string &filepath) {
147+
return std::filesystem::absolute(filepath).string();
146148
}
147149

148-
static void processUseFile(std::vector<AstNode> &nodes, const std::string &filepath) {
150+
static void processUseFile(std::vector<AstNode> &astNodes, const std::string &filepath,
151+
const context::Options &options) {
149152
const std::string absolutePath = getAbsolutePath(filepath);
150153
if (loadedFiles.contains(absolutePath)) {
151154
// Circular Dependency or Duplicate Load
152155
return;
153156
}
154157
loadedFiles.insert(absolutePath);
155-
auto lexerValue = Lexer::fromFile(filepath, optionsValue);
158+
auto lexerValue = Lexer::fromFile(filepath, options);
156159
const auto tokens = lexerValue.lex();
157-
if (optionsValue.debug) {
160+
if (options.debug) {
158161
for (const auto &token: tokens) {
159-
optionsValue.logger.debug(token);
162+
options.logger.debug(token);
160163
}
161164
}
162-
for (Parser parser(tokens, optionsValue); auto &astNode: parser.program.astNodes) {
163-
nodes.emplace_back(std::move(astNode));
165+
for (auto [astastNodes] = Parser(tokens, options).parse(); auto &astNode: astastNodes) {
166+
astNodes.emplace_back(std::move(astNode));
164167
}
165168
}
166169

167-
std::vector<AstNode> Parser::build(const std::vector<token::Token> &tokens, size_t &index) {
168-
std::vector<AstNode> nodes;
170+
std::vector<AstNode> Parser::build() {
171+
std::vector<AstNode> astNodes;
169172
while (!std::holds_alternative<token::Eof>(tokens[index].tokenType)) {
170173
const token::Token &token = tokens[index];
171174
std::visit([&]<typename T0>(T0 &&) {
@@ -174,24 +177,24 @@ namespace frontend {
174177
if (const auto identifierValue = std::get<token::Identifier>(tokens[index].tokenType).value;
175178
identifierValue == "use") {
176179
++index; // consume "use"
177-
assertToken<token::String>(tokens, index);
180+
assertToken<token::String>();
178181
const std::string filepath = unescapeString(
179182
std::get<token::String>(tokens[index].tokenType).value);
180183
++index; // consume <filepath>
181-
processUseFile(nodes, filepath);
184+
processUseFile(astNodes, filepath, options);
182185
} else {
183-
nodes.push_back(AstNode{std::move(parseDefinitionAstNode(tokens, index))});
186+
astNodes.push_back(AstNode{std::move(parseDefinitionAstNode())});
184187
}
185188
} else if constexpr (std::is_same_v<T, token::String> ||
186189
std::is_same_v<T, token::Float> ||
187190
std::is_same_v<T, token::BackwardSlash> ||
188191
std::is_same_v<T, token::OpenParenthesis>) {
189-
nodes.push_back(AstNode{std::move(parseExpression(tokens, index))});
192+
astNodes.push_back(AstNode{std::move(parseExpression())});
190193
} else {
191-
optionsValue.logger.error(token.location, "syntax error: unexpected token ", token.toString());
194+
options.logger.error(token.location, "syntax error: unexpected token ", token.toString());
192195
}
193196
}, token.tokenType);
194197
}
195-
return nodes;
198+
return astNodes;
196199
}
197200
}

‎src/main.cpp‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ int main(const int argc, char **argv) {
2727
}
2828
}
2929
// Parse
30-
auto parser = frontend::Parser(tokens);
30+
auto program = frontend::Parser(tokens).parse();
3131
if (debug) {
32-
std::cout << parser.program << std::endl;
32+
std::cout << program << std::endl;
3333
}
3434
// Interpret
35-
auto result = interpreter::interpret(parser.program);
35+
auto result = interpreter::interpret(program);
3636
return EXIT_SUCCESS;
3737
}
3838
}

‎src/repl.cpp‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,17 @@ namespace repl {
3333
}
3434
}
3535

36-
frontend::Parser parser(tokens, subOptions);
36+
frontend::Program program = frontend::Parser(tokens, subOptions).parse();
3737
if (subOptions.debug) {
38-
for (const auto &node: parser.program.astNodes) {
38+
for (const auto &node: program.astNodes) {
3939
subOptions.logger.debug(node);
4040
}
4141
}
4242

4343
const std::optional<std::shared_ptr<interpreter::Environment> > temporaryEnvironment = sharedEnvironment;
4444
// Merge loaded_env into shared_env
4545
if (const auto [loadedEnvironment, _, resultantOptions] = interpreter::interpret(
46-
parser.program, temporaryEnvironment, subOptions); loadedEnvironment) {
46+
program, temporaryEnvironment, subOptions); loadedEnvironment) {
4747
if (!sharedEnvironment) {
4848
sharedEnvironment = loadedEnvironment;
4949
} else {
@@ -213,14 +213,14 @@ namespace repl {
213213
}
214214

215215
// Parse
216-
frontend::Parser parserValue(tokens, optionsValue);
216+
frontend::Program program = frontend::Parser(tokens, optionsValue).parse();
217217
if (optionsValue.debug) {
218-
optionsValue.logger.debug(parserValue.program);
218+
optionsValue.logger.debug(program);
219219
}
220220

221221
// Interpret
222222
const auto [globalEnvironment, value, resultantOptions] = interpreter::interpret(
223-
parserValue.program, sharedGlobalEnvironment, optionsValue);
223+
program, sharedGlobalEnvironment, optionsValue);
224224
if (resultantOptions.sideEffects) {
225225
std::cout << std::endl;
226226
}

‎tests/tests.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616

1717
# TODO: Also log the time taken.
18+
# TODO: Add tests for REPL.
1819

1920
def execCommand(command):
2021
return subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

0 commit comments

Comments
 (0)