Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 56 additions & 42 deletions starlark/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,63 +272,77 @@ class Parser {
}

std::optional<Expression> parse_expression(Token &token) {
auto operand = parse_operand(token);
if (!operand) {
auto expr = parse_operand(token);
if (!expr) {
std::cerr << "Failed to parse operand.\n";
return std::nullopt;
}

auto next = next_token();
if (!next) {
// This is fine.
} else if (std::holds_alternative<token::LParen>(*next)) {
auto args = parse_argument_list();
if (!args) {
std::cerr << "Failed to parse argument list.\n";
return std::nullopt;
}

return CallExpr{
.target = std::make_shared<Expression>(std::move(*operand)),
.args = std::move(*args),
};
} else if (std::holds_alternative<token::LBracket>(*next)) {
next = next_token();
while (true) {
auto next = next_token();
if (!next) {
std::cerr << "Unexpected end of input after '['.\n";
return std::nullopt;
return expr;
}

auto index_expr = parse_expression(*next);
if (!index_expr) {
std::cerr << "Failed to parse index expression.\n";
return std::nullopt;
if (std::holds_alternative<token::LParen>(*next)) {
auto args = parse_argument_list();
if (!args) {
std::cerr << "Failed to parse argument list.\n";
return std::nullopt;
}

expr = CallExpr{
.target = std::make_shared<Expression>(std::move(*expr)),
.args = std::move(*args),
};

continue;
}

if (!expect_next_token(token::RBracket{})) {
return std::nullopt;
if (std::holds_alternative<token::LBracket>(*next)) {
next = next_token();
if (!next) {
std::cerr << "Unexpected end of input after '['.\n";
return std::nullopt;
}

auto index_expr = parse_expression(*next);
if (!index_expr) {
std::cerr << "Failed to parse index expression.\n";
return std::nullopt;
}

if (!expect_next_token(token::RBracket{})) {
return std::nullopt;
}

expr = SliceExpr{
.target = std::make_shared<Expression>(std::move(*expr)),
.index = std::make_shared<Expression>(std::move(*index_expr)),
};

continue;
}

return SliceExpr{
.target = std::make_shared<Expression>(std::move(*operand)),
.index = std::make_shared<Expression>(std::move(*index_expr)),
};
} else if (std::holds_alternative<token::Dot>(*next)) {
auto member_token = next_token();
if (!member_token || !std::holds_alternative<token::Identifier>(*member_token)) {
std::cerr << "Expected identifier after '.'.\n";
return std::nullopt;
if (std::holds_alternative<token::Dot>(*next)) {
auto member_token = next_token();
if (!member_token || !std::holds_alternative<token::Identifier>(*member_token)) {
std::cerr << "Expected identifier after '.'.\n";
return std::nullopt;
}

expr = MemberExpr{
.target = std::make_shared<Expression>(std::move(*expr)),
.member = Identifier{.name = std::get<token::Identifier>(*member_token).name},
};

continue;
}

return MemberExpr{
.target = std::make_shared<Expression>(std::move(*operand)),
.member = Identifier{.name = std::get<token::Identifier>(*member_token).name},
};
} else {
// We didn't end up using the next token, so put it back for later.
reconsume(std::move(*next));
return expr;
}

return operand;
}

std::optional<std::vector<Argument>> parse_argument_list() {
Expand Down
33 changes: 33 additions & 0 deletions starlark/parser_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,39 @@ int main() {
},
},
},
{
"foo.baz[3].qux().bar",
starlark::Program{
.statements{
starlark::ExpressionStmt{
.expr{
starlark::MemberExpr{
.target = std::make_shared<starlark::Expression>(starlark::CallExpr{
.target =
std::make_shared<starlark::Expression>(starlark::MemberExpr{
.target = std::make_shared<
starlark::Expression>(starlark::SliceExpr{
.target = std::make_shared<starlark::Expression>(
starlark::MemberExpr{
.target =
std::make_shared<starlark::Expression>(
starlark::Identifier{"foo"}),
.member = starlark::Identifier{"baz"},
}),
.index = std::make_shared<starlark::Expression>(
starlark::IntLiteral{3}),
}),
.member = starlark::Identifier{"qux"},
}),
.args{},
}),
.member = starlark::Identifier{"bar"},
},
},
},
},
},
},
});

// TODO(robinlinden): Return error codes from parser and use that here.
Expand Down