323 lines
13 KiB
Text
323 lines
13 KiB
Text
%skeleton "lalr1.cc"
|
|
%require "3.8.1"
|
|
%header
|
|
|
|
%language "C++"
|
|
%define api.namespace {pslang::parser::bison}
|
|
%define api.location.type { ::pslang::ast::location }
|
|
|
|
%define api.token.raw
|
|
%define api.token.constructor
|
|
%define api.value.type variant
|
|
%define api.value.automove
|
|
|
|
%define parse.assert
|
|
%define parse.trace
|
|
%define parse.error detailed
|
|
%define parse.lac full
|
|
|
|
%locations
|
|
|
|
%code requires {
|
|
|
|
#include <pslang/ast/statement.hpp>
|
|
#include <pslang/ast/location.hpp>
|
|
#include <pslang/parser/indented_statement.hpp>
|
|
|
|
namespace pslang::parser {
|
|
|
|
struct context;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
%code {
|
|
|
|
#include <pslang/parser/context.hpp>
|
|
#include <pslang/parser/error.hpp>
|
|
|
|
#include <stdexcept>
|
|
#include <sstream>
|
|
#include <charconv>
|
|
|
|
#define YY_DECL ::pslang::parser::bison::parser::symbol_type yylex(::pslang::parser::context& ctx)
|
|
YY_DECL;
|
|
|
|
template <typename T>
|
|
::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, location};
|
|
}
|
|
|
|
}
|
|
|
|
%param { ::pslang::parser::context& ctx }
|
|
|
|
%define api.token.prefix {tok_}
|
|
|
|
%token newline "newline"
|
|
%token indent "indentation"
|
|
%token assignment "="
|
|
%token colon ":"
|
|
%token comma ","
|
|
%token dot "."
|
|
%token lparen "("
|
|
%token rparen ")"
|
|
%token lbracket "["
|
|
%token rbracket "]"
|
|
%token plus "+"
|
|
%token minus "-"
|
|
%token asterisk "*"
|
|
%token slash "/"
|
|
%token percent "%"
|
|
%token ampersand "&"
|
|
%token vertical_bar "|"
|
|
%token circumflex "^"
|
|
%token exclamation "!"
|
|
%token equals "=="
|
|
%token not_equals "!="
|
|
%token less "<"
|
|
%token greater ">"
|
|
%token less_equals "<="
|
|
%token greater_equals ">="
|
|
%token arrow "->"
|
|
|
|
%token <std::string> lit_i8
|
|
%token <std::string> lit_u8
|
|
%token <std::string> lit_i16
|
|
%token <std::string> lit_u16
|
|
%token <std::string> lit_i32
|
|
%token <std::string> lit_u32
|
|
%token <std::string> lit_i64
|
|
%token <std::string> lit_u64
|
|
|
|
%token <std::string> lit_f8
|
|
%token <std::string> lit_f16
|
|
%token <std::string> lit_f32
|
|
%token <std::string> lit_f64
|
|
|
|
%token <char> lit_char8
|
|
|
|
%token <std::string> name
|
|
|
|
%token const
|
|
%token let
|
|
%token mut
|
|
%token if
|
|
%token else
|
|
%token while
|
|
%token as
|
|
%token func
|
|
%token return
|
|
%token struct
|
|
%token true
|
|
%token false
|
|
|
|
%token unit
|
|
%token bool
|
|
%token i8
|
|
%token u8
|
|
%token i16
|
|
%token u16
|
|
%token i32
|
|
%token u32
|
|
%token i64
|
|
%token u64
|
|
%token f32
|
|
%token f64
|
|
|
|
%token end 0
|
|
|
|
%right arrow
|
|
%left ampersand vertical_bar circumflex
|
|
%left equals not_equals less greater less_equals greater_equals
|
|
%nonassoc as
|
|
%precedence UMINUS
|
|
%left plus minus
|
|
%left asterisk slash percent
|
|
%precedence NOT
|
|
%precedence lbracket
|
|
|
|
%type <indented_statement_list> indented_statement_list
|
|
%type <std::size_t> indentation
|
|
%type <ast::statement> statement
|
|
%type <std::vector<ast::function_definition::argument>> function_definition_argument_list
|
|
%type <std::vector<ast::function_definition::argument>> nonempty_function_definition_argument_list
|
|
%type <type::type_ptr> function_return_type
|
|
%type <ast::variable_declaration> variable_declaration
|
|
%type <ast::value_category> variable_keyword
|
|
%type <type::type> type_expression
|
|
%type <type::primitive_type> primitive_type
|
|
%type <std::vector<type::type_ptr>> function_paren_type_list
|
|
%type <std::vector<type::type_ptr>> two_or_more_type_list
|
|
%type <ast::expression> expression
|
|
%type <ast::expression> postfix_expression
|
|
%type <ast::expression> base_expression
|
|
%type <std::vector<ast::expression_ptr>> comma_separated_expression_list
|
|
%type <std::vector<ast::expression_ptr>> nonempty_comma_separated_expression_list
|
|
%type <ast::expression> literal
|
|
|
|
%%
|
|
|
|
module
|
|
: indented_statement_list end { ctx.result = $1; }
|
|
;
|
|
|
|
indented_statement_list
|
|
: indented_statement_list indentation statement newline { auto tmp = $1; tmp.statements.push_back({$2, std::make_unique<ast::statement>($3)}); $$ = std::move(tmp); }
|
|
| indented_statement_list indentation newline { $$ = $1; }
|
|
| %empty { $$ = {}; }
|
|
;
|
|
|
|
indentation
|
|
: indent indentation { $$ = $2 + 1ull; }
|
|
| %empty { $$ = 0ull; }
|
|
;
|
|
|
|
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), @$ }; }
|
|
| 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), @$}; }
|
|
;
|
|
|
|
function_definition_argument_list
|
|
: %empty { std::vector<ast::function_definition::argument> tmp; $$ = std::move(tmp); }
|
|
| nonempty_function_definition_argument_list { $$ = $1; }
|
|
;
|
|
|
|
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); }
|
|
| 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); }
|
|
;
|
|
|
|
function_return_type
|
|
: arrow type_expression { $$ = std::make_unique<type::type>($2); }
|
|
| %empty { $$ = std::make_unique<type::type>(type::unit_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
|
|
: const { $$ = ast::value_category::compile_time; }
|
|
| let { $$ = ast::value_category::constant; }
|
|
| mut { $$ = ast::value_category::_mutable; }
|
|
;
|
|
|
|
type_expression
|
|
: unit { $$ = type::type(type::unit_type{}); }
|
|
| primitive_type { $$ = type::type($1); }
|
|
| name { $$ = type::identifier{$1}; }
|
|
| type_expression lbracket lit_i32 rbracket { $$ = type::array_type{std::make_unique<type::type>($1), std::stoull($3)}; }
|
|
| type_expression arrow type_expression { std::vector<type::type_ptr> args; args.push_back(std::make_unique<type::type>($1)); $$ = type::function_type{std::move(args), std::make_unique<type::type>($3)}; }
|
|
| lparen function_paren_type_list rparen arrow type_expression { $$ = type::function_type{$2, std::make_unique<type::type>($5)}; }
|
|
| lparen type_expression rparen { $$ = $2; }
|
|
;
|
|
|
|
primitive_type
|
|
: bool { $$ = type::bool_type{}; }
|
|
| i8 { $$ = type::i8_type{}; }
|
|
| u8 { $$ = type::u8_type{}; }
|
|
| i16 { $$ = type::i16_type{}; }
|
|
| u16 { $$ = type::u16_type{}; }
|
|
| i32 { $$ = type::i32_type{}; }
|
|
| u32 { $$ = type::u32_type{}; }
|
|
| i64 { $$ = type::i64_type{}; }
|
|
| u64 { $$ = type::u64_type{}; }
|
|
| f32 { $$ = type::f32_type{}; }
|
|
| f64 { $$ = type::f64_type{}; }
|
|
;
|
|
|
|
function_paren_type_list
|
|
: %empty { std::vector<type::type_ptr> tmp; $$ = std::move(tmp); }
|
|
| two_or_more_type_list { $$ = $1; }
|
|
;
|
|
|
|
two_or_more_type_list
|
|
: type_expression comma type_expression { std::vector<type::type_ptr> tmp; tmp.push_back(std::make_unique<type::type>($1)); tmp.push_back(std::make_unique<type::type>($3)); $$ = std::move(tmp); }
|
|
| two_or_more_type_list comma type_expression { auto tmp = $1; tmp.push_back(std::make_unique<type::type>($3)); $$ = std::move(tmp); }
|
|
;
|
|
|
|
expression
|
|
: expression ampersand expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_and, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression vertical_bar expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_or, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression circumflex expression { $$ = ast::binary_operation{ast::binary_operation_type::logical_xor, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression equals expression { $$ = ast::binary_operation{ast::binary_operation_type::equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression not_equals expression { $$ = ast::binary_operation{ast::binary_operation_type::not_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression less expression { $$ = ast::binary_operation{ast::binary_operation_type::less, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression greater expression { $$ = ast::binary_operation{ast::binary_operation_type::greater, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression less_equals expression { $$ = ast::binary_operation{ast::binary_operation_type::less_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression greater_equals expression { $$ = ast::binary_operation{ast::binary_operation_type::greater_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression as type_expression { $$ = ast::cast_operation{ std::make_unique<ast::expression>($1), std::make_unique<type::type>($3), @$ }; }
|
|
| minus expression %prec UMINUS { $$ = ast::unary_operation{ast::unary_operation_type::negation, std::make_unique<ast::expression>($2), @$ }; }
|
|
| expression plus expression { $$ = ast::binary_operation{ast::binary_operation_type::addition, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression minus expression { $$ = ast::binary_operation{ast::binary_operation_type::subtraction, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression asterisk expression { $$ = ast::binary_operation{ast::binary_operation_type::multiplication, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression slash expression { $$ = ast::binary_operation{ast::binary_operation_type::division, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| expression percent expression { $$ = ast::binary_operation{ast::binary_operation_type::remainder, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
|
|
| exclamation expression %prec NOT { $$ = ast::unary_operation{ast::unary_operation_type::logical_not, std::make_unique<ast::expression>($2), @$ }; }
|
|
| postfix_expression { $$ = $1; }
|
|
;
|
|
|
|
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 lparen comma_separated_expression_list rparen { $$ = ast::function_call{std::make_unique<ast::expression>($1), $3, @$}; }
|
|
;
|
|
|
|
base_expression
|
|
: literal
|
|
| name { $$ = ast::identifier{$1, ctx.location}; }
|
|
| lparen expression rparen { $$ = $2; }
|
|
| lbracket nonempty_comma_separated_expression_list rbracket { $$ = ast::array{$2, @$}; }
|
|
;
|
|
|
|
comma_separated_expression_list
|
|
: %empty { std::vector<ast::expression_ptr> tmp; $$ = std::move(tmp); }
|
|
| nonempty_comma_separated_expression_list
|
|
;
|
|
|
|
nonempty_comma_separated_expression_list
|
|
: expression { std::vector<ast::expression_ptr> tmp; tmp.push_back(std::make_unique<ast::expression>($1)); $$ = std::move(tmp); }
|
|
| nonempty_comma_separated_expression_list comma expression { auto tmp = $1; tmp.push_back(std::make_unique<ast::expression>($3)); $$ = std::move(tmp); }
|
|
;
|
|
|
|
literal
|
|
: 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); }
|
|
| lit_char8 { $$ = ast::u8_literal{static_cast<std::uint8_t>($1), ctx.location}; }
|
|
;
|
|
|
|
%%
|
|
|
|
void pslang::parser::bison::parser::error(location_type const& location, std::string const& message)
|
|
{
|
|
throw ::pslang::parser::parse_error(message, location);
|
|
}
|