changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > core / lisp/lib/dat/toml.lisp

changeset 698: 96958d3eb5b0
parent: 686748796f08
author: Richard Westhaver <ellis@rwest.io>
date: Fri, 04 Oct 2024 22:04:59 -0400
permissions: -rw-r--r--
description: fixes
1 ;;; dat/toml.lisp --- TOML
2 
3 ;; TOML de/serialization for Lisp.
4 
5 ;;; Commentary:
6 
7 ;; This code was originally based on https://github.com/sheepduke/clop which
8 ;; provides a TOML parser using the ESRAP package.
9 
10 ;; ref: https://toml.io/en/v1.0.0
11 
12 ;; grammar: https://raw.githubusercontent.com/toml-lang/toml/1.0.0/toml.abnf
13 
14 #|
15 * TOML is case-sensitive.
16 * A TOML file must be a valid UTF-8 encoded Unicode document.
17 * Whitespace means tab (0x09) or space (0x20).
18 * Newline means LF (0x0A) or CRLF (0x0D 0x0A).
19 |#
20 
21 ;;; Code:
22 (in-package :dat/toml)
23 
24 ;;; Vars
25 (defvar *+inf* :+inf
26  "The value of +inf when decoding TOML.")
27 
28 (defvar *-inf* :-inf
29  "The value of -inf when decoding TOML.")
30 
31 (defvar *+nan* :+nan
32  "The value of +nan when decoding TOML.")
33 
34 (defvar *-nan* :-nan
35  "The value of -nan when decoding TOML.")
36 
37 (defclass toml-object () ())
38 
39 (defclass toml-table (toml-object)
40  ((table :initform (make-hash-table :test 'equal))))
41 
42 (defclass toml-inline-table (toml-table) ())
43 
44 (defclass toml-array-table (toml-table) ())
45 
46 (defclass toml-value (toml-object) ())
47 
48 (defclass toml-pair ()
49  ((key :type (or symbol string) :initarg :key) (val :type toml-value :initarg :val)))
50 
51 ;;; Collections
52 (defclass toml-document ()
53  ((children :accessor children
54  :type (or list (vector toml-object))
55  :documentation "A table of any kind. Note that for a table, its own name is not stored as a
56 property of itself, but as a hash key in children property of its parent
57 collection. The parsed result is a table representing root table.")))
58 
59 ;;; Read
60 (defun toml-read (stream &optional (eof-error-p t) eof-value)
61  (let ((c (peek-char t stream eof-error-p :eof)))
62  (case c
63  (:eof eof-value)
64  (#\[ (read-char stream) (toml-read-header stream)) ;; arrays are values only
65  (t (toml-read-key stream)))))
66 
67 (defun toml-peek-char (stream expected &key skip-ws)
68  (when (equal (peek-char skip-ws stream) expected)
69  (read-char stream)))
70 
71 (defun toml-read-header (stream)
72  (let ((c (peek-char t stream nil nil)))
73  (case c
74  ;; array-table
75  (#\[ (read-char stream) (toml-read-key stream))
76  (t (toml-read-key stream)))))
77 
78 (defun toml-read-key (stream))
79 
80 (defun toml-read-value (stream))
81 
82 (defun toml-read-pair (stream))
83 
84 ;;; Parser
85 
86 ;;;; Value
87 (defgeneric parse-value (type value))
88 
89 (defmethod parse-value ((type (eql :datetime)) value)
90  "Return a timestamp."
91  (parse-timestring (ppcre:regex-replace " " "T" value)))
92 
93 (defmethod parse-value ((type (eql :datetime-local)) value)
94  "Return a plist with keys (:year :month :day :hour :minute :second)."
95  (let* ((delimeter (sequence:elt value 10))
96  (splits (split-sequence delimeter value)))
97  (append (parse-value :date-local (car splits))
98  (parse-value :time-local (cadr splits)))))
99 
100 (defmethod parse-value ((type (eql :date-local)) value)
101  "Return a plist with keys (:year :month :day)."
102  (let* ((*default-timezone* +utc-zone+)
103  (timestamp (parse-timestring value)))
104  (list :year (timestamp-year timestamp)
105  :month (timestamp-month timestamp)
106  :day (timestamp-day timestamp))))
107 
108 (defmethod parse-value ((type (eql :time-local)) value)
109  "Return a plist with keys (:hour :minute :second)."
110  (let* ((*default-timezone* +utc-zone+)
111  (timestamp (parse-timestring value)))
112  (list :hour (timestamp-hour timestamp)
113  :minute (timestamp-minute timestamp)
114  :second (timestamp-second timestamp)
115  :microsecond (timestamp-microsecond timestamp))))
116 
117 (defmethod parse-value (type value)
118  value)
119 
120 ;;; Serde
121 
122 ;; TODO 2023-12-23:
123 
124 ;; (defun parse (text &key (style :alist))
125 ;; "Parse given string TEXT and convert the result to given STYLE.
126 ;; The STYLE can be one of:
127 ;; * :alist (the default)
128 ;; * :raw (should be rarely used)
129 
130 ;; The top-level of result is an alist.
131 
132 ;; You may implement your own style by implementing SERIALIZE method."
133 ;; (let* ((parsed (esrap:parse 'toml text)))
134 ;; (serialize parsed style)))
135 
136 ;; (defmethod serialize ((table toml-table) (format (eql :toml)) &key (style :alist))
137 ;; (loop with children = (children table)
138 ;; for key being the hash-keys of children
139 ;; collect (cons key (serialize (gethash key children) format :style style))))
140 
141 ;; (defmethod serialize ((table inline-toml-table) (format (eql :toml)) &key (style :alist))
142 ;; (loop with children = (children table)
143 ;; for key being the hash-keys of children
144 ;; collect (cons key (serialize (gethash key children) format :style style))))
145 
146 ;; (defmethod serialize ((table toml-table-array) (format (eql :toml)) &key style)
147 ;; (mapcar (lambda (it) (serialize it format :style style))
148 ;; (children table)))
149 
150 ;; (defmethod serialize (thing (format (eql :toml)) &key style)
151 ;; (declare (ignore style))
152 ;; thing)
153 
154 ;; (defmethod serialize ((thing list) (format (eql :toml)) &key)
155 ;; (if (listp (cdr thing))
156 ;; (mapcar (lambda (it) (serialize it :toml)) thing)
157 ;; thing))
158 
159 ;; (defmethod serialize (thing (format (eql :toml)) &key)
160 ;; thing)