Fix filename tracking in locations & separate prelude location and full block location for AST nodes containing statement lists
This commit is contained in:
parent
3981b78b2d
commit
4b555c2ad4
10 changed files with 131 additions and 17 deletions
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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); }
|
||||||
|
|
|
||||||
|
|
@ -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), @$}; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue