aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/parser.y
blob: d97106fcae67b2c0982e0cb7c515800c8c68051c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
%glr-parser
%pure-parser
%locations
%error-verbose
%parse-param { yyscan_t scanner }
%parse-param { void * data }
%lex-param { yyscan_t scanner }

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <aterm2.h>

#include "parser-tab.h"
#include "lexer-tab.h"

void setParseResult(void * data, ATerm t);
void parseError(void * data, char * error, int line, int column);
ATerm absParsedPath(void * data, ATerm t);
ATerm fixAttrs(int recursive, ATermList as);

void yyerror(YYLTYPE * loc, yyscan_t scanner, void * data, char * s)
{
    parseError(data, s, loc->first_line, loc->first_column);
}
 
%}

%union {
  ATerm t;
  ATermList ts;
}

%type <t> start expr expr_function expr_assert expr_op
%type <t> expr_app expr_select expr_simple bind formal
%type <ts> binds ids expr_list formals
%token <t> ID INT STR PATH URI
%token IF THEN ELSE ASSERT LET REC INHERIT EQ NEQ AND OR IMPL

%nonassoc IMPL
%left OR
%left AND
%nonassoc EQ NEQ
%left NEG

%%

start: expr { setParseResult(data, $1); };

expr: expr_function;

expr_function
  : '{' formals '}' ':' expr_function
    { $$ = ATmake("Function(<term>, <term>)", $2, $5); }
  | expr_assert
  ;

expr_assert
  : ASSERT expr ';' expr_assert
    { $$ = ATmake("Assert(<term>, <term>)", $2, $4); }
  | expr_op
  ;

expr_op
  : '!' expr_op %prec NEG { $$ = ATmake("OpNot(<term>)", $2); }
  | expr_op EQ expr_op { $$ = ATmake("OpEq(<term>, <term>)", $1, $3); }
  | expr_op NEQ expr_op { $$ = ATmake("OpNEq(<term>, <term>)", $1, $3); }
  | expr_op AND expr_op { $$ = ATmake("OpAnd(<term>, <term>)", $1, $3); }
  | expr_op OR expr_op { $$ = ATmake("OpOr(<term>, <term>)", $1, $3); }
  | expr_op IMPL expr_op { $$ = ATmake("OpImpl(<term>, <term>)", $1, $3); }
  | expr_app
  ;

expr_app
  : expr_app expr_select
    { $$ = ATmake("Call(<term>, <term>)", $1, $2); }
  | expr_select { $$ = $1; }
  ;

expr_select
  : expr_select '.' ID
    { $$ = ATmake("Select(<term>, <term>)", $1, $3); }
  | expr_simple { $$ = $1; }
  ;

expr_simple
  : ID { $$ = ATmake("Var(<term>)", $1); }
  | INT { $$ = ATmake("Int(<term>)", $1); }
  | STR { $$ = ATmake("Str(<term>)", $1); }
  | PATH { $$ = ATmake("Path(<term>)", absParsedPath(data, $1)); }
  | URI { $$ = ATmake("Uri(<term>)", $1); }
  | '(' expr ')' { $$ = $2; }
  /* Let expressions `let {..., body = ...}' are just desugared
     into `(rec {..., body = ...}).body'. */
  | LET '{' binds '}'
    { $$ = ATmake("Select(<term>, \"body\")", fixAttrs(1, $3)); }
  | REC '{' binds '}'
    { $$ = fixAttrs(1, $3); }
  | '{' binds '}'
    { $$ = fixAttrs(0, $2); }
  | '[' expr_list ']' { $$ = ATmake("List(<term>)", $2); }
  | IF expr THEN expr ELSE expr
    { $$ = ATmake("If(<term>, <term>, <term>)", $2, $4, $6); }
  ;

binds
  : binds bind { $$ = ATinsert($1, $2); }
  | { $$ = ATempty; }
  ;

bind
  : ID '=' expr ';'
    { $$ = ATmake("Bind(<term>, <term>)", $1, $3); }
  | INHERIT ids ';'
    { $$ = ATmake("Inherit(<term>)", $2); }
  ;

ids: ids ID { $$ = ATinsert($1, $2); } | { $$ = ATempty; };

expr_list
  : expr_select expr_list { $$ = ATinsert($2, $1); }
    /* yes, this is right-recursive, but it doesn't matter since
       otherwise we would need ATreverse which requires unbounded
       stack space */
  | { $$ = ATempty; }
  ;

formals
  : formal ',' formals { $$ = ATinsert($3, $1); } /* idem - right recursive */
  | formal { $$ = ATinsert(ATempty, $1); }
  ;

formal
  : ID { $$ = ATmake("NoDefFormal(<term>)", $1); }
  | ID '?' expr { $$ = ATmake("DefFormal(<term>, <term>)", $1, $3); }
  ;
  
%%