feat(woc): wo.toml [deps] section — inline-table parsing (iter 15 Task 1)
The manifest grows [deps]: `name = { git = "...", rev = "..." }` — a
one-line inline table accepted ONLY under [deps] (a tiny scanner, not
split-on-comma: URLs may contain any character). git+rev both mandatory and
non-empty; duplicate dep names, unknown table keys, unquoted values, and
inline tables outside [deps] each keep/get a named diagnostic. Parse-only:
no fetch yet (Task 2).
Verified: well-formed parses; missing-rev / bare-value / outside-deps each
diagnose; woc-test 540/0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5312f9f8e8
commit
b5ccaacad3
1 changed files with 67 additions and 2 deletions
|
|
@ -653,13 +653,78 @@ let manifest_parse (path : string) : (string * string) list =
|
|||
in
|
||||
section := inner;
|
||||
if !section <> "runtime" && !section <> "build" && !section <> "share"
|
||||
&& !section <> "share.clients"
|
||||
&& !section <> "share.clients" && !section <> "deps"
|
||||
then
|
||||
fail !lineno
|
||||
(Printf.sprintf "unknown section [%s] (runtime and build exist)" !section)
|
||||
(Printf.sprintf "unknown section [%s] (runtime, build and deps exist)" !section)
|
||||
end
|
||||
else if !section = "share" || !section = "share.clients" then
|
||||
() (* iteration 9c manifest keys — parsed by the attach feature, ignored here *)
|
||||
else if !section = "deps" then begin
|
||||
(* iteration 15: `name = { git = "...", rev = "..." }` — the one-line
|
||||
inline table, accepted ONLY here. A tiny scanner rather than
|
||||
split-on-comma: the URL value may contain any character. *)
|
||||
match String.index_opt line '=' with
|
||||
| None -> fail !lineno "expected `name = { git = \"...\", rev = \"...\" }`"
|
||||
| Some eq ->
|
||||
let name = String.trim (String.sub line 0 eq) in
|
||||
if name = "" then fail !lineno "dependency name is empty";
|
||||
if List.mem_assoc ("deps." ^ name ^ ".git") !kvs then
|
||||
fail !lineno (Printf.sprintf "dependency `%s` declared twice" name);
|
||||
let body = String.trim (String.sub line (eq + 1) (String.length line - eq - 1)) in
|
||||
let blen = String.length body in
|
||||
if blen < 2 || body.[0] <> '{' || body.[blen - 1] <> '}' then
|
||||
fail !lineno
|
||||
(Printf.sprintf "`%s`: a dependency is an inline table `{ git = \"...\", rev = \"...\" }`" name);
|
||||
let inner = String.sub body 1 (blen - 2) in
|
||||
let i = ref 0 in
|
||||
let n = String.length inner in
|
||||
let git = ref None and rev = ref None in
|
||||
let skip_ws () = while !i < n && (inner.[!i] = ' ' || inner.[!i] = '\t') do incr i done in
|
||||
let read_ident () =
|
||||
let s = !i in
|
||||
while !i < n && inner.[!i] <> ' ' && inner.[!i] <> '\t' && inner.[!i] <> '=' do incr i done;
|
||||
String.sub inner s (!i - s)
|
||||
in
|
||||
let read_quoted () =
|
||||
if !i >= n || inner.[!i] <> '"' then fail !lineno "dependency values must be quoted strings";
|
||||
incr i;
|
||||
let s = !i in
|
||||
while !i < n && inner.[!i] <> '"' do incr i done;
|
||||
if !i >= n then fail !lineno "unterminated string in dependency table";
|
||||
let v = String.sub inner s (!i - s) in
|
||||
incr i;
|
||||
v
|
||||
in
|
||||
let continue_tbl = ref true in
|
||||
while !continue_tbl do
|
||||
skip_ws ();
|
||||
if !i >= n then continue_tbl := false
|
||||
else begin
|
||||
let k = read_ident () in
|
||||
skip_ws ();
|
||||
if !i >= n || inner.[!i] <> '=' then
|
||||
fail !lineno (Printf.sprintf "expected `=` after `%s` in dependency table" k);
|
||||
incr i;
|
||||
skip_ws ();
|
||||
let v = read_quoted () in
|
||||
(match k with
|
||||
| "git" -> git := Some v
|
||||
| "rev" -> rev := Some v
|
||||
| _ -> fail !lineno (Printf.sprintf "unknown key `%s` in dependency table (git, rev exist)" k));
|
||||
skip_ws ();
|
||||
if !i < n then
|
||||
if inner.[!i] = ',' then incr i
|
||||
else fail !lineno "expected `,` between dependency table entries"
|
||||
end
|
||||
done;
|
||||
(match (!git, !rev) with
|
||||
| Some g, Some r when g <> "" && r <> "" ->
|
||||
kvs := ("deps." ^ name ^ ".rev", r) :: ("deps." ^ name ^ ".git", g) :: !kvs
|
||||
| _ ->
|
||||
fail !lineno
|
||||
(Printf.sprintf "dependency `%s` needs both `git` and `rev` (exact tag or SHA)" name))
|
||||
end
|
||||
else
|
||||
match String.index_opt line '=' with
|
||||
| None -> fail !lineno "expected `key = \"value\"`"
|
||||
|
|
|
|||
Loading…
Reference in a new issue