Source file var.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
open! Core
open! Import0
include Var_intf
module Buffer = Buffer0

type 'a t =
  { symbol : Symbol.t
  ; type_ : 'a Value.Type.t
  }
[@@deriving fields]

let sexp_of_t _ { symbol; type_ } =
  [%message "" ~_:(symbol : Symbol.t) ~_:(type_ : _ Value.Type.t)]
;;

type 'a var = 'a t [@@deriving sexp_of]

let create symbol type_ =
  { symbol
  ; type_ =
      Value.Type.with_of_value_exn type_ (fun value ->
        try Value.Type.of_value_exn type_ value with
        | exn ->
          raise_s
            [%message
              ""
                ~_:(concat [ "invalid value for variable: "; symbol |> Symbol.name ])
                ~_:(exn : exn)])
  }
;;

module Wrap = struct
  let ( <: ) name type_ = create (name |> Symbol.intern) type_

  include (Value.Type : Value.Type.S)
end

let symbol_as_value t = t.symbol |> Symbol.to_value
let default_value = Funcall.Wrap.("default-value" <: Symbol.t @-> return value)
let default_value_exn t = default_value t.symbol |> Value.Type.of_value_exn t.type_
let default_boundp = Funcall.Wrap.("default-boundp" <: Symbol.t @-> return bool)
let default_value_is_defined t = default_boundp t.symbol
let set_default = Funcall.Wrap.("set-default" <: Symbol.t @-> value @-> return nil)
let set_default_value t a = set_default t.symbol (a |> Value.Type.to_value t.type_)

let make_variable_buffer_local =
  Funcall.Wrap.("make-variable-buffer-local" <: Symbol.t @-> return nil)
;;

let make_buffer_local_always t =
  add_gc_root (symbol_as_value t);
  make_variable_buffer_local t.symbol
;;

let local_variable_if_set_p =
  Funcall.Wrap.("local-variable-if-set-p" <: Symbol.t @-> Buffer.t @-> return bool)
;;

let is_buffer_local_if_set t buffer = local_variable_if_set_p t.symbol buffer

let is_buffer_local_always var =
  let buffer = Buffer.create ~name:"*for [Var.is_buffer_local_always]*" in
  let result = is_buffer_local_if_set var buffer in
  Buffer.Blocking.kill buffer;
  result
;;

module And_value = struct
  type t = T : 'a var * 'a -> t [@@deriving sexp_of]
end

module And_value_option = struct
  type t = T : 'a var * 'a option -> t [@@deriving sexp_of]
end