aboutsummaryrefslogtreecommitdiff
path: root/lib/syntax/tree.ml
blob: db8abd96c2f1d7f792b1b1ba8edba64cddf377ce (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
open StdLabels

module Ast = struct
  type 'a variable = { pos : 'a; name : string; index : 'a expression option }
  [@@deriving eq, show]

  and 'a expression =
    | Integer of 'a * string
    | Literal of 'a * string
    | Ident of 'a variable
    | BinaryOp of 'a * T.boperator * 'a expression * 'a expression
    | Op of 'a * T.uoperator * 'a expression
    | Function of 'a * T.function_ * 'a expression list
  [@@deriving eq, show]

  and 'a condition = 'a * 'a expression * 'a statement list

  and 'a statement =
    | If of {
        loc : 'a;
        then_ : 'a condition;
        elifs : 'a condition list;
        else_ : 'a statement list;
      }
    | Act of { loc : 'a; label : 'a expression; statements : 'a statement list }
    | Declaration of ('a * 'a variable * T.assignation_operator * 'a expression)
    | Expression of 'a expression
    | Comment of 'a
    | Call of 'a * T.keywords * 'a expression list
    | Location of 'a * string
  [@@deriving eq, show]
end

(** Default implementation for the expression *)
module Expression : S.Expression with type t' = S.pos Ast.expression = struct
  type t = S.pos Ast.expression
  type t' = t

  let v : t * Report.t list -> t' * Report.t list = fun (t, r) -> (t, r)

  let integer : S.pos -> string -> t S.repr =
   fun pos i r -> (Ast.Integer (pos, i), r)

  let literal : S.pos -> string -> t S.repr =
   fun pos l r -> (Ast.Literal (pos, l), r)

  let function_ : S.pos -> T.function_ -> t S.repr list -> t S.repr =
   fun pos name args r ->
    let args = List.map ~f:(fun f -> fst (f r)) args in
    (Ast.Function (pos, name, args), r)

  let uoperator : S.pos -> T.uoperator -> t S.repr -> t S.repr =
   fun pos op expression r ->
    let expression = fst (expression r) in
    (Ast.Op (pos, op, expression), r)

  let boperator : S.pos -> T.boperator -> t S.repr -> t S.repr -> t S.repr =
   fun pos op op1 op2 r ->
    let op1 = fst (op1 r) and op2 = fst (op2 r) in
    (Ast.BinaryOp (pos, op, op1, op2), r)

  let ident : (S.pos, t S.repr) S.variable -> t S.repr =
   fun { pos; name; index } r ->
    let index = Option.map (fun i -> fst (i r)) index in
    (Ast.Ident { pos; name; index }, r)
end

module Instruction :
  S.Instruction
    with type expression = Expression.t' S.repr
     and type t' = S.pos Ast.statement = struct
  type t = S.pos Ast.statement
  type t' = t

  let v = Fun.id

  type expression = Expression.t' S.repr

  let call : S.pos -> T.keywords -> expression list -> t S.repr =
   fun pos name args report ->
    let args = List.map ~f:(fun f -> fst (f [])) args in
    (Ast.Call (pos, name, args), report)

  let location : S.pos -> string -> t S.repr =
   fun loc label report -> (Ast.Location (loc, label), report)

  let comment : S.pos -> t S.repr = fun pos report -> (Ast.Comment pos, report)

  let expression : expression -> t S.repr =
   fun expr report -> (Ast.Expression (fst (expr [])), report)

  let if_ :
      S.pos ->
      (expression, t) S.clause ->
      elifs:(expression, t) S.clause list ->
      else_:t S.repr list ->
      t S.repr =
   fun pos predicate ~elifs ~else_ report ->
    let clause (pos, expr, repr) =
      let repr = List.map ~f:(fun instr -> fst @@ instr []) repr in
      (pos, fst @@ expr [], repr)
    in
    let elifs = List.map ~f:clause elifs
    and else_ = List.map ~f:(fun instr -> fst @@ instr []) else_ in

    (Ast.If { loc = pos; then_ = clause predicate; elifs; else_ }, report)

  let act : S.pos -> label:expression -> t S.repr list -> t S.repr =
   fun pos ~label statements report ->
    let label = fst (label [])
    and statements = List.map ~f:(fun instr -> fst @@ instr []) statements in
    (Ast.Act { loc = pos; label; statements }, report)

  let assign :
      S.pos ->
      (S.pos, expression) S.variable ->
      T.assignation_operator ->
      expression ->
      t S.repr =
   fun pos_loc { pos; name; index } op expr report ->
    (*let index = Option.map (fun i -> fst @@ Expression.observe (i [])) index*)
    let index = Option.map (fun f -> fst @@ f []) index in
    let expr = fst (expr []) in
    (Ast.Declaration (pos_loc, { pos; name; index }, op, expr), report)
end

module Location = struct
  type instruction = S.pos Ast.statement S.repr
  type repr = S.pos * S.pos Ast.statement list

  let location : S.pos -> instruction list -> repr =
   fun pos block ->
    let block = List.map block ~f:(fun b -> fst @@ b []) in
    (pos, block)
end