Fix filename tracking in locations & separate prelude location and full block location for AST nodes containing statement lists

This commit is contained in:
Nikita Lisitsa 2026-03-14 00:48:46 +03:00
parent 3981b78b2d
commit 4b555c2ad4
10 changed files with 131 additions and 17 deletions

View file

@ -36,6 +36,8 @@ namespace pslang::ast
{ {
expression_ptr condition; expression_ptr condition;
statement_list_ptr statements; statement_list_ptr statements;
location prelude_location;
location location;
}; };
std::vector<block> blocks; std::vector<block> blocks;
@ -46,7 +48,8 @@ namespace pslang::ast
{ {
expression_ptr condition; expression_ptr condition;
statement_list_ptr statements; statement_list_ptr statements;
ast::location location; location prelude_location;
location location;
}; };
} }

View file

@ -13,10 +13,11 @@ namespace pslang::ast
{ {
error(std::string message, location location) error(std::string message, location location)
: message_(std::move(message)) : message_(std::move(message))
, filename_(location.filename) , filename_(location.begin.filename)
, location_(location) , location_(location)
{ {
location_.filename = filename_; location_.begin.filename = filename_;
location_.end.filename = filename_;
} }
char const * what() const noexcept char const * what() const noexcept

View file

@ -24,18 +24,21 @@ namespace pslang::ast
std::string name; std::string name;
std::vector<argument> arguments; std::vector<argument> arguments;
type_ptr return_type; type_ptr return_type;
ast::location location; ast::location prelude_location;
}; };
struct function_definition struct function_definition
: function_declaration : function_declaration
{ {
statement_list_ptr statements; statement_list_ptr statements;
ast::location location;
}; };
struct foreign_function_declaration struct foreign_function_declaration
: function_declaration : function_declaration
{}; {
ast::location location;
};
struct return_statement struct return_statement
{ {

View file

@ -10,11 +10,11 @@ namespace pslang::ast
{ {
struct position struct position
{ {
std::string_view filename = {};
std::size_t line = 1; std::size_t line = 1;
std::size_t column = 1; std::size_t column = 1;
}; };
std::string_view filename;
position begin = {}; position begin = {};
position end = {}; position end = {};
@ -46,7 +46,6 @@ namespace pslang::ast
inline location merge(location const & l1,location const & l2) inline location merge(location const & l1,location const & l2)
{ {
return location { return location {
.filename = l1.filename,
.begin = l1.begin, .begin = l1.begin,
.end = l2.end, .end = l2.end,
}; };
@ -54,7 +53,7 @@ namespace pslang::ast
inline std::ostream & operator << (std::ostream & out, location const & location) inline std::ostream & operator << (std::ostream & out, location const & location)
{ {
out << location.filename << ':' << location.begin.line << '.' << location.begin.column; out << location.begin.filename << ':' << location.begin.line << '.' << location.begin.column;
std::size_t end_column = std::max<std::size_t>(1, location.end.column) - 1; std::size_t end_column = std::max<std::size_t>(1, location.end.column) - 1;
if (location.begin.line < location.end.line) if (location.begin.line < location.end.line)

View file

@ -22,6 +22,7 @@ namespace pslang::ast
{ {
std::string name; std::string name;
std::vector<field_definition> fields; std::vector<field_definition> fields;
ast::location prelude_location;
ast::location location; ast::location location;
}; };

View file

@ -3,8 +3,6 @@
#include <pslang/ast/error.hpp> #include <pslang/ast/error.hpp>
#include <pslang/types/type.hpp> #include <pslang/types/type.hpp>
#include <iostream>
namespace pslang::ast namespace pslang::ast
{ {
@ -41,6 +39,7 @@ namespace pslang::ast
void apply(function_definition const & node) void apply(function_definition const & node)
{ {
apply(*node.statements);
if (!types::equal(*get_type(*node.return_type), types::unit_type{})) if (!types::equal(*get_type(*node.return_type), types::unit_type{}))
if (node.statements->statements.empty() || (true if (node.statements->statements.empty() || (true
&& !std::get_if<return_statement>(node.statements->statements.back().get()) && !std::get_if<return_statement>(node.statements->statements.back().get())

View file

@ -53,7 +53,7 @@ f64 { return bp::make_f64(ctx.location); }
[a-zA-Z_]+[a-zA-Z0-9_]* { return bp::make_name(yytext, ctx.location); } [a-zA-Z_]+[a-zA-Z0-9_]* { return bp::make_name(yytext, ctx.location); }
"\n" { ctx.location.move_lines(1); return bp::make_newline(ctx.location); } "\n" { auto old_location = ctx.location; ctx.location.move_lines(1); return bp::make_newline(old_location); }
"\t" { return bp::make_indent(ctx.location); } "\t" { return bp::make_indent(ctx.location); }
"=" { return bp::make_assignment(ctx.location); } "=" { return bp::make_assignment(ctx.location); }
":" { return bp::make_colon(ctx.location); } ":" { return bp::make_colon(ctx.location); }

View file

@ -211,12 +211,12 @@ statement
| if expression colon { $$ = ast::if_block{std::make_unique<ast::expression>($2), @$}; } | if expression colon { $$ = ast::if_block{std::make_unique<ast::expression>($2), @$}; }
| else colon { $$ = ast::else_block{@$}; } | else colon { $$ = ast::else_block{@$}; }
| else if expression colon { $$ = ast::else_if_block{std::make_unique<ast::expression>($3), @$}; } | 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), {}, @$}; } | while expression colon { $$ = ast::while_block{std::make_unique<ast::expression>($2), {}, @$, @$}; }
| func name lparen function_declaration_argument_list rparen function_return_type colon { $$ = ast::function_definition{{$2, $4, $6, @$}, {}}; } | func name lparen function_declaration_argument_list rparen function_return_type colon { $$ = ast::function_definition{{$2, $4, $6, @$}, {}}; }
| foreign func name lparen function_declaration_argument_list rparen function_return_type { $$ = ast::foreign_function_declaration{{$3, $5, $7, @$}}; } | foreign func name lparen function_declaration_argument_list rparen function_return_type { $$ = ast::foreign_function_declaration{{$3, $5, $7, @$}}; }
| return expression { $$ = ast::return_statement{std::make_unique<ast::expression>($2), @$}; } | return expression { $$ = ast::return_statement{std::make_unique<ast::expression>($2), @$}; }
| return { $$ = ast::return_statement{nullptr, @$}; } | return { $$ = ast::return_statement{nullptr, @$}; }
| struct name colon { $$ = ast::struct_definition{$2, {}, @$}; } | struct name colon { $$ = ast::struct_definition{$2, {}, @$, @$}; }
| name colon type_expression { $$ = ast::field_definition{$1, std::make_unique<ast::type>($3), @$}; } | name colon type_expression { $$ = ast::field_definition{$1, std::make_unique<ast::type>($3), @$}; }
; ;

View file

@ -1,12 +1,118 @@
#include <pslang/parser/indented_statement.hpp> #include <pslang/parser/indented_statement.hpp>
#include <pslang/parser/error.hpp> #include <pslang/parser/error.hpp>
#include <pslang/ast/statement.hpp> #include <pslang/ast/statement.hpp>
#include <pslang/ast/statement_visitor.hpp>
#include <vector> #include <vector>
namespace pslang::parser namespace pslang::parser
{ {
namespace
{
struct fill_location_visitor
: ast::statement_visitor<fill_location_visitor>
{
using statement_visitor::apply;
ast::location apply(ast::expression_ptr const & node)
{
return ast::get_location(node);
}
ast::location apply(ast::assignment const & node)
{
return node.location;
}
ast::location apply(ast::variable_declaration const & node)
{
return node.location;
}
ast::location apply(ast::if_block const & node)
{
return node.location;
}
ast::location apply(ast::else_block const & node)
{
return node.location;
}
ast::location apply(ast::else_if_block const & node)
{
return node.location;
}
ast::location apply(ast::if_chain & node)
{
bool first = true;
for (auto & block : node.blocks)
{
block.location = apply(*block.statements);
if (first)
node.location = block.location;
else
node.location = ast::merge(node.location, block.location);
first = false;
}
return node.location;
}
ast::location apply(ast::while_block & node)
{
return node.location = ast::merge(node.prelude_location, apply(*node.statements));
}
ast::location apply(ast::function_definition & node)
{
return node.location = ast::merge(node.prelude_location, apply(*node.statements));
}
ast::location apply(ast::foreign_function_declaration & node)
{
return node.location = node.prelude_location;
}
ast::location apply(ast::return_statement const & node)
{
return node.location;
}
ast::location apply(ast::field_definition const & node)
{
return node.location;
}
ast::location apply(ast::struct_definition & node)
{
node.location = node.prelude_location;
for (auto const & field : node.fields)
node.location = ast::merge(node.location, apply(field));
return node.location;
}
ast::location apply(ast::statement_list & list)
{
ast::location result;
bool first = true;
for (auto & statement : list.statements)
{
auto statement_location = apply(*statement);
if (first)
result = statement_location;
else
result = ast::merge(result, statement_location);
first = false;
}
return result;
}
};
}
ast::statement_list_ptr finalize(indented_statement_list statements) ast::statement_list_ptr finalize(indented_statement_list statements)
{ {
ast::statement_list_ptr result = std::make_unique<ast::statement_list>(); ast::statement_list_ptr result = std::make_unique<ast::statement_list>();
@ -64,7 +170,7 @@ namespace pslang::parser
{ {
ast::if_chain chain; ast::if_chain chain;
chain.location = if_block->location; chain.location = if_block->location;
chain.blocks.push_back({.condition = std::move(if_block->condition), .statements = std::make_unique<ast::statement_list>()}); chain.blocks.push_back({.condition = std::move(if_block->condition), .statements = std::make_unique<ast::statement_list>(), .prelude_location = if_block->location});
list = chain.blocks.back().statements.get(); list = chain.blocks.back().statements.get();
current_statement_list(location)->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)));
} }
@ -76,7 +182,7 @@ namespace pslang::parser
if (!chain || chain->blocks.empty() || !chain->blocks.back().condition) if (!chain || chain->blocks.empty() || !chain->blocks.back().condition)
throw parse_error("Unexpected else block", location); throw parse_error("Unexpected else block", location);
chain->blocks.push_back({.condition = nullptr, .statements = std::make_unique<ast::statement_list>()}); chain->blocks.push_back({.condition = nullptr, .statements = std::make_unique<ast::statement_list>(), .prelude_location = else_block->location});
list = chain->blocks.back().statements.get(); list = chain->blocks.back().statements.get();
} }
else if (auto else_if_block = std::get_if<ast::else_if_block>(statement.statement.get())) else if (auto else_if_block = std::get_if<ast::else_if_block>(statement.statement.get()))
@ -87,7 +193,7 @@ namespace pslang::parser
if (!chain || chain->blocks.empty() || !chain->blocks.back().condition) if (!chain || chain->blocks.empty() || !chain->blocks.back().condition)
throw parse_error("Unexpected else if block", location); throw parse_error("Unexpected else if block", location);
chain->blocks.push_back({.condition = std::move(else_if_block->condition), .statements = std::make_unique<ast::statement_list>()}); chain->blocks.push_back({.condition = std::move(else_if_block->condition), .statements = std::make_unique<ast::statement_list>(), .prelude_location = else_if_block->location});
list = chain->blocks.back().statements.get(); list = chain->blocks.back().statements.get();
} }
else if (auto while_block = std::get_if<ast::while_block>(statement.statement.get())) else if (auto while_block = std::get_if<ast::while_block>(statement.statement.get()))
@ -140,6 +246,8 @@ namespace pslang::parser
} }
} }
fill_location_visitor{}.apply(*result);
return result; return result;
} }

View file

@ -14,7 +14,7 @@ namespace pslang::parser
if (!yyin) if (!yyin)
throw std::system_error(std::make_error_code(static_cast<std::errc>(errno))); throw std::system_error(std::make_error_code(static_cast<std::errc>(errno)));
ast::location location{path}; ast::location location{.begin = {.filename = path}, .end = {.filename = path}};
indented_statement_list result; indented_statement_list result;
context ctx{location, result}; context ctx{location, result};