Source file ast.ml
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
open Fmlib
module Located = Character_parser.Located
module Position = Character_parser.Position
type range = Position.t * Position.t
module Expression = struct
type operator = string * Operator.t
type argument_type =
| Normal
| Operand
type t =
t0 Located.t
and t0 =
| Proposition
| Any
| Identifier of string
| Number of string
| Char of int
| String of string
| Operator of operator
| Typed of t * t
| Application of t * (t * argument_type) list
| Function of
formal_argument list
* t option
* t
| Product of formal_argument list * t
and formal_argument =
string Located.t * t option
let make_binary (e1: t) (op: operator Located.t) (e2: t): t =
let pos_start = Located.start e1
and pos_end = Located.end_ e2
and op_str,_ = Located.value op
in
Located.make
pos_start
(if op_str = ":" then
Typed (e1, e2)
else if op_str = "->" then
let name = Located.map (fun _ -> "_") e1 in
match Located.value e2 with
| Product (formal_arguments, result_type) ->
Product ( (name, Some e1) :: formal_arguments, result_type )
| _ ->
Product ([name, Some e1], e2)
else
Application (
Located.map (fun (op_str,_) -> Identifier op_str) op,
[ e1, Operand;
e2, Operand]))
pos_end
let rec binary
(e0:t)
(rest: (operator Located.t * t) list)
: (t, range * string * string) result
=
let module Res =
Monad.Result
(struct type t = range * string * string end)
in
match rest with
| [] ->
Ok e0
| [op, e1] ->
Ok (make_binary e0 op e1)
| (op1,e1) :: (op2,e2) :: rest ->
let op1_string, op1_data = Located.value op1
and op2_string, op2_data = Located.value op2
in
let cmp = Operator.compare op1_data op2_data in
if cmp = 0 then
match Operator.associativity op1_data with
| Operator.No ->
Error ((Located.start e0, Located.end_ e2), op1_string, op2_string)
| Operator.Left ->
binary (make_binary e0 op1 e1) ((op2,e2) :: rest)
| Operator.Right ->
Res.map (make_binary e0 op1) (binary e1 ((op2,e2) :: rest))
else if cmp = +1 then
binary (make_binary e0 op1 e1) ((op2,e2) :: rest)
else
let rest2, rest3 =
List.split_at
(fun (op,_) ->
Operator.precedence (snd (Located.value op))
<= Operator.precedence op1_data)
rest
in
Res.(binary e1 ((op2,e2) :: rest2)
>>= fun e ->
binary (make_binary e0 op1 e) rest3)
end