<commit_before>%{
#include "blaze.h"
#include "parse.h"
#include "lex.h"

void yyerror(YYLTYPE* yylloc, LexerContext* ctx, const char* msg) {
    error(*yylloc, "%s", msg);
}

LexerContext parse_string(const char* file, const char* module,
    const char* fcont) {
    LexerContext ctx;
    lex_context_init(&ctx, file, module, fcont);
    yyparse(&ctx);
    return ctx;
}

#define scanner ctx->scanner

#define N(x,k,l) x = new(Node); x->kind = k; x->loc = l;
%}

%union {
    Token t;
    Node* n;
    List(Node*) l;
    struct {
        Node* rn;
        String* rs;
        int import, exportc;
    } funbody;
    int i;
}

%define parse.error verbose
%define parse.lac full
%define api.pure full
%locations

%parse-param { LexerContext* ctx }
%lex-param { void* scanner  }

%token <t> TINDENT
%token <t> TUNINDENT
%token <t> TNEWL
%token <t> TERROR
%token <t> TINDERROR

%token <t> TARROW
%token <t> TLP
%token <t> TRP
%token <t> TCOMMA
%token <t> TCOLON
%token <t> TSEMIC
%token <t> TEQ

%token <t> TSTAR
%token <t> TAND

%token <t> TFUN
%token <t> TLET
%token <t> TMUT
%token <t> TVAR
%token <t> TRETURN
%token <t> TTYPEOF
%token <t> TEXPORTC
%token <t> TGLOBAL
%token <t> TID
%token <t> TINT
%token <t> TSTRING

%type <n> tstmt
%type <n> fun
%type <n> funret
%type <funbody> funbody
%type <n> arglist
%type <n> arglist2
%type <n> decl
%type <n> body
%type <n> body2
%type <n> stmt
%type <n> let
%type <n> assign
%type <n> return
%type <n> texpr
%type <n> typeof
%type <n> expr
%type <n> name
%type <n> id
%type <n> dec
%type <n> ptr
%type <n> call
%type <l> callargs
%type <l> callargs2

%type <i> letspec

%destructor { if ($$.s) string_free($$.s); } <t>
%destructor { node_free($$); } <n>

%%

prog : ws { N(ctx->result, Nmodule, yylloc) }
     | prog tstmt ws { list_append(ctx->result->sons, $2); }

tstmt : fun

fun : TFUN id arglist funret funbody {
    N($$, Nfun, $2->loc)
    $$->s = string_clone($2->s);
    node_free($2);
    list_append($$->sons, $4);
    list_append($$->sons, $3);
    if ($5.import) $$->import = $5.rs;
    else list_append($$->sons, $5.rn);
    if ($5.exportc) $$->exportc = $5.rs;
    $$->flags |= Fcst | Faddr;
}

funbody : TCOLON body { $$.exportc = 0; $$.import = 0; $$.rn = $2; }
        | TEXPORTC TSTRING TCOLON body {
            $$.exportc = 1;
            $$.import = 0;
            $$.rs = $2.s;
            $$.rn = $4;
        }
        | TSTRING     { $$.exportc = 0; $$.import = 1; $$.rs = $1.s; }

funret : { $$ = NULL; }
       | TARROW texpr { $$ = $2; }

arglist :         { N($$, Narglist, yylloc) }
        | TLP TRP { N($$, Narglist, $1.loc); }
        | TLP arglist2 TRP { $$ = $2; $$->loc = $1.loc; }

arglist2 : decl { N($$, Narglist, $1->loc); list_append($$->sons, $1); }
         | arglist2 TCOMMA decl { $$ = $1; list_append($$->sons, $3); }

decl : id TCOLON texpr {
    N($$, Ndecl, $1->loc);
    $$->s = string_clone($1->s);
    node_free($1);
    list_append($$->sons, $3);
}

body : indent body2 unindent { $$ = $2; }
     | stmt { N($$, Nbody, $1->loc); list_append($$->sons, $1); }

body2 : stmt { N($$, Nbody, $1->loc); list_append($$->sons, $1); }
      | body2 sep stmt { $$ = $1; list_append($$->sons, $3); }

sep : TSEMIC | TNEWL

stmt : let    { $$ = $1; }
     | assign { $$ = $1; }
     | return { $$ = $1; }
     | call   { $$ = $1; }

let : TLET letspec id TEQ expr {<commit_msg>Some globals<commit_after>%{
#include "blaze.h"
#include "parse.h"
#include "lex.h"

void yyerror(YYLTYPE* yylloc, LexerContext* ctx, const char* msg) {
    error(*yylloc, "%s", msg);
}

LexerContext parse_string(const char* file, const char* module,
    const char* fcont) {
    LexerContext ctx;
    lex_context_init(&ctx, file, module, fcont);
    yyparse(&ctx);
    return ctx;
}

#define scanner ctx->scanner

#define N(x,k,l) x = new(Node); x->kind = k; x->loc = l;
%}

%union {
    Token t;
    Node* n;
    List(Node*) l;
    struct {
        Node* rn;
        String* rs;
        int import, exportc;
    } funbody;
    int i;
}

%define parse.error verbose
%define parse.lac full
%define api.pure full
%locations

%parse-param { LexerContext* ctx }
%lex-param { void* scanner  }

%token <t> TINDENT
%token <t> TUNINDENT
%token <t> TNEWL
%token <t> TERROR
%token <t> TINDERROR

%token <t> TARROW
%token <t> TLP
%token <t> TRP
%token <t> TCOMMA
%token <t> TCOLON
%token <t> TSEMIC
%token <t> TEQ

%token <t> TSTAR
%token <t> TAND

%token <t> TFUN
%token <t> TLET
%token <t> TMUT
%token <t> TVAR
%token <t> TRETURN
%token <t> TTYPEOF
%token <t> TEXPORTC
%token <t> TGLOBAL
%token <t> TID
%token <t> TINT
%token <t> TSTRING

%type <n> tstmt
%type <n> fun
%type <n> funret
%type <funbody> funbody
%type <n> global
%type <n> arglist
%type <n> arglist2
%type <n> decl
%type <n> body
%type <n> body2
%type <n> stmt
%type <n> let
%type <n> assign
%type <n> return
%type <n> texpr
%type <n> typeof
%type <n> expr
%type <n> name
%type <n> id
%type <n> dec
%type <n> ptr
%type <n> call
%type <l> callargs
%type <l> callargs2

%type <i> letspec

%destructor { if ($$.s) string_free($$.s); } <t>
%destructor { node_free($$); } <n>

%%

prog : ws { N(ctx->result, Nmodule, yylloc) }
     | prog tstmt ws { list_append(ctx->result->sons, $2); }

tstmt : fun | global

fun : TFUN id arglist funret funbody {
    N($$, Nfun, $2->loc)
    $$->s = string_clone($2->s);
    node_free($2);
    list_append($$->sons, $4);
    list_append($$->sons, $3);
    if ($5.import) $$->import = $5.rs;
    else list_append($$->sons, $5.rn);
    if ($5.exportc) $$->exportc = $5.rs;
    $$->flags |= Fcst | Faddr;
}

funbody : TCOLON body { $$.exportc = 0; $$.import = 0; $$.rn = $2; }
        | TEXPORTC TSTRING TCOLON body {
            $$.exportc = 1;
            $$.import = 0;
            $$.rs = $2.s;
            $$.rn = $4;
        }
        | TSTRING     { $$.exportc = 0; $$.import = 1; $$.rs = $1.s; }

funret : { $$ = NULL; }
       | TARROW texpr { $$ = $2; }

arglist :         { N($$, Narglist, yylloc) }
        | TLP TRP { N($$, Narglist, $1.loc); }
        | TLP arglist2 TRP { $$ = $2; $$->loc = $1.loc; }

arglist2 : decl { N($$, Narglist, $1->loc); list_append($$->sons, $1); }
         | arglist2 TCOMMA decl { $$ = $1; list_append($$->sons, $3); }

global : TGLOBAL decl { $$ = $2; $$->loc = $1.loc; }

decl : id TCOLON texpr {
    N($$, Ndecl, $1->loc);
    $$->s = string_clone($1->s);
    node_free($1);
    list_append($$->sons, $3);
}

body : indent body2 unindent { $$ = $2; }
     | stmt { N($$, Nbody, $1->loc); list_append($$->sons, $1); }

body2 : stmt { N($$, Nbody, $1->loc); list_append($$->sons, $1); }
      | body2 sep stmt { $$ = $1; list_append($$->sons, $3); }

sep : TSEMIC | TNEWL

stmt : let    { $$ = $1; }
     | assign { $$ = $1; }
     | return { $$ = $1; }
     | call   { $$ = $1; }

let : TLET letspec id TEQ expr {
{'fraction_non_alphanumeric': 0.20802115469369767, 'fraction_numerical': 0.015866020273248127, 'mean_word_length': 2.8033519553072628, 'pattern_counts': {'":': 0, '<': 106, '<?xml version=': 0, '>': 163, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5139333', 'n_tokens_mistral': 2953, 'n_tokens_neox': 2905, 'n_words': 799}