Skip to content

Commit

Permalink
Allow unnamed objects (like functions) at expression scope, see #193
Browse files Browse the repository at this point in the history
…comment thread

Sample test case:

```
print: (x:_) = {
    for x do :(elem:_) = {
        std::cout << elem << " ";
    }
}

main: ()->int = {
    print( : std::vector = (5,1); );
}
```
  • Loading branch information
hsutter committed Jan 7, 2023
1 parent 7606052 commit 1090a31
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 20 deletions.
24 changes: 20 additions & 4 deletions source/cppfront.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1655,14 +1655,30 @@ class cppfront

if (n.expr.index() == primary_expression_node::declaration)
{
// This must be an anonymous declaration
auto& decl = std::get<primary_expression_node::declaration>(n.expr);
assert(decl && !decl->identifier);

// The usual non-null assertion, plus it should be an anonymous function
assert(decl && !decl->identifier && decl->is(declaration_node::function));
// Handle an anonymous function
if (decl->is(declaration_node::function)) {
auto lambda_intro = build_capture_lambda_intro_for(decl->captures, n.position());
emit(*decl, lambda_intro);
}
// Else an anonymous object as 'typeid { initializer }'
else {
assert(decl->is(declaration_node::object));
auto& type_id = std::get<declaration_node::object>(decl->type);

printer.add_pad_in_this_line( -5 );

auto lambda_intro = build_capture_lambda_intro_for(decl->captures, n.position());
emit(*type_id);
printer.print_cpp2("{", decl->position());

emit(*decl, lambda_intro);
assert(decl->initializer);
emit(*decl->initializer, false);

printer.print_cpp2("}", decl->position());
}
}
}

Expand Down
32 changes: 16 additions & 16 deletions source/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,7 @@ struct declaration_node
source_position pos;
std::unique_ptr<unqualified_id_node> identifier;

enum active : std::uint8_t { function, object };
enum active : std::uint8_t { function, object, udt_type };
std::variant<
std::unique_ptr<function_type_node>,
std::unique_ptr<type_id_node>
Expand Down Expand Up @@ -1563,7 +1563,7 @@ class parser
}

if (curr().type() == lexeme::LeftParen
// If in the future (not now) we want to experiment with braced-expressions
// If in the future (not now) we decide to allow braced-expressions
// || curr().type() == lexeme::LeftBrace
)
{
Expand All @@ -1589,25 +1589,25 @@ class parser
return n;
}

if (auto decl = unnamed_declaration(curr().position(), true, true)) // captures are allowed
if (auto decl = unnamed_declaration(curr().position(), false, true)) // captures are allowed
{
assert (!decl->identifier && "ICE: declaration should have been unnamed");
if (!decl->is(declaration_node::function)) {
error("an unnamed declaration at expression scope must be a function");
if (decl->is(declaration_node::udt_type)) {
error("(temporary alpha limitation) an unnamed declaration at expression scope must be a function or an object");
next();
return {};
}
auto& func = std::get<declaration_node::function>(decl->type);
assert(func);
if (func->returns.index() == function_type_node::list) {
error("an unnamed function at expression scope currently cannot return multiple values");
next();
return {};
}
if (!func->contracts.empty()) {
error("an unnamed function at expression scope currently cannot have contracts");
next();
return {};
if (auto func = std::get_if<declaration_node::function>(&decl->type)) {
if ((*func)->returns.index() == function_type_node::list) {
error("an unnamed function at expression scope currently cannot return multiple values");
next();
return {};
}
if (!(*func)->contracts.empty()) {
error("an unnamed function at expression scope currently cannot have contracts");
next();
return {};
}
}

n->expr = std::move(decl);
Expand Down

0 comments on commit 1090a31

Please sign in to comment.