• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

formalsec / smtml / 529

27 Apr 2026 11:42AM UTC coverage: 48.244% (-0.05%) from 48.293%
529

push

github

filipeom
Disable implicit transitive deps

0 of 3 new or added lines in 1 file covered. (0.0%)

2 existing lines in 1 file now uncovered.

2417 of 5010 relevant lines covered (48.24%)

41.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

23.46
/src/smtml/dolmenexpr_to_expr.ml
1
(* SPDX-License-Identifier: MIT *)
2
(* Copyright (C) 2023-2026 formalsec *)
3
(* Written by Hichem Rami Ait El Hara *)
4

5
module DExpr = Dolmen_std.Expr
6
module DTy = DExpr.Ty
7
module DTerm = DExpr.Term
8
module DBuiltin = Dolmen_std.Builtin
9
module DM = Dolmen_model
10

11
module Builtin = struct
12
  (* additional builtins *)
13

14
  let string_ty_cst : DExpr.Term.ty_const =
15
    DExpr.Id.mk ~builtin:DBuiltin.Base
28✔
16
      (Dolmen_std.Path.global "StringTy")
28✔
17
      DExpr.{ arity = 0; alias = No_alias }
18

19
  let string_ty = DTy.apply string_ty_cst []
28✔
20

21
  let float32_ty = DTy.float 8 24
28✔
22

23
  let float64_ty = DTy.float 11 53
28✔
24

25
  let int_to_string : DExpr.term_cst =
26
    DExpr.Id.mk ~name:"IntToString" ~builtin:DBuiltin.Base
28✔
27
      (Dolmen_std.Path.global "IntToString")
28✔
28
      (DTy.arrow [ DTy.int ] string_ty)
28✔
29

30
  let string_to_int : DExpr.term_cst =
31
    DExpr.Id.mk ~name:"StringToInt" ~builtin:DBuiltin.Base
28✔
32
      (Dolmen_std.Path.global "StringToInt")
28✔
33
      (DTy.arrow [ string_ty ] DTy.int)
28✔
34

35
  let real_to_string : DExpr.term_cst =
36
    DExpr.Id.mk ~name:"RealToString" ~builtin:DBuiltin.Base
28✔
37
      (Dolmen_std.Path.global "RealToString")
28✔
38
      (DTy.arrow [ DTy.real ] string_ty)
28✔
39

40
  let string_to_real : DExpr.term_cst =
41
    DExpr.Id.mk ~name:"StringToReal" ~builtin:DBuiltin.Base
28✔
42
      (Dolmen_std.Path.global "StringToReal")
28✔
43
      (DTy.arrow [ string_ty ] DTy.real)
28✔
44

45
  let real_to_uint32 : DExpr.term_cst =
46
    DExpr.Id.mk ~name:"RealToUInt32" ~builtin:DBuiltin.Base
28✔
47
      (Dolmen_std.Path.global "RealToUInt32")
28✔
48
      (DTy.arrow [ DTy.real ] DTy.real)
28✔
49

50
  let trim_string : DExpr.term_cst =
51
    DExpr.Id.mk ~name:"TrimString" ~builtin:DBuiltin.Base
28✔
52
      (Dolmen_std.Path.global "TrimString")
28✔
53
      (DTy.arrow [ string_ty ] string_ty)
28✔
54

55
  let f32_to_string : DExpr.term_cst =
56
    DExpr.Id.mk ~name:"F32ToString" ~builtin:DBuiltin.Base
28✔
57
      (Dolmen_std.Path.global "F32ToString")
28✔
58
      (DTy.arrow [ float32_ty ] string_ty)
28✔
59

60
  let string_to_f32 : DExpr.term_cst =
61
    DExpr.Id.mk ~name:"StringToF32" ~builtin:DBuiltin.Base
28✔
62
      (Dolmen_std.Path.global "StringToF32")
28✔
63
      (DTy.arrow [ string_ty ] float32_ty)
28✔
64

65
  let f64_to_string : DExpr.term_cst =
66
    DExpr.Id.mk ~name:"F64ToString" ~builtin:DBuiltin.Base
28✔
67
      (Dolmen_std.Path.global "F64ToString")
28✔
68
      (DTy.arrow [ float64_ty ] string_ty)
28✔
69

70
  let string_to_f64 : DExpr.term_cst =
71
    DExpr.Id.mk ~name:"StringToF64" ~builtin:DBuiltin.Base
28✔
72
      (Dolmen_std.Path.global "StringToF64")
28✔
73
      (DTy.arrow [ string_ty ] float64_ty)
28✔
74
end
75

76
module DolmenIntf = struct
77
  include DTerm
78

79
  module ConstMap = Map.Make (struct
80
    type t = DTerm.Const.t
81

82
    let compare = DTerm.Const.compare
83
  end)
84

85
  type ty = DTy.t
86

87
  type term = DTerm.t
88

89
  type interp = DM.Value.t
90

91
  type func_decl = DTerm.Const.t
92

93
  type model = interp ConstMap.t
94

95
  let true_ = DTerm._true
96

97
  let false_ = DTerm._false
98

99
  let int i = DTerm.Int.mk (string_of_int i)
×
100

101
  let real r = DTerm.Real.mk (string_of_float r)
×
102

103
  let const s ty = DTerm.of_cst (DTerm.Const.mk (Dolmen_std.Path.global s) ty)
×
104

105
  let not_ = DTerm.neg
106

107
  let and_ a b = DTerm._and [ a; b ]
×
108

109
  let or_ a b = DTerm._or [ a; b ]
×
110

111
  let implies = DTerm.imply
112

113
  let logand = DTerm._and
114

115
  let logor = DTerm._or
116

117
  let get_vars_from_terms tl =
118
    List.map
×
119
      (fun (t : DTerm.t) ->
120
        match t.term_descr with
×
121
        | Var v -> v
×
122
        | _ ->
×
123
          Fmt.failwith {|Can't quantify non-variable term "%a"|} DTerm.print t )
124
      tl
125

126
  let forall tl t =
127
    let tvl = get_vars_from_terms tl in
×
128
    DTerm.all ([], tvl) t
×
129

130
  let exists (tl : term list) t =
131
    let tvl = get_vars_from_terms tl in
×
132
    DTerm.ex ([], tvl) t
×
133

134
  let nary_to_binary f tl =
135
    let rec aux acc = function
×
136
      | [] -> acc
×
137
      | h :: t -> aux (DTerm.apply_cst f [] [ acc; h ]) t
×
138
    in
139
    match tl with
140
    | h1 :: h2 :: t -> aux (DTerm.apply_cst f [] [ h1; h2 ]) t
×
141
    | _ ->
×
142
      Fmt.failwith {|%a applied to less than two terms|} DTerm.Const.print f
143

144
  let int_of_term (t : DTerm.t) =
145
    match t.term_descr with
×
146
    | Cst { builtin = DBuiltin.Bitvec i; _ } ->
×
147
      (* There may be a proper alternative to int_of_string somewhere,
148
         since its hidden by prelude. *)
149
      Z.to_int (Z.of_string i)
×
150
    | _ ->
×
151
      Fmt.failwith
152
        {|int_of_term: expected a term that is an integer constant, instead got: %a|}
153
        DTerm.print t
154

155
  module Types = struct
156
    include DTy
157

158
    let regexp = DTy.string_reg_lang
159

160
    let ty = DTerm.ty
161

162
    let to_ety (ty : DTy.t) : Ty.t =
163
      match ty with
×
164
      | { ty_descr = TyApp ({ builtin = DBuiltin.Int; _ }, _); _ } -> Ty_int
×
165
      | { ty_descr = TyApp ({ builtin = DBuiltin.Real; _ }, _); _ } -> Ty_real
×
166
      | { ty_descr = TyApp ({ builtin = DBuiltin.Prop; _ }, _); _ } -> Ty_bool
×
167
      | { ty_descr =
×
168
            TyApp
169
              ( { builtin = DBuiltin.Base
170
                ; path = Absolute { name = "StringTy"; _ }
171
                ; _
172
                }
173
              , _ )
174
        ; _
175
        } ->
176
        Ty_str
177
      | { ty_descr = TyApp ({ builtin = DBuiltin.Bitv n; _ }, _); _ } ->
×
178
        Ty_bitv n
179
      | { ty_descr = TyApp ({ builtin = DBuiltin.Float (8, 24); _ }, _); _ } ->
×
180
        Ty_fp 32
181
      | { ty_descr = TyApp ({ builtin = DBuiltin.Float (11, 53); _ }, _); _ } ->
×
182
        Ty_fp 64
183
      | _ -> Fmt.failwith {|Unsupported dolmen type "%a"|} DTy.print ty
×
184
  end
185

186
  module Interp = struct
187
    let to_int interp =
188
      match DM.Value.extract ~ops:DM.Int.ops interp with
×
189
      | Some z -> Z.to_int z
×
190
      | _ -> assert false
191

192
    let to_real interp =
193
      match DM.Value.extract ~ops:DM.Real.ops interp with
×
194
      | Some q -> Q.to_float q
×
195
      | _ -> assert false
196

197
    let to_bool interp =
198
      match DM.Value.extract ~ops:DM.Bool.ops interp with
×
199
      | Some b -> b
×
200
      | None -> assert false
201

202
    let to_string _ = assert false
×
203

204
    let to_bitv interp _n =
205
      match DM.Value.extract ~ops:DM.Bitv.ops interp with
×
206
      | Some z -> z
×
207
      | _ -> assert false
208

209
    let to_float interp _eb _sb =
210
      match DM.Value.extract ~ops:DM.Fp.ops interp with
×
211
      | Some f -> Farith.F.to_float Farith.Mode.NE f
×
212
      | _ -> assert false
213
  end
214

215
  module Int = struct
216
    include DTerm.Int
217

218
    let neg = DTerm.Int.minus
219

220
    let to_bv = DTerm.Bitv.of_int
221

222
    let mod_ = DTerm.Int.rem_f
223
  end
224

225
  module Real = struct
226
    include DTerm.Real
227

228
    let neg = DTerm.Real.minus
229
  end
230

231
  module String = struct
232
    include DTerm.String
233

234
    let v = DTerm.String.of_ustring
235

236
    let to_re = DTerm.String.RegLan.of_string
237

238
    let at t ~pos = DTerm.String.at t pos
×
239

240
    let concat = nary_to_binary DTerm.Const.String.concat
28✔
241

242
    let contains t ~sub = DTerm.String.contains t sub
×
243

244
    let is_prefix t ~prefix = DTerm.String.is_prefix t prefix
×
245

246
    let is_suffix t ~suffix = DTerm.String.is_suffix t suffix
×
247

248
    let le = DTerm.String.leq
249

250
    let sub t ~pos ~len = DTerm.String.sub t pos len
×
251

252
    let index_of t ~sub ~pos = DTerm.String.index_of t sub pos
×
253

254
    let replace t ~pattern ~with_ = DTerm.String.replace t pattern with_
×
255

256
    let replace_all t ~pattern ~with_ = DTerm.String.replace_all t pattern with_
×
257

258
    let replace_re t ~pattern ~with_ = DTerm.String.replace_re t pattern with_
×
259

260
    let replace_re_all t ~pattern ~with_ =
261
      DTerm.String.replace_re_all t pattern with_
×
262
  end
263

264
  module Re = struct
265
    let all () = DTerm.String.RegLan.all
×
266

267
    let allchar () = DTerm.String.RegLan.allchar
×
268

269
    let none () = DTerm.String.RegLan.empty
×
270

271
    let star = DTerm.String.RegLan.star
272

273
    let plus = DTerm.String.RegLan.cross
274

275
    let opt = DTerm.String.RegLan.option
276

277
    let comp = DTerm.String.RegLan.complement
278

279
    let range = DTerm.String.RegLan.range
280

281
    let diff = DTerm.String.RegLan.diff
282

283
    let inter = DTerm.String.RegLan.inter
284

285
    let loop ~min ~max t = DTerm.String.RegLan.loop min max t
×
286

287
    let union = nary_to_binary DTerm.Const.String.Reg_Lang.union
28✔
288

289
    let concat = nary_to_binary DTerm.Const.String.Reg_Lang.concat
28✔
290
  end
291

292
  module Bitv = struct
293
    include DTerm.Bitv
294

295
    let int_to_bitvector (n : Z.t) (bits : int) : string =
296
      let two_pow_n = Z.shift_left Z.one bits in
×
297
      let unsigned_bv = if Z.lt n Z.zero then Z.add two_pow_n n else n in
×
298
      let rec to_bitlist acc n bits =
299
        if bits = 0 then acc
×
300
        else
301
          let bit = Z.(logand n one |> to_string) in
×
302
          to_bitlist
NEW
303
            (Smtml_prelude.String.cat bit acc)
×
NEW
304
            (Z.shift_right n 1) (bits - 1)
×
305
      in
306
      to_bitlist "" unsigned_bv bits
307

308
    let v (i : string) (n : int) =
309
      let bv = int_to_bitvector (Z.of_string i) n in
×
310
      DTerm.Bitv.mk bv
×
311

312
    let of_z (v : Z.t) (n : int) = DTerm.Bitv.mk (int_to_bitvector v n)
×
313

314
    let lognot = DTerm.Bitv.not
315

316
    let to_int ~signed:_ = DTerm.Bitv.to_nat
×
317

318
    let div = DTerm.Bitv.sdiv
319

320
    let div_u = DTerm.Bitv.udiv
321

322
    let logor = DTerm.Bitv.or_
323

324
    let logand = DTerm.Bitv.and_
325

326
    let logxor = DTerm.Bitv.xor
327

328
    let shl = DTerm.Bitv.shl
329

330
    let ashr = DTerm.Bitv.ashr
331

332
    let lshr = DTerm.Bitv.lshr
333

334
    let rem = DTerm.Bitv.srem
335

336
    let rem_u = DTerm.Bitv.urem
337

338
    let rotate_left t1 t2 = DTerm.Bitv.rotate_left (int_of_term t2) t1
×
339

340
    let rotate_right t1 t2 = DTerm.Bitv.rotate_right (int_of_term t2) t1
×
341

342
    let nego _ = Fmt.failwith "Dolmenexpr: nego not implemented"
×
343

344
    let addo ~signed:_ = Fmt.failwith "Dolmenexpr: addo not implemented"
×
345

346
    let subo ~signed:_ = Fmt.failwith "Dolmenexpr: subo not implemented"
×
347

348
    let mulo ~signed:_ = Fmt.failwith "Dolmenexpr: mulo not implemented"
×
349

350
    let divo _ = Fmt.failwith "Dolmenexpr: divo not implemented"
×
351

352
    let lt = DTerm.Bitv.slt
353

354
    let lt_u = DTerm.Bitv.ult
355

356
    let le = DTerm.Bitv.sle
357

358
    let le_u = DTerm.Bitv.ule
359

360
    let gt = DTerm.Bitv.sgt
361

362
    let gt_u = DTerm.Bitv.ugt
363

364
    let ge = DTerm.Bitv.sge
365

366
    let ge_u = DTerm.Bitv.uge
367

368
    let extract t ~high ~low = DTerm.Bitv.extract high low t
×
369
  end
370

371
  module Float = struct
372
    include DTerm.Float
373

374
    module Rounding_mode = struct
375
      let rne = DTerm.Float.roundNearestTiesToEven
376

377
      let rna = DTerm.Float.roundNearestTiesToAway
378

379
      let rtp = DTerm.Float.roundTowardPositive
380

381
      let rtn = DTerm.Float.roundTowardNegative
382

383
      let rtz = DTerm.Float.roundTowardZero
384
    end
385

386
    let v f e s =
387
      DTerm.Float.real_to_fp e s DTerm.Float.roundTowardZero
×
NEW
388
        (DTerm.Real.mk (Smtml_prelude.Float.to_string f))
×
389

390
    let sqrt ~rm t = DTerm.Float.sqrt rm t
×
391

392
    let is_normal = DTerm.Float.isNormal
393

394
    let is_subnormal = DTerm.Float.isSubnormal
395

396
    let is_negative = DTerm.Float.isNegative
397

398
    let is_positive = DTerm.Float.isPositive
399

400
    let is_infinite = DTerm.Float.isInfinite
401

402
    let is_nan = DTerm.Float.isNaN
403

404
    let is_zero = DTerm.Float.isZero
405

406
    let round_to_integral ~rm t = DTerm.Float.roundToIntegral rm t
×
407

408
    let add ~rm t1 t2 = DTerm.Float.add rm t1 t2
×
409

410
    let sub ~rm t1 t2 = DTerm.Float.sub rm t1 t2
×
411

412
    let mul ~rm t1 t2 = DTerm.Float.mul rm t1 t2
×
413

414
    let div ~rm t1 t2 = DTerm.Float.div rm t1 t2
×
415

416
    let fma ~rm a b c = DTerm.Float.fma rm a b c
×
417

418
    let le = DTerm.Float.leq
419

420
    let ge = DTerm.Float.geq
421

422
    let to_fp e s ~rm fp = DTerm.Float.to_fp e s rm fp
×
423

424
    let sbv_to_fp e s ~rm bv = DTerm.Float.sbv_to_fp e s rm bv
×
425

426
    let ubv_to_fp e s ~rm bv = DTerm.Float.ubv_to_fp e s rm bv
×
427

428
    let to_ubv n ~rm fp = DTerm.Float.to_ubv n rm fp
×
429

430
    let to_sbv n ~rm fp = DTerm.Float.to_sbv n rm fp
×
431

432
    let of_ieee_bv eb sb bv = DTerm.Float.ieee_format_to_fp eb sb bv
×
433

434
    let to_ieee_bv = None
435
  end
436

437
  module Func = struct
438
    let make name tyl ty =
439
      DTerm.Const.mk (Dolmen_std.Path.global name) (DTy.arrow tyl ty)
×
440

441
    let apply f tl = DTerm.apply_cst f [] tl
×
442
  end
443

444
  module Adt = struct
445
    module Cons = struct
446
      type t = Dolmen_std.Path.t * (ty * Dolmen_std.Path.t option) list
447

448
      let make _ ~fields:_ = assert false
×
449
    end
450

451
    type t = DExpr.ty_def * (func_decl * (ty * func_decl option) list) list
452

453
    let make cons_name cons =
454
      let cons_name = DTy.Const.mk (Dolmen_std.Path.local cons_name) 0 in
×
455
      DTerm.define_adt cons_name [] cons
×
456

457
    let ty _ = assert false
×
458

459
    let constructor _ = assert false
×
460

461
    let selector _ = assert false
×
462

463
    let tester _ = assert false
×
464
  end
465

466
  module Smtlib = struct
467
    let pp ?name:_ ?logic:_ ?status:_ = Fmt.list DTerm.print
×
468
  end
469

470
  module Model = struct
471
    let tcst_to_symbol (c : DTerm.Const.t) : Symbol.t =
472
      match c with
×
473
      | { builtin = DBuiltin.Base
×
474
        ; path = Local { name } | Absolute { name; _ }
×
475
        ; id_ty
476
        ; _
477
        } ->
478
        Symbol.make (Types.to_ety id_ty) name
×
479
      | _ ->
×
480
        Fmt.failwith {|Unsupported constant term "%a"|} DExpr.Print.term_cst c
481

482
    let get_defval (c : DTerm.Const.t) : DM.Value.t =
483
      match DTerm.Const.ty c with
×
484
      | { ty_descr = TyApp ({ builtin = DBuiltin.Int; _ }, _); _ } ->
×
485
        DM.Int.mk Z.zero
486
      | { ty_descr = TyApp ({ builtin = DBuiltin.Real; _ }, _); _ } ->
×
487
        DM.Real.mk Q.zero
488
      | { ty_descr = TyApp ({ builtin = DBuiltin.Prop; _ }, _); _ } ->
×
489
        DM.Bool.mk false
490
      | { ty_descr = TyApp ({ builtin = DBuiltin.Bitv n; _ }, _); _ } ->
×
491
        DM.Bitv.mk n Z.zero
492
      | { ty_descr = TyApp ({ builtin = DBuiltin.Float _; _ }, _); _ } ->
×
493
        DM.Fp.mk (Farith.F.of_float 0.)
×
494
      | _ -> assert false
495

496
    let get_symbols (m : model) =
497
      ConstMap.fold (fun tcst _ acc -> tcst_to_symbol tcst :: acc) m []
×
498

499
    let eval ?(ctx = Symbol.Map.empty) ?completion:_ (m : model) (e : term) :
×
500
      interp option =
501
      let m =
×
502
        ConstMap.fold (fun c v acc -> DM.Model.Cst.add c v acc) m DM.Model.empty
×
503
      in
504
      let m =
×
505
        Symbol.Map.fold
506
          (fun _ (t : term) acc ->
507
            match t with
×
508
            | { term_descr = Cst c; _ } -> (
×
509
              match DM.Model.Cst.find_opt c acc with
510
              | Some _ -> acc
×
511
              | None -> DM.Model.Cst.add c (get_defval c) acc )
×
512
            | _ -> assert false )
513
          ctx m
514
      in
515
      let env =
×
516
        DM.Env.mk m
517
          ~builtins:
518
            (DM.Eval.builtins
×
519
               [ DM.Core.builtins
520
               ; DM.Bool.builtins
521
               ; DM.Int.builtins
522
               ; DM.Rat.builtins
523
               ; DM.Real.builtins
524
               ; DM.Bitv.builtins
525
               ; DM.Fp.builtins
526
               ] )
527
      in
528
      let v = DM.Eval.eval env e in
×
529
      Some v
×
530
  end
531
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc