Add source location to all AST nodes

This commit is contained in:
Nikita Lisitsa 2025-12-18 13:07:42 +03:00
parent 6a3835951f
commit 16680ad801
16 changed files with 204 additions and 70 deletions

View file

@ -1,6 +1,7 @@
#pragma once
#include <pslang/ast/expression_fwd.hpp>
#include <pslang/ast/location.hpp>
#include <vector>
@ -10,12 +11,14 @@ namespace pslang::ast
struct array
{
std::vector<expression_ptr> elements;
ast::location location;
};
struct array_access
{
expression_ptr array;
expression_ptr index;
ast::location location;
};
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <pslang/ast/expression_fwd.hpp>
#include <pslang/ast/location.hpp>
#include <pslang/type/type.hpp>
namespace pslang::ast
@ -10,6 +11,7 @@ namespace pslang::ast
{
expression_ptr expression;
type::type_ptr type;
ast::location location;
};
}

View file

@ -2,6 +2,7 @@
#include <pslang/ast/expression_fwd.hpp>
#include <pslang/ast/statement_fwd.hpp>
#include <pslang/ast/location.hpp>
namespace pslang::ast
{
@ -13,17 +14,20 @@ namespace pslang::ast
{
expression_ptr condition;
statement_list_ptr statements;
ast::location location;
};
struct else_block
{
statement_list_ptr statements;
ast::location location;
};
struct else_if_block
{
expression_ptr condition;
statement_list_ptr statements;
ast::location location;
};
// Interpreted as a consecutive "if -> else if -> else if -> else" chain
@ -38,12 +42,14 @@ namespace pslang::ast
};
std::vector<block> blocks;
ast::location location;
};
struct while_block
{
expression_ptr condition;
statement_list_ptr statements;
ast::location location;
};
}

View file

@ -1,5 +1,6 @@
#pragma once
#include <pslang/ast/location.hpp>
#include <pslang/ast/literal.hpp>
#include <pslang/ast/identifier.hpp>
#include <pslang/ast/operation.hpp>
@ -16,6 +17,7 @@ namespace pslang::ast
{
unary_operation_type type;
expression_ptr arg1;
ast::location location;
};
struct binary_operation
@ -23,6 +25,7 @@ namespace pslang::ast
binary_operation_type type;
expression_ptr arg1;
expression_ptr arg2;
ast::location location;
};
using expression_impl = std::variant<
@ -43,4 +46,6 @@ namespace pslang::ast
using expression_impl::expression_impl;
};
location get_location(expression const & expression);
}

View file

@ -2,6 +2,7 @@
#include <pslang/ast/statement_fwd.hpp>
#include <pslang/ast/expression_fwd.hpp>
#include <pslang/ast/location.hpp>
#include <pslang/type/type_fwd.hpp>
#include <string>
@ -16,18 +17,21 @@ namespace pslang::ast
{
std::string name;
type::type_ptr type;
ast::location location;
};
std::string name;
std::vector<argument> arguments;
type::type_ptr return_type;
statement_list_ptr statements;
ast::location location;
};
struct function_call
{
std::string name;
std::vector<expression_ptr> arguments;
ast::location location;
};
}

View file

@ -1,5 +1,7 @@
#pragma once
#include <pslang/ast/location.hpp>
#include <string>
namespace pslang::ast
@ -8,6 +10,7 @@ namespace pslang::ast
struct identifier
{
std::string name;
ast::location location;
};
}

View file

@ -1,5 +1,7 @@
#pragma once
#include <pslang/ast/location.hpp>
#include <variant>
#include <cstdint>
@ -10,6 +12,7 @@ namespace pslang::ast
struct numeric_literal_base
{
T value;
ast::location location;
};
using bool_literal = numeric_literal_base<bool>;

View file

@ -43,6 +43,15 @@ namespace pslang::ast
}
};
inline location merge(location const & l1,location const & l2)
{
return location {
.filename = l1.filename,
.begin = l1.begin,
.end = l2.end,
};
}
inline std::ostream & operator << (std::ostream & out, location const & location)
{
out << location.filename << ':' << location.begin.line << '.' << location.begin.column;

View file

@ -1,5 +1,6 @@
#pragma once
#include <pslang/ast/location.hpp>
#include <pslang/ast/expression.hpp>
#include <pslang/ast/value_category.hpp>
#include <pslang/ast/control.hpp>
@ -19,18 +20,21 @@ namespace pslang::ast
std::string name;
type::type_ptr type;
expression_ptr initializer;
ast::location location;
};
struct assignment
{
expression_ptr lhs;
expression_ptr rhs;
ast::location location;
};
struct return_statement
{
// can be null, which means "return unit"
expression_ptr value;
ast::location location;
};
using statement_impl = std::variant<
@ -54,4 +58,6 @@ namespace pslang::ast
using statement_impl::statement_impl;
};
location get_location(statement const & statement);
}

View file

@ -2,6 +2,7 @@
#include <pslang/type/type_fwd.hpp>
#include <pslang/ast/expression_fwd.hpp>
#include <pslang/ast/location.hpp>
#include <string>
#include <vector>
@ -13,18 +14,21 @@ namespace pslang::ast
{
std::string name;
type::type_ptr type;
ast::location location;
};
struct struct_definition
{
std::string name;
std::vector<field_definition> fields;
ast::location location;
};
struct field_access
{
expression_ptr object;
std::string field_name;
ast::location location;
};
}

View file

@ -0,0 +1,38 @@
#include <pslang/ast/expression.hpp>
namespace pslang::ast
{
namespace
{
template <typename T>
location get_location_impl(numeric_literal_base<T> const & expression)
{
return expression.location;
}
location get_location_impl(literal const & expression)
{
return std::visit([](auto const & expression){ return get_location_impl(expression); }, expression);
}
template <typename Expression>
location get_location_impl(Expression const & expression)
{
return expression.location;
}
location get_location_impl(expression const & expression)
{
return std::visit([](auto const & expression){ return get_location_impl(expression); }, expression);
}
}
location get_location(expression const & expression)
{
return get_location_impl(expression);
}
}

View file

@ -0,0 +1,32 @@
#include <pslang/ast/statement.hpp>
namespace pslang::ast
{
namespace
{
location get_location_impl(expression_ptr const & statement)
{
return get_location(*statement);
}
template <typename Statement>
location get_location_impl(Statement const & statement)
{
return statement.location;
}
location get_location_impl(statement const & statement)
{
return std::visit([](auto const & statement){ return get_location_impl(statement); }, statement);
}
}
location get_location(statement const & statement)
{
return get_location_impl(statement);
}
}

View file

@ -4,6 +4,8 @@
#include <pslang/ast/expression.hpp>
#include <pslang/type/print.hpp>
#include <pslang/parser/error.hpp>
#include <sstream>
#include <optional>

View file

@ -35,4 +35,20 @@ namespace pslang::parser
ast::location location_;
};
struct internal_error
: std::exception
{
internal_error(std::string message)
: message_(message)
{}
char const * what() const noexcept
{
return message_.c_str();
}
private:
std::string message_;
};
}

View file

@ -56,13 +56,13 @@ struct context;
YY_DECL;
template <typename T>
::pslang::ast::literal parse_numeric_literal(std::string const & str)
::pslang::ast::literal parse_numeric_literal(std::string const & str, ::pslang::ast::location const & location)
{
T value;
auto result = std::from_chars(str.data(), str.data() + str.size(), value);
if (result.ec != std::errc())
throw std::system_error(std::make_error_code(result.ec));
return ::pslang::ast::numeric_literal_base<T>{value};
return ::pslang::ast::numeric_literal_base<T>{value, location};
}
}
@ -185,17 +185,17 @@ indentation
statement
: expression { $$ = std::make_unique<ast::expression>($1); }
| expression assignment expression { $$ = ast::assignment{ std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| expression assignment expression { $$ = ast::assignment{ std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| variable_declaration { $$ = $1; }
| if expression colon { $$ = ast::if_block{std::make_unique<ast::expression>($2), {}}; }
| else colon { $$ = ast::else_block{{}}; }
| else if expression colon { $$ = ast::else_if_block{std::make_unique<ast::expression>($3), {}}; }
| while expression colon { $$ = ast::while_block{std::make_unique<ast::expression>($2), {}}; }
| func name lparen function_definition_argument_list rparen function_return_type colon { $$ = ast::function_definition{$2, $4, $6, {}}; }
| return expression { $$ = ast::return_statement{std::make_unique<ast::expression>($2)}; }
| return { $$ = ast::return_statement{nullptr}; }
| struct name colon { $$ = ast::struct_definition{$2, {}}; }
| name colon type_expression { $$ = ast::field_definition{$1, std::make_unique<type::type>($3)}; }
| if expression colon { $$ = ast::if_block{std::make_unique<ast::expression>($2), {}, @$}; }
| else colon { $$ = ast::else_block{{}, @$}; }
| else if expression colon { $$ = ast::else_if_block{std::make_unique<ast::expression>($3), {}, @$}; }
| while expression colon { $$ = ast::while_block{std::make_unique<ast::expression>($2), {}, @$}; }
| func name lparen function_definition_argument_list rparen function_return_type colon { $$ = ast::function_definition{$2, $4, $6, {}, @$}; }
| return expression { $$ = ast::return_statement{std::make_unique<ast::expression>($2), @$}; }
| return { $$ = ast::return_statement{nullptr, @$}; }
| struct name colon { $$ = ast::struct_definition{$2, {}, @$}; }
| name colon type_expression { $$ = ast::field_definition{$1, std::make_unique<type::type>($3), @$}; }
;
function_definition_argument_list
@ -204,7 +204,7 @@ function_definition_argument_list
;
nonempty_function_definition_argument_list
: name colon type_expression { std::vector<ast::function_definition::argument> tmp; tmp.push_back({.name = $1, .type = std::make_unique<type::type>($3)}); $$ = std::move(tmp); }
: name colon type_expression { std::vector<ast::function_definition::argument> tmp; tmp.push_back({.name = $1, .type = std::make_unique<type::type>($3), @$}); $$ = std::move(tmp); }
| nonempty_function_definition_argument_list comma name colon type_expression { auto tmp = $1; tmp.push_back({.name = $3, .type = std::make_unique<type::type>($5)}); $$ = std::move(tmp); }
;
@ -214,8 +214,8 @@ function_return_type
;
variable_declaration
: variable_keyword name assignment expression { $$ = ast::variable_declaration{$1, $2, nullptr, std::make_unique<ast::expression>($4)}; }
| variable_keyword name colon type_expression assignment expression { $$ = ast::variable_declaration{$1, $2, std::make_unique<type::type>($4), std::make_unique<ast::expression>($6)}; }
: variable_keyword name assignment expression { $$ = ast::variable_declaration{$1, $2, nullptr, std::make_unique<ast::expression>($4), @$}; }
| variable_keyword name colon type_expression assignment expression { $$ = ast::variable_declaration{$1, $2, std::make_unique<type::type>($4), std::make_unique<ast::expression>($6), @$}; }
;
variable_keyword
@ -251,61 +251,61 @@ expression
bool_expression
: compare_expression { $$ = $1; }
| bool_expression ampersand compare_expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_and, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| bool_expression vertical_bar compare_expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_or, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| bool_expression circumflex compare_expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_xor, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| bool_expression ampersand compare_expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_and, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| bool_expression vertical_bar compare_expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_or, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| bool_expression circumflex compare_expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_xor, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
;
compare_expression
: as_expression { $$ = $1; }
| compare_expression equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| compare_expression not_equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::not_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| compare_expression less as_expression { $$ = ast::binary_operation{ast::binary_operation_type::less, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| compare_expression greater as_expression { $$ = ast::binary_operation{ast::binary_operation_type::greater, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| compare_expression less_equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::less_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| compare_expression greater_equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::greater_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| compare_expression equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| compare_expression not_equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::not_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| compare_expression less as_expression { $$ = ast::binary_operation{ast::binary_operation_type::less, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| compare_expression greater as_expression { $$ = ast::binary_operation{ast::binary_operation_type::greater, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| compare_expression less_equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::less_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| compare_expression greater_equals as_expression { $$ = ast::binary_operation{ast::binary_operation_type::greater_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
;
as_expression
: negate_expression { $$ = $1; }
| negate_expression as type_expression { $$ = ast::cast_operation{ std::make_unique<ast::expression>($1), std::make_unique<type::type>($3) }; }
| negate_expression as type_expression { $$ = ast::cast_operation{ std::make_unique<ast::expression>($1), std::make_unique<type::type>($3), @$ }; }
;
negate_expression
: sum_expression { $$ = $1; }
| minus sum_expression { $$ = ast::unary_operation{ast::unary_operation_type::negation, std::make_unique<ast::expression>($2) }; }
| minus sum_expression { $$ = ast::unary_operation{ast::unary_operation_type::negation, std::make_unique<ast::expression>($2), @$ }; }
;
sum_expression
: mult_expression { $$ = $1; }
| sum_expression plus mult_expression { $$ = ast::binary_operation{ast::binary_operation_type::addition, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| sum_expression minus mult_expression { $$ = ast::binary_operation{ast::binary_operation_type::subtraction, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| sum_expression plus mult_expression { $$ = ast::binary_operation{ast::binary_operation_type::addition, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| sum_expression minus mult_expression { $$ = ast::binary_operation{ast::binary_operation_type::subtraction, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
;
mult_expression
: not_expression { $$ = $1; }
| mult_expression asterisk not_expression { $$ = ast::binary_operation{ast::binary_operation_type::multiplication, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| mult_expression slash not_expression { $$ = ast::binary_operation{ast::binary_operation_type::division, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| mult_expression percent not_expression { $$ = ast::binary_operation{ast::binary_operation_type::remainder, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3) }; }
| mult_expression asterisk not_expression { $$ = ast::binary_operation{ast::binary_operation_type::multiplication, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| mult_expression slash not_expression { $$ = ast::binary_operation{ast::binary_operation_type::division, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| mult_expression percent not_expression { $$ = ast::binary_operation{ast::binary_operation_type::remainder, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
;
not_expression
: postfix_expression
| exclamation postfix_expression { $$ = ast::unary_operation{ast::unary_operation_type::logical_not, std::make_unique<ast::expression>($2) }; }
| exclamation postfix_expression { $$ = ast::unary_operation{ast::unary_operation_type::logical_not, std::make_unique<ast::expression>($2), @$ }; }
;
postfix_expression
: base_expression
| postfix_expression lbracket expression rbracket { $$ = ast::array_access{std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3)}; }
| postfix_expression dot name { $$ = ast::field_access{std::make_unique<ast::expression>($1), $3}; }
| postfix_expression lbracket expression rbracket { $$ = ast::array_access{std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$}; }
| postfix_expression dot name { $$ = ast::field_access{std::make_unique<ast::expression>($1), $3, @$}; }
;
base_expression
: literal
| name { $$ = ast::identifier{$1}; }
| name { $$ = ast::identifier{$1, ctx.location}; }
| lparen expression rparen { $$ = $2; }
| name lparen comma_separated_expression_list rparen { $$ = ast::function_call{$1, $3}; }
| lbracket nonempty_comma_separated_expression_list rbracket { $$ = ast::array{$2}; }
| name lparen comma_separated_expression_list rparen { $$ = ast::function_call{$1, $3, @$}; }
| lbracket nonempty_comma_separated_expression_list rbracket { $$ = ast::array{$2, @$}; }
;
comma_separated_expression_list
@ -319,18 +319,18 @@ nonempty_comma_separated_expression_list
;
literal
: true { $$ = ast::literal(ast::bool_literal{true}); }
| false { $$ = ast::literal(ast::bool_literal{false}); }
| lit_i8 { $$ = parse_numeric_literal<std::int8_t>($1); }
| lit_u8 { $$ = parse_numeric_literal<std::uint8_t>($1); }
| lit_i16 { $$ = parse_numeric_literal<std::int16_t>($1); }
| lit_u16 { $$ = parse_numeric_literal<std::uint16_t>($1); }
| lit_i32 { $$ = parse_numeric_literal<std::int32_t>($1); }
| lit_u32 { $$ = parse_numeric_literal<std::uint32_t>($1); }
| lit_i64 { $$ = parse_numeric_literal<std::int64_t>($1); }
| lit_u64 { $$ = parse_numeric_literal<std::uint64_t>($1); }
| lit_f32 { $$ = parse_numeric_literal<float>($1); }
| lit_f64 { $$ = parse_numeric_literal<double>($1); }
: true { $$ = ast::literal(ast::bool_literal{true, ctx.location}); }
| false { $$ = ast::literal(ast::bool_literal{false, ctx.location}); }
| lit_i8 { $$ = parse_numeric_literal<std::int8_t>($1, ctx.location); }
| lit_u8 { $$ = parse_numeric_literal<std::uint8_t>($1, ctx.location); }
| lit_i16 { $$ = parse_numeric_literal<std::int16_t>($1, ctx.location); }
| lit_u16 { $$ = parse_numeric_literal<std::uint16_t>($1, ctx.location); }
| lit_i32 { $$ = parse_numeric_literal<std::int32_t>($1, ctx.location); }
| lit_u32 { $$ = parse_numeric_literal<std::uint32_t>($1, ctx.location); }
| lit_i64 { $$ = parse_numeric_literal<std::int64_t>($1, ctx.location); }
| lit_u64 { $$ = parse_numeric_literal<std::uint64_t>($1, ctx.location); }
| lit_f32 { $$ = parse_numeric_literal<float>($1, ctx.location); }
| lit_f64 { $$ = parse_numeric_literal<double>($1, ctx.location); }
;
%%

View file

@ -1,4 +1,5 @@
#include <pslang/parser/indented_statement.hpp>
#include <pslang/parser/error.hpp>
#include <pslang/ast/statement.hpp>
#include <stdexcept>
@ -93,18 +94,18 @@ namespace pslang::parser
stack.push_back(result.get());
std::size_t current_indent = 0;
auto current_statement_list = [&]() -> ast::statement_list *
auto current_statement_list = [&](ast::location const & location) -> ast::statement_list *
{
if (stack.empty())
throw std::runtime_error("Internal error: empty finilization stack");
throw internal_error("empty finilization stack");
if (auto list = std::get_if<ast::statement_list *>(&stack.back()))
return *list;
throw std::runtime_error("Unexpected statement inside struct definition");
throw parse_error("unexpected statement inside struct definition", location);
};
auto current_struct_definition = [&]() -> ast::struct_definition *
auto current_struct_definition = [&](ast::location const & location) -> ast::struct_definition *
{
if (stack.empty())
throw std::runtime_error("Internal error: empty finilization stack");
@ -112,15 +113,15 @@ namespace pslang::parser
if (auto list = std::get_if<ast::struct_definition *>(&stack.back()))
return *list;
throw std::runtime_error("Unexpected statement outside struct definition");
throw parse_error("unexpected statement outside struct definition", location);
};
for (auto & statement : statements.statements)
{
auto location = ast::get_location(*statement.statement);
if (statement.indentation > current_indent)
{
throw std::runtime_error("Unexpected indent");
}
throw parse_error("unexpected indent", location);
while (statement.indentation < current_indent)
{
@ -136,41 +137,41 @@ namespace pslang::parser
{
ast::if_chain chain;
chain.blocks.push_back({.condition = std::move(if_block->condition), .statements = std::move(if_block->statements)});
current_statement_list()->statements.push_back(std::make_unique<ast::statement>(std::move(chain)));
current_statement_list(location)->statements.push_back(std::make_unique<ast::statement>(std::move(chain)));
}
else if (auto else_block = std::get_if<ast::else_block>(statement.statement.get()))
{
if (current_statement_list()->statements.empty())
throw std::runtime_error("Unexpected else block");
auto chain = std::get_if<ast::if_chain>(current_statement_list()->statements.back().get());
if (current_statement_list(location)->statements.empty())
throw parse_error("unexpected else block", location);
auto chain = std::get_if<ast::if_chain>(current_statement_list(location)->statements.back().get());
if (!chain || chain->blocks.empty() || !chain->blocks.back().condition)
throw std::runtime_error("Unexpected else block");
throw parse_error("unexpected else block", location);
chain->blocks.push_back({.condition = nullptr, .statements = std::move(else_block->statements)});
}
else if (auto else_if_block = std::get_if<ast::else_if_block>(statement.statement.get()))
{
if (current_statement_list()->statements.empty())
throw std::runtime_error("Unexpected else if block");
auto chain = std::get_if<ast::if_chain>(current_statement_list()->statements.back().get());
if (current_statement_list(location)->statements.empty())
throw parse_error("unexpected else if block", location);
auto chain = std::get_if<ast::if_chain>(current_statement_list(location)->statements.back().get());
if (!chain || chain->blocks.empty() || !chain->blocks.back().condition)
throw std::runtime_error("Unexpected else if block");
throw parse_error("unexpected else if block", location);
chain->blocks.push_back({.condition = std::move(else_if_block->condition), .statements = std::move(else_if_block->statements)});
}
else if (auto field_definition = std::get_if<ast::field_definition>(statement.statement.get()))
{
current_struct_definition()->fields.push_back(*field_definition);
current_struct_definition(location)->fields.push_back(*field_definition);
}
else if (std::get_if<ast::struct_definition>(statement.statement.get()))
{
current_statement_list()->statements.push_back(std::move(statement.statement));
stack.push_back(std::get_if<ast::struct_definition>(current_statement_list()->statements.back().get()));
current_statement_list(location)->statements.push_back(std::move(statement.statement));
stack.push_back(std::get_if<ast::struct_definition>(current_statement_list(location)->statements.back().get()));
++current_indent;
}
else
{
current_statement_list()->statements.push_back(std::move(statement.statement));
current_statement_list(location)->statements.push_back(std::move(statement.statement));
}
if (list)