json.monkey2 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. #rem monkeydoc
  2. JSON (JavaScript Object Notation) is a lightweight data-interchange format.
  3. \## Reading JSON data
  4. Use the [[JsonObject.Load]] function to load JSON data from a file, or [[JsonObject.Parse]] to parse JSON data from a string.
  5. \## Writing JSON data
  6. To save a JSON object, use the [[JsonObject.Save]] function.
  7. #end
  8. Namespace std.json
  9. #rem monkeydoc JsonError class.
  10. #end
  11. Class JsonError Extends Throwable
  12. End
  13. #rem monkeydoc JsonValue class.
  14. This is base class of all JsonValue types.
  15. #end
  16. Class JsonValue
  17. Const NullValue:=New JsonValue
  18. #rem monkeydoc True if value is null.
  19. #end
  20. Property IsNull:Bool()
  21. Return Self=NullValue
  22. End
  23. #rem monkeydoc True if value is a bool.
  24. #end
  25. Property IsBool:Bool() Virtual
  26. Return False
  27. End
  28. #rem monkeydoc True if value is a number.
  29. #end
  30. Property IsNumber:Bool() Virtual
  31. Return False
  32. End
  33. #rem monkeydoc True if value is a string.
  34. #end
  35. Property IsString:Bool() Virtual
  36. Return False
  37. End
  38. #rem monkeydoc True if value is an array.
  39. #end
  40. Property IsArray:Bool() Virtual
  41. Return False
  42. End
  43. #rem monkeydoc True if value is an object.
  44. #end
  45. Property IsObject:Bool() Virtual
  46. Return False
  47. End
  48. #rem monkeydoc Gets bool value.
  49. If the value is a bool, returns its actual value.
  50. If the value is not a bool, false is returned by default.
  51. #end
  52. Method ToBool:Bool() Virtual
  53. Return False
  54. End
  55. #rem monkeydoc Gets number value.
  56. If the value is a number, returns its actual value.
  57. If the value is not a number, 0 is returned by default.
  58. #end
  59. Method ToNumber:Double() Virtual
  60. Return 0
  61. End
  62. #rem monkeydoc Gets string value.
  63. If the value is a string, returns its actual value.
  64. If the value is not a string, "" is returned by default.
  65. #end
  66. Method ToString:String() Virtual
  67. Return ""
  68. End
  69. #rem monkeydoc Gets array value.
  70. If the value is an array, returns its actual value in the form of a Stack<JsonValue> object.
  71. If the value is not an array, null is returned by default.
  72. #end
  73. Method ToArray:Stack<JsonValue>() Virtual
  74. Return Null
  75. End
  76. #rem monkeydoc Gets object value.
  77. If the value is an object, returns its actual value in the form of a StringMap<JsonValue> object.
  78. If the value is not an object, null is returned by default.
  79. #end
  80. Method ToObject:StringMap<JsonValue>() Virtual
  81. Return Null
  82. End
  83. #rem monkeydoc Converts the value to a JSON string.
  84. #end
  85. Method ToJson:String() Virtual
  86. Local buf:=New StringStack
  87. PushJson( buf )
  88. Return buf.Join( "" )
  89. End
  90. #rem monkeydoc Saves the value as a JSON string to a file.
  91. #end
  92. Method Save:Bool( path:String )
  93. Local buf:=New StringStack
  94. PushJson( buf )
  95. Local src:=buf.Join( "" )
  96. Return stringio.SaveString( src,path )
  97. End
  98. #rem monkeydoc Load the value from a JSON string stored in a file.
  99. #end
  100. Function Load:JsonValue( path:String,throwex:Bool=False )
  101. Local src:=stringio.LoadString( path )
  102. If Not src Return Null
  103. Return Parse( src,throwex )
  104. End
  105. #rem monkeydoc Creates a JSONValue from a JSON string.
  106. Returns null if the json could not be parsed.
  107. #end
  108. Function Parse:JsonValue( src:String,throwex:Bool=False )
  109. Try
  110. Local parser:=New JsonParser( src )
  111. Return parser.ParseValue()
  112. Catch ex:JsonError
  113. If throwex Throw ex
  114. End
  115. Return Null
  116. End
  117. Protected
  118. Global _indent:String
  119. #rem monkeydoc @hidden
  120. #end
  121. Method New()
  122. End
  123. #rem monkeydoc @hidden
  124. #end
  125. Method PushJson:Void( buf:StringStack ) Virtual
  126. buf.Push( ToJson() )
  127. End
  128. End
  129. #rem monkeydoc JsonBool class.
  130. #end
  131. Class JsonBool Extends JsonValue
  132. Const TrueValue:JsonBool=New JsonBool( True )
  133. Const FalseValue:JsonBool=New JsonBool( False )
  134. Method New( data:Bool=False )
  135. _data=data
  136. End
  137. #rem monkeydoc @hidden Deprecated!
  138. #end
  139. Property Data:Bool()
  140. Return _data
  141. Setter( data:Bool )
  142. _data=data
  143. End
  144. Property IsBool:Bool() Override
  145. Return True
  146. End
  147. Method ToBool:Bool() Override
  148. Return _data
  149. End
  150. #rem monkeydoc @hidden Deprecated!
  151. #end
  152. Method ToNumber:Double() Override
  153. Return _data
  154. End
  155. #rem monkeydoc @hidden Deprecated!
  156. #end
  157. Method ToString:String() Override
  158. Return _data ? "true" Else "false"
  159. End
  160. Method ToJson:String() Override
  161. If _data Return "true"
  162. Return "false"
  163. End
  164. Private
  165. Field _data:Bool
  166. End
  167. #rem monkeydoc JsonNumber class.
  168. #end
  169. Class JsonNumber Extends JsonValue
  170. Method New( data:Double=0 )
  171. _data=data
  172. End
  173. #rem monkeydoc @hidden Deprecated!
  174. #end
  175. Property Data:Double()
  176. Return _data
  177. Setter( data:Double )
  178. _data=data
  179. End
  180. Property IsNumber:Bool() Override
  181. Return True
  182. End
  183. Method ToNumber:Double() Override
  184. Return _data
  185. End
  186. #rem monkeydoc @hidden Deprecated!
  187. #end
  188. Method ToBool:Bool() Override
  189. Return _data
  190. End
  191. #rem monkeydoc @hidden Deprecated!
  192. #end
  193. Method ToString:String() Override
  194. Return _data
  195. End
  196. Method ToJson:String() Override
  197. Return String( _data )
  198. End
  199. Private
  200. Field _data:Double
  201. End
  202. #rem monkeydoc JsonString class.
  203. #end
  204. Class JsonString Extends JsonValue
  205. Method New( data:String="" )
  206. _data=data
  207. End
  208. #rem monkeydoc @hidden Deprecated!
  209. #end
  210. Property Data:String()
  211. Return _data
  212. Setter( data:String )
  213. _data=data
  214. End
  215. Property IsString:Bool() Override
  216. Return True
  217. End
  218. Method ToString:String() Override
  219. Return _data
  220. End
  221. #rem monkeydoc @hidden Deprecated!
  222. #end
  223. Method ToBool:Bool() Override
  224. Return _data
  225. End
  226. #rem monkeydoc @hidden Deprecated!
  227. #end
  228. Method ToNumber:Double() Override
  229. Return Double( _data )
  230. End
  231. Method ToJson:String() Override
  232. Return "~q"+_data.Replace( "~q","\~q" )+"~q"
  233. End
  234. Private
  235. Field _data:String
  236. End
  237. #rem monkeydoc JsonArray class.
  238. #end
  239. Class JsonArray Extends JsonValue
  240. Method New( length:Int=0 )
  241. _data=New Stack<JsonValue>( length )
  242. End
  243. Method New( data:JsonValue[] )
  244. _data=New Stack<JsonValue>( data )
  245. End
  246. Method New( data:Stack<JsonValue> )
  247. _data=data
  248. End
  249. #rem monkeydoc @hidden Deprecated!
  250. #end
  251. Property Data:Stack<JsonValue>()
  252. Return _data
  253. Setter( data:Stack<JsonValue> )
  254. _data=data
  255. End
  256. #rem monkeydoc Returns true.
  257. #end
  258. Property IsArray:Bool() Override
  259. Return True
  260. End
  261. #rem monkeydoc Gets the internal stack used to store the array.
  262. #end
  263. Method ToArray:Stack<JsonValue>() Override
  264. Return _data
  265. End
  266. #rem monkeydoc Gets an array element.
  267. Returns the json value at `index`, or null if `index` is out of range.
  268. @param index Array index.
  269. #end
  270. Method GetValue:JsonValue( index:int )
  271. Return Null
  272. End
  273. #rem monkeydoc Gets a bool array element.
  274. Returns the bool value at `index`, or false if `index` is out of range or the value at `index` is not a bool.
  275. @param index Array index.
  276. #end
  277. Method GetBool:Bool( index:int )
  278. Local value:=GetValue( index )
  279. If value Return value.ToBool()
  280. Return False
  281. End
  282. #rem monkeydoc Gets a numeric array element.
  283. Returns the numeric value at `index`, or 0 if `index` is out of range or the value at `index` is not numeric.
  284. @param index Array index.
  285. #end
  286. Method GetNumber:Double( index:int )
  287. Local value:=GetValue( index )
  288. If value Return value.ToNumber()
  289. Return 0
  290. End
  291. #rem monkeydoc Gets a string array element.
  292. Returns the string value at `index`, or an empty string if `index` is out of range or the value at `index` is not a string.
  293. @param index Array index.
  294. #end
  295. Method GetString:String( index:Int )
  296. Local value:=GetValue( index )
  297. If value Return value.ToString()
  298. Return ""
  299. End
  300. #rem monkeydoc Gets an array array element.
  301. Returns the array at `index`, or null if `index` is out of range or the value at `index` is not an array.
  302. @param index Array index.
  303. #end
  304. Method GetArray:JsonArray( index:int )
  305. Return Cast<JsonArray>( GetValue( index ) )
  306. End
  307. #rem monkeydoc Gets an object array element.
  308. Returns the object at `index`, or null if `index` is out of range or the value at `index` is not an object.
  309. @param index Array index.
  310. #end
  311. Method GetObject:JsonObject( index:Int )
  312. Return Cast<JsonObject>( GetValue( index ) )
  313. End
  314. #rem monkeydoc True if array is empty.
  315. #end
  316. Property Empty:Bool()
  317. Return _data.Empty
  318. End
  319. #rem monkeydoc Length of the array.
  320. #end
  321. Property Length:Int()
  322. Return _data.Length
  323. End
  324. #rem monkeydoc Gets the json value at an index.
  325. Returns the json value at `index`, or null if `index` is out of range.
  326. @param index The index.
  327. @return The json value at `index`.
  328. #end
  329. Operator[]:JsonValue( index:Int )
  330. If index<0 Or index>=_data.Length Return null
  331. Return _data[index]
  332. End
  333. #rem monkeydoc Sets the json value at an index.
  334. Sets the json value at `index` to `value`, or does nothing if `index` is out of range.
  335. @param index The index.
  336. @param value The json value to store at `index`.
  337. #end
  338. Operator[]=( index:Int,value:JsonValue )
  339. If index<0 Or index>=_data.Length Return
  340. DebugAssert( index>=0 )
  341. If index>=_data.Length _data.Resize( index+1 )
  342. _data[index]=value
  343. End
  344. #rem monkeydoc Gets an iterator to all json values in the array.
  345. #end
  346. Method All:Stack<JsonValue>.Iterator()
  347. Return _data.All()
  348. End
  349. #rem monkeydoc Adds a json value to the array.
  350. @param value The json value to add.
  351. #end
  352. Method Push( value:JsonValue )
  353. _data.Push( value )
  354. End
  355. #rem monkeydoc @hidden
  356. #end
  357. Method Add( value:JsonValue )
  358. _data.Add( value )
  359. End
  360. Private
  361. Field _data:Stack<JsonValue>
  362. Method PushJson:Void( buf:StringStack ) Override
  363. buf.Push( "[" )
  364. Local indent:=_indent
  365. Local n:=0
  366. For Local value:=Eachin _data
  367. If n
  368. buf.Push( "," )
  369. Endif
  370. n+=1
  371. If value
  372. buf.Push( value.ToJson() )
  373. Else
  374. buf.Push( "null" )
  375. Endif
  376. Next
  377. _indent=indent
  378. buf.Push( "]" )
  379. End
  380. End
  381. #rem monkeydoc JsonObject class.
  382. #end
  383. Class JsonObject Extends JsonValue
  384. Method New( data:StringMap<JsonValue> =Null )
  385. If Not data data=New StringMap<JsonValue>
  386. _data=data
  387. End
  388. #rem monkeydoc @hidden Deprecated!
  389. #end
  390. Property Data:StringMap<JsonValue>()
  391. Return _data
  392. Setter( data:StringMap<JsonValue> )
  393. _data=data
  394. End
  395. #rem monkeydoc Returns True.
  396. #end
  397. Property IsObject:Bool() Override
  398. Return True
  399. End
  400. #rem monkeydoc Gets the internal string map used to store the object.
  401. #end
  402. Method ToObject:StringMap<JsonValue>() Override
  403. Return _data
  404. End
  405. #rem monkeydoc Gets the value associated with a key.
  406. Returns the json value associated with `key`, or null if `key` does not exist.
  407. @param index Object key.
  408. #end
  409. Method GetValue:JsonValue( key:String )
  410. Return _data[key]
  411. End
  412. #rem monkeydoc Gets a bool from an object.
  413. Returns the bool value associated with `key`, or false if `key` does not exist or the value associated with `key` is not a bool.
  414. @param key Object key.
  415. #end
  416. Method GetBool:Bool( key:String )
  417. Local value:=GetValue( key )
  418. If value Return value.ToBool()
  419. Return False
  420. End
  421. #rem monkeydoc Gets a number from an object.
  422. Returns the numeric value associated with `key`, or 0 if `key` does not exist or the value associated with `key` is not numeric.
  423. @param key Object key.
  424. #end
  425. Method GetNumber:Double( key:String )
  426. Local value:=GetValue( key )
  427. If value Return value.ToNumber()
  428. Return 0
  429. End
  430. #rem monkeydoc Gets a string from an object.
  431. Returns the string value associated with `key`, or an empty string if `key` does not exist or the value associated with `key` is not a string.
  432. @param key Object key.
  433. #end
  434. Method GetString:String( key:String )
  435. Local value:=GetValue( key )
  436. If value Return value.ToString()
  437. Return ""
  438. End
  439. #rem monkeydoc Gets an array from an object.
  440. Returns the json array associated with `key`, or null if `key` does not exist or the value associated with `key` is not an array.
  441. @param key Object key.
  442. #end
  443. Method GetArray:JsonArray( key:String )
  444. Return Cast<JsonArray>( GetValue( key ) )
  445. End
  446. #rem monkeydoc Gets an object from the object.
  447. Returns the json object associated with `key`, or null if `key` does not exist or the value associated with `key` is not an object.
  448. @param key Object key.
  449. @return A json object.
  450. #end
  451. Method GetObject:JsonObject( key:String )
  452. Return Cast<JsonObject>( GetValue( key ) )
  453. End
  454. #rem monkeydoc True if object is empty.
  455. #end
  456. Property Empty:Bool()
  457. Return _data.Empty
  458. End
  459. #rem monkeydoc Counts the number of keys in the object.
  460. Returns the number of keys contained in the object.
  461. @return The number of keys.
  462. #end
  463. Method Count:Int()
  464. Return _data.Count()
  465. End
  466. #rem monkeydoc Checks if the object contains a key.
  467. Returns true if object contains `key`.
  468. @param key Key to check for.
  469. @return True if object contains `key`.
  470. #end
  471. Method Contains:Bool( key:String )
  472. Return _data.Contains( key )
  473. End
  474. #rem monkeydoc Gets an iterator to all json values in the object.
  475. #end
  476. Method All:StringMap<JsonValue>.Iterator()
  477. Return _data.All()
  478. End
  479. #rem monkeydoc Gets the json value associated with a key.
  480. Returns the json value associated with `key`, or null if `key` does not exist.
  481. @param key The key.
  482. @return The json value associated with `key`.
  483. #end
  484. Operator[]:JsonValue( key:String )
  485. Return _data[key]
  486. End
  487. #rem monkeydoc Sets the json value in the object.
  488. Sets the json value associated with `key` to `value`.
  489. @param key The key.
  490. @param value The json value to associate with `key`.
  491. #end
  492. Operator[]=( key:String,value:JsonValue )
  493. _data[key]=value
  494. End
  495. Function Load:JsonObject( path:String,throwex:Bool=False )
  496. Local src:=std.stringio.LoadString( path )
  497. If Not src Return Null
  498. Return Parse( src,throwex )
  499. End
  500. Function Parse:JsonObject( json:String,throwex:Bool=False )
  501. Try
  502. Local parser:=New JsonParser( json )
  503. Return New JsonObject( parser.ParseObject() )
  504. Catch ex:JsonError
  505. If throwex Throw ex
  506. End
  507. Return Null
  508. End
  509. Private
  510. Field _data:StringMap<JsonValue>
  511. Method PushJson:Void( buf:StringStack ) Override
  512. buf.Push( "{~n" )
  513. _indent+="~t"
  514. Local t:=False
  515. For Local it:=Eachin _data
  516. If t buf.Push( ",~n" )
  517. buf.Push( _indent+"~q"+it.Key.Replace( "~q","\~q" )+"~q:" )
  518. If it.Value
  519. buf.Push( it.Value.ToJson() )
  520. Else
  521. buf.Push( "null" )
  522. Endif
  523. t=True
  524. Next
  525. _indent=_indent.Slice( 0,-1 )
  526. buf.Push( "~n"+_indent+"}" )
  527. End
  528. End
  529. #rem monkeydoc JsonParser class.
  530. #end
  531. Class JsonParser
  532. Method New( json:String )
  533. _text=json
  534. Bump()
  535. End
  536. Method ParseValue:JsonValue()
  537. If TokeType=T_STRING Return New JsonString( ParseString() )
  538. If TokeType=T_NUMBER Return New JsonNumber( ParseNumber() )
  539. If Toke="{" Return New JsonObject( ParseObject() )
  540. If Toke="[" Return New JsonArray( ParseArray() )
  541. If CParse( "true" ) Return JsonBool.TrueValue
  542. If CParse( "false" ) Return JsonBool.FalseValue
  543. If CParse( "null" ) Return JsonValue.NullValue
  544. Return Null
  545. End
  546. Private
  547. Const T_EOF:=0
  548. Const T_STRING:=1
  549. Const T_NUMBER:=2
  550. Const T_SYMBOL:=3
  551. Const T_IDENT:=4
  552. Field _text:String
  553. Field _toke:String
  554. Field _type:Int
  555. Field _pos:Int
  556. Method GetChar:Int()
  557. If _pos=_text.Length Throw New JsonError()
  558. _pos+=1
  559. Return _text[_pos-1]
  560. End
  561. Method PeekChar:Int()
  562. If _pos=_text.Length Return 0
  563. Return _text[_pos]
  564. End
  565. Method ParseChar:Void( chr:Int )
  566. If _pos>=_text.Length Or _text[_pos]<>chr Throw New JsonError()
  567. _pos+=1
  568. End
  569. Method CParseChar:Bool( chr:Int )
  570. If _pos>=_text.Length Or _text[_pos]<>chr Return False
  571. _pos+=1
  572. Return True
  573. End
  574. Method CParseDigits:Bool()
  575. Local p:=_pos
  576. While _pos<_text.Length And _text[_pos]>=48 And _text[_pos]<=57
  577. _pos+=1
  578. Wend
  579. Return _pos>p
  580. End
  581. Method Bump:String()
  582. While _pos<_text.Length
  583. If _text[_pos]=47
  584. '// comment? - can't live without 'em!
  585. If _pos+1=_text.Length Or _text[_pos+1]<>47 Exit
  586. _pos+=2
  587. While _pos<_text.Length And _text[_pos]<>10
  588. _pos+=1
  589. Wend
  590. If _pos<_text.Length _pos+=1
  591. Else
  592. If _text[_pos]>32 Exit
  593. _pos+=1
  594. Endif
  595. Wend
  596. If _pos=_text.Length
  597. _toke=""
  598. _type=T_EOF
  599. Return _toke
  600. Endif
  601. Local pos:=_pos
  602. Local chr:=GetChar()
  603. If chr=34
  604. Repeat
  605. Local chr:=GetChar()
  606. If chr=34 Exit
  607. If chr=92 GetChar()
  608. Forever
  609. _type=T_STRING
  610. Else If chr=39
  611. Repeat
  612. Local chr:=GetChar()
  613. If chr=39 Exit
  614. If chr=92 GetChar()
  615. Forever
  616. _type=T_STRING
  617. Else If (chr>=48 And chr<=57) Or chr=45
  618. If chr=45 '-
  619. chr=GetChar()
  620. If chr<48 Or chr>57 Throw New JsonError()
  621. Endif
  622. If chr<>48 '0
  623. CParseDigits()
  624. End
  625. If CParseChar( 46 ) '.
  626. CParseDigits()
  627. Endif
  628. If CParseChar( 69 ) Or CParseChar( 101 ) 'e E
  629. If PeekChar()=43 Or PeekChar()=45 GetChar() '+ -
  630. If Not CParseDigits() Throw New JsonError()
  631. Endif
  632. _type=T_NUMBER
  633. Else If (chr>=65 And chr<91) Or (chr>=97 And chr<123) Or chr=95
  634. chr=PeekChar()
  635. While (chr>=65 And chr<91) Or (chr>=97 And chr<123) Or (chr>=48 And chr<58) Or chr=95
  636. GetChar()
  637. chr=PeekChar()
  638. Wend
  639. _type=T_IDENT
  640. Else
  641. _type=T_SYMBOL
  642. Endif
  643. _toke=_text.Slice( pos,_pos )
  644. Return _toke
  645. End
  646. Property Toke:String()
  647. Return _toke
  648. End
  649. Property TokeType:Int()
  650. Return _type
  651. End
  652. Method CParse:Bool( toke:String )
  653. If toke<>_toke Return False
  654. Bump()
  655. Return True
  656. End
  657. Method Parse:Void( toke:String )
  658. If Not CParse( toke ) Throw New JsonError()
  659. End
  660. Method ParseObject:StringMap<JsonValue>()
  661. Parse( "{" )
  662. Local map:=New StringMap<JsonValue>
  663. If CParse( "}" ) Return map
  664. Repeat
  665. Local name:=Toke
  666. If TokeType=T_IDENT
  667. Bump()
  668. Else
  669. name=ParseString()
  670. Endif
  671. Parse( ":" )
  672. Local value:=ParseValue()
  673. map.Set( name,value )
  674. Until Not CParse( "," )
  675. Parse( "}" )
  676. Return map
  677. End
  678. Method ParseArray:Stack<JsonValue>()
  679. Parse( "[" )
  680. Local stack:=New Stack<JsonValue>
  681. If CParse( "]" ) Return stack
  682. Repeat
  683. Local value:=ParseValue()
  684. stack.Add( value )
  685. Until Not CParse( "," )
  686. Parse( "]" )
  687. Return stack
  688. End
  689. Method ParseString:String()
  690. If TokeType<>T_STRING Throw New JsonError()
  691. Local toke:=Toke.Slice( 1,-1 )
  692. Local i:=toke.Find( "\" )
  693. If i<>-1
  694. Local frags:=New StringStack,p:=0,esc:=""
  695. Repeat
  696. If i+1>=toke.Length Throw New JsonError()
  697. frags.Push( toke.Slice( p,i ) )
  698. Select toke[i+1]
  699. Case 34 esc="~q" '\"
  700. Case 92 esc="\" '\\
  701. Case 47 esc="/" '\/
  702. Case 98 esc=String.FromChar( 8 ) '\b
  703. Case 102 esc=String.FromChar( 12 ) '\f
  704. Case 114 esc=String.FromChar( 13 ) '\r
  705. Case 110 esc=String.FromChar( 10 ) '\n
  706. Case 117 '\uxxxx
  707. If i+6>toke.Length Throw New JsonError()
  708. Local val:=0
  709. For Local j:=2 Until 6
  710. Local chr:=toke[i+j]
  711. If chr>=48 And chr<58
  712. val=val Shl 4 | (chr-48)
  713. Else If chr>=65 And chr<123
  714. chr&=31
  715. If chr<1 Or chr>6 Throw New JsonError()
  716. val=val Shl 4 | (chr+9)
  717. Else
  718. Throw New JsonError()
  719. Endif
  720. Next
  721. esc=String.FromChar( val )
  722. i+=4
  723. Default
  724. Throw New JsonError()
  725. End
  726. frags.Push( esc )
  727. p=i+2
  728. i=toke.Find( "\",p )
  729. If i<>-1 Continue
  730. frags.Push( toke.Slice( p ) )
  731. Exit
  732. Forever
  733. toke=frags.Join( "" )
  734. Endif
  735. Bump()
  736. Return toke
  737. End
  738. Method ParseNumber:Double()
  739. If TokeType<>T_NUMBER Throw New JsonError()
  740. Local toke:=Toke
  741. Bump()
  742. Return Double( toke )
  743. End
  744. End