From 23012fef7ba9e7de749cf0ed52266029a8ef6b8d Mon Sep 17 00:00:00 2001 From: "carpentry-heartbeat[bot]" Date: Mon, 20 Jul 2026 18:17:17 +0200 Subject: [PATCH] Fix documented parse return type and the broken README example The docs claimed `Reader.parse` returns `(Result (Array (Box Form)) ParseErr)`; it has returned `(Result (Array (Box Located)) ParseErr)` since 0.2.0. The example did not compile: `Box.peek` yields a `&Located` where `Form.str` wants a `&Form`, and bare `println` is not a symbol. `Located` appeared nowhere in the README, so `Located.form` -- needed to get any value out of the parser -- was undiscoverable. Adds a section covering it and the position fields. --- README.md | 43 +++++++++++++++++++++++++++++++------ carp-reader.carp | 9 ++++---- docs/Reader.html | 9 ++++---- docs/carp-reader_index.html | 8 ++++--- docs/index.html | 8 ++++--- gendocs.carp | 8 ++++--- 6 files changed, 62 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 2179728..3d66e13 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,43 @@ in which Carp gets parsed into a structured `Form` AST. Built on (match (Reader.parse "; greeting\n(defn hello [name] (println &name))") (Result.Success forms) (for [i 0 (Array.length &forms)] - (println &(Form.str (Box.peek (Array.unsafe-nth &forms i))))) + (IO.println &(Form.str (Located.form (Box.peek (Array.unsafe-nth &forms i)))))) (Result.Error e) (IO.errorln &(Parser.format-error &e))) ``` -`Reader.parse` returns `(Result (Array (Box Form)) ParseErr)`. +`Reader.parse` returns `(Result (Array (Box Located)) ParseErr)`. + +## Located + +Every node the parser emits — top-level and nested alike — is a `Located`, +not a bare `Form`: + +```clojure +(deftype Located + [form Form + info Info ; position of the form's first byte + end Info]) ; position just past its last byte + +(deftype Info + [pos Int ; byte offset + line Int + col Int]) +``` + +`Located.form` unwraps it, so it is the accessor you reach for in almost any +use of this library: + +```clojure +(let [l (Box.peek (Array.unsafe-nth &forms 0))] + (println* (Form.str (Located.form l)) + " at line " @(Info.line (Located.info l)) + ", column " @(Info.col (Located.info l)))) +``` + +`Located.str` is shorthand for `(Form.str (Located.form l))` when you do not +need the position. Nodes that reader macros synthesize rather than read from +source carry `Info.synthetic`, whose fields are all `0`. ## Form shape @@ -36,10 +67,10 @@ in which Carp gets parsed into a structured `Form` AST. Built on (Str [String]) (Pat [String]) ; #"..." pattern literal (Sym [(Array String)]) ; ["Foo" "Bar" "baz"] - (Lst [(Array (Box Form))]) ; (...) - (Arr [(Array (Box Form))]) ; [...] - (StaticArr [(Array (Box Form))]) ; $[...] - (Dict [(Array (Box Form))]) ; {...} + (Lst [(Array (Box Located))]) ; (...) + (Arr [(Array (Box Located))]) ; [...] + (StaticArr [(Array (Box Located))]) ; $[...] + (Dict [(Array (Box Located))]) ; {...} (Cmt [String])) ; ; line comment ``` diff --git a/carp-reader.carp b/carp-reader.carp index 3856de3..9357fa9 100644 --- a/carp-reader.carp +++ b/carp-reader.carp @@ -1025,12 +1025,13 @@ you need it.") 0)) (doc parse "parses a Carp source string into an array of top-level - `Form` forms. Comments are preserved as `Form.Cmt` nodes interspersed - with real forms.") + nodes, yielding `(Result (Array (Box Located)) ParseErr)`. Use + `Located.form` to reach the `Form` inside a `Located`. Comments are + preserved as `Form.Cmt` nodes interspersed with real forms.") (defn parse [src] (Parser.parse (many-forms) src)) - (doc parse-form "parses exactly one top-level `Form` form. Use - `parse` for whole-file inputs.") + (doc parse-form "parses exactly one top-level form, yielding + `(Result Located ParseErr)`. Use `parse` for whole-file inputs.") (defn parse-form [src] (Parser.parse (Parser.then (skip-ws) (Parser.before (Parser.recurse &*form*) (skip-ws))) diff --git a/docs/Reader.html b/docs/Reader.html index 8a63789..684339a 100644 --- a/docs/Reader.html +++ b/docs/Reader.html @@ -434,8 +434,9 @@

parses a Carp source string into an array of top-level -Form forms. Comments are preserved as Form.Cmt nodes interspersed -with real forms.

+nodes, yielding (Result (Array (Box Located)) ParseErr). Use +Located.form to reach the Form inside a Located. Comments are +preserved as Form.Cmt nodes interspersed with real forms.

@@ -455,8 +456,8 @@

(parse-form src)

-

parses exactly one top-level Form form. Use -parse for whole-file inputs.

+

parses exactly one top-level form, yielding +(Result Located ParseErr). Use parse for whole-file inputs.

diff --git a/docs/carp-reader_index.html b/docs/carp-reader_index.html index 8f16e3c..4875018 100644 --- a/docs/carp-reader_index.html +++ b/docs/carp-reader_index.html @@ -34,9 +34,11 @@

(load "git@github.com:carpentry-org/carp-reader@0.3.7")
 
 (match (Reader.parse "(defn hello [] (println \"hi\"))")
-  (Result.Success forms) (for [i 0 (Array.length &forms)]
-                           (println &(Form.str (Box.peek (Array.unsafe-nth &forms i)))))
-  (Result.Error e)       (IO.errorln &(Parser.format-error &e)))
+  (Result.Success forms)
+    (for [i 0 (Array.length &forms)]
+      (IO.println &(Form.str (Located.form (Box.peek (Array.unsafe-nth &forms i))))))
+  (Result.Error e)
+    (IO.errorln &(Parser.format-error &e)))
 

Modules