Skip to content

Commit

Permalink
Mostly update to KDL v2.0.0-draft.4
Browse files Browse the repository at this point in the history
- Equal sign is now defined as `=` | U+FE66 | U+FF1D | U+1F7F0
- BOM is allowed in the start of the document only
- Added \s escape sequence
- Disallowed invalid escape sequences
- Allowed EOF right after the \ line continuation
- Strings and identifiers cannot include characters from the "Disallowed
  Literal Code Points" list
- true, false, and null values are now written as #true, #false, #null
  respectively
- Changed the raw string syntax from r"raw" to #"raw"#
- Removed no-whitespace checks around = and type annotations
- Strings can now be written as bare identifiers
- Added multi-line "dedented" strings, newlines in single-line strings
  are disallowed
- Newlines in multi-line strings are normalized to \n
- Identifiers cannot start with .<digits> anymore (optionally prefixed by +-)
- Added #inf, #-inf, #nan numbers
- true, false, inf, -inf, nan are invalid identifiers
- Small documentation improvements

TODO: The correct by the spec handling of whitespace is still to be implemented.
TODO: The pretty-printer doesn't yet work well for some special symbols and
      generally isn't good enough in edge cases.

Other KDL v2 changes have alredy been implemented before, namely:
Line Tabulation as whitespace, \/ is no longer an escape sequence, \ whitespace
escape.

#1
  • Loading branch information
eilvelia committed Apr 1, 2024
1 parent d238285 commit 78c1c5f
Show file tree
Hide file tree
Showing 13 changed files with 693 additions and 473 deletions.
11 changes: 3 additions & 8 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,11 @@

## Unreleased

- Updated to KDL v2.0 (many breaking changes, see the KDL changelog).
- Reworked numbers: added the `Kdl.Num` module, including
`Kdl.Num.to_{string,float,int,int32,int64,nativeint}` and other functions.
- `Kdl.L`: Added `(.@!())` and `(.@!())<-` indexing operators as raising
versions of `(.@())` and `(.@()<-)`.
- Reworked numbers: added the `Kdl.Num` module,
`Kdl.Num.to_{string,float,int,int32,int64,nativeint}` and other functions.
- Updated to KDL v2.0:
- - Added Line Tabulation U+000B to whitespace characters.
- - Removed `\/` from escape sequences.
- - Added whitespace escape sequence: all whitespace (including multiple
newlines) is removed after `\`.
- - Identifiers cannot start with `r#` anymore.
- `interpret` now raises `Invalid_annotation` instead of `Failure`.
- `i8`, `i16`, etc. wrappers over `interpret` are removed.
- Dropped support for OCaml < 4.10.0.
Expand Down
77 changes: 0 additions & 77 deletions GRAMMAR.md

This file was deleted.

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License

Copyright (c) 2022-2023 https://github.com/Bannerets <[email protected]>
Copyright (c) 2022-2024 https://github.com/Bannerets <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
[ci-badge]: https://github.com/Bannerets/ocaml-kdl/actions/workflows/ci.yml/badge.svg
[ci-page]: https://github.com/Bannerets/ocaml-kdl/actions/workflows/ci.yml

An OCaml implementation of the [KDL][] 1.0 document language.
An OCaml implementation of the [KDL][] Document Language, version 2.0.0.

[KDL]: https://github.com/kdl-org/kdl

```console
$ opam install kdl
```

**Note**: This is the working version for KDL v2. For the published version of
ocaml-kdl for KDL v1, see the `v0.1.0` tag.

## Features

- [x] Parsing
Expand Down
21 changes: 14 additions & 7 deletions src/ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ module Num = struct
| `Decimal of string
]

(* Note: Float.to_string outputs "inf", "-inf", "nan" for the infinity,
neg_infinity, and nan values respectively; Float.of_string can parse those
strings. That makes the functions suitable for KDL's #inf, #-inf, #nan
as-is. *)

let to_string : [< t ] -> string = function
| `Int int -> Int.to_string int
| `Int_raw str
Expand Down Expand Up @@ -56,10 +61,12 @@ module Num = struct
let[@inline] to_unsigned_literal lit =
(* 42 -> 0u42, 0x42 -> 0x42, etc. somewhat hacky *)
if String.length lit >= 1 && lit.[0] = '-'
&& not (String.length lit = 2 && lit.[1] = '0') then None else
let with_prefix = String.length lit >= 3
&& (lit.[1] = 'x' || lit.[1] = 'o' || lit.[1] = 'b') in
Some (if with_prefix then lit else "0u" ^ lit)
&& not (String.length lit = 2 && lit.[1] = '0') then
None
else
let with_prefix = String.length lit >= 3
&& (lit.[1] = 'x' || lit.[1] = 'o' || lit.[1] = 'b') in
Some (if with_prefix then lit else "0u" ^ lit)
end

let to_int : [< t ] -> int option = function
Expand Down Expand Up @@ -236,10 +243,10 @@ type annot_value = string option * value
type prop = string * annot_value

type node = {
name : string; (** An identifier or a quoted string *)
name : string;
annot : string option;
args : annot_value list;
props : prop list; (** [props] is an assoc list; the order of [props] is unspecified *)
props : prop list; (** [props] is an assoc list; the order is unspecified *)
children : node list;
}

Expand All @@ -262,7 +269,7 @@ let equal_prop (name1, annot_value1 : prop) (name2, annot_value2 : prop) =

open struct
(* This is the implementation of List.equal from OCaml 4.14.0, present
for backward compatibility with OCaml < 4.12.0 *)
for backward compatibility with OCaml < 4.12.0 *)
let rec list_equal eq l1 l2 =
match l1, l2 with
| [], [] -> true
Expand Down
45 changes: 29 additions & 16 deletions src/kdl.mli
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
(** {1 The definition of a KDL document} *)
(** Implementation of the {{:https://github.com/kdl-org/kdl} KDL} Document
Language 2.0.
KDL is a serialization format and configuration language, similarly to JSON,
YAML, TOML, edn, and so on.
Small examples can be found in the README of the ocaml-kdl repository.
*)

(** {1:types The definition of a KDL document} *)

module Num : sig
(** KDL numbers. *)
Expand All @@ -13,7 +22,8 @@ module Num : sig
is parsed as [`Decimal] (stored as string) if it is written in the [e]
scientific notation or contains the [.] decimal separator. If an integer
is too large for the OCaml [int], it is parsed as [`Int_raw] instead of
[`Int]. The strings are not normalized in any way.
[`Int]. The strings are not normalized in any way. [`Decimal] also
includes special values: ["inf"], ["-inf"], ["nan"].
In general, one should not pattern match over specific constructors of the
variant, and instead use the [to_*] functions below while matching over
Expand Down Expand Up @@ -101,9 +111,11 @@ type annot_value = string option * value
type prop = string * annot_value
(** A KDL property is a key-value pair. *)

(** A KDL node.
(** A KDL node. Nodes consist of the node name, optional type annotation,
ordered arguments (values), unordered properties (a key-value map), and
children nodes.
[props] is an association list; the order of [props] is unspecified. *)
[props] is an association list; the order of the list is unspecified. *)
type node =
{ name : string
; annot : string option
Expand All @@ -117,11 +129,11 @@ type t = node list
(** {1 Parsing} *)

type error_loc = Lexing.position * Lexing.position
(** The location generated by [sedlex].
(** The error location as generated by [sedlex].
Note: the positions count unicode code points, not bytes. *)

type error = string * error_loc
(** A parsing error. *)
(** A parsing error: pair of the error message and error location. *)

val show_error : error -> string

Expand Down Expand Up @@ -177,7 +189,7 @@ val equal_node : node -> node -> bool

val equal : t -> t -> bool

(** {1 Sexp conversions} *)
(** {1:sexp Sexp conversions} *)

val sexp_of_value : [< value] -> Sexplib0.Sexp.t

Expand All @@ -189,7 +201,7 @@ val sexp_of_node : node -> Sexplib0.Sexp.t

val sexp_of_t : t -> Sexplib0.Sexp.t

(** {1 Pretty-printing} *)
(** {1:pretty Pretty-printing} *)

val indent : int ref
(** [indent] is the number of spaces used per indentation level.
Expand Down Expand Up @@ -224,7 +236,7 @@ val to_string : t -> string
val show : t -> string
(** Alias for [to_string]. *)

(** {1 Type annotations} *)
(** {1:annots Type annotations} *)

(** KDL {{:https://github.com/kdl-org/kdl/blob/1.0.0/SPEC.md#type-annotation} defines}
reserved type annotations. Some of them are supported out of the box in
Expand Down Expand Up @@ -291,10 +303,10 @@ module L : sig
(** [l1 // l2] is an infix operator for [compose l2 l1]. *)

val (|--) : ('a, 'b) lens -> ('b, 'c) lens -> ('a, 'c) lens
(** Alias for [(//)]. *)
(** Alias for [(//)], the lens composition.. *)

val get : 'a -> ('a, 'b) lens -> 'b option
(** Run the getter ([lens.get]). Returns [Some value] if the lens
(** Run the getter ([lens.get]). Results in [Some value] if the lens
successfully matches, or [None] otherwise. *)

val set : 'a -> 'b -> ('a, 'b) lens -> 'a option
Expand Down Expand Up @@ -327,20 +339,21 @@ module L : sig
(** The combination of [get] and [set]. *)

val node_name : (node, string) lens
(** Lens to [node.name]. *)
(** Lens to [node.name], the node name. *)

val node_annot : (node, string) lens
(** Lens to [node.annot]. *)
(** Lens to [node.annot], the optional type annotation of a node (if the
annotation is not set, the partial lens fails). *)

val node_annot_opt : (node, string option) lens
(** Lens to [node.annot] as an [option]. Pass [None] to remove the
annotation. *)

val args : (node, annot_value list) lens
(** Lens to [node.args]. *)
(** Lens to [node.args], the node arguments. *)

val props : (node, prop list) lens
(** Lens to [node.props]. *)
(** Lens to [node.props], the node properties. *)

val children : (node, node list) lens
(** Lens to [node.children], i.e. all children of a node. *)
Expand Down Expand Up @@ -380,7 +393,7 @@ module L : sig
(** Lens to [annot] in the [annot_value] pair. *)

val annot_opt : (annot_value, string option) lens
(** Lens to [annot] as [option]. Pass [None] to unset the annotation. *)
(** Lens to [annot] as an [option]. Pass [None] to unset the annotation. *)

val string : (value, string) lens
(** Lens to a string value. *)
Expand Down
Loading

0 comments on commit 78c1c5f

Please sign in to comment.