Source file string_manipulation.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
(**The String Manipulation Module of the B# STD*)

(**A Generic function to extract two arguments and apply a function*)
let two_argument_func func list_of_arguments =
  if List.length list_of_arguments < 2 then
    Parser.Exception
      (new Parser.arg
         ("This function requires two arguments and you supplied "
         ^ string_of_int (List.length list_of_arguments)
         ^ "arguments"))
  else
    let head, tail = (List.hd list_of_arguments, List.tl list_of_arguments) in
    let head2 = List.hd tail in
    func head head2

(**A Generic function to extract three arguments and apply a function*)
let three_argument_func func list_of_arguments =
  if List.length list_of_arguments < 3 then
    Parser.Exception
      (new Parser.arg
         ("This function requires three arguments and you supplied "
         ^ string_of_int (List.length list_of_arguments)
         ^ "arguments"))
  else
    let head, tail = (List.hd list_of_arguments, List.tl list_of_arguments) in
    let head2, tail2 = (List.hd tail, List.tl tail) in
    let head3 = List.hd tail2 in
    func head head2 head3

(**Takes an integer and a string and returns a string of n times the inputed one*)
let proto_create n s =
  match (n, s) with
  | Parser.Argument (Parser.I n), Parser.Argument (Parser.Str s) ->
      Parser.Argument
        (Parser.Str (Array.make n s |> Array.to_list |> String.concat ""))
  | _ ->
      Parser.Exception
        (new Parser.type_error "arguments must be an integer and a string")

(**Take three strings and returns a string where all occurence of s2 have been replaced by s3 in s1*)
let proto_replace s1 s2 s3 =
  match (s1, s2, s3) with
  | ( Parser.Argument (Parser.Str s1),
      Parser.Argument (Parser.Str s2),
      Parser.Argument (Parser.Str s3) ) ->
      let regex = Str.regexp s2 in
      let s = Str.global_replace regex s3 s1 in
      Parser.Argument (Parser.Str s)
  | _ -> Parser.Exception (new Parser.type_error "arguments must be strings")

(**Transform a string into a list of character (but in the type String)*)
let explode s =
  List.init (String.length s) (fun i -> String.get s i |> Char.escaped)

(**Takes a string and transform it into an array of char with explode*)
let transform_to_array list_of_arguments =
  let aux s1 =
    match s1 with
    | Parser.Argument (Parser.Str s1) ->
        explode s1 |> List.map Parser.create_string_argument |> Array.of_list
        |> fun a -> Parser.TBL a
    | _ -> Parser.Exception (new Parser.type_error "argument must be a string")
  in
  match list_of_arguments with
  | [] ->
      Parser.Exception
        (new Parser.arg
           "This function requires one argument and you supplied none")
  | t :: _ -> aux t

(**Extract the string from a parameter*)
let extract_string_from_arg param =
  match param with
  | Parser.Argument (Parser.Str s) -> s
  | Parser.Argument (Parser.I i) -> string_of_int i
  | Parser.Argument (Parser.D d) -> string_of_float d
  | Parser.Argument (Parser.Bool b) -> string_of_bool b
  | _ -> ""

(**Transform an array into a string*)
let transform_from_array list_of_arguments =
  let aux arr =
    match arr with
    | Parser.TBL arr ->
        Parser.Argument
          (Parser.Str
             (Array.map extract_string_from_arg arr
             |> Array.to_list |> String.concat ""))
    | _ -> Parser.Exception (new Parser.type_error "argument must be an array")
  in
  match list_of_arguments with
  | [] ->
      Parser.Exception
        (new Parser.arg
           "This function requires one argument and you supplied none")
  | t :: _ -> aux t

(**Takes two string and returns s1^s2*)
let proto_concat s1 s2 =
  match (s1, s2) with
  | Parser.Argument (Parser.Str s1), Parser.Argument (Parser.Str s2) ->
      Parser.Argument (Parser.Str (s1 ^ s2))
  | _ -> Parser.Exception (new Parser.type_error "arguments must be strings")

(**Takes an integer and a string and returns s.[n]*)
let proto_access n s =
  match (n, s) with
  | Parser.Argument (Parser.I n), Parser.Argument (Parser.Str s) ->
      if n >= String.length s then
        Parser.Exception
          (new Parser.outofbound
             ("The string is only of length" ^ string_of_int (String.length s)))
      else Parser.Argument (Parser.Str (String.make 1 s.[n]))
  | _ ->
      Parser.Exception
        (new Parser.type_error "arguments must be an integer and a string")

(**Split s1 at every s2 occurences*)
let proto_split s1 s2 =
  match (s1, s2) with
  | Parser.Argument (Parser.Str s1), Parser.Argument (Parser.Str s2) ->
      let regex = Str.regexp s2 in
      let arr = Str.split regex s1 in
      let al = List.map Parser.create_string_argument arr in
      Parser.TBL (Array.of_list al)
  | _ -> Parser.Exception (new Parser.type_error "arguments must be strings")

(**Creates the function with the generic method and the proto one*)

let replace = three_argument_func proto_replace
let concat = two_argument_func proto_concat
let create = two_argument_func proto_create
let access = two_argument_func proto_access
let split = two_argument_func proto_split

(**Conversion*)

(**Converts an element to a string*)
let convert_to_string list_of_arguments =
  match list_of_arguments with
  | [] ->
      Parser.Exception
        (new Parser.arg
           "this function requires an argument and you supplied none")
  | Parser.Argument (Parser.I i) :: _ ->
      Parser.create_string_argument (string_of_int i)
  | Parser.Argument (Parser.D d) :: _ ->
      Parser.create_string_argument (string_of_float d)
  | Parser.Argument (Parser.Bool b) :: _ ->
      Parser.create_string_argument (string_of_bool b)
  | _ ->
      Parser.Exception
        (new Parser.type_error
           "the supplied types are not convertible to string")

(**Converts a string to an integer*)
let int_from_string list_of_arguments =
  match list_of_arguments with
  | [] ->
      Parser.Exception
        (new Parser.arg
           "this function requires an argument and you supplied none")
  | Parser.Argument (Parser.Str s) :: _ -> (
      try Parser.create_int_argument (int_of_string s)
      with Failure _ ->
        Parser.Exception (new Parser.bag_exception "Error while converting"))
  | _ ->
      Parser.Exception (new Parser.type_error "the argument must be a string")

(**Converts a string to a float*)
let double_from_string list_of_arguments =
  match list_of_arguments with
  | [] ->
      Parser.Exception
        (new Parser.arg
           "this function requires an argument and you supplied none")
  | Parser.Argument (Parser.Str s) :: _ -> (
      try Parser.create_float_argument (float_of_string s)
      with Failure _ ->
        Parser.Exception (new Parser.bag_exception "Error while converting"))
  | _ ->
      Parser.Exception (new Parser.type_error "the argument must be a string")

(**Converts a string to a boolean*)
let bool_from_string list_of_arguments =
  match list_of_arguments with
  | [] ->
      Parser.Exception
        (new Parser.arg
           "this function requires an argument and you supplied none")
  | Parser.Argument (Parser.Str s) :: _ -> (
      try Parser.create_bool_argument (bool_of_string s)
      with Failure _ ->
        Parser.Exception (new Parser.bag_exception "Error while converting"))
  | _ ->
      Parser.Exception (new Parser.type_error "the argument must be a string")