README.md (4975B)
1 # NickelEval.jl 2 3 Julia bindings for the [Nickel](https://nickel-lang.org/) configuration language, using the official Nickel C API. 4 5 Evaluate Nickel code directly from Julia with native type conversion and export to JSON/TOML/YAML. No Nickel CLI required. 6 7 ## Installation 8 9 ### From LouLouLibs Registry (Recommended) 10 11 ```julia 12 using Pkg 13 Pkg.Registry.add(url="https://github.com/LouLouLibs/loulouJL") 14 Pkg.add("NickelEval") 15 ``` 16 17 ### From GitHub URL 18 19 ```julia 20 using Pkg 21 Pkg.add(url="https://github.com/LouLouLibs/NickelEval.jl") 22 ``` 23 24 Pre-built binaries are downloaded automatically on supported platforms (macOS Apple Silicon, Linux x86_64). For other platforms, build from source: 25 26 ```bash 27 NICKELEVAL_BUILD_FFI=true julia -e 'using Pkg; Pkg.build("NickelEval")' 28 ``` 29 30 ## Quick Start 31 32 ```julia 33 using NickelEval 34 35 # Simple evaluation 36 nickel_eval("1 + 2") # => 3 37 38 # Records return Dict{String, Any} 39 config = nickel_eval("{ name = \"alice\", age = 30 }") 40 config["name"] # => "alice" 41 config["age"] # => 30 42 43 # String macro for inline Nickel 44 ncl"[1, 2, 3] |> std.array.map (fun x => x * 2)" 45 # => [2, 4, 6] 46 ``` 47 48 ## Typed Evaluation 49 50 Convert Nickel values directly to Julia types: 51 52 ```julia 53 # Typed dictionaries 54 nickel_eval("{ a = 1, b = 2 }", Dict{String, Int}) 55 # => Dict{String, Int64}("a" => 1, "b" => 2) 56 57 # Typed arrays 58 nickel_eval("[1, 2, 3, 4, 5]", Vector{Int}) 59 # => [1, 2, 3, 4, 5] 60 61 # NamedTuples for structured data 62 config = nickel_eval(""" 63 { 64 host = "localhost", 65 port = 8080, 66 debug = true 67 } 68 """, @NamedTuple{host::String, port::Int, debug::Bool}) 69 # => (host = "localhost", port = 8080, debug = true) 70 71 config.port # => 8080 72 ``` 73 74 ## Enums 75 76 Nickel enum types are preserved: 77 78 ```julia 79 result = nickel_eval("'Some 42") 80 result.tag # => :Some 81 result.arg # => 42 82 result == :Some # => true 83 84 nickel_eval("'None").tag # => :None 85 ``` 86 87 ## Export to Configuration Formats 88 89 Generate JSON, TOML, or YAML from Nickel: 90 91 ```julia 92 # JSON 93 nickel_to_json("{ name = \"myapp\", port = 8080 }") 94 # => "{\n \"name\": \"myapp\",\n \"port\": 8080\n}" 95 96 # TOML 97 nickel_to_toml("{ name = \"myapp\", port = 8080 }") 98 # => "name = \"myapp\"\nport = 8080\n" 99 100 # YAML 101 nickel_to_yaml("{ name = \"myapp\", port = 8080 }") 102 # => "name: myapp\nport: 8080\n" 103 ``` 104 105 ### Generate Config Files 106 107 ```julia 108 config_ncl = """ 109 { 110 database = { 111 host = "localhost", 112 port = 5432, 113 name = "mydb" 114 }, 115 server = { 116 host = "0.0.0.0", 117 port = 8080 118 } 119 } 120 """ 121 122 write("config.toml", nickel_to_toml(config_ncl)) 123 write("config.yaml", nickel_to_yaml(config_ncl)) 124 ``` 125 126 ## File Evaluation 127 128 Evaluate `.ncl` files with full import support: 129 130 ```julia 131 # config.ncl: 132 # let shared = import "shared.ncl" in 133 # { name = shared.project_name, version = "1.0" } 134 135 config = nickel_eval_file("config.ncl") 136 config["name"] # => "MyProject" 137 138 # Typed 139 nickel_eval_file("config.ncl", @NamedTuple{name::String, version::String}) 140 ``` 141 142 Import paths are resolved relative to the file's directory. 143 144 ## Building from Source 145 146 Pre-built binaries are downloaded automatically on macOS Apple Silicon and Linux x86_64. On other platforms (or if `check_ffi_available()` returns `false`), build from source: 147 148 ```bash 149 # Requires Rust (https://rustup.rs/) 150 NICKELEVAL_BUILD_FFI=true julia -e 'using Pkg; Pkg.build("NickelEval")' 151 ``` 152 153 ### HPC / Slurm Clusters 154 155 The pre-built Linux binary requires glibc >= 2.29. On older systems (RHEL 8, CentOS 8), it will warn and fall back gracefully. Build from source inside Julia: 156 157 ```julia 158 using NickelEval 159 build_ffi() # builds from source, no restart needed 160 ``` 161 162 This requires Rust. If `cargo` isn't available: 163 164 ```bash 165 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 166 source ~/.cargo/env 167 ``` 168 169 Then run `build_ffi()` again. 170 171 ## API Reference 172 173 ### Evaluation 174 175 | Function | Description | 176 |----------|-------------| 177 | `nickel_eval(code)` | Evaluate Nickel code, return Julia native types | 178 | `nickel_eval(code, T)` | Evaluate and convert to type `T` | 179 | `nickel_eval_file(path)` | Evaluate a `.ncl` file with import support | 180 | `@ncl_str` | String macro for inline evaluation | 181 | `check_ffi_available()` | Check if the C API library is loaded | 182 | `build_ffi()` | Build C API library from source (requires Rust) | 183 184 ### Export 185 186 | Function | Description | 187 |----------|-------------| 188 | `nickel_to_json(code)` | Export to JSON string | 189 | `nickel_to_toml(code)` | Export to TOML string | 190 | `nickel_to_yaml(code)` | Export to YAML string | 191 192 ## Type Conversion 193 194 | Nickel Type | Julia Type | 195 |-------------|------------| 196 | Number (integer) | `Int64` | 197 | Number (float) | `Float64` | 198 | String | `String` | 199 | Bool | `Bool` | 200 | Array | `Vector{Any}` (or `Vector{T}` with typed eval) | 201 | Record | `Dict{String, Any}` (or `NamedTuple` / `Dict{K,V}` with typed eval) | 202 | Null | `nothing` | 203 | Enum | `NickelEnum(tag, arg)` | 204 205 ## Error Handling 206 207 ```julia 208 try 209 nickel_eval("{ x = }") # syntax error 210 catch e 211 if e isa NickelError 212 println("Nickel error: ", e.message) 213 end 214 end 215 ``` 216 217 ## License 218 219 MIT