pslang/libs/parser/rules/pslang.y

285 lines
9.3 KiB
Text

%skeleton "lalr1.cc"
%require "3.8.1"
%header
%language "C++"
%define api.namespace {pslang::parser::bison}
%define api.location.file "pslang/parser/location.hpp"
%define api.location.include "<pslang/parser/location.hpp>"
%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
%{
#include <stdio.h>
void yyerror(char const * s)
{
printf("error: %s\n", s);
}
%}
%code requires {
#include <pslang/ast/statement.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)
{
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};
}
}
%param { ::pslang::parser::context& ctx }
%define api.token.prefix {tok_}
%token newline "newline"
%token indent "indentation"
%token assignment "="
%token colon ":"
%token lparen "("
%token rparen ")"
%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 <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 <std::string> name
%token const
%token let
%token mut
%token if
%token else
%token while
%token as
%token true
%token false
%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
%type <indented_statement_list> indented_statement_list
%type <std::size_t> indentation
%type <ast::statement> statement
%type <ast::variable_declaration> variable_declaration
%type <ast::value_category> variable_keyword
%type <type::type> type_expression
%type <type::primitive_type> primitive_type
%type <ast::expression> expression
%type <ast::expression> bool_expression
%type <ast::expression> compare_expression
%type <ast::expression> as_expression
%type <ast::expression> negate_expression
%type <ast::expression> sum_expression
%type <ast::expression> mult_expression
%type <ast::expression> not_expression
%type <ast::expression> base_expression
%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), {}}; }
;
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
: primitive_type { $$ = type::type($1); }
;
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{}; }
;
expression
: bool_expression { $$ = $1; }
;
bool_expression
: 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 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) }; }
;
compare_expression
: 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 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 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 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
: 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
: sum_expression { $$ = $1; }
| minus sum_expression { $$ = ast::unary_operation{ast::unary_operation_type::negation, std::make_unique<ast::expression>($2) }; }
;
sum_expression
: 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 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
: 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 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) }; }
;
not_expression
: base_expression
| exclamation base_expression { $$ = ast::unary_operation{ast::unary_operation_type::logical_not, std::make_unique<ast::expression>($2) }; }
;
base_expression
: literal
| name { $$ = ast::identifier{$1}; }
| lparen expression rparen { $$ = $2; }
;
literal
: true { $$ = ast::literal(ast::bool_literal{true}); }
| false { $$ = ast::literal(ast::bool_literal{false}); }
| lit_i8 { $$ = parse_numeric_literal<std::int8_t>($1); }
| lit_u8 { $$ = parse_numeric_literal<std::uint8_t>($1); }
| lit_i16 { $$ = parse_numeric_literal<std::int16_t>($1); }
| lit_u16 { $$ = parse_numeric_literal<std::uint16_t>($1); }
| lit_i32 { $$ = parse_numeric_literal<std::int32_t>($1); }
| lit_u32 { $$ = parse_numeric_literal<std::uint32_t>($1); }
| lit_i64 { $$ = parse_numeric_literal<std::int64_t>($1); }
| lit_u64 { $$ = parse_numeric_literal<std::uint64_t>($1); }
| lit_f32 { $$ = parse_numeric_literal<float>($1); }
| lit_f64 { $$ = parse_numeric_literal<double>($1); }
;
%%
void pslang::parser::bison::parser::error(location_type const& location, std::string const& message)
{
throw ::pslang::parser::parse_error(message, location);
}