#include #include #include #include namespace pslang::parser { ast::statement_list_ptr finalize(indented_statement_list statements) { ast::statement_list_ptr result = std::make_unique(); using stack_entry = std::variant; std::vector stack; stack.push_back(result.get()); std::size_t current_indent = 0; std::size_t in_function_scope = 0; auto current_statement_list = [&](ast::location const & location) -> ast::statement_list * { if (stack.empty()) throw internal_error("Empty finilization stack"); if (auto list = std::get_if(&stack.back())) return *list; throw parse_error("Unexpected statement inside struct definition", location); }; auto current_struct_definition = [&](ast::location const & location) -> ast::struct_definition * { if (stack.empty()) throw internal_error("Empty finilization stack"); if (auto list = std::get_if(&stack.back())) return *list; 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 parse_error("Unexpected indent", location); while (statement.indentation < current_indent) { stack.pop_back(); --current_indent; if (in_function_scope > 0) --in_function_scope; } // Now statement.indentation == current_indent ast::statement_list * list = nullptr; bool is_function_definition = false; if (auto if_block = std::get_if(statement.statement.get())) { ast::if_chain chain; chain.location = if_block->location; chain.blocks.push_back({.condition = std::move(if_block->condition), .statements = std::make_unique()}); list = chain.blocks.back().statements.get(); current_statement_list(location)->statements.push_back(std::make_unique(std::move(chain))); } else if (auto else_block = std::get_if(statement.statement.get())) { if (current_statement_list(location)->statements.empty()) throw parse_error("Unexpected else block", location); auto chain = std::get_if(current_statement_list(location)->statements.back().get()); if (!chain || chain->blocks.empty() || !chain->blocks.back().condition) throw parse_error("Unexpected else block", location); chain->blocks.push_back({.condition = nullptr, .statements = std::make_unique()}); list = chain->blocks.back().statements.get(); } else if (auto else_if_block = std::get_if(statement.statement.get())) { if (current_statement_list(location)->statements.empty()) throw parse_error("Unexpected else if block", location); auto chain = std::get_if(current_statement_list(location)->statements.back().get()); if (!chain || chain->blocks.empty() || !chain->blocks.back().condition) throw parse_error("Unexpected else if block", location); chain->blocks.push_back({.condition = std::move(else_if_block->condition), .statements = std::make_unique()}); list = chain->blocks.back().statements.get(); } else if (auto while_block = std::get_if(statement.statement.get())) { while_block->statements = std::make_unique(); list = while_block->statements.get(); current_statement_list(location)->statements.push_back(std::move(statement.statement)); } else if (auto function_definition = std::get_if(statement.statement.get())) { function_definition->statements = std::make_unique(); list = function_definition->statements.get(); current_statement_list(location)->statements.push_back(std::move(statement.statement)); is_function_definition = true; } else if (auto field_definition = std::get_if(statement.statement.get())) { auto current = current_struct_definition(location); for (auto const & field : current->fields) if (field.name == field_definition->name) throw parse_error("Duplicate field definition: \"" + field.name + "\"", field.location); current->fields.push_back(*field_definition); } else if (std::get_if(statement.statement.get())) { current_statement_list(location)->statements.push_back(std::move(statement.statement)); stack.push_back(std::get_if(current_statement_list(location)->statements.back().get())); ++current_indent; if (in_function_scope > 0) ++in_function_scope; } else if (auto return_statement = std::get_if(statement.statement.get())) { if (in_function_scope == 0) throw parse_error("Return statement outside of function scope", return_statement->location); return_statement->level = stack.size() - in_function_scope; current_statement_list(location)->statements.push_back(std::move(statement.statement)); } else { current_statement_list(location)->statements.push_back(std::move(statement.statement)); } if (list) { stack.push_back(list); ++current_indent; if (in_function_scope > 0 || is_function_definition) ++in_function_scope; } } return result; } }