%skeleton "lalr1.cc"
%require  "3.2"
%debug
%defines
%define api.parser.class {Parser}
%define parse.error verbose

%code requires{
#include <variant>
#include <node.h>
class Scanner;
struct State;
#define YY_NULLPTR nullptr
}

%parse-param { Scanner &scanner }
%parse-param { std::pair<std::string, std::unique_ptr<Node>> *result }
%parse-param { State *state }

%code {
#include <lexer_base.h>
#undef yylex
#define yylex scanner.yylex
}

%define api.value.type {parser_var_ty}
%define parse.assert
%locations

%destructor {
    if (auto **node_ptr = std::get_if<Node*>(&$$)) {
        auto *node = *node_ptr;
        node->a.release();
        node->b.release();
        delete node;
    }
} <>

%token END 0 "eof"

%token LBRACE RBRACE EQUAL NUM IDENT

%left PLUS MINUS
%left MUL DIV

%%

assign : IDENT EQUAL e0 END { *result = std::move(std::pair{std::get<std::string>($1), std::unique_ptr<Node>(std::get<Node*>($3))}); }

var : NUM { $$ = new_node<Node::type::NUM>($1); }
    | IDENT { $$ = new_node<Node::type::VAR>($1); }
    ;

e3 : var
   | LBRACE e0 RBRACE { $$ = $2; }
   ;

e2 : MINUS e3 { $$ = new_node<Node::type::NEG>($2); }
   | e3
   ;

e1 : e1 MUL e2 { $$ = new_node<Node::type::MUL>($1, $3); }
   | e1 DIV e2 { $$ = new_node<Node::type::DIV>($1, $3); }
   | e2
   ;

e0 : e0 PLUS  e1 { $$ = new_node<Node::type::PLUS >($1, $3); }
   | e0 MINUS e1 { $$ = new_node<Node::type::MINUS>($1, $3); }
   | e1
   ;

%%
