Skip to content

Commit 801b72c

Browse files
committed
fix(faces): stop appending ; to -- comment lines in LucidScript
The previous pipeline first called `convert_dashdash_comment` (turning `-- text` into `// text`), then passed the result to `strip_dashdash_comment`. Because `strip_dashdash_comment` scans for `--` and found none in the converted line, it returned the entire `// text` string as the "code part". That code part fell through to the expression handler, which appended `;`, producing `// text;`. Fix: apply `strip_dashdash_comment` directly to the raw (pre-conversion) line. A `-- comment` line now yields an empty code part and a populated comment_opt, so it is emitted as `// text\n` with no trailing `;`. As a side effect, `convert_dashdash_comment` becomes unused and is deleted. `is_blank_line` is updated to treat canonical `//` lines as blank (so the next-meaningful-indent scan skips them), and a new dispatch branch in `transform_source` passes canonical `//`/`/*` lines through unchanged before they can reach the equation handler. Updated snapshot `tests/faces/hello-lucid.expected.txt`.
1 parent d2875a5 commit 801b72c

2 files changed

Lines changed: 32 additions & 36 deletions

File tree

lib/lucid_face.ml

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
- Span fidelity: errors refer to the canonical text, not Lucid source.
5151
*)
5252

53-
(* ─── Character helpers ──────────────────────────────────────────────── *)
53+
(* ─── Character helpers ──────────────────────────────────────────── *)
5454

5555
let is_id_char c =
5656
(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
@@ -70,16 +70,7 @@ let indent_of line =
7070
while !i < len && (line.[!i] = ' ' || line.[!i] = '\t') do incr i done;
7171
!i
7272

73-
(* ─── Comment handling ───────────────────────────────────────────────── *)
74-
75-
(** Convert a leading [-- comment] to [// comment] at the original indent. *)
76-
let convert_dashdash_comment line =
77-
let trimmed = String.trim line in
78-
if starts_with trimmed "--" then
79-
let indent_len = String.length line - String.length trimmed in
80-
let indent = String.sub line 0 indent_len in
81-
indent ^ "//" ^ String.sub trimmed 2 (String.length trimmed - 2)
82-
else line
73+
(* ─── Comment handling ────────────────────────────────────────────── *)
8374

8475
(** Strip a trailing [-- ...] comment (respecting string literals) and
8576
return [(code_part, comment_text option)]. *)
@@ -105,7 +96,7 @@ let strip_dashdash_comment line =
10596
else (String.sub line 0 !cut,
10697
Some (String.sub line (!cut + 2) (len - !cut - 2)))
10798

108-
(* ─── Word-level keyword substitution ────────────────────────────────── *)
99+
(* ─── Word-level keyword substitution ───────────────────────────────────── *)
109100

110101
let replace_word ~from_w ~to_w s =
111102
let flen = String.length from_w in
@@ -144,7 +135,7 @@ let apply_logic_subs s =
144135
let s = replace_word ~from_w:"not" ~to_w:"!" s in
145136
s
146137

147-
(* ─── Module path helpers ────────────────────────────────────────────── *)
138+
(* ─── Module path helpers ────────────────────────────────────────────────── *)
148139

149140
(** [Data.Map.Strict] → [Data::Map::Strict]. *)
150141
let dots_to_colons s =
@@ -156,7 +147,7 @@ let dots_to_colons s =
156147
) s;
157148
Buffer.contents buf
158149

159-
(* ─── Import translation ─────────────────────────────────────────────── *)
150+
(* ─── Import translation ───────────────────────────────────────────────────── *)
160151

161152
(** Try to transform a PureScript [import …] line. *)
162153
let transform_import_line stripped =
@@ -221,7 +212,7 @@ let transform_import_line stripped =
221212
end
222213
end
223214

224-
(* ─── Module declaration ─────────────────────────────────────────────── *)
215+
(* ─── Module declaration ───────────────────────────────────────────────────── *)
225216

226217
(** [module Foo where] / [module Foo (exports) where] → [module Foo;].
227218
Canonical AffineScript uses [module] as a file-level header (no
@@ -252,7 +243,7 @@ let transform_module_line stripped =
252243
Some (Printf.sprintf "module %s;" mod_path)
253244
end
254245

255-
(* ─── Type signature handling ────────────────────────────────────────── *)
246+
(* ─── Type signature handling ──────────────────────────────────────────────── *)
256247

257248
(** A line of the form [name :: type ...] is a type signature. Lucid keeps
258249
it as a comment so the canonical type inferer is the source of truth.
@@ -267,7 +258,7 @@ let is_type_signature stripped =
267258
has_dcolon && len > 0
268259
&& (stripped.[0] >= 'a' && stripped.[0] <= 'z' || stripped.[0] = '_')
269260

270-
(* ─── Data / class / instance declarations ───────────────────────────── *)
261+
(* ─── Data / class / instance declarations ───────────────────────────────────── *)
271262

272263
(** [data Foo a b = Ctor1 a | Ctor2] → [type Foo[a, b] = Ctor1(a) | Ctor2].
273264
Best-effort: parameterised constructor arguments wrapped in parens. *)
@@ -350,7 +341,7 @@ let transform_instance_decl stripped =
350341
| _ -> Some (Printf.sprintf "impl %s {" body)
351342
end
352343

353-
(* ─── Function equations ─────────────────────────────────────────────── *)
344+
(* ─── Function equations ────────────────────────────────────────────────────── *)
354345

355346
(** [f x y = expr] — wrap parameters and emit canonical [fn].
356347
Returns [None] when the line isn't a recognisable equation. *)
@@ -395,7 +386,7 @@ let transform_equation stripped =
395386
end
396387
end
397388

398-
(* ─── Expression-level substitutions ─────────────────────────────────── *)
389+
(* ─── Expression-level substitutions ───────────────────────────────────────────── *)
399390

400391
(** [\x -> body] / [\x y -> body] → [(x, y) => body]. *)
401392
let transform_lambda_inline s =
@@ -535,11 +526,14 @@ let render_block_head head marker =
535526
head ^ " = {"
536527
| _ -> head
537528

538-
(* ─── Main transformer ───────────────────────────────────────────────── *)
529+
(* ─── Main transformer ───────────────────────────────────────────────────────── *)
539530

540531
let is_blank_line raw =
541-
let (code, _) = strip_dashdash_comment (String.trim raw) in
542-
String.trim code = ""
532+
let t = String.trim raw in
533+
if starts_with t "//" then true
534+
else
535+
let (code, _) = strip_dashdash_comment t in
536+
String.trim code = ""
543537

544538
let transform_source source =
545539
let lines = Array.of_list (String.split_on_char '\n' source) in
@@ -571,8 +565,7 @@ let transform_source source =
571565
for i = 0 to n - 1 do
572566
let raw_line = lines.(i) in
573567
let ind = indent_of raw_line in
574-
let line = convert_dashdash_comment raw_line in
575-
let (code_part, comment_opt) = strip_dashdash_comment (String.trim line) in
568+
let (code_part, comment_opt) = strip_dashdash_comment (String.trim raw_line) in
576569
let stripped = String.trim code_part in
577570

578571
let with_comment line_text =
@@ -585,6 +578,10 @@ let transform_source source =
585578
(match comment_opt with
586579
| Some c -> Buffer.add_string out ("// " ^ String.trim c ^ "\n")
587580
| None -> Buffer.add_char out '\n')
581+
end else if starts_with stripped "//" || starts_with stripped "/*" then begin
582+
(* Already-canonical comment lines pass through unchanged. *)
583+
let indent_str = String.make ind ' ' in
584+
Buffer.add_string out (indent_str ^ stripped ^ "\n")
588585
end else if is_type_signature stripped then begin
589586
(* Keep type signatures as a comment so the inferer drives types. *)
590587
let indent_str = String.make ind ' ' in
@@ -661,7 +658,7 @@ let transform_source source =
661658
done;
662659
Buffer.contents out
663660

664-
(* ─── Entry points ───────────────────────────────────────────────────── *)
661+
(* ─── Entry points ────────────────────────────────────────────────────────────── *)
665662

666663
let parse_string_lucid ~file content =
667664
let canonical = transform_source content in
Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
// SPDX-License-Identifier: AGPL-3.0-or-later;
2-
// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell;
3-
//;
4-
// LucidScript face. Distinctive features exercised: module declaration;
5-
// with `where`, type signatures kept as comments, equation-style;
6-
// function definitions, `; // ` line comments. (The unit-parameter idiom
7-
// `main () = …` lowers to canonical `fn main() { … }`. Function;
8-
// application uses canonical paren syntax `f(x)` rather than Haskell;
9-
// currying `f x` — see examples/faces/README.adoc.);
10-
// face: lucidscript;
1+
// SPDX-License-Identifier: AGPL-3.0-or-later
2+
// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell
3+
//
4+
// LucidScript face. Distinctive features exercised: module declaration
5+
// with `where`, type signatures kept as comments, equation-style
6+
// function definitions, `--` line comments. (The unit-parameter idiom
7+
// `main () = …` lowers to canonical `fn main() { … }`. Function
8+
// application uses canonical paren syntax `f(x)` rather than Haskell
9+
// currying `f x` — see examples/faces/README.adoc.)
10+
// face: lucidscript
1111

1212
module Hello;
1313

@@ -17,4 +17,3 @@ effect IO {
1717

1818
// main :: -{IO}-> ()
1919
fn main() { println("Hello, LucidScript!") }
20-

0 commit comments

Comments
 (0)