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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <pslang/ast/location.hpp>
#include <pslang/ast/literal.hpp> #include <pslang/ast/literal.hpp>
#include <pslang/ast/identifier.hpp> #include <pslang/ast/identifier.hpp>
#include <pslang/ast/operation.hpp> #include <pslang/ast/operation.hpp>
@ -16,6 +17,7 @@ namespace pslang::ast
{ {
unary_operation_type type; unary_operation_type type;
expression_ptr arg1; expression_ptr arg1;
ast::location location;
}; };
struct binary_operation struct binary_operation
@ -23,6 +25,7 @@ namespace pslang::ast
binary_operation_type type; binary_operation_type type;
expression_ptr arg1; expression_ptr arg1;
expression_ptr arg2; expression_ptr arg2;
ast::location location;
}; };
using expression_impl = std::variant< using expression_impl = std::variant<
@ -43,4 +46,6 @@ namespace pslang::ast
using expression_impl::expression_impl; 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/statement_fwd.hpp>
#include <pslang/ast/expression_fwd.hpp> #include <pslang/ast/expression_fwd.hpp>
#include <pslang/ast/location.hpp>
#include <pslang/type/type_fwd.hpp> #include <pslang/type/type_fwd.hpp>
#include <string> #include <string>
@ -16,18 +17,21 @@ namespace pslang::ast
{ {
std::string name; std::string name;
type::type_ptr type; type::type_ptr type;
ast::location location;
}; };
std::string name; std::string name;
std::vector<argument> arguments; std::vector<argument> arguments;
type::type_ptr return_type; type::type_ptr return_type;
statement_list_ptr statements; statement_list_ptr statements;
ast::location location;
}; };
struct function_call struct function_call
{ {
std::string name; std::string name;
std::vector<expression_ptr> arguments; std::vector<expression_ptr> arguments;
ast::location location;
}; };
} }

View file

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

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <pslang/ast/location.hpp>
#include <variant> #include <variant>
#include <cstdint> #include <cstdint>
@ -10,6 +12,7 @@ namespace pslang::ast
struct numeric_literal_base struct numeric_literal_base
{ {
T value; T value;
ast::location location;
}; };
using bool_literal = numeric_literal_base<bool>; 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) inline std::ostream & operator << (std::ostream & out, location const & location)
{ {
out << location.filename << ':' << location.begin.line << '.' << location.begin.column; out << location.filename << ':' << location.begin.line << '.' << location.begin.column;

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <pslang/ast/location.hpp>
#include <pslang/ast/expression.hpp> #include <pslang/ast/expression.hpp>
#include <pslang/ast/value_category.hpp> #include <pslang/ast/value_category.hpp>
#include <pslang/ast/control.hpp> #include <pslang/ast/control.hpp>
@ -19,18 +20,21 @@ namespace pslang::ast
std::string name; std::string name;
type::type_ptr type; type::type_ptr type;
expression_ptr initializer; expression_ptr initializer;
ast::location location;
}; };
struct assignment struct assignment
{ {
expression_ptr lhs; expression_ptr lhs;
expression_ptr rhs; expression_ptr rhs;
ast::location location;
}; };
struct return_statement struct return_statement
{ {
// can be null, which means "return unit" // can be null, which means "return unit"
expression_ptr value; expression_ptr value;
ast::location location;
}; };
using statement_impl = std::variant< using statement_impl = std::variant<
@ -54,4 +58,6 @@ namespace pslang::ast
using statement_impl::statement_impl; 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/type/type_fwd.hpp>
#include <pslang/ast/expression_fwd.hpp> #include <pslang/ast/expression_fwd.hpp>
#include <pslang/ast/location.hpp>
#include <string> #include <string>
#include <vector> #include <vector>
@ -13,18 +14,21 @@ namespace pslang::ast
{ {
std::string name; std::string name;
type::type_ptr type; type::type_ptr type;
ast::location location;
}; };
struct struct_definition struct struct_definition
{ {
std::string name; std::string name;
std::vector<field_definition> fields; std::vector<field_definition> fields;
ast::location location;
}; };
struct field_access struct field_access
{ {
expression_ptr object; expression_ptr object;
std::string field_name; 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/ast/expression.hpp>
#include <pslang/type/print.hpp> #include <pslang/type/print.hpp>
#include <pslang/parser/error.hpp>
#include <sstream> #include <sstream>
#include <optional> #include <optional>

View file

@ -35,4 +35,20 @@ namespace pslang::parser
ast::location location_; 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; YY_DECL;
template <typename T> 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; T value;
auto result = std::from_chars(str.data(), str.data() + str.size(), value); auto result = std::from_chars(str.data(), str.data() + str.size(), value);
if (result.ec != std::errc()) if (result.ec != std::errc())
throw std::system_error(std::make_error_code(result.ec)); 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 statement
: expression { $$ = std::make_unique<ast::expression>($1); } : 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; } | variable_declaration { $$ = $1; }
| 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_definition_argument_list rparen function_return_type colon { $$ = ast::function_definition{$2, $4, $6, {}}; } | 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 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<type::type>($3)}; } | name colon type_expression { $$ = ast::field_definition{$1, std::make_unique<type::type>($3), @$}; }
; ;
function_definition_argument_list function_definition_argument_list
@ -204,7 +204,7 @@ function_definition_argument_list
; ;
nonempty_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); } | 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_declaration
: variable_keyword name assignment expression { $$ = ast::variable_declaration{$1, $2, nullptr, std::make_unique<ast::expression>($4)}; } : 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 colon type_expression assignment expression { $$ = ast::variable_declaration{$1, $2, std::make_unique<type::type>($4), std::make_unique<ast::expression>($6), @$}; }
; ;
variable_keyword variable_keyword
@ -251,61 +251,61 @@ expression
bool_expression bool_expression
: compare_expression { $$ = $1; } : 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 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 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 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 compare_expression
: as_expression { $$ = $1; } : 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 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 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 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 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 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 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 as_expression
: negate_expression { $$ = $1; } : 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 negate_expression
: sum_expression { $$ = $1; } : 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 sum_expression
: mult_expression { $$ = $1; } : 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 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 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 mult_expression
: not_expression { $$ = $1; } : 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 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 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 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 not_expression
: postfix_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 postfix_expression
: base_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 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 dot name { $$ = ast::field_access{std::make_unique<ast::expression>($1), $3, @$}; }
; ;
base_expression base_expression
: literal : literal
| name { $$ = ast::identifier{$1}; } | name { $$ = ast::identifier{$1, ctx.location}; }
| lparen expression rparen { $$ = $2; } | lparen expression rparen { $$ = $2; }
| name lparen comma_separated_expression_list rparen { $$ = ast::function_call{$1, $3}; } | name lparen comma_separated_expression_list rparen { $$ = ast::function_call{$1, $3, @$}; }
| lbracket nonempty_comma_separated_expression_list rbracket { $$ = ast::array{$2}; } | lbracket nonempty_comma_separated_expression_list rbracket { $$ = ast::array{$2, @$}; }
; ;
comma_separated_expression_list comma_separated_expression_list
@ -319,18 +319,18 @@ nonempty_comma_separated_expression_list
; ;
literal literal
: true { $$ = ast::literal(ast::bool_literal{true}); } : true { $$ = ast::literal(ast::bool_literal{true, ctx.location}); }
| false { $$ = ast::literal(ast::bool_literal{false}); } | false { $$ = ast::literal(ast::bool_literal{false, ctx.location}); }
| lit_i8 { $$ = parse_numeric_literal<std::int8_t>($1); } | lit_i8 { $$ = parse_numeric_literal<std::int8_t>($1, ctx.location); }
| lit_u8 { $$ = parse_numeric_literal<std::uint8_t>($1); } | lit_u8 { $$ = parse_numeric_literal<std::uint8_t>($1, ctx.location); }
| lit_i16 { $$ = parse_numeric_literal<std::int16_t>($1); } | lit_i16 { $$ = parse_numeric_literal<std::int16_t>($1, ctx.location); }
| lit_u16 { $$ = parse_numeric_literal<std::uint16_t>($1); } | lit_u16 { $$ = parse_numeric_literal<std::uint16_t>($1, ctx.location); }
| lit_i32 { $$ = parse_numeric_literal<std::int32_t>($1); } | lit_i32 { $$ = parse_numeric_literal<std::int32_t>($1, ctx.location); }
| lit_u32 { $$ = parse_numeric_literal<std::uint32_t>($1); } | lit_u32 { $$ = parse_numeric_literal<std::uint32_t>($1, ctx.location); }
| lit_i64 { $$ = parse_numeric_literal<std::int64_t>($1); } | lit_i64 { $$ = parse_numeric_literal<std::int64_t>($1, ctx.location); }
| lit_u64 { $$ = parse_numeric_literal<std::uint64_t>($1); } | lit_u64 { $$ = parse_numeric_literal<std::uint64_t>($1, ctx.location); }
| lit_f32 { $$ = parse_numeric_literal<float>($1); } | lit_f32 { $$ = parse_numeric_literal<float>($1, ctx.location); }
| lit_f64 { $$ = parse_numeric_literal<double>($1); } | lit_f64 { $$ = parse_numeric_literal<double>($1, ctx.location); }
; ;
%% %%

View file

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