aboutsummaryrefslogtreecommitdiff
path: root/lib/syntax/tree.ml
blob: cf02bf623f3bb04e21c390f5c0e900f52eb3bb32 (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
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 -> t' * Report.t list = fun t -> (t, [])
  let integer : S.pos -> string -> t = fun pos i -> Ast.Integer (pos, i)
  let literal : S.pos -> string -> t = fun pos l -> Ast.Literal (pos, l)

  let function_ : S.pos -> T.function_ -> t list -> t =
   fun pos name args -> Ast.Function (pos, name, args)

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

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

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

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

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

  type expression = Expression.t' * Report.t list

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

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

  let comment : S.pos -> t S.repr = fun pos _ -> Ast.Comment pos

  let expression : expression -> t S.repr =
   fun expr _ -> Ast.Expression (fst expr)

  let if_ :
      S.pos ->
      (expression, t) S.clause ->
      elifs:(expression, t) S.clause list ->
      else_:(S.pos * t S.repr list) option ->
      t S.repr =
   fun pos predicate ~elifs ~else_ _ ->
    let clause (pos, expr, repr) =
      let repr = List.map ~f:(fun instr -> instr []) repr in
      (pos, fst @@ expr, repr)
    in
    let elifs = List.map ~f:clause elifs
    and else_ =
      match else_ with
      | None -> []
      | Some (_, instructions) ->
          List.map ~f:(fun instr -> instr []) instructions
    in

    Ast.If { loc = pos; then_ = clause predicate; elifs; else_ }

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

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

module Location = struct
  type instruction = (Instruction.t' * Report.t list) S.repr
  type t = S.pos * S.pos Ast.statement list

  let location : S.pos -> instruction list -> (t * Report.t list) S.repr =
   fun pos block report ->
    let report, block =
      List.fold_left_map ~init:report block ~f:(fun report b ->
          let v, report = b report in
          (report, v))
    in
    ((pos, block), report)
end