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
extern crate proc_macro;
use TokenStream;
/// Embeds and evaluates a Haskell Core expression at runtime.
///
/// Accepts either a `.cbor` path (pre-compiled CBOR) or a `.hs` path (Haskell
/// source compiled on-demand via `nix run .#tidepool-extract`).
///
/// For `.cbor` paths, the file is embedded directly via `include_bytes!`. For
/// `.hs` paths, the macro invokes GHC through nix at compile time, producing
/// CBOR in `target/tidepool-cbor/`, then embeds the result. The `.hs` source
/// file is tracked by cargo for automatic recompilation.
///
/// # Haskell Source Support
///
/// When given a `.hs` path, the macro compiles it via `nix run .#tidepool-extract`.
/// This requires `nix` to be available on `PATH`.
///
/// **Path resolution:** `.hs` paths resolve relative to `CARGO_MANIFEST_DIR`
/// (the crate root). `.cbor` paths resolve relative to the calling file (standard
/// `include_bytes!` behavior).
///
/// For modules with multiple top-level bindings, specify which binding to
/// evaluate using the `::binding` syntax. If only one binding exists (excluding
/// metadata), it is selected automatically.
///
/// # Panics
///
/// The generated code will panic during CBOR deserialization if the embedded data
/// is malformed or incompatible with the expected format.
///
/// # Dependencies
///
/// The expansion of this macro expects the following crates to be available in the
/// caller's scope:
///
/// - `tidepool_repr`
/// - `tidepool_eval`
///
/// # Returns
///
/// Returns a `Result<tidepool_eval::Value, tidepool_eval::error::EvalError>`.
///
/// # Examples
///
/// ```ignore
/// // Pre-compiled CBOR
/// let val = haskell_eval!("../../haskell/test/Identity_cbor/identity.cbor").unwrap();
///
/// // Haskell source (single binding)
/// let val = haskell_eval!("../../haskell/test/SingleBinding.hs").unwrap();
///
/// // Haskell source with binding selector
/// let val = haskell_eval!("../../haskell/test/Identity.hs::identity").unwrap();
/// ```
/// Embeds a Haskell Core expression and its DataConTable without evaluating.
///
/// Unlike `haskell_eval!`, this macro does NOT evaluate the expression. It
/// returns `(CoreExpr, DataConTable)` — suitable for effect-driven execution
/// via `EffectMachine` where the caller controls evaluation.
///
/// Accepts the same path formats as `haskell_eval!`:
/// - `.cbor` path (pre-compiled CBOR, requires a sibling `meta.cbor`)
/// - `.hs` path (compiled on-demand via `nix run .#tidepool-extract`)
/// - `.hs::binding` syntax for multi-binding modules
///
/// # Returns
///
/// Returns `(tidepool_repr::CoreExpr, tidepool_repr::DataConTable)`.
///
/// # Examples
///
/// ```ignore
/// let (expr, table) = haskell_expr!("../Guess.hs::game");
/// let mut heap = tidepool_eval::heap::VecHeap::new();
/// let mut machine = tidepool_effect::EffectMachine::new(&table, &mut heap).unwrap();
/// ```
/// Embeds inline Haskell source as a Core expression with its DataConTable.
///
/// Writes the Haskell source to a temporary file, compiles it via
/// `nix run .#tidepool-extract`, and embeds the resulting CBOR.
///
/// Supports `include` paths for importing local Haskell modules.
///
/// # Returns
///
/// Returns `(tidepool_repr::CoreExpr, tidepool_repr::DataConTable)`.
///
/// # Examples
///
/// ```ignore
/// let (expr, table) = haskell_inline! {
/// target = "game",
/// include = "haskell",
/// r#"
/// import Effects
///
/// game :: Eff '[Console, Rng] ()
/// game = do
/// target <- randInt 1 100
/// emit "I'm thinking of a number between 1 and 100."
/// guessLoop target
/// "#
/// };
/// ```