Skip to content

Commit eb7a251

Browse files
authored
uses context variables to store the current theory (#1342)
* Introduces context variables to the knowledge library * makes theory a part of the context Introduces the [Theory.current] and [Theory.with_current] functions.
1 parent 46e6454 commit eb7a251

File tree

4 files changed

+121
-41
lines changed

4 files changed

+121
-41
lines changed

lib/bap/bap_project.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,10 @@ let create
408408
Signal.send Info.got_code code;
409409
Signal.send Info.got_spec spec;
410410
let run k =
411-
let k = KB.(set_package package >>= fun () -> k) in
411+
let k = KB.(set_package package >>= fun () ->
412+
Theory.instance () >>= fun theory ->
413+
Theory.with_current theory @@ fun () ->
414+
k) in
412415
State.Toplevel.run spec target ~code ~memory file k in
413416
let state = match state with
414417
| Some state -> state

lib/bap_core_theory/bap_core_theory.mli

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,8 @@
266266
267267
{[
268268
let () =
269-
Theory.declare "my-constant-tracker"
270-
Theory.instance ~require:["bap.std:constant-tracker"] >>=
269+
Theory.declare "my-constant-tracker" @@
270+
Theory.instance ~require:["bap.std:constant-tracker"] >>=
271271
Theory.require >>|
272272
fun (module Base) : Theory.core -> (module struct
273273
include Base
@@ -3030,29 +3030,39 @@ module Theory : sig
30303030
(module Core) knowledge ->
30313031
unit
30323032

3033-
(** [instance ()] creates an instance of the Core Theory.
3033+
(** [instance ()] returns the current or creates a new instance of
3034+
the core theory.
30343035
3035-
The instance is built from all theories that match the context
3036-
specified by the [features] list and provide features specified
3037-
by the [requires] list. If any theory is subsumed by other
3038-
theory, then it is excluded.
3036+
If no parameters of the [instance] function were specialized
3037+
and there is an instance of the current theory then this
3038+
instance is returned.
30393039
3040-
If no instances satisfy this requirement than the empty theory
3040+
Otherwise, the instance is built from all theories that match
3041+
the context specified by the [context] list and provide features
3042+
specified by the [requires] list. If any theory is subsumed by
3043+
other theory, then it is excluded.
3044+
3045+
If no instances satisfy this requirement then the empty theory
30413046
is returned. If only one theory satisfies the requirement, then
30423047
it is returned. If many theories match, then a join of all
30433048
theories is computed, stored in the knowledge base, and the
30443049
resulting theory is returned.
30453050
3046-
To manifest a theory into an structure, use the [require] function.
3051+
To manifest a theory into an structure, use the [require]
3052+
function. The [current] function is equivalent to the
3053+
composition [instance >=> require], use this function, if you
3054+
want to use the current theory.
30473055
3048-
@param features is a set of features that define the context,
3056+
@param context is a set of features that define the context,
30493057
only those theories that have a context that is a subset of
30503058
provided will be instantiated.
30513059
30523060
@param requires is a set of semantic features that are
30533061
required. Defaults to the set of all possible features, i.e., if
30543062
unspecified, then all instances applicable to the context will
30553063
be loaded.
3064+
3065+
@since 2.4.0 respects the currently set theory.
30563066
*)
30573067
val instance :
30583068
?context:string list ->
@@ -3062,15 +3072,19 @@ module Theory : sig
30623072
(** [require theory] manifests the [theory] as an OCaml structure.
30633073
30643074
It is only possible to create an instance of theory using the
3065-
{!instance} function. For example, the following will create an
3066-
theory that is a join all currently declared theories (which are
3067-
not specific to any context),
3075+
{!instance} function, but see also {!current}.
3076+
3077+
For example, the following will create an theory that is a join
3078+
all currently declared theories (which are not specific to any
3079+
context),
30683080
30693081
{[
3070-
Theory.(instance>=>require) () -> fun (module Core) ->
3082+
let* (module CT) = Theory.(instance>=>require) () in
30713083
]}
30723084
3073-
To a create an instance for a specific context and requirements,
3085+
where [let*] comes from [KB.Let].
3086+
3087+
To create an instance for a specific context and requirements,
30743088
30753089
{[
30763090
Theory.instance ()
@@ -3089,6 +3103,41 @@ module Theory : sig
30893103
*)
30903104
val require : theory -> (module Core) knowledge
30913105

3106+
3107+
3108+
(** [current] returns the current core theory structure.
3109+
3110+
This function is the same as [instance >=> require].
3111+
3112+
If there is no current theory set in the contex (via the
3113+
{!with_current} function) then a new structure is created,
3114+
otherwise returns the current selected theory.
3115+
3116+
An example of usage,
3117+
3118+
{[
3119+
let add x y =
3120+
let* (module CT) = current in
3121+
CT.add x y
3122+
]}
3123+
3124+
@since 2.4.0
3125+
*)
3126+
val current : (module Core) knowledge
3127+
3128+
(** [with_current t f] sets [t] as the current theory in the scope of [f].
3129+
3130+
Evaluates compuation [f] in the theory of [t]. After [f] is
3131+
evaluated the current theory is restored. This function could be
3132+
safely called recursively, i.e., in a scope of another call to
3133+
[with_current]. Effectively, [with_current], which uses
3134+
[KB.Context.with_var] underneath the hood, creates a dynamic
3135+
scope for the theory variable.
3136+
3137+
@since 2.4.0
3138+
*)
3139+
val with_current : theory -> (unit -> 'a knowledge) -> 'a knowledge
3140+
30923141
(** Sorts implementing IEEE754 formats.
30933142
30943143
This module provides an infinite set of indexed sorts for

lib/bap_core_theory/bap_core_theory_manager.ml

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -311,19 +311,33 @@ let slot = Knowledge.Class.property theory "instance" domain
311311
~package:"core"
312312
~desc:"The theory structure"
313313

314-
315-
let str_ctxt () ctxt =
316-
List.to_string (Set.to_list ctxt) ~f:ident
314+
let current = Knowledge.Context.declare
315+
~package:"core" "*current-theory*"
316+
!!(Knowledge.Object.null theory)
317317

318318
module Theory = (val Knowledge.Object.derive theory)
319319

320+
let theories = KB.Context.declare
321+
~package:"core" "*theories*"
322+
!!None
323+
320324
let theories () =
321-
let init = Map.empty (module Theory) in
322-
Hashtbl.to_alist known_theories |>
323-
Knowledge.List.fold ~init ~f:(fun theories (name,def) ->
324-
Knowledge.Symbol.intern (Name.unqualified name) theory
325-
~package:(Name.package name) >>| fun name ->
326-
Map.add_exn theories name def)
325+
KB.Context.get theories >>= function
326+
| Some theories -> !!theories
327+
| None ->
328+
let init = Map.empty (module Theory) in
329+
Hashtbl.to_alist known_theories |>
330+
Knowledge.List.fold ~init ~f:(fun theories (name,def) ->
331+
Knowledge.Symbol.intern (Name.unqualified name) theory
332+
~package:(Name.package name) >>| fun name ->
333+
Map.add_exn theories name def) >>= fun r ->
334+
KB.Context.set theories (Some r) >>| fun () ->
335+
r
336+
337+
338+
let str_ctxt () ctxt =
339+
List.to_string (Set.to_list ctxt) ~f:ident
340+
327341

328342
let is_applicable ~provided ~requires =
329343
Set.for_all requires ~f:(Set.mem provided)
@@ -388,22 +402,30 @@ let instantiate t =
388402
id
389403

390404
let instance ?context ?requires () =
391-
theories () >>| Map.data >>| refine ?context ?requires >>= function
392-
| [] -> theory_for_id Empty.theory.id
393-
| [t] ->
394-
instantiate t
395-
| theories ->
396-
List.fold theories ~init:(Set.empty (module Name)) ~f:(fun names t ->
397-
Set.union names t.id) |>
398-
theory_for_id >>= fun id ->
399-
is_instantiated id >>= function
400-
| true -> Knowledge.return id
401-
| false ->
402-
Knowledge.List.map theories
403-
~f:(instantiate >=> Knowledge.collect slot) >>|
404-
List.reduce_balanced_exn ~f:merge >>=
405-
Knowledge.provide slot id >>| fun () ->
406-
id
405+
KB.Context.get current >>= fun theory ->
406+
match context, requires with
407+
| None,None when not (Knowledge.Object.is_null theory) -> !!theory
408+
| _ ->
409+
theories () >>| Map.data >>| refine ?context ?requires >>= function
410+
| [] -> theory_for_id Empty.theory.id
411+
| [t] ->
412+
instantiate t
413+
| theories ->
414+
List.fold theories ~init:(Set.empty (module Name)) ~f:(fun names t ->
415+
Set.union names t.id) |>
416+
theory_for_id >>= fun id ->
417+
is_instantiated id >>= function
418+
| true -> Knowledge.return id
419+
| false ->
420+
Knowledge.List.map theories
421+
~f:(instantiate >=> Knowledge.collect slot) >>|
422+
List.reduce_balanced_exn ~f:merge >>=
423+
Knowledge.provide slot id >>| fun () ->
424+
id
425+
426+
let with_current t f =
427+
Knowledge.Context.with_var current t f
428+
407429

408430
let require name =
409431
let open Knowledge.Syntax in
@@ -413,6 +435,8 @@ let require name =
413435
| None -> Knowledge.collect slot name >>| fun t ->
414436
t.structure
415437

438+
let current = (instance >=> require) ()
439+
416440

417441
module Documentation = struct
418442
module Theory = struct

lib/bap_core_theory/bap_core_theory_manager.mli

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ val instance :
1818

1919
val require : theory -> (module Core) knowledge
2020

21+
val with_current : theory -> (unit -> 'a knowledge) -> 'a knowledge
22+
23+
val current : (module Core) knowledge
24+
2125
module Documentation : sig
2226
module Theory : sig
2327
type t

0 commit comments

Comments
 (0)