2020-03-08 02:21:55 +03:00
|
|
|
(*
|
2020-04-16 18:47:35 +03:00
|
|
|
This file is part of the Catala compiler, a specification language for tax and social benefits
|
2020-03-08 02:21:55 +03:00
|
|
|
computation rules.
|
2021-05-27 19:56:47 +03:00
|
|
|
Copyright (C) 2020 Inria, contributors: Denis Merigoux <denis.merigoux@inria.fr>,
|
|
|
|
Emile Rolley <emile.rolley@tuta.io>
|
2020-03-08 02:21:55 +03:00
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
2021-03-09 20:48:58 +03:00
|
|
|
*)
|
2020-03-08 02:21:55 +03:00
|
|
|
|
|
|
|
%{
|
2022-11-21 12:46:17 +03:00
|
|
|
open Catala_utils
|
2021-05-15 02:16:08 +03:00
|
|
|
%}
|
2020-03-08 02:21:55 +03:00
|
|
|
|
2021-04-30 10:59:09 +03:00
|
|
|
%parameter<Localisation: sig
|
2021-08-19 19:26:06 +03:00
|
|
|
val lex_builtin: string -> Ast.builtin_expression option
|
2021-04-30 10:59:09 +03:00
|
|
|
end>
|
2020-04-03 23:34:11 +03:00
|
|
|
|
2021-05-15 02:16:08 +03:00
|
|
|
%type <Ast.source_file> source_file
|
2020-03-08 02:21:55 +03:00
|
|
|
|
2021-05-15 02:16:08 +03:00
|
|
|
%start source_file
|
2020-03-08 02:21:55 +03:00
|
|
|
|
2021-08-19 12:19:45 +03:00
|
|
|
(* The token is returned for every line of law text, make them right-associative
|
|
|
|
so that we concat them efficiently as much as possible. *)
|
|
|
|
%right LAW_TEXT
|
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
(* Precedence of expression constructions *)
|
|
|
|
%right top_expr
|
|
|
|
%right ALT
|
|
|
|
%right let_expr IS
|
2023-01-04 12:54:12 +03:00
|
|
|
%right AND OR XOR
|
|
|
|
%nonassoc GREATER GREATER_EQUAL LESSER LESSER_EQUAL EQUAL NOT_EQUAL
|
|
|
|
%left PLUS MINUS PLUSPLUS
|
|
|
|
%left MULT DIV
|
2022-12-19 12:51:35 +03:00
|
|
|
%right apply OF CONTAINS FOR SUCH WITH
|
2022-12-14 17:45:13 +03:00
|
|
|
%right unop_expr
|
|
|
|
%right CONTENT
|
|
|
|
%left DOT
|
2020-03-08 02:21:55 +03:00
|
|
|
%%
|
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
let pos(x) ==
|
|
|
|
| ~=x ; { Pos.from_lpos $loc }
|
|
|
|
|
|
|
|
let addpos(x) ==
|
|
|
|
| ~=x ; { x, Pos.from_lpos $loc(x) }
|
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let typ_base :=
|
2022-12-14 17:45:13 +03:00
|
|
|
| INTEGER ; { Integer }
|
|
|
|
| BOOLEAN ; { Boolean }
|
|
|
|
| MONEY ; { Money }
|
|
|
|
| DURATION ; { Duration }
|
|
|
|
| TEXT ; { Text }
|
|
|
|
| DECIMAL ; { Decimal }
|
|
|
|
| DATE ; { Date }
|
2022-12-15 13:48:48 +03:00
|
|
|
| c = UIDENT ; <Named>
|
2020-04-14 12:46:48 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let typ :=
|
2022-12-14 17:45:13 +03:00
|
|
|
| t = typ_base ; <Primitive>
|
|
|
|
| COLLECTION ; t = addpos(typ) ; <Collection>
|
2020-03-08 07:01:26 +03:00
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
let qident ==
|
|
|
|
| b = separated_nonempty_list(DOT, ident) ; <>
|
|
|
|
|
|
|
|
(* let path :=
|
|
|
|
* | { [] } %prec qpath
|
|
|
|
* | ~=constructor ; DOT ; ~=path ; <List.cons> %prec qpath *)
|
|
|
|
(* Not yet supported, at the moment it's just an option: *)
|
|
|
|
let path ==
|
|
|
|
| { None }
|
|
|
|
| ~=constructor ; DOT ; <Some>
|
|
|
|
|
|
|
|
let expression ==
|
|
|
|
| e = addpos(naked_expression) ; { (e: expression) }
|
2020-04-14 18:29:50 +03:00
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
let naked_expression :=
|
2022-12-15 13:48:48 +03:00
|
|
|
| q = LIDENT ; {
|
2021-08-19 19:26:06 +03:00
|
|
|
(match Localisation.lex_builtin q with
|
|
|
|
| Some b -> Builtin b
|
2022-12-14 17:45:13 +03:00
|
|
|
| None -> Ident q)
|
|
|
|
}
|
|
|
|
| l = literal ; {
|
|
|
|
Literal l
|
|
|
|
}
|
2022-12-20 18:17:22 +03:00
|
|
|
| LPAREN ; e = expression ; RPAREN ; <Paren>
|
2022-12-14 17:45:13 +03:00
|
|
|
| e = expression ;
|
|
|
|
DOT ; c = path ;
|
|
|
|
i = ident ; {
|
|
|
|
Dotted (e, c, i)
|
2020-07-01 00:15:14 +03:00
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| CARDINAL ; {
|
2022-12-14 17:45:13 +03:00
|
|
|
Builtin Cardinal
|
|
|
|
}
|
|
|
|
| DECIMAL ; {
|
|
|
|
Builtin ToDecimal
|
|
|
|
}
|
|
|
|
| MONEY ; {
|
|
|
|
Builtin ToMoney
|
2022-10-21 16:47:17 +03:00
|
|
|
}
|
2022-12-15 13:48:48 +03:00
|
|
|
| LBRACKET ; l = separated_list(SEMICOLON, expression) ; RBRACKET ; {
|
2022-12-14 17:45:13 +03:00
|
|
|
ArrayLit l
|
2022-10-21 16:47:17 +03:00
|
|
|
}
|
2022-12-14 17:45:13 +03:00
|
|
|
| e = struct_or_enum_inject ; <>
|
|
|
|
| e1 = expression ;
|
|
|
|
OF ;
|
|
|
|
e2 = expression ; {
|
|
|
|
FunCall (e1, e2)
|
|
|
|
} %prec apply
|
|
|
|
| OUTPUT ; OF ;
|
|
|
|
c = constructor ;
|
|
|
|
fields = option(scope_call_args) ; {
|
|
|
|
let fields = Option.value ~default:[] fields in
|
|
|
|
ScopeCall (c, fields)
|
2020-04-14 20:13:20 +03:00
|
|
|
}
|
2022-12-14 17:45:13 +03:00
|
|
|
| e = expression ;
|
|
|
|
WITH ; c = constructor_binding ; {
|
|
|
|
TestMatchCase (e, (c, Pos.from_lpos $sloc))
|
|
|
|
}
|
|
|
|
| e1 = expression ;
|
|
|
|
CONTAINS ;
|
|
|
|
e2 = expression ; {
|
|
|
|
MemCollection (e2, e1)
|
|
|
|
} %prec apply
|
|
|
|
| SUM ; typ = addpos(typ_base) ;
|
|
|
|
OF ; coll = expression ; {
|
|
|
|
CollectionOp (AggregateSum { typ = Marked.unmark typ }, coll)
|
|
|
|
} %prec apply
|
|
|
|
| f = expression ;
|
|
|
|
FOR ; i = ident ;
|
|
|
|
AMONG ; coll = expression ; {
|
|
|
|
CollectionOp (Map {f = i, f}, coll)
|
|
|
|
} %prec apply
|
|
|
|
| max = minmax ;
|
|
|
|
OF ; coll = expression ;
|
|
|
|
OR ; IF ; COLLECTION ; EMPTY ; THEN ;
|
|
|
|
default = expression ; {
|
|
|
|
CollectionOp (AggregateExtremum { max; default }, coll)
|
|
|
|
} %prec apply
|
|
|
|
| op = unop ; e = expression ; {
|
|
|
|
Unop (op, e)
|
|
|
|
} %prec unop_expr
|
|
|
|
| e1 = expression ;
|
2023-01-04 12:54:12 +03:00
|
|
|
binop = addpos(binop) ;
|
2022-12-14 17:45:13 +03:00
|
|
|
e2 = expression ; {
|
|
|
|
Binop (binop, e1, e2)
|
2023-01-04 12:54:12 +03:00
|
|
|
}
|
2022-12-14 17:45:13 +03:00
|
|
|
| EXISTS ; i = ident ;
|
|
|
|
AMONG ; coll = expression ;
|
|
|
|
SUCH ; THAT ; predicate = expression ; {
|
|
|
|
CollectionOp (Exists {predicate = i, predicate}, coll)
|
|
|
|
} %prec let_expr
|
|
|
|
| FOR ; ALL ; i = ident ;
|
|
|
|
AMONG ; coll = expression ;
|
|
|
|
WE_HAVE ; predicate = expression ; {
|
|
|
|
CollectionOp (Forall {predicate = i, predicate}, coll)
|
|
|
|
} %prec let_expr
|
|
|
|
| MATCH ; e = expression ;
|
|
|
|
WITH ;
|
|
|
|
arms = addpos(nonempty_list(addpos(preceded(ALT, match_arm)))) ; {
|
|
|
|
MatchWith (e, arms)
|
|
|
|
}
|
|
|
|
| IF ; e1 = expression ;
|
|
|
|
THEN ; e2 = expression ;
|
|
|
|
ELSE ; e3 = expression ; {
|
|
|
|
IfThenElse (e1, e2, e3)
|
|
|
|
} %prec let_expr
|
|
|
|
| LET ; id = ident ;
|
|
|
|
DEFINED_AS ; e1 = expression ;
|
|
|
|
IN ; e2 = expression ; {
|
|
|
|
LetIn (id, e1, e2)
|
|
|
|
} %prec let_expr
|
|
|
|
| i = ident ;
|
|
|
|
AMONG ; coll = expression ;
|
|
|
|
SUCH ; THAT ; f = expression ; {
|
|
|
|
CollectionOp (Filter {f = i, f}, coll)
|
|
|
|
} %prec top_expr
|
2022-12-19 12:51:35 +03:00
|
|
|
| fmap = expression ;
|
|
|
|
FOR ; i = ident ;
|
|
|
|
AMONG ; coll = expression ;
|
|
|
|
SUCH ; THAT ; ffilt = expression ; {
|
|
|
|
CollectionOp (Map {f = i, fmap}, (CollectionOp (Filter {f = i, ffilt}, coll), Pos.from_lpos $loc))
|
|
|
|
} %prec top_expr
|
2022-12-14 17:45:13 +03:00
|
|
|
| i = ident ;
|
|
|
|
AMONG ; coll = expression ;
|
|
|
|
SUCH ; THAT ; f = expression ;
|
|
|
|
IS ; max = minmax ;
|
|
|
|
OR ; IF ; COLLECTION ; EMPTY ; THEN ; default = expression ; {
|
|
|
|
CollectionOp (AggregateArgExtremum { max; default; f = i, f }, coll)
|
|
|
|
} %prec top_expr
|
2020-07-01 00:15:14 +03:00
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
|
|
|
|
let struct_content_field :=
|
|
|
|
| field = ident ; COLON ; e = expression ; <>
|
|
|
|
|
|
|
|
let enum_content_opt :=
|
|
|
|
| {None} %prec CONTENT
|
|
|
|
| CONTENT ; ~ = expression ; <Some> %prec CONTENT
|
|
|
|
|
|
|
|
let struct_or_enum_inject ==
|
|
|
|
| ~ = path ;
|
|
|
|
~ = constructor ;
|
|
|
|
data = enum_content_opt ; {
|
|
|
|
EnumInject(path, constructor, data)
|
|
|
|
}
|
|
|
|
| _ = path ;
|
|
|
|
c = constructor ;
|
2022-12-15 13:48:48 +03:00
|
|
|
LBRACE ;
|
2022-12-14 17:45:13 +03:00
|
|
|
fields = nonempty_list(preceded(ALT, struct_content_field)) ;
|
2022-12-15 13:48:48 +03:00
|
|
|
RBRACE ; {
|
2022-12-14 17:45:13 +03:00
|
|
|
StructLit(c, fields)
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2021-03-09 20:48:58 +03:00
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
let num_literal ==
|
|
|
|
| d = INT_LITERAL ; <Int>
|
2022-12-13 19:55:16 +03:00
|
|
|
| d = DECIMAL_LITERAL ; {
|
2022-12-14 17:45:13 +03:00
|
|
|
let (d1, d2) = d in Dec (d1, d2)
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2020-04-14 20:13:20 +03:00
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
let unit_literal ==
|
|
|
|
| PERCENT ; { Percent }
|
|
|
|
| YEAR ; { Year}
|
|
|
|
| MONTH ; { Month }
|
|
|
|
| DAY ; { Day }
|
2020-04-11 19:16:15 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let literal :=
|
2022-12-14 17:45:13 +03:00
|
|
|
| l = addpos(num_literal); u = option(addpos(unit_literal)) ; <LNumber>
|
2022-12-13 19:55:16 +03:00
|
|
|
| money = MONEY_AMOUNT ; {
|
2020-04-25 16:17:44 +03:00
|
|
|
let (units, cents) = money in
|
2022-12-14 17:45:13 +03:00
|
|
|
LMoneyAmount {
|
2020-04-25 16:17:44 +03:00
|
|
|
money_amount_units = units;
|
|
|
|
money_amount_cents = cents;
|
2022-12-14 17:45:13 +03:00
|
|
|
}
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2022-12-15 13:48:48 +03:00
|
|
|
| BAR ; d = DATE_LITERAL ; BAR ; {
|
2022-07-21 15:14:22 +03:00
|
|
|
let (y,m,d) = d in
|
2022-12-14 17:45:13 +03:00
|
|
|
LDate {
|
2021-05-15 02:16:08 +03:00
|
|
|
literal_date_year = y;
|
|
|
|
literal_date_month = m;
|
|
|
|
literal_date_day = d;
|
2022-12-14 17:45:13 +03:00
|
|
|
}
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2022-12-14 17:45:13 +03:00
|
|
|
| TRUE ; { LBool true }
|
|
|
|
| FALSE ; { LBool false }
|
2022-12-13 19:55:16 +03:00
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
let scope_call_args ==
|
2022-12-13 19:55:16 +03:00
|
|
|
| WITH_V ;
|
2022-12-15 13:48:48 +03:00
|
|
|
LBRACE ;
|
2022-12-13 19:55:16 +03:00
|
|
|
fields = list(preceded (ALT, struct_content_field)) ;
|
2022-12-15 13:48:48 +03:00
|
|
|
RBRACE ; {
|
2022-12-07 20:31:08 +03:00
|
|
|
fields
|
|
|
|
}
|
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
let minmax ==
|
2022-12-13 19:55:16 +03:00
|
|
|
| MAXIMUM ; { true }
|
|
|
|
| MINIMUM ; { false }
|
2022-12-12 18:02:07 +03:00
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
let unop ==
|
2022-12-13 19:55:16 +03:00
|
|
|
| NOT ; { (Not, Pos.from_lpos $sloc) }
|
|
|
|
| k = MINUS ; { (Minus k, Pos.from_lpos $sloc) }
|
2022-05-11 19:27:14 +03:00
|
|
|
|
2023-01-04 12:54:12 +03:00
|
|
|
let binop ==
|
|
|
|
| k = MULT ; <Mult>
|
|
|
|
| k = DIV ; <Div>
|
|
|
|
| k = PLUS ; <Add>
|
|
|
|
| k = MINUS ; <Sub>
|
|
|
|
| PLUSPLUS ; { Concat }
|
|
|
|
| k = LESSER ; <Lt>
|
|
|
|
| k = LESSER_EQUAL ; <Lte>
|
|
|
|
| k = GREATER ; <Gt>
|
|
|
|
| k = GREATER_EQUAL ; <Gte>
|
|
|
|
| EQUAL ; { Eq }
|
|
|
|
| NOT_EQUAL ; { Neq }
|
2022-12-20 18:17:22 +03:00
|
|
|
| AND ; { And }
|
|
|
|
| OR ; { Or }
|
|
|
|
| XOR ; { Xor }
|
2021-03-09 20:48:58 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let constructor_binding :=
|
2022-12-14 17:45:13 +03:00
|
|
|
| ~ = path; ~ = constructor ; OF ; ~ = ident ; {
|
|
|
|
([path, constructor], Some ident)
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2022-12-14 17:45:13 +03:00
|
|
|
| ~ = path; ~ = constructor ; {
|
|
|
|
([path, constructor], None)
|
|
|
|
} %prec apply
|
2020-03-08 08:06:32 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let match_arm :=
|
2022-12-14 17:45:13 +03:00
|
|
|
| WILDCARD ; COLON ; ~ = expression ; <WildCard>
|
|
|
|
%prec ALT
|
|
|
|
| pat = addpos(constructor_binding) ;
|
|
|
|
COLON ; e = expression ; {
|
|
|
|
MatchCase {
|
|
|
|
match_case_pattern = pat;
|
2021-06-01 19:56:03 +03:00
|
|
|
match_case_expr = e;
|
2022-12-14 17:45:13 +03:00
|
|
|
}
|
|
|
|
} %prec ALT
|
2021-05-15 02:16:08 +03:00
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
let condition ==
|
|
|
|
| UNDER_CONDITION ; e = expression ; <>
|
2020-03-08 07:01:26 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let condition_consequence :=
|
|
|
|
| cond = condition ; CONSEQUENCE ; { cond }
|
2020-03-08 08:30:05 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let rule_expr :=
|
2022-12-14 17:45:13 +03:00
|
|
|
| i = addpos(qident) ; p = option(definition_parameters) ; <>
|
2020-04-14 20:16:40 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let rule_consequence :=
|
|
|
|
| flag = option(NOT); FILLED ; {
|
2022-12-14 17:45:13 +03:00
|
|
|
None = flag
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2020-08-07 11:57:57 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let rule :=
|
|
|
|
| label = option(label) ;
|
|
|
|
except = option(exception_to) ;
|
|
|
|
RULE ;
|
|
|
|
name_and_param = rule_expr ;
|
|
|
|
cond = option(condition_consequence) ;
|
|
|
|
state = option(state) ;
|
2022-12-14 17:45:13 +03:00
|
|
|
consequence = addpos(rule_consequence) ; {
|
2022-12-13 19:55:16 +03:00
|
|
|
let (name, param_applied) = name_and_param in
|
|
|
|
let cons : bool Marked.pos = consequence in
|
|
|
|
let rule_exception = match except with
|
|
|
|
| None -> NotAnException
|
|
|
|
| Some x -> x
|
|
|
|
in
|
|
|
|
{
|
|
|
|
rule_label = label;
|
|
|
|
rule_exception_to = rule_exception;
|
|
|
|
rule_parameter = param_applied;
|
|
|
|
rule_condition = cond;
|
|
|
|
rule_name = name;
|
|
|
|
rule_id = Shared_ast.RuleName.fresh
|
|
|
|
(String.concat "." (List.map (fun i -> Marked.unmark i) (Marked.unmark name)),
|
|
|
|
Pos.from_lpos $sloc);
|
|
|
|
rule_consequence = cons;
|
|
|
|
rule_state = state;
|
|
|
|
}, $sloc
|
|
|
|
}
|
|
|
|
|
|
|
|
let definition_parameters :=
|
|
|
|
| OF ; i = ident ; { i }
|
|
|
|
|
|
|
|
let label :=
|
|
|
|
| LABEL ; i = ident ; { i }
|
|
|
|
|
|
|
|
let state :=
|
|
|
|
| STATE ; s = ident ; { s }
|
|
|
|
|
|
|
|
let exception_to :=
|
|
|
|
| EXCEPTION ; i = option(ident) ; {
|
|
|
|
match i with
|
|
|
|
| None -> UnlabeledException
|
|
|
|
| Some x -> ExceptionToLabel x
|
|
|
|
}
|
|
|
|
|
|
|
|
let definition :=
|
2022-12-20 15:10:41 +03:00
|
|
|
| label = option(label);
|
2022-12-13 19:55:16 +03:00
|
|
|
except = option(exception_to) ;
|
|
|
|
DEFINITION ;
|
2022-12-14 17:45:13 +03:00
|
|
|
name = addpos(qident) ;
|
2022-12-13 19:55:16 +03:00
|
|
|
param = option(definition_parameters) ;
|
|
|
|
state = option(state) ;
|
|
|
|
cond = option(condition_consequence) ;
|
|
|
|
DEFINED_AS ;
|
|
|
|
e = expression ; {
|
|
|
|
let def_exception = match except with
|
|
|
|
| None -> NotAnException
|
|
|
|
| Some x -> x
|
|
|
|
in
|
|
|
|
{
|
|
|
|
definition_label = label;
|
|
|
|
definition_exception_to = def_exception;
|
|
|
|
definition_name = name;
|
|
|
|
definition_parameter = param;
|
|
|
|
definition_condition = cond;
|
|
|
|
definition_id =
|
|
|
|
Shared_ast.RuleName.fresh
|
2022-05-30 12:20:48 +03:00
|
|
|
(String.concat "." (List.map (fun i -> Marked.unmark i) (Marked.unmark name)),
|
2021-11-28 15:09:44 +03:00
|
|
|
Pos.from_lpos $sloc);
|
2022-12-13 19:55:16 +03:00
|
|
|
definition_expr = e;
|
|
|
|
definition_state = state;
|
|
|
|
}, $sloc
|
|
|
|
}
|
|
|
|
|
|
|
|
let variation_type :=
|
|
|
|
| INCREASING ; { (Increasing, Pos.from_lpos $sloc) }
|
|
|
|
| DECREASING ; { (Decreasing, Pos.from_lpos $sloc) }
|
|
|
|
|
|
|
|
let assertion_base :=
|
|
|
|
| e = expression ; { let (e, _) = e in (e, Pos.from_lpos $sloc) }
|
|
|
|
|
|
|
|
let assertion :=
|
|
|
|
| cond = option(condition_consequence) ;
|
|
|
|
base = assertion_base ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
(Assertion {
|
|
|
|
assertion_condition = cond;
|
2020-04-25 15:21:26 +03:00
|
|
|
assertion_content = base;
|
2021-03-09 20:48:58 +03:00
|
|
|
})
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2022-12-14 17:45:13 +03:00
|
|
|
| FIXED ; q = addpos(qident) ; BY ; i = ident ; {
|
2022-12-13 19:55:16 +03:00
|
|
|
MetaAssertion (FixedBy (q, i))
|
|
|
|
}
|
2022-12-14 17:45:13 +03:00
|
|
|
| VARIES ; q = addpos(qident) ;
|
|
|
|
WITH_V ; e = expression ;
|
2022-12-13 19:55:16 +03:00
|
|
|
t = option(variation_type) ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
MetaAssertion (VariesWith (q, e, t))
|
|
|
|
}
|
2020-03-08 08:06:32 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let scope_item :=
|
|
|
|
| r = rule ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
let (r, _) = r in (Rule r, Pos.from_lpos $sloc)
|
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| d = definition ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
let (d, _) = d in (Definition d, Pos.from_lpos $sloc)
|
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| ASSERTION ; contents = assertion ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
(contents, Pos.from_lpos $sloc)
|
|
|
|
}
|
2020-03-08 06:28:45 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let ident :=
|
2022-12-15 13:48:48 +03:00
|
|
|
| i = LIDENT ; {
|
2021-08-19 19:26:06 +03:00
|
|
|
match Localisation.lex_builtin i with
|
|
|
|
| Some _ ->
|
2022-12-13 19:55:16 +03:00
|
|
|
Errors.raise_spanned_error
|
|
|
|
(Pos.from_lpos $sloc)
|
|
|
|
"Reserved builtin name"
|
2021-08-19 19:26:06 +03:00
|
|
|
| None ->
|
2022-12-13 19:55:16 +03:00
|
|
|
(i, Pos.from_lpos $sloc)
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2020-04-14 12:46:48 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let condition_pos :=
|
|
|
|
| CONDITION ; { Pos.from_lpos $sloc }
|
2020-04-14 12:46:48 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let struct_scope_base :=
|
|
|
|
| DATA ; i = ident ;
|
2022-12-14 17:45:13 +03:00
|
|
|
CONTENT ; t = addpos(typ) ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
let t, pos = t in
|
|
|
|
(i, (Data t, pos))
|
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| pos = condition_pos ; i = ident ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
(i, (Condition, pos))
|
|
|
|
}
|
2020-04-03 23:58:34 +03:00
|
|
|
|
2022-12-14 17:45:13 +03:00
|
|
|
let struct_scope_func ==
|
|
|
|
| DEPENDS ; t = addpos(typ) ; { t }
|
2020-04-03 23:58:34 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let struct_scope :=
|
|
|
|
| name_and_typ = struct_scope_base ;
|
|
|
|
func_typ = option(struct_scope_func) ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
let (name, typ) = name_and_typ in
|
|
|
|
let (typ, typ_pos) = typ in
|
2022-12-13 19:55:16 +03:00
|
|
|
{
|
2021-05-15 02:16:08 +03:00
|
|
|
struct_decl_field_name = name;
|
2020-04-14 13:34:09 +03:00
|
|
|
struct_decl_field_typ = match func_typ with
|
|
|
|
| None -> (Base typ, typ_pos)
|
2022-12-13 19:55:16 +03:00
|
|
|
| Some (arg_typ, arg_pos) ->
|
|
|
|
Func {
|
|
|
|
arg_typ = (Data arg_typ, arg_pos);
|
|
|
|
return_typ = (typ, typ_pos);
|
|
|
|
}, Pos.from_lpos $sloc ;
|
|
|
|
}, Pos.from_lpos $sloc
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2020-04-03 23:58:34 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let scope_decl_item_attribute_input :=
|
|
|
|
| CONTEXT ; { Context, Pos.from_lpos $sloc }
|
|
|
|
| INPUT ; { Input, Pos.from_lpos $sloc }
|
2022-01-27 20:03:47 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let scope_decl_item_attribute_output :=
|
|
|
|
| OUTPUT ; { true, Pos.from_lpos $sloc }
|
2022-02-07 12:30:36 +03:00
|
|
|
| { false, Pos.from_lpos $sloc }
|
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let scope_decl_item_attribute :=
|
|
|
|
| input = scope_decl_item_attribute_input ;
|
|
|
|
output = scope_decl_item_attribute_output ; {
|
2022-02-07 12:30:36 +03:00
|
|
|
{
|
|
|
|
scope_decl_context_io_input = input;
|
2022-02-07 14:04:48 +03:00
|
|
|
scope_decl_context_io_output = output
|
2022-02-07 12:30:36 +03:00
|
|
|
}
|
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| INTERNAL ; {
|
2022-02-07 14:04:48 +03:00
|
|
|
{
|
|
|
|
scope_decl_context_io_input = (Internal, Pos.from_lpos $sloc);
|
|
|
|
scope_decl_context_io_output = (false, Pos.from_lpos $sloc)
|
|
|
|
}
|
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| OUTPUT ; {
|
2022-02-07 14:04:48 +03:00
|
|
|
{
|
|
|
|
scope_decl_context_io_input = (Internal, Pos.from_lpos $sloc);
|
|
|
|
scope_decl_context_io_output = (true, Pos.from_lpos $sloc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-07 12:30:36 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let scope_decl_item :=
|
|
|
|
| attr = scope_decl_item_attribute ;
|
|
|
|
i = ident ;
|
2022-12-14 17:45:13 +03:00
|
|
|
CONTENT ; t = addpos(typ) ;
|
2022-12-13 19:55:16 +03:00
|
|
|
func_typ = option(struct_scope_func) ;
|
|
|
|
states = list(state) ; {
|
|
|
|
(ContextData {
|
2021-05-15 02:16:08 +03:00
|
|
|
scope_decl_context_item_name = i;
|
2022-01-27 20:03:47 +03:00
|
|
|
scope_decl_context_item_attribute = attr;
|
2020-05-14 22:19:46 +03:00
|
|
|
scope_decl_context_item_typ =
|
2022-02-28 16:33:07 +03:00
|
|
|
(let (typ, typ_pos) = t in
|
2020-04-14 13:54:40 +03:00
|
|
|
match func_typ with
|
2020-05-07 10:40:09 +03:00
|
|
|
| None -> (Base (Data typ), typ_pos)
|
2022-12-13 19:55:16 +03:00
|
|
|
| Some (arg_typ, arg_pos) ->
|
|
|
|
Func {
|
|
|
|
arg_typ = (Data arg_typ, arg_pos);
|
|
|
|
return_typ = (Data typ, typ_pos);
|
|
|
|
}, Pos.from_lpos $sloc);
|
2022-02-28 16:33:07 +03:00
|
|
|
scope_decl_context_item_states = states;
|
2022-12-13 19:55:16 +03:00
|
|
|
}, Pos.from_lpos $sloc)
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| i = ident ; SCOPE ; c = constructor ; {
|
|
|
|
(ContextScope{
|
2021-05-15 02:16:08 +03:00
|
|
|
scope_decl_context_scope_name = i;
|
|
|
|
scope_decl_context_scope_sub_scope = c;
|
2022-02-07 12:30:36 +03:00
|
|
|
scope_decl_context_scope_attribute = {
|
|
|
|
scope_decl_context_io_input = (Internal, Pos.from_lpos $sloc);
|
|
|
|
scope_decl_context_io_output = (false, Pos.from_lpos $sloc);
|
|
|
|
};
|
2022-12-13 19:55:16 +03:00
|
|
|
}, Pos.from_lpos $sloc)
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| attr = scope_decl_item_attribute ;
|
|
|
|
i = ident ;
|
|
|
|
_condition = CONDITION ;
|
|
|
|
func_typ = option(struct_scope_func) ;
|
|
|
|
states = list(state) ; {
|
|
|
|
ContextData {
|
2021-05-15 02:16:08 +03:00
|
|
|
scope_decl_context_item_name = i;
|
2022-01-27 20:03:47 +03:00
|
|
|
scope_decl_context_item_attribute = attr;
|
2021-05-15 02:16:08 +03:00
|
|
|
scope_decl_context_item_typ =
|
2022-02-28 16:33:07 +03:00
|
|
|
(match func_typ with
|
2021-05-15 02:16:08 +03:00
|
|
|
| None -> (Base (Condition), Pos.from_lpos $loc(_condition))
|
2022-12-13 19:55:16 +03:00
|
|
|
| Some (arg_typ, arg_pos) ->
|
|
|
|
Func {
|
|
|
|
arg_typ = (Data arg_typ, arg_pos);
|
|
|
|
return_typ = (Condition, Pos.from_lpos $loc(_condition));
|
|
|
|
}, Pos.from_lpos $sloc);
|
2022-02-28 16:33:07 +03:00
|
|
|
scope_decl_context_item_states = states;
|
2022-12-13 19:55:16 +03:00
|
|
|
}, Pos.from_lpos $sloc
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2020-04-03 23:58:34 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let enum_decl_line :=
|
|
|
|
| ALT ; c = constructor ;
|
2022-12-19 12:51:35 +03:00
|
|
|
t = option(preceded(CONTENT,addpos(typ))) ; {
|
|
|
|
{
|
2021-05-15 02:16:08 +03:00
|
|
|
enum_decl_case_name = c;
|
2022-12-19 12:51:35 +03:00
|
|
|
enum_decl_case_typ =
|
|
|
|
Option.map (fun (t, t_pos) -> Base (Data t), t_pos) t;
|
|
|
|
}, Pos.from_lpos $sloc
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2020-04-14 12:46:48 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let constructor :=
|
2022-12-15 13:48:48 +03:00
|
|
|
| ~ = addpos(UIDENT) ; <>
|
2020-04-10 13:55:18 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let scope_use_condition :=
|
2022-12-14 17:45:13 +03:00
|
|
|
| UNDER_CONDITION ; e = expression ; <>
|
2020-05-18 12:29:22 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let code_item :=
|
|
|
|
| SCOPE ; c = constructor ;
|
|
|
|
e = option(scope_use_condition) ;
|
|
|
|
COLON ; items = nonempty_list(scope_item) ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
(ScopeUse {
|
|
|
|
scope_use_name = c;
|
2020-05-18 12:29:22 +03:00
|
|
|
scope_use_condition = e;
|
2020-05-14 22:19:46 +03:00
|
|
|
scope_use_items = items;
|
2021-05-15 02:16:08 +03:00
|
|
|
}, Pos.from_lpos $sloc)
|
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| DECLARATION ; STRUCT ; c = constructor ;
|
|
|
|
COLON ; scopes = list(struct_scope) ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
(StructDecl {
|
|
|
|
struct_decl_name = c;
|
2020-05-14 22:19:46 +03:00
|
|
|
struct_decl_fields = scopes;
|
2021-05-15 02:16:08 +03:00
|
|
|
}, Pos.from_lpos $sloc)
|
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| DECLARATION ; SCOPE ; c = constructor ;
|
|
|
|
COLON ; context = nonempty_list(scope_decl_item) ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
(ScopeDecl {
|
|
|
|
scope_decl_name = c;
|
|
|
|
scope_decl_context = context;
|
|
|
|
}, Pos.from_lpos $sloc)
|
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| DECLARATION ; ENUM ; c = constructor ;
|
|
|
|
COLON ; cases = list(enum_decl_line) ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
(EnumDecl {
|
|
|
|
enum_decl_name = c;
|
2020-04-14 13:34:09 +03:00
|
|
|
enum_decl_cases = cases;
|
2021-05-15 02:16:08 +03:00
|
|
|
}, Pos.from_lpos $sloc)
|
|
|
|
}
|
2021-03-09 20:48:58 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let code :=
|
|
|
|
| code = list(code_item) ; { (code, Pos.from_lpos $sloc) }
|
2021-03-09 20:48:58 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let metadata_block :=
|
|
|
|
| BEGIN_METADATA ; option(law_text) ;
|
|
|
|
code_and_pos = code ;
|
|
|
|
text = END_CODE ; {
|
2022-08-16 12:46:20 +03:00
|
|
|
let (code, _) = code_and_pos in
|
|
|
|
(code, (text, Pos.from_lpos $sloc))
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let law_heading :=
|
|
|
|
| title = LAW_HEADING ; {
|
2022-09-07 18:14:22 +03:00
|
|
|
let (title, id, is_archive, precedence) = title in {
|
2021-05-15 02:16:08 +03:00
|
|
|
law_heading_name = (title, Pos.from_lpos $sloc);
|
|
|
|
law_heading_id = id;
|
2022-09-07 18:14:22 +03:00
|
|
|
law_heading_is_archive = is_archive;
|
2020-10-04 02:25:37 +03:00
|
|
|
law_heading_precedence = precedence;
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let law_text :=
|
|
|
|
| lines = nonempty_list(LAW_TEXT) ; { String.trim (String.concat "" lines) }
|
2021-05-15 02:16:08 +03:00
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let source_file_item :=
|
|
|
|
| text = law_text ; { LawText text }
|
|
|
|
| BEGIN_CODE ;
|
|
|
|
code_and_pos = code ;
|
|
|
|
text = END_CODE ; {
|
2022-08-10 19:04:44 +03:00
|
|
|
let (code, _) = code_and_pos in
|
2022-08-10 11:45:49 +03:00
|
|
|
CodeBlock (code, (text, Pos.from_lpos $sloc), false)
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| heading = law_heading ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
LawHeading (heading, [])
|
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| code = metadata_block ; {
|
2021-05-15 02:16:08 +03:00
|
|
|
let (code, source_repr) = code in
|
|
|
|
CodeBlock (code, source_repr, true)
|
|
|
|
}
|
2022-12-13 19:55:16 +03:00
|
|
|
| BEGIN_DIRECTIVE ; LAW_INCLUDE ; COLON ;
|
|
|
|
args = nonempty_list(DIRECTIVE_ARG) ;
|
|
|
|
page = option(AT_PAGE) ;
|
|
|
|
END_DIRECTIVE ; {
|
2021-08-17 16:49:48 +03:00
|
|
|
let filename = String.trim (String.concat "" args) in
|
|
|
|
let pos = Pos.from_lpos $sloc in
|
2023-01-04 18:29:21 +03:00
|
|
|
let jorftext = Re.Pcre.regexp "(JORFARTI\\d{12}|LEGIARTI\\d{12}|CETATEXT\\d{12})" in
|
2021-08-17 16:49:48 +03:00
|
|
|
if Re.Pcre.pmatch ~rex:jorftext filename && page = None then
|
|
|
|
LawInclude (Ast.LegislativeText (filename, pos))
|
|
|
|
else if Filename.extension filename = ".pdf" || page <> None then
|
|
|
|
LawInclude (Ast.PdfFile ((filename, pos), page))
|
|
|
|
else
|
|
|
|
LawInclude (Ast.CatalaFile (filename, pos))
|
2021-05-15 02:16:08 +03:00
|
|
|
}
|
|
|
|
|
2022-12-13 19:55:16 +03:00
|
|
|
let source_file :=
|
|
|
|
| hd = source_file_item ; tl = source_file ; { hd::tl }
|
|
|
|
| EOF ; { [] }
|