json.monkey2 23 KB

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