nickel_lang.h (20408B)
1 // SPDX-License-Identifier: MIT 2 3 #ifndef NICKEL_LANG_H 4 #define NICKEL_LANG_H 5 6 #include <stdint.h> 7 8 /** 9 * For functions that can fail, these are the interpretations of the return value. 10 */ 11 typedef enum { 12 /** 13 * A successful result. 14 */ 15 NICKEL_RESULT_OK = 0, 16 /** 17 * A bad result. 18 */ 19 NICKEL_RESULT_ERR = 1, 20 } nickel_result; 21 22 /** 23 * For functions that can fail, these are the interpretations of the return value. 24 */ 25 typedef enum { 26 /** 27 * Format an error as human-readable text. 28 */ 29 NICKEL_ERROR_FORMAT_TEXT = 0, 30 /** 31 * Format an error as human-readable text, with ANSI color codes. 32 */ 33 NICKEL_ERROR_FORMAT_ANSI_TEXT = 1, 34 /** 35 * Format an error as JSON. 36 */ 37 NICKEL_ERROR_FORMAT_JSON = 2, 38 /** 39 * Format an error as YAML. 40 */ 41 NICKEL_ERROR_FORMAT_YAML = 3, 42 /** 43 * Format an error as TOML. 44 */ 45 NICKEL_ERROR_FORMAT_TOML = 4, 46 } nickel_error_format; 47 48 /** 49 * A Nickel array. 50 * 51 * See [`nickel_expr_is_array`] and [`nickel_expr_as_array`]. 52 */ 53 typedef struct nickel_array nickel_array; 54 55 /** 56 * The main entry point. 57 */ 58 typedef struct nickel_context nickel_context; 59 60 /** 61 * A Nickel error. 62 * 63 * If you want to collect an error message from a fallible function 64 * (like `nickel_context_eval_deep`), first allocate an error using 65 * `nickel_error_alloc`, and then pass the resulting pointer to your fallible 66 * function. If that function fails, it will save the error data in your 67 * `nickel_error`. 68 */ 69 typedef struct nickel_error nickel_error; 70 71 /** 72 * A Nickel expression. 73 * 74 * This might be fully evaluated (for example, if you got it from [`nickel_context_eval_deep`]) 75 * or might have unevaluated sub-expressions (if you got it from [`nickel_context_eval_shallow`]). 76 */ 77 typedef struct nickel_expr nickel_expr; 78 79 /** 80 * A Nickel number. 81 * 82 * See [`nickel_expr_is_number`] and [`nickel_expr_as_number`]. 83 */ 84 typedef struct nickel_number nickel_number; 85 86 /** 87 * A Nickel record. 88 * 89 * See [`nickel_expr_is_record`] and [`nickel_expr_as_record`]. 90 */ 91 typedef struct nickel_record nickel_record; 92 93 /** 94 * A Nickel string. 95 */ 96 typedef struct nickel_string nickel_string; 97 98 /** 99 * A callback function for writing data. 100 * 101 * This function will be called with a buffer (`buf`) of data, having length 102 * `len`. It need not consume the entire buffer, and should return the number 103 * of bytes consumed. 104 */ 105 typedef uintptr_t (*nickel_write_callback)(void *context, const uint8_t *buf, uintptr_t len); 106 107 /** 108 * A callback function for flushing data that was written by a write callback. 109 */ 110 typedef void (*nickel_flush_callback)(const void *context); 111 112 #ifdef __cplusplus 113 extern "C" { 114 #endif // __cplusplus 115 116 /** 117 * Allocate a new [`nickel_context`], which can be used to evaluate Nickel expressions. 118 * 119 * Returns a newly-allocated [`nickel_context`] that can be freed with [`nickel_context_free`]. 120 */ 121 nickel_context *nickel_context_alloc(void); 122 123 /** 124 * Free a [`nickel_context`] that was created with [`nickel_context_alloc`]. 125 */ 126 void nickel_context_free(nickel_context *ctx); 127 128 /** 129 * Provide a callback that will be called when evaluating Nickel 130 * code that uses `std.trace`. 131 */ 132 void nickel_context_set_trace_callback(nickel_context *ctx, 133 nickel_write_callback write, 134 nickel_flush_callback flush, 135 void *user_data); 136 137 /** 138 * Provide a name for the main input program. 139 * 140 * This is used to format error messages. If you read the main input 141 * program from a file, its path is a good choice. 142 * 143 * `name` should be a UTF-8-encoded, null-terminated string. It is only 144 * borrowed temporarily; the pointer need not remain valid. 145 */ 146 void nickel_context_set_source_name(nickel_context *ctx, const char *name); 147 148 /** 149 * Evaluate a Nickel program deeply. 150 * 151 * "Deeply" means that we recursively evaluate records and arrays. For 152 * an alternative, see [`nickel_context_eval_shallow`]. 153 * 154 * - `src` is a null-terminated string containing UTF-8-encoded Nickel source. 155 * - `out_expr` either NULL or something that was created with [`nickel_expr_alloc`] 156 * - `out_error` can be NULL if you aren't interested in getting detailed 157 * error messages 158 * 159 * If evaluation is successful, returns `NICKEL_RESULT_OK` and replaces 160 * the value at `out_expr` (if non-NULL) with the newly-evaluated Nickel expression. 161 * 162 * If evaluation fails, returns `NICKEL_RESULT_ERR` and replaces the 163 * value at `out_error` (if non-NULL) by a pointer to a newly-allocated Nickel error. 164 * That error should be freed with `nickel_error_free` when you are 165 * done with it. 166 */ 167 nickel_result nickel_context_eval_deep(nickel_context *ctx, 168 const char *src, 169 nickel_expr *out_expr, 170 nickel_error *out_error); 171 172 /** 173 * Evaluate a Nickel program deeply. 174 * 175 * This differs from [`nickel_context_eval_deep`] in that it ignores 176 * fields marked as `not_exported`. 177 * 178 * - `src` is a null-terminated string containing UTF-8-encoded Nickel source. 179 * - `out_expr` either NULL or something that was created with [`nickel_expr_alloc`] 180 * - `out_error` can be NULL if you aren't interested in getting detailed 181 * error messages 182 * 183 * If evaluation is successful, returns `NICKEL_RESULT_OK` and replaces 184 * the value at `out_expr` (if non-NULL) with the newly-evaluated Nickel expression. 185 * 186 * If evaluation fails, returns `NICKEL_RESULT_ERR` and replaces the 187 * value at `out_error` (if non-NULL) by a pointer to a newly-allocated Nickel error. 188 * That error should be freed with `nickel_error_free` when you are 189 * done with it. 190 */ 191 nickel_result nickel_context_eval_deep_for_export(nickel_context *ctx, 192 const char *src, 193 nickel_expr *out_expr, 194 nickel_error *out_error); 195 196 /** 197 * Evaluate a Nickel program to weak head normal form (WHNF). 198 * 199 * The result of this evaluation is a null, bool, number, string, 200 * enum, record, or array. In case it's a record, array, or enum 201 * variant, the payload (record values, array elements, or enum 202 * payloads) will be left unevaluated. 203 * 204 * Sub-expressions of the result can be evaluated further by [nickel_context_eval_expr_shallow]. 205 * 206 * - `src` is a null-terminated string containing UTF-8-encoded Nickel source. 207 * - `out_expr` is either NULL or something that was created with [`nickel_expr_alloc`] 208 * - `out_error` can be NULL if you aren't interested in getting detailed 209 * error messages 210 * 211 * If evaluation is successful, returns `NICKEL_RESULT_OK` and replaces the value at `out_expr` 212 * (if non-NULL) with the newly-evaluated Nickel expression. 213 * 214 * If evaluation fails, returns `NICKEL_RESULT_ERR` and replaces the value at `out_error` (if 215 * non-NULL) by a pointer to a newly-allocated Nickel error. That error should be freed with 216 * `nickel_error_free` when you are done with it. 217 */ 218 nickel_result nickel_context_eval_shallow(nickel_context *ctx, 219 const char *src, 220 nickel_expr *out_expr, 221 nickel_error *out_error); 222 223 /** 224 * Allocate a new Nickel expression. 225 * 226 * The returned expression pointer can be used to store the results of 227 * evaluation, for example by passing it as the `out_expr` location of 228 * `nickel_context_eval_deep`. 229 * 230 * Each call to `nickel_expr_alloc` should be paired with a call to 231 * `nickel_expr_free`. The various functions (like `nickel_context_eval_deep`) 232 * that take an `out_expr` parameter overwrite the existing expression 233 * contents, and do not affect the pairing of `nickel_expr_alloc` and 234 * `nickel_expr_free`. 235 * 236 * For example: 237 * 238 * ```c 239 * nickel_context *ctx = nickel_context_alloc(); 240 * nickel_context *expr = nickel_expr_alloc(); 241 * 242 * nickel_context_eval_deep(ctx, "{ foo = 1 }", expr, NULL); 243 * 244 * // now expr is a record 245 * printf("record: %d\n", nickel_expr_is_record(expr)); 246 * 247 * nickel_context_eval_deep(ctx, "[1, 2, 3]", expr, NULL); 248 * 249 * // now expr is an array 250 * printf("array: %d\n", nickel_expr_is_array(expr)); 251 * 252 * // the calls to nickel_context_eval_deep haven't created any new exprs: 253 * // we only need to free it once 254 * nickel_expr_free(expr); 255 * nickel_context_free(ctx); 256 * ``` 257 * 258 * An `Expr` owns its data. There are various ways to get a reference to 259 * data owned by an expression, which are then invalidated when the expression 260 * is freed (by `nickel_expr_free`) or overwritten (for example, by 261 * `nickel_context_deep_eval`). 262 * 263 * ```c 264 * nickel_context *ctx = nickel_context_alloc(); 265 * nickel_expr *expr = nickel_expr_alloc(); 266 * 267 * nickel_context_eval_deep(ctx, "{ foo = 1 }", expr, NULL); 268 * 269 * nickel_record *rec = nickel_expr_as_record(expr); 270 * nickel_expr *field = nickel_expr_alloc(); 271 * nickel_record_value_by_name(rec, "foo", field); 272 * 273 * // Now `rec` points to data owned by `expr`, but `field` 274 * // owns its own data. The following deallocation invalidates 275 * // `rec`, but not `field`. 276 * nickel_expr_free(expr); 277 * printf("number: %d\n", nickel_expr_is_number(field)); 278 * ``` 279 */ 280 nickel_expr *nickel_expr_alloc(void); 281 282 /** 283 * Free a Nickel expression. 284 * 285 * See [`nickel_expr_alloc`]. 286 */ 287 void nickel_expr_free(nickel_expr *expr); 288 289 /** 290 * Is this expression a boolean? 291 */ 292 int nickel_expr_is_bool(const nickel_expr *expr); 293 294 /** 295 * Is this expression a number? 296 */ 297 int nickel_expr_is_number(const nickel_expr *expr); 298 299 /** 300 * Is this expression a string? 301 */ 302 int nickel_expr_is_str(const nickel_expr *expr); 303 304 /** 305 * Is this expression an enum tag? 306 */ 307 int nickel_expr_is_enum_tag(const nickel_expr *expr); 308 309 /** 310 * Is this expression an enum variant? 311 */ 312 int nickel_expr_is_enum_variant(const nickel_expr *expr); 313 314 /** 315 * Is this expression a record? 316 */ 317 int nickel_expr_is_record(const nickel_expr *expr); 318 319 /** 320 * Is this expression an array? 321 */ 322 int nickel_expr_is_array(const nickel_expr *expr); 323 324 /** 325 * Has this expression been evaluated? 326 * 327 * An evaluated expression is either null, or it's a number, bool, string, record, array, or enum. 328 * If this expression is not a value, you probably got it from looking inside the result of 329 * [`nickel_context_eval_shallow`], and you can use the [`nickel_context_eval_expr_shallow`] to 330 * evaluate this expression further. 331 */ 332 int nickel_expr_is_value(const nickel_expr *expr); 333 334 /** 335 * Is this expression null? 336 */ 337 int nickel_expr_is_null(const nickel_expr *expr); 338 339 /** 340 * If this expression is a boolean, returns that boolean. 341 * 342 * # Panics 343 * 344 * Panics if `expr` is not a boolean. 345 */ 346 int nickel_expr_as_bool(const nickel_expr *expr); 347 348 /** 349 * If this expression is a string, returns that string. 350 * 351 * A pointer to the string contents, which are UTF-8 encoded, is returned in 352 * `out_str`. These contents are *not* null-terminated. The return value of this 353 * function is the length of these contents. 354 * 355 * The returned string contents are owned by this `Expr`, and will be invalidated 356 * when the `Expr` is freed with [`nickel_expr_free`]. 357 * 358 * # Panics 359 * 360 * Panics if `expr` is not a string. 361 */ 362 uintptr_t nickel_expr_as_str(const nickel_expr *expr, const char **out_str); 363 364 /** 365 * If this expression is a number, returns the number. 366 * 367 * The returned number pointer borrows from `expr`, and will be invalidated 368 * when `expr` is overwritten or freed. 369 * 370 * # Panics 371 * 372 * Panics if `expr` is not an number. 373 */ 374 const nickel_number *nickel_expr_as_number(const nickel_expr *expr); 375 376 /** 377 * If this expression is an enum tag, returns its string value. 378 * 379 * A pointer to the string contents, which are UTF-8 encoded, is returned in 380 * `out_str`. These contents are *not* null-terminated. The return value of this 381 * function is the length of these contents. 382 * 383 * The returned string contents point to an interned string and will never be 384 * invalidated. 385 * 386 * # Panics 387 * 388 * Panics if `expr` is null or is not an enum tag. 389 */ 390 uintptr_t nickel_expr_as_enum_tag(const nickel_expr *expr, const char **out_str); 391 392 /** 393 * If this expression is an enum variant, returns its string value and its payload. 394 * 395 * A pointer to the string contents, which are UTF-8 encoded, is returned in 396 * `out_str`. These contents are *not* null-terminated. The return value of this 397 * function is the length of these contents. 398 * 399 * The returned string contents point to an interned string and will never be 400 * invalidated. 401 * 402 * # Panics 403 * 404 * Panics if `expr` is not an enum tag. 405 */ 406 uintptr_t nickel_expr_as_enum_variant(const nickel_expr *expr, 407 const char **out_str, 408 nickel_expr *out_expr); 409 410 /** 411 * If this expression is a record, returns the record. 412 * 413 * The returned record pointer borrows from `expr`, and will be invalidated 414 * when `expr` is overwritten or freed. 415 * 416 * # Panics 417 * 418 * Panics if `expr` is not an record. 419 */ 420 const nickel_record *nickel_expr_as_record(const nickel_expr *expr); 421 422 /** 423 * If this expression is an array, returns the array. 424 * 425 * The returned array pointer borrows from `expr`, and will be invalidated 426 * when `expr` is overwritten or freed. 427 * 428 * # Panics 429 * 430 * Panics if `expr` is not an array. 431 */ 432 const nickel_array *nickel_expr_as_array(const nickel_expr *expr); 433 434 /** 435 * Converts an expression to JSON. 436 * 437 * This is fallible because enum variants have no canonical conversion to 438 * JSON: if the expression contains any enum variants, this will fail. 439 * This also fails if the expression contains any unevaluated sub-expressions. 440 */ 441 nickel_result nickel_context_expr_to_json(nickel_context *ctx, 442 const nickel_expr *expr, 443 nickel_string *out_string, 444 nickel_error *out_err); 445 446 /** 447 * Converts an expression to YAML. 448 * 449 * This is fallible because enum variants have no canonical conversion to 450 * YAML: if the expression contains any enum variants, this will fail. 451 * This also fails if the expression contains any unevaluated sub-expressions. 452 */ 453 nickel_result nickel_context_expr_to_yaml(nickel_context *ctx, 454 const nickel_expr *expr, 455 nickel_string *out_string, 456 nickel_error *out_err); 457 458 /** 459 * Converts an expression to TOML. 460 * 461 * This is fallible because enum variants have no canonical conversion to 462 * TOML: if the expression contains any enum variants, this will fail. 463 * This also fails if the expression contains any unevaluated sub-expressions. 464 */ 465 nickel_result nickel_context_expr_to_toml(nickel_context *ctx, 466 const nickel_expr *expr, 467 nickel_string *out_string, 468 nickel_error *out_err); 469 470 /** 471 * Is this number an integer within the range of an `int64_t`? 472 */ 473 int nickel_number_is_i64(const nickel_number *num); 474 475 /** 476 * If this number is an integer within the range of an `int64_t`, returns it. 477 * 478 * # Panics 479 * 480 * Panics if this number is not an integer in the appropriate range (you should 481 * check with [`nickel_number_is_i64`] first). 482 */ 483 int64_t nickel_number_as_i64(const nickel_number *num); 484 485 /** 486 * The value of this number, rounded to the nearest `double`. 487 */ 488 double nickel_number_as_f64(const nickel_number *num); 489 490 /** 491 * The value of this number, as an exact rational number. 492 * 493 * - `out_numerator` must have been allocated with [`nickel_string_alloc`]. It 494 * will be overwritten with the numerator, as a decimal string. 495 * - `out_denominator` must have been allocated with [`nickel_string_alloc`]. 496 * It will be overwritten with the denominator, as a decimal string. 497 */ 498 void nickel_number_as_rational(const nickel_number *num, 499 nickel_string *out_numerator, 500 nickel_string *out_denominator); 501 502 /** 503 * The number of elements of this Nickel array. 504 */ 505 uintptr_t nickel_array_len(const nickel_array *arr); 506 507 /** 508 * Retrieve the element at the given array index. 509 * 510 * The retrieved element will be written to `out_expr`, which must have been allocated with 511 * [`nickel_expr_alloc`]. 512 * 513 * # Panics 514 * 515 * Panics if the given index is out of bounds. 516 */ 517 void nickel_array_get(const nickel_array *arr, uintptr_t idx, nickel_expr *out_expr); 518 519 /** 520 * The number of keys in this Nickel record. 521 */ 522 uintptr_t nickel_record_len(const nickel_record *rec); 523 524 /** 525 * Retrieve the key and value at the given index. 526 * 527 * If this record was deeply evaluated, every key will come with a value. 528 * However, shallowly evaluated records may have fields with no value. 529 * 530 * Returns 1 if the key came with a value, and 0 if it didn't. The value 531 * will be written to `out_expr` if it is non-NULL. 532 * 533 * # Panics 534 * 535 * Panics if `idx` is out of range. 536 */ 537 int nickel_record_key_value_by_index(const nickel_record *rec, 538 uintptr_t idx, 539 const char **out_key, 540 uintptr_t *out_key_len, 541 nickel_expr *out_expr); 542 543 /** 544 * Look up a key in this record and return its value, if there is one. 545 * 546 * Returns 1 if the key has a value, and 0 if it didn't. The value is 547 * written to `out_expr` if it is non-NULL. 548 */ 549 int nickel_record_value_by_name(const nickel_record *rec, const char *key, nickel_expr *out_expr); 550 551 /** 552 * Allocates a new string. 553 * 554 * The lifecycle management of a string is much like that of an expression 555 * (see `nickel_expr_alloc`). It gets allocated here, modified by various other 556 * functions, and finally is freed by a call to `nickel_string_free`. 557 */ 558 nickel_string *nickel_string_alloc(void); 559 560 /** 561 * Frees a string. 562 */ 563 void nickel_string_free(nickel_string *s); 564 565 /** 566 * Retrieve the data inside a string. 567 * 568 * A pointer to the string contents, which are UTF-8 encoded, is written to 569 * `data`. These contents are *not* null-terminated, but their length (in bytes) 570 * is written to `len`. The string contents will be invalidated when `s` is 571 * freed or overwritten. 572 */ 573 void nickel_string_data(const nickel_string *s, const char **data, uintptr_t *len); 574 575 /** 576 * Evaluate an expression to weak head normal form (WHNF). 577 * 578 * This has no effect if the expression is already evaluated (see 579 * [`nickel_expr_is_value`]). 580 * 581 * The result of this evaluation is a null, bool, number, string, 582 * enum, record, or array. In case it's a record, array, or enum 583 * variant, the payload (record values, array elements, or enum 584 * payloads) will be left unevaluated. 585 */ 586 nickel_result nickel_context_eval_expr_shallow(nickel_context *ctx, 587 const nickel_expr *expr, 588 nickel_expr *out_expr, 589 nickel_error *out_error); 590 591 /** 592 * Allocate a new `nickel_error`. 593 */ 594 nickel_error *nickel_error_alloc(void); 595 596 /** 597 * Frees a `nickel_error`. 598 */ 599 void nickel_error_free(nickel_error *err); 600 601 /** 602 * Write out an error as a user- or machine-readable diagnostic. 603 * 604 * - `err` must have been allocated by `nickel_error_alloc` and initialized by some failing 605 * function (like `nickel_context_eval_deep`). 606 * - `write` is a callback function that will be invoked with UTF-8 encoded data. 607 * - `write_payload` is optional extra data to pass to `write` 608 * - `format` selects the error-rendering format. 609 */ 610 nickel_result nickel_error_display(const nickel_error *err, 611 nickel_write_callback write, 612 void *write_payload, 613 nickel_error_format format); 614 615 /** 616 * Write out an error as a user- or machine-readable diagnostic. 617 * 618 * This is like `nickel_error_format`, but writes the error to a string instead 619 * of via a callback function. 620 */ 621 nickel_result nickel_error_format_as_string(const nickel_error *err, 622 nickel_string *out_string, 623 nickel_error_format format); 624 625 #ifdef __cplusplus 626 } // extern "C" 627 #endif // __cplusplus 628 629 #endif /* NICKEL_LANG_H */