PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/sys/dotnet/fanx/serial/ObjDecoder.cs

https://bitbucket.org/bedlaczech/fan-1.0
C# | 756 lines | 474 code | 91 blank | 191 comment | 144 complexity | e03fb2fb8bb3f570561adbbfa95e26ac MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2007, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 10 Sep 07 Andy Frank Creation
  7. //
  8. using System.Collections;
  9. using Fan.Sys;
  10. using Fanx.Util;
  11. namespace Fanx.Serial
  12. {
  13. /// <summary>
  14. /// ObjDecoder parses an object tree from an input stream.
  15. /// </summary>
  16. public class ObjDecoder
  17. {
  18. //////////////////////////////////////////////////////////////////////////
  19. // Static
  20. //////////////////////////////////////////////////////////////////////////
  21. public static object decode(string s)
  22. {
  23. return new ObjDecoder(FanStr.@in(s), null).readObj();
  24. }
  25. //////////////////////////////////////////////////////////////////////////
  26. // Constructor
  27. //////////////////////////////////////////////////////////////////////////
  28. /// <summary>
  29. /// Construct for input stream.
  30. /// </summary>
  31. public ObjDecoder(InStream @in, Map options)
  32. {
  33. tokenizer = new Tokenizer(@in);
  34. this.options = options;
  35. consume();
  36. }
  37. //////////////////////////////////////////////////////////////////////////
  38. // Parse
  39. //////////////////////////////////////////////////////////////////////////
  40. /// <summary>
  41. /// Read an object from the stream.
  42. /// </summary>
  43. public object readObj()
  44. {
  45. readHeader();
  46. return readObj(null, null, true);
  47. }
  48. /// <summary>
  49. /// header := [using]*
  50. /// </summary>
  51. private void readHeader()
  52. {
  53. while (curt == Token.USING)
  54. {
  55. Using u = readUsing();
  56. if (usings == null) usings = new Using[8];
  57. if (numUsings >= usings.Length)
  58. {
  59. Using[] temp = new Using[usings.Length*2];
  60. System.Array.Copy(usings, 0, temp, 0, numUsings);
  61. usings = temp;
  62. }
  63. usings[numUsings++] = u;
  64. }
  65. }
  66. /// <summary>
  67. /// using := usingPod | usingType | usingAs
  68. /// usingPod := "using" podName
  69. /// usingType := "using" podName::typeName
  70. /// usingAs := "using" podName::typeName "as" name
  71. /// </summary>
  72. private Using readUsing()
  73. {
  74. consume();
  75. int line = tokenizer.m_line;
  76. string podName = consumeId("Expecting pod name");
  77. Pod pod = Pod.find(podName, false);
  78. if (pod == null) throw err("Unknown pod: " + podName);
  79. if (curt != Token.DOUBLE_COLON)
  80. {
  81. endOfStmt(line);
  82. return new UsingPod(pod);
  83. }
  84. consume();
  85. string typeName = consumeId("Expecting type name");
  86. Type t = pod.type(typeName, false);
  87. if (t == null) throw err("Unknown type: " + podName + "::" + typeName);
  88. if (curt == Token.AS)
  89. {
  90. consume();
  91. typeName = consumeId("Expecting using as name");
  92. }
  93. endOfStmt(line);
  94. return new UsingType(t, typeName);
  95. }
  96. /// <summary>
  97. /// obj := literal | simple | complex
  98. /// </summary>
  99. private object readObj(Field curField, Type peekType, bool root)
  100. {
  101. // literals are stand alone
  102. if (Token.isLiteral(curt))
  103. {
  104. object val = tokenizer.m_val;
  105. consume();
  106. return val;
  107. }
  108. // [ is always list/map collection
  109. if (curt == Token.LBRACKET)
  110. return readCollection(curField, peekType);
  111. // at this point all remaining options must start
  112. // with a type signature - if peekType is non-null
  113. // then we've already read the type signature
  114. int line = tokenizer.m_line;
  115. Type t = (peekType != null) ? peekType : readType();
  116. // type: type#"
  117. // simple: type(
  118. // list/map: type[
  119. // complex: type || type{
  120. if (curt == Token.LPAREN)
  121. return readSimple(line, t);
  122. else if (curt == Token.POUND)
  123. return readTypeOrSlotLiteral(line, t);
  124. else if (curt == Token.LBRACKET)
  125. return readCollection(curField, t);
  126. else
  127. return readComplex(line, t, root);
  128. }
  129. /// <summary>
  130. /// typeLiteral := type "#"
  131. /// slotLiteral := type "#" id
  132. /// </summary>
  133. private object readTypeOrSlotLiteral(int line, Type t)
  134. {
  135. consume(Token.POUND, "Expected '#' for type literal");
  136. if (curt == Token.ID && !isEndOfStmt(line))
  137. {
  138. string slotName = consumeId("slot literal name");
  139. return t.slot(slotName);
  140. }
  141. else
  142. {
  143. return t;
  144. }
  145. }
  146. /// <summary>
  147. /// simple := type "(" str ")"
  148. /// </summary>
  149. private object readSimple(int line, Type t)
  150. {
  151. // parse: type(str)
  152. consume(Token.LPAREN, "Expected ( in simple");
  153. string str = consumeStr("Expected string literal for simple");
  154. consume(Token.RPAREN, "Expected ) in simple");
  155. // lookup the fromStr method
  156. t.finish();
  157. Method m = t.method("fromStr", false);
  158. if (m == null)
  159. throw err("Missing method: " + t.qname() + ".fromStr", line);
  160. // invoke parse method to translate into instance
  161. try
  162. {
  163. return m.invoke(null, new object[] { str });
  164. }
  165. catch (ParseErr.Val e)
  166. {
  167. throw ParseErr.make(e.err().msg() + " [Line " + line + "]").val;
  168. }
  169. catch (System.Exception e)
  170. {
  171. throw ParseErr.make(e.ToString() + " [Line " + line + "]", e).val;
  172. }
  173. }
  174. //////////////////////////////////////////////////////////////////////////
  175. // Complex
  176. //////////////////////////////////////////////////////////////////////////
  177. /// <summary>
  178. /// complex := type [fields]
  179. /// fields := "{" field (eos field)* "}"
  180. /// field := name "=" obj
  181. /// </summary>
  182. private object readComplex(int line, Type t, bool root)
  183. {
  184. Map toSet = new Map(Sys.FieldType, Sys.ObjType.toNullable());
  185. List toAdd = new List(Sys.ObjType.toNullable());
  186. // read fields/collection into toSet/toAdd
  187. readComplexFields(t, toSet, toAdd);
  188. // get the make constructor
  189. Method makeCtor = t.method("make", false);
  190. if (makeCtor == null || !makeCtor.isPublic())
  191. throw err("Missing public constructor " + t.qname() + ".make", line);
  192. // get argument lists
  193. List args = null;
  194. if (root && options != null)
  195. args = (List)options.get("makeArgs");
  196. // construct object
  197. object obj = null;
  198. bool setAfterCtor = true;
  199. try
  200. {
  201. // if first parameter is an function then pass toSet
  202. // as an it-block for setting the fields
  203. Param p = (Param)makeCtor.@params().first();
  204. if (args == null && p != null && p.type().fits(Sys.FuncType))
  205. {
  206. args = new List(Sys.ObjType).add(Field.makeSetFunc(toSet));
  207. setAfterCtor = false;
  208. }
  209. // invoke make to construct object
  210. obj = makeCtor.callList(args);
  211. }
  212. catch (System.Exception e)
  213. {
  214. throw err("Cannot make " + t + ": " + e, line, e);
  215. }
  216. // set fields (if not passed to ctor as it-block)
  217. if (setAfterCtor && toSet.size() > 0)
  218. {
  219. IDictionaryEnumerator en = toSet.pairsIterator();
  220. while (en.MoveNext())
  221. {
  222. complexSet(obj, (Field)en.Key, en.Value, line);
  223. }
  224. }
  225. // add
  226. if (toAdd.size() > 0)
  227. {
  228. Method addMethod = t.method("add", false);
  229. if (addMethod == null) throw err("Method not found: " + t.qname() + ".add", line);
  230. for (int i=0; i<toAdd.sz(); ++i)
  231. complexAdd(t, obj, addMethod, toAdd.get(i), line);
  232. }
  233. return obj;
  234. }
  235. private void readComplexFields(Type t, Map toSet, List toAdd)
  236. {
  237. if (curt != Token.LBRACE) return;
  238. consume();
  239. // fields and/or collection items
  240. while (curt != Token.RBRACE)
  241. {
  242. // try to read "id =" to see if we have a field
  243. int line = tokenizer.m_line;
  244. bool readField = false;
  245. if (curt == Token.ID)
  246. {
  247. string name = consumeId("Expected field name");
  248. if (curt == Token.EQ)
  249. {
  250. // we have "id =" so read field
  251. consume();
  252. readComplexSet(t, line, name, toSet);
  253. readField = true;
  254. }
  255. else
  256. {
  257. // pushback to reset on start of collection item
  258. tokenizer.undo(tokenizer.m_type, tokenizer.m_val, tokenizer.m_line);
  259. curt = tokenizer.reset(Token.ID, name, line);
  260. }
  261. }
  262. // if we didn't read a field, we assume a collection item
  263. if (!readField) readComplexAdd(t, line, toAdd);
  264. if (curt == Token.COMMA) consume();
  265. else endOfStmt(line);
  266. }
  267. consume(Token.RBRACE, "Expected '}'");
  268. }
  269. void readComplexSet(Type t, int line, string name, Map toSet)
  270. {
  271. // resolve field
  272. Field field = t.field(name, false);
  273. if (field == null) throw err("Field not found: " + t.qname() + "." + name, line);
  274. // parse value
  275. object val = readObj(field, null, false);
  276. try
  277. {
  278. // if const field, then make val immutable
  279. if (field.isConst()) val = OpUtil.toImmutable(val);
  280. }
  281. catch (System.Exception ex)
  282. {
  283. throw err("Cannot make object const for " + field.qname() + ": " + ex, line, ex);
  284. }
  285. // add to map
  286. toSet.set(field, val);
  287. }
  288. void complexSet(object obj, Field field, object val, int line)
  289. {
  290. try
  291. {
  292. if (field.isConst())
  293. field.set(obj, OpUtil.toImmutable(val), false);
  294. else
  295. field.set(obj, val);
  296. }
  297. catch (System.Exception ex)
  298. {
  299. throw err("Cannot set field " + field.qname() + ": " + ex, line, ex);
  300. }
  301. }
  302. void readComplexAdd(Type t, int line, List toAdd)
  303. {
  304. object val = readObj(null, null, false);
  305. // add to list
  306. toAdd.add(val);
  307. }
  308. void complexAdd(Type t, object obj, Method addMethod, object val, int line)
  309. {
  310. try
  311. {
  312. addMethod.invoke(obj, new object[] { val });
  313. }
  314. catch (System.Exception ex)
  315. {
  316. throw err("Cannot call " + t.qname() + ".add: " + ex, line, ex);
  317. }
  318. }
  319. //////////////////////////////////////////////////////////////////////////
  320. // Collection
  321. //////////////////////////////////////////////////////////////////////////
  322. /// <summary>
  323. /// collection := list | map
  324. /// </summary>
  325. private object readCollection(Field curField, Type t)
  326. {
  327. // opening [
  328. consume(Token.LBRACKET, "Expecting '['");
  329. // if this could be a map type signature:
  330. // [qname:qname]
  331. // [qname:qname][]
  332. // [qname:qname][][] ...
  333. // or it could just be the type signature of
  334. // of a embedded simple, complex, or list
  335. Type peekType = null;
  336. if (curt == Token.ID && t == null)
  337. {
  338. // peek at the type
  339. peekType = readType();
  340. // if we have [mapType] then this is non-inferred type signature
  341. if (curt == Token.RBRACKET && peekType is MapType)
  342. {
  343. t = peekType; peekType = null;
  344. consume();
  345. while (curt == Token.LRBRACKET) { consume(); t = t.toListOf(); }
  346. if (curt == Token.QUESTION) { consume(); t = t.toNullable(); }
  347. if (curt == Token.POUND) { consume(); return t; }
  348. consume(Token.LBRACKET, "Expecting '['");
  349. }
  350. }
  351. // handle special case of [,]
  352. if (curt == Token.COMMA && peekType == null)
  353. {
  354. consume();
  355. consume(Token.RBRACKET, "Expecting ']'");
  356. return new List(toListOfType(t, curField, false));
  357. }
  358. // handle special case of [:]
  359. if (curt == Token.COLON && peekType == null)
  360. {
  361. consume();
  362. consume(Token.RBRACKET, "Expecting ']'");
  363. return new Map(toMapType(t, curField, false));
  364. }
  365. // read first list item or first map key
  366. object first = readObj(null, peekType, false);
  367. // now we can distinguish b/w list and map
  368. if (curt == Token.COLON)
  369. return readMap(toMapType(t, curField, true), first);
  370. else
  371. return readList(toListOfType(t, curField, true), first);
  372. }
  373. /// <summary>
  374. /// list := "[" obj ("," obj)* "]"
  375. /// </summary>
  376. private object readList(Type of, object first)
  377. {
  378. // setup accumulator
  379. object[] acc = new object[8];
  380. int n = 0;
  381. acc[n++] = first;
  382. // parse list items
  383. while (curt != Token.RBRACKET)
  384. {
  385. consume(Token.COMMA, "Expected ','");
  386. if (curt == Token.RBRACKET) break;
  387. if (n >= acc.Length)
  388. {
  389. object[] temp = new object[n*2];
  390. System.Array.Copy(acc, 0, temp, 0, n);
  391. acc = temp;
  392. }
  393. acc[n++] = readObj(null, null, false);
  394. }
  395. consume(Token.RBRACKET, "Expected ']'");
  396. // infer type if needed
  397. if (of == null) of = Type.common(acc, n);
  398. return new List(of, acc, n);
  399. }
  400. /// <summary>
  401. /// map := "[" mapPair ("," mapPair)* "]"
  402. /// mapPair := obj ":" + obj
  403. /// </summary>
  404. private object readMap(MapType mapType, object firstKey)
  405. {
  406. // setup accumulator
  407. Hashtable map = new Hashtable();
  408. // finish first pair
  409. consume(Token.COLON, "Expected ':'");
  410. map[firstKey] = readObj(null, null, false);
  411. // parse map pairs
  412. while (curt != Token.RBRACKET)
  413. {
  414. consume(Token.COMMA, "Expected ','");
  415. if (curt == Token.RBRACKET) break;
  416. object key = readObj(null, null, false);
  417. consume(Token.COLON, "Expected ':'");
  418. object val = readObj(null, null, false);
  419. map[key] = val;
  420. }
  421. consume(Token.RBRACKET, "Expected ']'");
  422. // infer type if necessary
  423. if (mapType == null)
  424. {
  425. int size = map.Count;
  426. object[] keys = new object[map.Count];
  427. object[] vals = new object[map.Count];
  428. IDictionaryEnumerator en = map.GetEnumerator();
  429. int i = 0;
  430. while (en.MoveNext())
  431. {
  432. keys[i] = en.Key;
  433. vals[i] = en.Value;
  434. i++;
  435. }
  436. Type k = Type.common(keys, size);
  437. Type v = Type.common(vals, size);
  438. mapType = new MapType(k, v);
  439. }
  440. return new Map((MapType)mapType, map);
  441. }
  442. /// <summary>
  443. /// Figure out the type of the list:
  444. /// 1) if t was explicit then use it
  445. /// 2) if we have field typed as a list, then use its definition
  446. /// 3) if inferred is false, then drop back to list of Obj
  447. /// 4) If inferred is true then return null and we'll infer the common type
  448. /// </summary>
  449. private Type toListOfType(Type t, Field curField, bool infer)
  450. {
  451. if (t != null) return t;
  452. if (curField != null)
  453. {
  454. Type ft = curField.type().toNonNullable();
  455. if (ft is ListType) return ((ListType)ft).m_v;
  456. }
  457. if (infer) return null;
  458. return Sys.ObjType.toNullable();
  459. }
  460. /// <summary>
  461. /// Figure out the map type:
  462. /// 1) if t was explicit then use it (check that it was a map type)
  463. /// 2) if we have field typed as a map , then use its definition
  464. /// 3) if inferred is false, then drop back to Obj:Obj
  465. /// 4) If inferred is true then return null and we'll infer the common key/val types
  466. /// </summary>
  467. private MapType toMapType(Type t, Field curField, bool infer)
  468. {
  469. if (t != null)
  470. {
  471. try { return (MapType)t; }
  472. catch (System.InvalidCastException) { throw err("Invalid map type: " + t); }
  473. }
  474. if (curField != null)
  475. {
  476. Type ft = curField.type().toNonNullable();
  477. if (ft is MapType) return (MapType)ft;
  478. }
  479. if (infer) return null;
  480. return defaultMapType;
  481. }
  482. private static readonly MapType defaultMapType = new MapType(Sys.ObjType, Sys.ObjType.toNullable());
  483. //////////////////////////////////////////////////////////////////////////
  484. // Type
  485. //////////////////////////////////////////////////////////////////////////
  486. /// <summary>
  487. /// type := listSig | mapSig1 | mapSig2 | qname
  488. /// listSig := type "[]"
  489. /// mapSig1 := type ":" type
  490. /// mapSig2 := "[" type ":" type "]"
  491. ///
  492. /// Note: the mapSig2 with brackets is handled by the
  493. /// method succinctly named readMapTypeOrCollection().
  494. /// </summary>
  495. private Type readType() { return readType(false); }
  496. private Type readType(bool lbracket)
  497. {
  498. Type t = readSimpleType();
  499. if (curt == Token.QUESTION)
  500. {
  501. consume();
  502. t = t.toNullable();
  503. }
  504. if (curt == Token.COLON)
  505. {
  506. consume();
  507. t = new MapType(t, readType());
  508. }
  509. while (curt == Token.LRBRACKET)
  510. {
  511. consume();
  512. t = t.toListOf();
  513. }
  514. if (curt == Token.QUESTION)
  515. {
  516. consume();
  517. t = t.toNullable();
  518. }
  519. return t;
  520. }
  521. /// <summary>
  522. /// qname := [podName "::"] typeName
  523. /// </summary>
  524. private Type readSimpleType()
  525. {
  526. // parse identifier
  527. int line = tokenizer.m_line;
  528. string n = consumeId("Expected type signature");
  529. // check for using imported name
  530. if (curt != Token.DOUBLE_COLON)
  531. {
  532. for (int i=0; i<numUsings; ++i)
  533. {
  534. Type t = usings[i].resolve(n);
  535. if (t != null) return t;
  536. }
  537. throw err("Unresolved type name: " + n);
  538. }
  539. // must be fully qualified
  540. consume(Token.DOUBLE_COLON, "Expected :: in type qname");
  541. string typeName = consumeId("Expected type name");
  542. // resolve pod
  543. Pod pod = Pod.find(n, false);
  544. if (pod == null) throw err("Pod not found: " + n, line);
  545. // resolve type
  546. Type type = pod.type(typeName, false);
  547. if (type == null) throw err("Type not found: " + n+ "::" + typeName, line);
  548. return type;
  549. }
  550. //////////////////////////////////////////////////////////////////////////
  551. // Error Handling
  552. //////////////////////////////////////////////////////////////////////////
  553. /// <summary>
  554. /// Create error reporting exception.
  555. /// </summary>
  556. internal static System.Exception err(string msg, int line) { return err(msg, line, null); }
  557. internal static System.Exception err(string msg, int line, System.Exception ex)
  558. {
  559. return IOErr.make(msg + " [Line " + line + "]", ex).val;
  560. }
  561. /// <summary>
  562. /// Create exception based on tokenizers current line.
  563. /// </summary>
  564. private System.Exception err(string msg)
  565. {
  566. return err(msg, tokenizer.m_line);
  567. }
  568. //////////////////////////////////////////////////////////////////////////
  569. // Tokens
  570. //////////////////////////////////////////////////////////////////////////
  571. /// <summary>
  572. /// Consume the current token as a identifier.
  573. /// </summary>
  574. private string consumeId(string expected)
  575. {
  576. verify(Token.ID, expected);
  577. string id = (string)tokenizer.m_val;
  578. consume();
  579. return id;
  580. }
  581. /// <summary>
  582. /// Consume the current token as a string literal.
  583. /// </summary>
  584. private string consumeStr(string expected)
  585. {
  586. verify(Token.STR_LITERAL, expected);
  587. string id = (string)tokenizer.m_val;
  588. consume();
  589. return id;
  590. }
  591. /// <summary>
  592. /// Check that the current token matches the
  593. /// specified type, and then consume it.
  594. /// </summary>
  595. private void consume(int type, string expected)
  596. {
  597. verify(type, expected);
  598. consume();
  599. }
  600. /// <summary>
  601. /// Check that the current token matches the specified
  602. /// type, but do not consume it.
  603. /// </summary>
  604. private void verify(int type, string expected)
  605. {
  606. if (curt != type)
  607. throw err(expected + ", not '" + Token.toString(curt) + "'");
  608. }
  609. /// <summary>
  610. /// Consume the current token.
  611. /// </summary>
  612. private void consume()
  613. {
  614. curt = tokenizer.next();
  615. }
  616. /// <summary>
  617. /// Is current token part of the next statement?
  618. /// </summary>
  619. private bool isEndOfStmt(int lastLine)
  620. {
  621. if (curt == Token.EOF) return true;
  622. if (curt == Token.SEMICOLON) return true;
  623. return lastLine < tokenizer.m_line;
  624. }
  625. /// <summary>
  626. /// Statements can be terminated with a semicolon, end of line or } end of block.
  627. /// </summary>
  628. private void endOfStmt(int lastLine)
  629. {
  630. if (curt == Token.EOF) return;
  631. if (curt == Token.SEMICOLON) { consume(); return; }
  632. if (lastLine < tokenizer.m_line) return;
  633. if (curt == Token.RBRACE) return;
  634. throw err("Expected end of statement: semicolon, newline, or end of block; not '" + Token.toString(curt) + "'");
  635. }
  636. //////////////////////////////////////////////////////////////////////////
  637. // Using
  638. //////////////////////////////////////////////////////////////////////////
  639. internal abstract class Using
  640. {
  641. internal abstract Type resolve(string name);
  642. }
  643. internal class UsingPod : Using
  644. {
  645. internal UsingPod(Pod p) { pod = p; }
  646. internal override Type resolve(string n) { return pod.type(n, false); }
  647. Pod pod;
  648. }
  649. internal class UsingType : Using
  650. {
  651. internal UsingType(Type t, string n) { type = t; name = n; }
  652. internal override Type resolve(string n) { return name == n ? type : null; }
  653. string name;
  654. Type type;
  655. }
  656. //////////////////////////////////////////////////////////////////////////
  657. // Fields
  658. //////////////////////////////////////////////////////////////////////////
  659. internal Tokenizer tokenizer; // tokenizer
  660. internal int curt; // current token type
  661. internal Map options; // decode option name/value pairs
  662. internal Using[] usings; // using imports
  663. internal int numUsings = 0; // number of using imports
  664. }
  665. }