PageRenderTime 59ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/Ruby/Libraries.Yaml/Engine/BaseConstructor.cs

http://github.com/IronLanguages/main
C# | 674 lines | 577 code | 73 blank | 24 comment | 129 complexity | 221ff1dae2c8186a02a4b636f83613c5 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. // Version: CPL 1.0
  2. //
  3. // The contents of this file are subject to the Common Public
  4. // License Version 1.0 (the "License"); you may not use this file
  5. // except in compliance with the License. You may obtain a copy of
  6. // the License at http://www.eclipse.org/legal/cpl-v10.html
  7. //
  8. // Software distributed under the License is distributed on an "AS
  9. // IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10. // implied. See the License for the specific language governing
  11. // rights and limitations under the License.
  12. //
  13. // Copyright (C) 2007 Ola Bini <ola@ologix.com>
  14. // Copyright (c) Microsoft Corporation.
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Globalization;
  19. using System.Linq;
  20. using System.Text.RegularExpressions;
  21. using Microsoft.Scripting;
  22. using Microsoft.Scripting.Runtime;
  23. using IronRuby.Builtins;
  24. using IronRuby.Runtime;
  25. using Microsoft.Scripting.Utils;
  26. using System.Reflection;
  27. using System.Text;
  28. namespace IronRuby.StandardLibrary.Yaml {
  29. public delegate void RecursiveFixer(Node node, object real);
  30. public delegate object YamlConstructor(BaseConstructor self, Node node);
  31. public delegate object YamlMultiConstructor(BaseConstructor self, string pref, Node node);
  32. public class BaseConstructor : IEnumerable<object> {
  33. private readonly static Dictionary<string, YamlConstructor> _yamlConstructors = new Dictionary<string, YamlConstructor>();
  34. private readonly static Dictionary<string, YamlMultiConstructor> _yamlMultiConstructors = new Dictionary<string, YamlMultiConstructor>();
  35. private readonly static Dictionary<string, Regex> _yamlMultiRegexps = new Dictionary<string, Regex>();
  36. private readonly Dictionary<Node, List<RecursiveFixer>>/*!*/ _recursiveObjects = new Dictionary<Node, List<RecursiveFixer>>();
  37. private readonly NodeProvider/*!*/ _nodeProvider;
  38. private readonly RubyGlobalScope/*!*/ _globalScope;
  39. public BaseConstructor(NodeProvider/*!*/ nodeProvider, RubyGlobalScope/*!*/ globalScope) {
  40. Assert.NotNull(nodeProvider, globalScope);
  41. _nodeProvider = nodeProvider;
  42. _globalScope = globalScope;
  43. }
  44. public RubyGlobalScope/*!*/ GlobalScope {
  45. get { return _globalScope; }
  46. }
  47. public Encoding/*!*/ Encoding {
  48. get { return _nodeProvider.Encoding; }
  49. }
  50. public virtual YamlConstructor GetYamlConstructor(string key) {
  51. YamlConstructor result;
  52. _yamlConstructors.TryGetValue(key, out result);
  53. return result;
  54. }
  55. public virtual YamlMultiConstructor GetYamlMultiConstructor(string key) {
  56. YamlMultiConstructor result;
  57. _yamlMultiConstructors.TryGetValue(key, out result);
  58. return result;
  59. }
  60. public virtual Regex GetYamlMultiRegexp(string key) {
  61. Regex result;
  62. _yamlMultiRegexps.TryGetValue(key, out result);
  63. return result;
  64. }
  65. public virtual ICollection<string> GetYamlMultiRegexps() {
  66. return _yamlMultiRegexps.Keys;
  67. }
  68. public static void AddConstructor(string tag, YamlConstructor ctor) {
  69. _yamlConstructors.Add(tag,ctor);
  70. }
  71. public static void AddMultiConstructor(string tagPrefix, YamlMultiConstructor ctor) {
  72. _yamlMultiConstructors.Add(tagPrefix,ctor);
  73. _yamlMultiRegexps.Add(tagPrefix, YamlUtils.CompiledRegex("^" + tagPrefix));
  74. }
  75. public bool CheckData() {
  76. return _nodeProvider.CheckNode();
  77. }
  78. public object GetData() {
  79. if (_nodeProvider.CheckNode()) {
  80. Node node = _nodeProvider.GetNode();
  81. if(null != node) {
  82. return ConstructDocument(node);
  83. }
  84. }
  85. return null;
  86. }
  87. public object ConstructDocument(Node node) {
  88. object data = ConstructObject(node);
  89. _recursiveObjects.Clear();
  90. return data;
  91. }
  92. private YamlConstructor yamlMultiAdapter(YamlMultiConstructor ctor, string prefix) {
  93. return delegate(BaseConstructor self, Node node) { return ctor(self, prefix, node); };
  94. }
  95. public static Node GetNullNode() {
  96. return new ScalarNode(Tags.Null, null, ScalarQuotingStyle.None);
  97. }
  98. public object ConstructObject(Node node) {
  99. if (node == null) {
  100. node = GetNullNode();
  101. }
  102. if(_recursiveObjects.ContainsKey(node)) {
  103. return new LinkNode(node);
  104. }
  105. _recursiveObjects.Add(node, new List<RecursiveFixer>());
  106. YamlConstructor ctor = GetYamlConstructor(node.Tag ?? node.DefaultTag);
  107. if (ctor == null) {
  108. bool through = true;
  109. foreach (string tagPrefix in GetYamlMultiRegexps()) {
  110. Regex reg = GetYamlMultiRegexp(tagPrefix);
  111. if (reg.IsMatch(node.Tag)) {
  112. string tagSuffix = node.Tag.Substring(tagPrefix.Length);
  113. ctor = yamlMultiAdapter(GetYamlMultiConstructor(tagPrefix), tagSuffix);
  114. through = false;
  115. break;
  116. }
  117. }
  118. if (through) {
  119. YamlMultiConstructor xctor = GetYamlMultiConstructor("");
  120. if(null != xctor) {
  121. ctor = yamlMultiAdapter(xctor,node.Tag);
  122. } else {
  123. ctor = GetYamlConstructor("");
  124. if (ctor == null) {
  125. ctor = (s, n) => s.ConstructPrimitive(n);
  126. }
  127. }
  128. }
  129. }
  130. object data = ctor(this, node);
  131. DoRecursionFix(node,data);
  132. return data;
  133. }
  134. public void DoRecursionFix(Node node, object obj) {
  135. List<RecursiveFixer> ll;
  136. if (_recursiveObjects.TryGetValue(node, out ll)) {
  137. _recursiveObjects.Remove(node);
  138. foreach (RecursiveFixer fixer in ll) {
  139. fixer(node, obj);
  140. }
  141. }
  142. }
  143. public object ConstructPrimitive(Node node) {
  144. if (node is ScalarNode) {
  145. return ConstructScalar(node);
  146. } else if (node is SequenceNode) {
  147. return ConstructSequence(node);
  148. } else if (node is MappingNode) {
  149. return ConstructMapping(node);
  150. } else {
  151. throw new ConstructorException("unexpected node type: " + node);
  152. }
  153. }
  154. /// <summary>
  155. /// Returns the value of the scalar.
  156. /// </summary>
  157. public string ConstructScalar(Node/*!*/ node) {
  158. ScalarNode scalar = node as ScalarNode;
  159. if (scalar == null) {
  160. MappingNode mapNode = node as MappingNode;
  161. if (mapNode != null) {
  162. foreach (KeyValuePair<Node, Node> entry in mapNode.Nodes) {
  163. if (entry.Key.Tag == "tag:yaml.org,2002:value") {
  164. return ConstructScalar(entry.Value);
  165. }
  166. }
  167. }
  168. throw new ConstructorException("expected a scalar or mapping node, but found: " + node);
  169. }
  170. return scalar.Value;
  171. }
  172. public object/*!*/ ConstructPrivateType(Node node) {
  173. object val = null;
  174. ScalarNode scalar = node as ScalarNode;
  175. if (scalar != null) {
  176. val = scalar.Value;
  177. } else if (node is MappingNode) {
  178. val = ConstructMapping(node);
  179. } else if (node is SequenceNode) {
  180. val = ConstructSequence(node);
  181. } else {
  182. throw new ConstructorException("unexpected node type: " + node);
  183. }
  184. return new PrivateType(node.Tag,val);
  185. }
  186. //TODO: remove Ruby-specific stuff from this layer
  187. public RubyArray/*!*/ ConstructSequence(Node/*!*/ sequenceNode) {
  188. SequenceNode seq = sequenceNode as SequenceNode;
  189. if(seq == null) {
  190. throw new ConstructorException("expected a sequence node, but found: " + sequenceNode);
  191. }
  192. IList<Node> @internal = seq.Nodes;
  193. RubyArray val = new RubyArray(@internal.Count);
  194. foreach (Node node in @internal) {
  195. object obj = ConstructObject(node);
  196. LinkNode linkNode = obj as LinkNode;
  197. if (linkNode != null) {
  198. int ix = val.Count;
  199. AddFixer(linkNode.Linked, delegate (Node n, object real) {
  200. val[ix] = real;
  201. });
  202. }
  203. val.Add(obj);
  204. }
  205. return val;
  206. }
  207. //TODO: remove Ruby-specific stuff from this layer
  208. public Hash ConstructMapping(Node mappingNode) {
  209. MappingNode map = mappingNode as MappingNode;
  210. if (map == null) {
  211. throw new ConstructorException("expected a mapping node, but found: " + mappingNode);
  212. }
  213. Hash mapping = new Hash(_globalScope.Context);
  214. LinkedList<Hash> merge = null;
  215. foreach (KeyValuePair<Node, Node> entry in map.Nodes) {
  216. Node key_v = entry.Key;
  217. Node value_v = entry.Value;
  218. if (key_v.Tag == "tag:yaml.org,2002:merge") {
  219. if (merge != null) {
  220. throw new ConstructorException("while constructing a mapping: found duplicate merge key");
  221. }
  222. SequenceNode sequence;
  223. merge = new LinkedList<Hash>();
  224. if (value_v is MappingNode) {
  225. merge.AddLast(ConstructMapping(value_v));
  226. } else if ((sequence = value_v as SequenceNode) != null) {
  227. foreach (Node subNode in sequence.Nodes) {
  228. if (!(subNode is MappingNode)) {
  229. throw new ConstructorException("while constructing a mapping: expected a mapping for merging, but found: " + subNode);
  230. }
  231. merge.AddFirst(ConstructMapping(subNode));
  232. }
  233. } else {
  234. throw new ConstructorException("while constructing a mapping: expected a mapping or list of mappings for merging, but found: " + value_v);
  235. }
  236. } else if (key_v.Tag == "tag:yaml.org,2002:value") {
  237. if(mapping.ContainsKey("=")) {
  238. throw new ConstructorException("while construction a mapping: found duplicate value key");
  239. }
  240. mapping.Add("=", ConstructObject(value_v));
  241. } else {
  242. object kk = ConstructObject(key_v);
  243. object vv = ConstructObject(value_v);
  244. LinkNode linkNode = vv as LinkNode;
  245. if (linkNode != null) {
  246. AddFixer(linkNode.Linked, delegate (Node node, object real) {
  247. IDictionaryOps.SetElement(_globalScope.Context, mapping, kk, real);
  248. });
  249. }
  250. IDictionaryOps.SetElement(_globalScope.Context, mapping, kk, vv);
  251. }
  252. }
  253. if (null != merge) {
  254. merge.AddLast(mapping);
  255. mapping = new Hash(_globalScope.Context);
  256. foreach (Hash m in merge) {
  257. foreach (KeyValuePair<object, object> e in m) {
  258. IDictionaryOps.SetElement(_globalScope.Context, mapping, e.Key, e.Value);
  259. }
  260. }
  261. }
  262. return mapping;
  263. }
  264. public void AddFixer(Node node, RecursiveFixer fixer) {
  265. List<RecursiveFixer> ll;
  266. if (!_recursiveObjects.TryGetValue(node, out ll)) {
  267. _recursiveObjects.Add(node, ll = new List<RecursiveFixer>());
  268. }
  269. ll.Add(fixer);
  270. }
  271. public object ConstructPairs(Node mappingNode) {
  272. MappingNode map = mappingNode as MappingNode;
  273. if (map == null) {
  274. throw new ConstructorException("expected a mapping node, but found: " + mappingNode);
  275. }
  276. List<object[]> result = new List<object[]>();
  277. foreach (KeyValuePair<Node, Node> entry in map.Nodes) {
  278. result.Add(new object[] { ConstructObject(entry.Key), ConstructObject(entry.Value) });
  279. }
  280. return result;
  281. }
  282. #region IEnumerable<object> Members
  283. public IEnumerator<object> GetEnumerator() {
  284. while (CheckData()) {
  285. yield return GetData();
  286. }
  287. }
  288. IEnumerator IEnumerable.GetEnumerator() {
  289. return GetEnumerator();
  290. }
  291. #endregion
  292. #region Statics
  293. static BaseConstructor() {
  294. AddConstructor(Tags.Null, ConstructYamlNull);
  295. AddConstructor(Tags.Bool, ConstructYamlBool);
  296. AddConstructor(Tags.True, ConstructYamlBool);
  297. AddConstructor(Tags.False, ConstructYamlBool);
  298. AddConstructor("tag:yaml.org,2002:omap", ConstructYamlOmap);
  299. AddConstructor("tag:yaml.org,2002:pairs", ConstructYamlPairs);
  300. AddConstructor("tag:yaml.org,2002:set", ConstructYamlSet);
  301. AddConstructor(Tags.Int, ConstructYamlInt);
  302. AddConstructor(Tags.Float, ConstructYamlFloat);
  303. AddConstructor(Tags.Timestamp, ConstructYamlTimestamp);
  304. AddConstructor(Tags.TimestampYmd, ConstructYamlTimestampYmd);
  305. AddConstructor(Tags.Str, ConstructYamlStr);
  306. AddConstructor(Tags.Binary, ConstructYamlBinary);
  307. AddConstructor(Tags.Seq, ConstructYamlSeq);
  308. AddConstructor(Tags.Map, ConstructYamlMap);
  309. AddConstructor("", (self, node) => self.ConstructPrivateType(node));
  310. AddMultiConstructor(Tags.Seq + ":", ConstructSpecializedSequence);
  311. AddMultiConstructor(Tags.Map + ":", ConstructSpecializedMap);
  312. AddMultiConstructor("!cli/object:", ConstructCliObject);
  313. AddMultiConstructor("tag:cli.yaml.org,2002:object:", ConstructCliObject);
  314. }
  315. public static object ConstructYamlNull(BaseConstructor/*!*/ ctor, Node/*!*/ node) {
  316. return null;
  317. }
  318. public static object ConstructYamlBool(BaseConstructor/*!*/ ctor, Node/*!*/ node) {
  319. bool result;
  320. if (TryConstructYamlBool(ctor, node, out result)) {
  321. return ScriptingRuntimeHelpers.BooleanToObject(result);
  322. }
  323. return null;
  324. }
  325. public static bool TryConstructYamlBool(BaseConstructor/*!*/ ctor, Node/*!*/ node, out bool result) {
  326. var b = ResolverScanner.ToBool(ctor.ConstructScalar(node));
  327. if (b != null) {
  328. result = b.Value;
  329. return true;
  330. } else {
  331. result = false;
  332. return false;
  333. }
  334. }
  335. public static object ConstructYamlOmap(BaseConstructor/*!*/ ctor, Node/*!*/ node) {
  336. return ctor.ConstructPairs(node);
  337. }
  338. public static object ConstructYamlPairs(BaseConstructor/*!*/ ctor, Node/*!*/ node) {
  339. return ConstructYamlOmap(ctor, node);
  340. }
  341. public static ICollection ConstructYamlSet(BaseConstructor/*!*/ ctor, Node/*!*/ node) {
  342. return ctor.ConstructMapping(node).Keys;
  343. }
  344. public static string ConstructYamlStr(BaseConstructor/*!*/ ctor, Node/*!*/ node) {
  345. return ctor.ConstructScalar(node);
  346. }
  347. public static RubyArray ConstructYamlSeq(BaseConstructor/*!*/ ctor, Node/*!*/ node) {
  348. return ctor.ConstructSequence(node);
  349. }
  350. public static Hash ConstructYamlMap(BaseConstructor/*!*/ ctor, Node/*!*/ node) {
  351. return ctor.ConstructMapping(node);
  352. }
  353. public static object constructUndefined(BaseConstructor/*!*/ ctor, Node/*!*/ node) {
  354. throw new ConstructorException("could not determine a constructor for the tag: " + node.Tag);
  355. }
  356. private static Regex _timestampRegexp;
  357. private static Regex TimestampRegex {
  358. get {
  359. return _timestampRegexp ?? (_timestampRegexp = new Regex(@"
  360. ^[ \t]*
  361. ( # Year
  362. -?
  363. [0-9][0-9][0-9][0-9]
  364. )
  365. -
  366. ([0-9][0-9]?) # Month
  367. -
  368. ([0-9][0-9]?) # Day
  369. (?:
  370. (?:
  371. [Tt]
  372. |
  373. [ \t]+
  374. )
  375. ([0-9][0-9]?) # Hour
  376. :
  377. ([0-9][0-9]) # Minute
  378. :
  379. ([0-9][0-9]) # Seconds
  380. (?:
  381. .
  382. ([0-9]*) # Fractional seconds
  383. )?
  384. (?:
  385. [ \t]*
  386. ( # utc
  387. Z
  388. |
  389. ([-+][0-9][0-9]?) # timezoneh
  390. (?: # timezonem
  391. :([0-9][0-9])?
  392. )?
  393. )?
  394. )
  395. )?
  396. [ \t]*$",
  397. RegexOptions.IgnorePatternWhitespace | RegexOptions.CultureInvariant));
  398. }
  399. }
  400. private static Regex _ymdRegex;
  401. internal static Regex YmdRegex {
  402. get {
  403. return _ymdRegex ?? (_ymdRegex =
  404. new Regex("^(-?[0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$", RegexOptions.CultureInvariant)
  405. );
  406. }
  407. }
  408. public static object ConstructYamlTimestampYmd(BaseConstructor ctor, Node node) {
  409. ScalarNode scalar = node as ScalarNode;
  410. if (scalar == null) {
  411. throw new ConstructorException("can only contruct timestamp from scalar node");
  412. }
  413. Match match = YmdRegex.Match(scalar.Value);
  414. if (match.Success) {
  415. int year_ymd = int.Parse(match.Groups[1].Value);
  416. int month_ymd = int.Parse(match.Groups[2].Value);
  417. int day_ymd = int.Parse(match.Groups[3].Value);
  418. // TODO: local/utc/...
  419. return new RubyTime(new DateTime(year_ymd, month_ymd, day_ymd, 0, 0, 0, 0, DateTimeKind.Local));
  420. }
  421. throw new ConstructorException("Invalid tag:yaml.org,2002:timestamp#ymd value.");
  422. }
  423. public static object ConstructYamlTimestamp(BaseConstructor ctor, Node node) {
  424. ScalarNode scalar = node as ScalarNode;
  425. if (scalar == null) {
  426. throw new ConstructorException("can only contruct timestamp from scalar node");
  427. }
  428. Match match = TimestampRegex.Match(scalar.Value);
  429. if (!match.Success) {
  430. return ctor.ConstructPrivateType(node);
  431. }
  432. string year_s = match.Groups[1].Value;
  433. string month_s = match.Groups[2].Value;
  434. string day_s = match.Groups[3].Value;
  435. string hour_s = match.Groups[4].Value;
  436. string min_s = match.Groups[5].Value;
  437. string sec_s = match.Groups[6].Value;
  438. string fract_s = match.Groups[7].Value;
  439. string utc = match.Groups[8].Value;
  440. string timezoneh_s = match.Groups[9].Value;
  441. string timezonem_s = match.Groups[10].Value;
  442. bool isUtc = utc == "Z" || utc == "z";
  443. DateTime dt = new DateTime(
  444. year_s != "" ? Int32.Parse(year_s, CultureInfo.InvariantCulture) : 0,
  445. month_s != "" ? Int32.Parse(month_s, CultureInfo.InvariantCulture) : 1,
  446. day_s != "" ? Int32.Parse(day_s, CultureInfo.InvariantCulture) : 1,
  447. hour_s != "" ? Int32.Parse(hour_s, CultureInfo.InvariantCulture) : 0,
  448. min_s != "" ? Int32.Parse(min_s, CultureInfo.InvariantCulture) : 0,
  449. sec_s != "" ? Int32.Parse(sec_s, CultureInfo.InvariantCulture) : 0,
  450. DateTimeKind.Utc
  451. );
  452. if (!String.IsNullOrEmpty(fract_s)) {
  453. long fract = Int32.Parse(fract_s, CultureInfo.InvariantCulture);
  454. if (fract > 0) {
  455. while (fract < 1000000) {
  456. fract *= 10;
  457. }
  458. dt = dt.AddTicks(fract);
  459. }
  460. }
  461. if (!isUtc) {
  462. if (timezoneh_s != "" || timezonem_s != "") {
  463. int zone = 0;
  464. int sign = +1;
  465. if (timezoneh_s != "") {
  466. if (timezoneh_s.StartsWith("-", StringComparison.Ordinal)) {
  467. sign = -1;
  468. }
  469. zone += Int32.Parse(timezoneh_s.Substring(1), CultureInfo.InvariantCulture) * 3600000;
  470. }
  471. if (timezonem_s != "") {
  472. zone += Int32.Parse(timezonem_s, CultureInfo.InvariantCulture) * 60000;
  473. }
  474. dt = dt.AddMilliseconds(-sign * zone);
  475. }
  476. dt = RubyTime.ToLocalTime(dt);
  477. }
  478. return new RubyTime(dt);
  479. }
  480. public static object ConstructYamlInt(BaseConstructor ctor, Node node) {
  481. string value = ctor.ConstructScalar(node).Replace("_", "").Replace(",", "");
  482. int sign = +1;
  483. char first = value[0];
  484. if (first == '-') {
  485. sign = -1;
  486. value = value.Substring(1);
  487. } else if (first == '+') {
  488. value = value.Substring(1);
  489. }
  490. int @base = 10;
  491. if (value == "0") {
  492. return 0;
  493. } else if (value.StartsWith("0b", StringComparison.Ordinal)) {
  494. value = value.Substring(2);
  495. @base = 2;
  496. } else if (value.StartsWith("0x", StringComparison.Ordinal)) {
  497. value = value.Substring(2);
  498. @base = 16;
  499. } else if (value.StartsWith("0", StringComparison.Ordinal)) {
  500. value = value.Substring(1);
  501. @base = 8;
  502. } else if (value.IndexOf(':') != -1) {
  503. string[] digits = value.Split(':');
  504. int bes = 1;
  505. int val = 0;
  506. for (int i = 0, j = digits.Length; i < j; i++) {
  507. val += (int.Parse(digits[(j - i) - 1]) * bes);
  508. bes *= 60;
  509. }
  510. return sign * val;
  511. }
  512. try {
  513. // LiteralParser.ParseInteger delegate handles parsing & conversion to BigInteger (if needed)
  514. return LiteralParser.ParseInteger(sign, value, @base);
  515. } catch (Exception e) {
  516. throw new ConstructorException(string.Format("Could not parse integer value: '{0}' (sign {1}, base {2})", value, sign, @base), e);
  517. }
  518. }
  519. public static object ConstructYamlFloat(BaseConstructor ctor, Node node) {
  520. string value = ctor.ConstructScalar(node).Replace("_", "").Replace(",", "");
  521. int sign = +1;
  522. char first = value[0];
  523. if (first == '-') {
  524. sign = -1;
  525. value = value.Substring(1);
  526. } else if (first == '+') {
  527. value = value.Substring(1);
  528. }
  529. string valLower = value.ToLowerInvariant();
  530. if (valLower == ".inf") {
  531. return sign == -1 ? Double.NegativeInfinity : Double.PositiveInfinity;
  532. } else if (valLower == ".nan") {
  533. return double.NaN;
  534. } else if (value.IndexOf(':') != -1) {
  535. string[] digits = value.Split(':');
  536. int bes = 1;
  537. double val = 0.0;
  538. for (int i = 0, j = digits.Length; i < j; i++) {
  539. val += (double.Parse(digits[(j - i) - 1], CultureInfo.InvariantCulture) * bes);
  540. bes *= 60;
  541. }
  542. return sign * val;
  543. } else {
  544. return sign * double.Parse(value, CultureInfo.InvariantCulture);
  545. }
  546. }
  547. public static byte[] ConstructYamlBinary(BaseConstructor ctor, Node node) {
  548. string val = ctor.ConstructScalar(node).Replace("\r", "").Replace("\n", "");
  549. return Convert.FromBase64String(val);
  550. }
  551. public static object ConstructSpecializedSequence(BaseConstructor ctor, string pref, Node node) {
  552. RubyArray result = null;
  553. try {
  554. result = (RubyArray)Type.GetType(pref).GetConstructor(ReflectionUtils.EmptyTypes).Invoke(null);
  555. } catch (Exception e) {
  556. throw new ConstructorException("Can't construct a sequence from class: " + pref, e);
  557. }
  558. foreach (object x in ctor.ConstructSequence(node)) {
  559. result.Add(x);
  560. }
  561. return result;
  562. }
  563. public static object ConstructSpecializedMap(BaseConstructor ctor, string pref, Node node) {
  564. Hash result = null;
  565. try {
  566. result = (Hash)Type.GetType(pref).GetConstructor(ReflectionUtils.EmptyTypes).Invoke(null);
  567. } catch (Exception e) {
  568. throw new ConstructorException("Can't construct a mapping from class: " + pref, e);
  569. }
  570. foreach (KeyValuePair<object, object> e in ctor.ConstructMapping(node)) {
  571. result.Add(e.Key, e.Value);
  572. }
  573. return result;
  574. }
  575. public static object ConstructCliObject(BaseConstructor ctor, string pref, Node node) {
  576. // TODO: should this use serialization or some more standard CLR mechanism?
  577. // (it is very ad-hoc)
  578. // TODO: use DLR APIs instead of reflection
  579. try {
  580. Type type = Type.GetType(pref);
  581. object result = type.GetConstructor(ReflectionUtils.EmptyTypes).Invoke(null);
  582. foreach (KeyValuePair<object, object> e in ctor.ConstructMapping(node)) {
  583. string name = e.Key.ToString();
  584. name = "" + name[0].ToString().ToUpperInvariant() + name.Substring(1);
  585. PropertyInfo prop = type.GetInheritedProperties(name).First();
  586. prop.SetValue(result, Convert.ChangeType(e.Value, prop.PropertyType, CultureInfo.InvariantCulture), null);
  587. }
  588. return result;
  589. } catch (Exception e) {
  590. throw new ConstructorException("Can't construct a CLI object from class: " + pref, e);
  591. }
  592. }
  593. #endregion
  594. }
  595. }