123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566(* Claude Code
*
* Copyright (C) 2026 Yoann Padioleau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* (LGPL) as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*)(* See Json.mli *)typet=Null|Boolofbool|Numberoffloat|Stringofstring|Arrayoftlist|Objectof(string*t)listexceptionBadofint*string(* value := object | array | string | number | - number | true | false | null
* object := { (string : value ,)* } array := [ (value ,)* ] *)letparse(text:string):(t,string)result=matchJs_lexer.tokenizetextwith|exceptionJs_lexer.Error(line,msg)->Error(Printf.sprintf"line %d: %s"linemsg)|tokens->(lettoks=reftokensinletpeek():Js_lexer.token=match!tokswitht::_->t|[]->{kind=Eof;line=0;newline_before=false}inletnext()=lett=peek()in(toks:=match!tokswith_::r->r|[]->[]);tinletfail(t:Js_lexer.token)=raise(Bad(t.line,"unexpected "^Js_lexer.to_stringt.kind))inletexpectp=lett=next()inift.kind<>Punctpthenfailtin(* the items up to [close], a comma after each but maybe the last *)letitemscloseitem=letout=ref[]inwhile(peek()).kind<>Punctclosedoout:=item()::!out;if(peek()).kind<>Punctclosethenexpect","done;ignore(next());List.rev!outinletrecvalue():t=lett=next()inmatcht.kindwith|Punct"{"->Object(items"}"(fun()->letk=next()inmatchk.kindwith|Strings->expect":";(s,value())|_->failk))|Punct"["->Array(items"]"value)|Punct"-"->(match(next()).kindwithNumbern->Number(-.n)|_->failt)|Strings->Strings|Numbern->Numbern|Keyword"true"->Booltrue|Keyword"false"->Boolfalse|Keyword"null"->Null|_->failtinmatchletv=value()inlett=next()inift.kind<>Eofthenfailt;vwith|v->Okv|exceptionBad(line,msg)->Error(Printf.sprintf"line %d: %s"linemsg))letmember(k:string)(v:t):toption=matchvwithObjectfields->List.assoc_optkfields|_->None