PageRenderTime 50ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/Languages/Ruby/Libraries/ParseTree/IronRubyParseTreeOps.cs

http://github.com/IronLanguages/main
C# | 1517 lines | 1072 code | 309 blank | 136 comment | 248 complexity | 33597a9eebc857616345ae889729df84 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.Runtime.InteropServices;
  19. using IronRuby.Builtins;
  20. using IronRuby.Compiler;
  21. using IronRuby.Compiler.Ast;
  22. using IronRuby.Runtime;
  23. using IronRuby.Runtime.Calls;
  24. using Microsoft.Scripting;
  25. using Microsoft.Scripting.Runtime;
  26. using Microsoft.Scripting.Utils;
  27. namespace IronRuby.StandardLibrary.ParseTree {
  28. [RubyModule("IronRuby", Extends = typeof(Ruby))]
  29. public static class IronRubyOps {
  30. [RubyModule("ParseTree")]
  31. public static class ParseTreeOps {
  32. [RubyMethod("parse_tree_for_meth")]
  33. public static RubyArray/*!*/ CreateParseTreeForMethod(object self,
  34. [NotNull]RubyModule/*!*/ module, [DefaultProtocol, NotNull]string/*!*/ methodName, bool isClassMethod) {
  35. // TODO:
  36. // bool includeNewLines = IncludeNewLines(module.Context, self);
  37. if (isClassMethod) {
  38. module = module.ImmediateClass;
  39. }
  40. var member = module.GetMethod(methodName);
  41. // TODO: aliases, module_functions, define_methods, method witch changed visibility:
  42. var method = member as RubyMethodInfo;
  43. if (method == null) {
  44. return RubyArray.Create(null);
  45. }
  46. var visitor = new AstVisitor(module.Context, GetNodeNames(module.Context, self), false);
  47. visitor.Walk(method.GetSyntaxTree());
  48. return visitor.Result;
  49. }
  50. [RubyMethod("parse_tree_for_str")]
  51. public static RubyArray/*!*/ CreateParseTreeForString(RubyScope/*!*/ scope, object self,
  52. [NotNull]MutableString/*!*/ code, [Optional, NotNull]MutableString/*!*/ file, int line) {
  53. SourceUnit source = scope.RubyContext.CreateSnippet(
  54. code.ConvertToString(),
  55. file != null ? file.ConvertToString() : null,
  56. SourceCodeKind.Statements
  57. );
  58. var options = RubyUtils.CreateCompilerOptionsForEval(scope, line);
  59. SourceUnitTree ast = new Parser().Parse(source, options, scope.RubyContext.RuntimeErrorSink);
  60. // TODO:
  61. // bool includeNewLines = IncludeNewLines(scope.RubyContext, self);
  62. var visitor = new AstVisitor(scope.RubyContext, GetNodeNames(scope.RubyContext, self), false);
  63. visitor.Walk(ast);
  64. return visitor.Result;
  65. }
  66. #if TODO
  67. private static bool IncludeNewLines(RubyContext/*!*/ context, object self) {
  68. object value;
  69. if (context.TryGetInstanceVariable(self, "@include_newlines", out value)) {
  70. return Protocols.IsTrue(value);
  71. }
  72. return false;
  73. }
  74. #endif
  75. private static RubyArray/*!*/ GetNodeNames(RubyContext/*!*/ context, object self) {
  76. object value;
  77. context.GetClassOf(self).TryGetConstant(null, "NODE_NAMES", out value);
  78. return value as RubyArray ?? new RubyArray();
  79. }
  80. private enum NodeKind {
  81. // 00
  82. Method, fbody, cfunc, scope, block,
  83. @if, @case, when, opt_n, @while,
  84. // 10
  85. until, iter, @for, @break, next,
  86. redo, retry, begin, rescue, resbody,
  87. // 20
  88. ensure, and, or, not, masgn,
  89. lasgn, dasgn, dasgn_curr, gasgn, iasgn,
  90. // 30
  91. cdecl, cvasgn, cvdecl, op_asgn1, op_asgn2,
  92. op_asgn_and, op_asgn_or, call, fcall, vcall,
  93. // 40
  94. super, zsuper, array, zarray, hash,
  95. @return, yield, lvar, dvar, gvar,
  96. // 50
  97. ivar, @const, cvar, nth_ref, back_ref,
  98. match, match2, match3, lit, str,
  99. // 60
  100. dstr, xstr, dxstr, evstr, dregx,
  101. dregx_once, args, argscat, argspush, splat,
  102. // 70
  103. to_ary, svalue, block_arg, block_pass, defn,
  104. defs, alias, valias, undef, @class,
  105. // 80
  106. module, sclass, colon2, colon3, cref,
  107. dot2, dot3, flip2, flip3, attrset,
  108. // 90
  109. self, nil, @true, @false, defined,
  110. // 95
  111. newline, postexe, alloca, dmethod, bmethod,
  112. // 100
  113. memo, ifunc, dsym, attrasgn,
  114. last
  115. }
  116. private sealed class Rhs {
  117. public object Value { get; set; }
  118. public bool InBlockParameters { get; set; }
  119. public bool InCompoundLhs { get; set; }
  120. public bool InTopCompoundLhs { get; set; }
  121. public bool IsRhsArg { get; set; }
  122. }
  123. private sealed class AstVisitor : Walker {
  124. private static readonly Rhs BlockRhs = new Rhs { InBlockParameters = true };
  125. private static readonly object Skip = new object();
  126. private object _result;
  127. private RubyEncoding _encoding;
  128. // null -> no rhs
  129. private Rhs _rhs;
  130. private readonly RubyContext/*!*/ _context;
  131. private readonly RubyArray/*!*/ _nodeNames;
  132. private bool _isMethodAlias;
  133. public AstVisitor(RubyContext/*!*/ context, RubyArray/*!*/ nodeNames, bool isMethodAlias) {
  134. Assert.NotNull(nodeNames);
  135. _nodeNames = nodeNames;
  136. _isMethodAlias = isMethodAlias;
  137. _context = context;
  138. }
  139. #region Helpers
  140. private RubySymbol/*!*/ CreateSymbol(string/*!*/ identifier) {
  141. return _context.CreateSymbol(identifier, _encoding);
  142. }
  143. private object GetNodeName(NodeKind nodeKind) {
  144. int index = (int)nodeKind;
  145. return (index < _nodeNames.Count) ? _nodeNames[index] : null;
  146. }
  147. private RubyArray/*!*/ MakeNode(NodeKind nodeKind, int valueCount) {
  148. var node = new RubyArray(1 + valueCount);
  149. node.Add(GetNodeName(nodeKind));
  150. return node;
  151. }
  152. private RubyArray/*!*/ MakeNode(NodeKind nodeKind) {
  153. var node = MakeNode(nodeKind, 0);
  154. return node;
  155. }
  156. private RubyArray/*!*/ MakeNode(NodeKind nodeKind, object value1) {
  157. var node = MakeNode(nodeKind, 1);
  158. node.Add(value1);
  159. return node;
  160. }
  161. private RubyArray/*!*/ MakeNode(NodeKind nodeKind, object value1, object value2) {
  162. var node = MakeNode(nodeKind, 2);
  163. node.Add(value1);
  164. node.Add(value2);
  165. return node;
  166. }
  167. private RubyArray/*!*/ MakeNode(NodeKind nodeKind, object value1, object value2, object value3) {
  168. var node = MakeNode(nodeKind, 3);
  169. node.Add(value1);
  170. node.Add(value2);
  171. node.Add(value3);
  172. return node;
  173. }
  174. public RubyArray/*!*/ Result {
  175. get {
  176. return (RubyArray)_result;
  177. }
  178. }
  179. private bool TryGetRhsValue(out object value) {
  180. if (_rhs != null && !_rhs.InBlockParameters && !_rhs.InCompoundLhs) {
  181. value = _rhs.Value;
  182. return true;
  183. } else {
  184. value = null;
  185. return false;
  186. }
  187. }
  188. private RubyArray/*!*/ AddRange<T>(RubyArray/*!*/ list, IEnumerable<T> nodes) where T : Node {
  189. if (nodes != null) {
  190. foreach (T node in nodes) {
  191. Walk(node);
  192. if (_result != Skip) {
  193. list.Add(_result);
  194. }
  195. }
  196. }
  197. return list;
  198. }
  199. private void UsingRhs(Rhs rhs, Action/*!*/ region) {
  200. var oldRhs = _rhs;
  201. _rhs = rhs;
  202. region();
  203. _rhs = oldRhs;
  204. }
  205. #endregion
  206. #region SourceUnitTree
  207. public override bool Enter(SourceUnitTree/*!*/ node) {
  208. _encoding = node.Encoding;
  209. if (node.Statements == null || node.Statements.Count == 0) {
  210. _result = new RubyArray();
  211. } else if (node.Statements.Count == 1) {
  212. Walk(node.Statements.First);
  213. _result = RubyArray.Create(_result);
  214. } else {
  215. _result = RubyArray.Create(AddRange(MakeNode(NodeKind.block, node.Statements.Count), node.Statements));
  216. }
  217. return false;
  218. }
  219. #endregion
  220. #region Literals
  221. public override bool Enter(Literal/*!*/ node) {
  222. if (node.Value == null) {
  223. _result = MakeNode(NodeKind.nil);
  224. } else if (node.Value is bool) {
  225. _result = MakeNode((bool)node.Value ? NodeKind.@true : NodeKind.@false);
  226. } else {
  227. _result = MakeNode(NodeKind.lit, node.Value);
  228. }
  229. return false;
  230. }
  231. private bool Enter(RangeExpression/*!*/ node, bool isCondition) {
  232. Literal litBegin = node.Begin as Literal;
  233. Literal litEnd = node.End as Literal;
  234. if (!isCondition && litBegin != null && litEnd != null && litBegin.Value is int && litBegin.Value is int) {
  235. _result = MakeNode(NodeKind.lit, new Range((int)litBegin.Value, (int)litEnd.Value, node.IsExclusive));
  236. } else {
  237. var range = MakeNode(isCondition ?
  238. (node.IsExclusive ? NodeKind.flip3 : NodeKind.flip2) :
  239. (node.IsExclusive ? NodeKind.dot3 : NodeKind.dot2), 2
  240. );
  241. Walk(node.Begin);
  242. range.Add(_result);
  243. Walk(node.End);
  244. range.Add(_result);
  245. _result = range;
  246. }
  247. return false;
  248. }
  249. public override bool Enter(RangeExpression/*!*/ node) {
  250. return Enter(node, false);
  251. }
  252. public override bool Enter(RangeCondition/*!*/ node) {
  253. return Enter(node.Range, true);
  254. }
  255. public override bool Enter(StringLiteral/*!*/ node) {
  256. _result = MakeNode(NodeKind.str, node.GetMutableString());
  257. return false;
  258. }
  259. public override bool Enter(SymbolLiteral/*!*/ node) {
  260. _result = MakeNode(NodeKind.lit, _context.CreateSymbol(node.GetMutableString()));
  261. return false;
  262. }
  263. public override bool Enter(FileLiteral/*!*/ node) {
  264. // TODO:
  265. _result = MakeNode(NodeKind.lit, CreateSymbol("__FILE__"));
  266. return false;
  267. }
  268. public override bool Enter(StringConstructor/*!*/ node) {
  269. StringLiteral lit;
  270. if (node.Parts.Count == 1 && (lit = node.Parts[0] as StringLiteral) != null) {
  271. NodeKind kind;
  272. object value;
  273. switch (node.Kind) {
  274. case StringKind.Symbol: kind = NodeKind.lit; value = _context.CreateSymbol(lit.GetMutableString()); break;
  275. case StringKind.Command: kind = NodeKind.xstr; value = lit.GetMutableString(); break;
  276. case StringKind.Mutable: kind = NodeKind.str; value = lit.GetMutableString(); break;
  277. default: throw Assert.Unreachable;
  278. }
  279. _result = MakeNode(kind, value);
  280. } else {
  281. NodeKind kind;
  282. switch (node.Kind) {
  283. case StringKind.Command: kind = NodeKind.dxstr; break;
  284. case StringKind.Symbol: kind = NodeKind.dsym; break;
  285. case StringKind.Mutable: kind = NodeKind.dstr; break;
  286. default: throw Assert.Unreachable;
  287. }
  288. _result = VisitStringConstructor(node.Parts, kind);
  289. }
  290. return false;
  291. }
  292. private RubyArray/*!*/ VisitStringConstructor(List<Expression>/*!*/ parts, NodeKind kind) {
  293. StringLiteral lit;
  294. var str = MakeNode(kind, parts.Count);
  295. if (parts.Count == 1) {
  296. str.Add(MutableString.FrozenEmpty);
  297. }
  298. for (int i = 0; i < parts.Count; i++) {
  299. var part = parts[i];
  300. lit = part as StringLiteral;
  301. if (lit != null) {
  302. object value = lit.GetMutableString();
  303. if (i > 0) {
  304. value = MakeNode(NodeKind.str, value);
  305. }
  306. str.Add(value);
  307. } else {
  308. Walk(part);
  309. str.Add(MakeNode(NodeKind.evstr, _result));
  310. }
  311. }
  312. return str;
  313. }
  314. public override bool Enter(RegularExpression/*!*/ node) {
  315. StringLiteral lit;
  316. if (node.Pattern.Count == 0) {
  317. _result = MakeNode(NodeKind.lit, new RubyRegex(MutableString.CreateEmpty(), node.Options));
  318. } else if (node.Pattern.Count == 1 && (lit = node.Pattern[0] as StringLiteral) != null) {
  319. _result = MakeNode(NodeKind.lit, new RubyRegex(lit.GetMutableString(), node.Options));
  320. } else {
  321. var regex = VisitStringConstructor(node.Pattern, NodeKind.dregx);
  322. if (node.Options != RubyRegexOptions.NONE) {
  323. regex.Add((int)node.Options);
  324. }
  325. _result = regex;
  326. }
  327. return false;
  328. }
  329. public override bool Enter(RegularExpressionCondition/*!*/ node) {
  330. Walk(node.RegularExpression);
  331. _result = MakeNode(NodeKind.match, _result);
  332. return false;
  333. }
  334. public override bool Enter(MatchExpression/*!*/ node) {
  335. var match = MakeNode(NodeKind.match2, 2);
  336. Walk(node.Regex);
  337. match.Add(_result);
  338. Walk(node.Expression);
  339. match.Add(_result);
  340. _result = match;
  341. return false;
  342. }
  343. public override bool Enter(HashConstructor/*!*/ node) {
  344. _result = MakeHash(node.Maplets);
  345. return false;
  346. }
  347. private RubyArray/*!*/ MakeHash(IList<Maplet>/*!*/ maplets) {
  348. var hash = MakeNode(NodeKind.hash, maplets.Count * 2);
  349. foreach (var maplet in maplets) {
  350. Walk(maplet.Key);
  351. hash.Add(_result);
  352. Walk(maplet.Value);
  353. hash.Add(_result);
  354. }
  355. return hash;
  356. }
  357. public override bool Enter(ArrayConstructor/*!*/ node) {
  358. if (node.Arguments.IsEmpty) {
  359. _result = MakeNode(NodeKind.zarray);
  360. } else {
  361. Walk(node.Arguments);
  362. if (_result == Skip) {
  363. _result = MakeNode(NodeKind.zarray);
  364. }
  365. }
  366. return false;
  367. }
  368. #endregion
  369. #region CallExpressions
  370. public override bool Enter(MethodCall/*!*/ node) {
  371. RubyArray call;
  372. if (node.Target != null) {
  373. call = MakeNode(NodeKind.call, 2 + SizeOf(node.Arguments));
  374. } else if (node.Arguments != null) {
  375. call = MakeNode(NodeKind.fcall, 1 + SizeOf(node.Arguments));
  376. } else {
  377. call = MakeNode(NodeKind.vcall, 1);
  378. }
  379. // add target:
  380. if (node.Target != null) {
  381. Walk(node.Target);
  382. call.Add(_result);
  383. }
  384. // add name:
  385. call.Add(CreateSymbol(node.MethodName));
  386. // add arguments:
  387. AddArguments(call, node.Arguments);
  388. _result = MakeCallWithBlock(node.Block, call);
  389. return false;
  390. }
  391. public override bool Enter(SuperCall/*!*/ node) {
  392. RubyArray call;
  393. if (node.Arguments != null) {
  394. call = MakeNode(NodeKind.super, SizeOf(node.Arguments));
  395. // add arguments:
  396. AddArguments(call, node.Arguments);
  397. } else {
  398. call = MakeNode(NodeKind.zsuper);
  399. }
  400. _result = MakeCallWithBlock(node.Block, call);
  401. return false;
  402. }
  403. public override bool Enter(YieldCall/*!*/ node) {
  404. var call = MakeNode(NodeKind.yield, SizeOf(node.Arguments));
  405. // add arguments:
  406. AddArguments(call, node.Arguments); // TODO: splat [:array, value]
  407. _result = call;
  408. return false;
  409. }
  410. private static int SizeOf(Arguments args) {
  411. return args != null && !args.IsEmpty ? 1 : 0;
  412. }
  413. private void AddArguments(RubyArray/*!*/ list, Arguments args) {
  414. if (args != null && !args.IsEmpty) {
  415. Walk(args);
  416. if (_result != Skip) {
  417. list.Add(_result);
  418. }
  419. }
  420. }
  421. public override bool Enter(Arguments/*!*/ node) {
  422. throw new NotSupportedException("TODO: argument splatting");
  423. #if TODO
  424. RubyArray exprs = VisitExpressionsAndMaplets(node);
  425. if (node.Array != null) {
  426. RubyArray args = MakeSplatArguments(exprs, node.Array);
  427. object rhsValue;
  428. if (TryGetRhsValue(out rhsValue)) {
  429. _result = MakeNode(NodeKind.argspush, args, rhsValue);
  430. } else {
  431. _result = args;
  432. }
  433. } else if (exprs != null) {
  434. _result = exprs;
  435. } else {
  436. _result = Skip;
  437. }
  438. return false;
  439. #endif
  440. }
  441. private RubyArray/*!*/ MakeSplatArguments(RubyArray/*!*/ exprs, Expression/*!*/ splattedValue) {
  442. RubyArray args;
  443. if (exprs != null) {
  444. args = MakeNode(NodeKind.argscat, 2);
  445. args.Add(exprs);
  446. } else {
  447. args = MakeNode(NodeKind.splat, 1);
  448. }
  449. Walk(splattedValue);
  450. args.Add(_result);
  451. return args;
  452. }
  453. private RubyArray VisitExpressionsAndMaplets(Arguments/*!*/ node) {
  454. if (!node.IsEmpty) {
  455. var array = MakeNode(NodeKind.array, node.Expressions.Length);
  456. AddRange(array, node.Expressions);
  457. // TDOO: 1.9? append RHS unless splat is present:
  458. object rhsValue;
  459. if (TryGetRhsValue(out rhsValue)) {
  460. array.Add(rhsValue);
  461. }
  462. return array;
  463. }
  464. return null;
  465. }
  466. public override bool Enter(Maplet/*!*/ node) {
  467. throw Assert.Unreachable;
  468. }
  469. #endregion
  470. #region Blocks
  471. private RubyArray/*!*/ MakeCallWithBlock(Block block, RubyArray/*!*/ call) {
  472. if (block != null) {
  473. var blockRef = block as BlockReference;
  474. if (blockRef != null) {
  475. var result = MakeNode(NodeKind.block_pass, 2); // 0 .. block, 1 .. call
  476. // block:
  477. Walk(blockRef.Expression);
  478. result.Add(_result);
  479. // call:
  480. result.Add(call);
  481. return result;
  482. } else {
  483. var blockDef = (BlockDefinition)block;
  484. var result = MakeNode(NodeKind.iter, 3); // 0 .. call, 1 .. args(opt), 2 .. body(opt)
  485. // call:
  486. result.Add(call);
  487. // block args:
  488. UsingRhs(BlockRhs, () => {
  489. Walk(blockDef.Parameters);
  490. result.Add(_result);
  491. });
  492. // block body:
  493. AddRange(result, blockDef.Body);
  494. return result;
  495. }
  496. } else {
  497. return call;
  498. }
  499. }
  500. public override bool Enter(BlockReference/*!*/ node) {
  501. throw Assert.Unreachable;
  502. }
  503. public override bool Enter(BlockDefinition/*!*/ node) {
  504. throw Assert.Unreachable;
  505. }
  506. #endregion
  507. #region Variables
  508. public bool EnterVariable(string/*!*/ name, NodeKind read, NodeKind write) {
  509. RubySymbol symbol = CreateSymbol(name);
  510. RubyArray variable;
  511. if (_rhs == null || _rhs.IsRhsArg) {
  512. variable = MakeNode(read, symbol);
  513. } else if (_rhs.InBlockParameters) {
  514. variable = MakeNode((write == NodeKind.lasgn) ? NodeKind.dasgn_curr : write, symbol);
  515. } else if (_rhs.InCompoundLhs) {
  516. variable = MakeNode(write, symbol);
  517. } else {
  518. variable = MakeNode(write, symbol, _rhs.Value);
  519. }
  520. _result = variable;
  521. return false;
  522. }
  523. public override bool Enter(ClassVariable/*!*/ node) {
  524. return EnterVariable(node.Name, NodeKind.cvar, NodeKind.cvdecl);
  525. }
  526. public override bool Enter(ConstantVariable/*!*/ node) {
  527. if (node.IsGlobal) {
  528. return EnterVariable(node.Name, NodeKind.colon3, NodeKind.cdecl);
  529. } else if (node.IsBound) {
  530. var qualified = MakeNode(NodeKind.colon2, 2);
  531. Walk(node.Qualifier);
  532. qualified.Add(_result);
  533. qualified.Add(CreateSymbol(node.Name));
  534. _result = qualified;
  535. return false;
  536. } else {
  537. return EnterVariable(node.Name, NodeKind.@const, NodeKind.cdecl);
  538. }
  539. }
  540. public override bool Enter(IronRuby.Compiler.Ast.GlobalVariable/*!*/ node) {
  541. return EnterVariable(node.FullName, NodeKind.gvar, NodeKind.gasgn);
  542. }
  543. public override bool Enter(InstanceVariable/*!*/ node) {
  544. return EnterVariable(node.Name, NodeKind.ivar, NodeKind.iasgn);
  545. }
  546. public override bool Enter(LocalVariable/*!*/ node) {
  547. return EnterVariable(node.Name, NodeKind.lvar, NodeKind.lasgn);
  548. }
  549. public override bool Enter(RegexMatchReference/*!*/ node) {
  550. if (node.FullName == "$~") {
  551. return EnterVariable(node.FullName, NodeKind.gvar, NodeKind.gasgn);
  552. } else if (node.Index > 0) {
  553. Debug.Assert(_rhs == null);
  554. _result = MakeNode(NodeKind.nth_ref, ScriptingRuntimeHelpers.Int32ToObject(node.Index));
  555. } else {
  556. Debug.Assert(_rhs == null);
  557. _result = MakeNode(NodeKind.back_ref, CreateSymbol(node.VariableName));
  558. }
  559. return false;
  560. }
  561. public override bool Enter(Placeholder/*!*/ node) {
  562. // nop
  563. _result = Skip;
  564. return false;
  565. }
  566. #endregion
  567. #region Assignment
  568. public override bool Enter(SimpleAssignmentExpression/*!*/ node) {
  569. bool isAnd = node.Operation == "&&";
  570. bool isOr = node.Operation == "||";
  571. var oldRhs = _rhs;
  572. _rhs = null;
  573. Walk(node.Right);
  574. var rvalue = _result;
  575. if (node.Operation != null && !isAnd && !isOr) {
  576. Walk(node.Left);
  577. rvalue = MakeNode(NodeKind.call, _result, CreateSymbol(node.Operation), MakeNode(NodeKind.array, rvalue));
  578. }
  579. _rhs = new Rhs { Value = rvalue };
  580. Walk(node.Left);
  581. if (isAnd || isOr) {
  582. var lvalue = _result;
  583. _rhs = null;
  584. Walk(node.Left);
  585. _result = MakeNode(isAnd ? NodeKind.op_asgn_and : NodeKind.op_asgn_or, _result, lvalue);
  586. }
  587. _rhs = oldRhs;
  588. return false;
  589. }
  590. public override bool Enter(MemberAssignmentExpression/*!*/ node) {
  591. // TODO:
  592. throw new NotImplementedException(node.NodeType.ToString());
  593. }
  594. public override bool Enter(ParallelAssignmentExpression/*!*/ node) {
  595. // TODO: 1.9:
  596. throw new NotSupportedException("TODO: parallel assignment");
  597. #if TODO
  598. var oldRhs = _rhs;
  599. _rhs = null;
  600. if (node.Right.SplattedValue == null && node.Right.RightValues.Length == 1 && node.Left.LeftValues.Length > 0) {
  601. Walk(node.Right.RightValues[0]);
  602. _rhs = new Rhs { InCompoundLhs = true, InTopCompoundLhs = true, Value = MakeNode(NodeKind.to_ary, _result) };
  603. } else if (node.Right.SplattedValue != null && node.Right.RightValues.Length == 0) {
  604. Walk(node.Right.SplattedValue);
  605. var rvalue = MakeNode(NodeKind.splat, _result);
  606. if (node.Left.UnsplattedValue == null && node.Left.LeftValues.Length == 1) {
  607. _rhs = new Rhs { Value = MakeNode(NodeKind.svalue, rvalue) };
  608. } else {
  609. _rhs = new Rhs { InCompoundLhs = true, InTopCompoundLhs = true, Value = rvalue };
  610. }
  611. } else {
  612. var exprs = AddRange(MakeNode(NodeKind.array, node.Right.RightValues.Length), node.Right.RightValues);
  613. if (node.Right.SplattedValue != null) {
  614. exprs = MakeSplatArguments(exprs, node.Right.SplattedValue);
  615. }
  616. if (node.Left.UnsplattedValue == null && node.Left.LeftValues.Length == 1) {
  617. _rhs = new Rhs { Value = MakeNode(NodeKind.svalue, exprs) };
  618. } else {
  619. _rhs = new Rhs { InCompoundLhs = true, InTopCompoundLhs = true, Value = exprs };
  620. }
  621. }
  622. Walk(node.Left);
  623. _rhs = oldRhs;
  624. return false;
  625. #endif
  626. }
  627. // RHS: [:call, ARRAY, :[], ARGUMENTS]
  628. // LHS: [:attrasgn, ARRAY, :[]=, ARGUMENTS + RHS]
  629. public override bool Enter(ArrayItemAccess/*!*/ node) {
  630. if (_rhs == null) {
  631. RubyArray call = MakeNode(NodeKind.call, 2 + SizeOf(node.Arguments));
  632. // add target:
  633. Walk(node.Array);
  634. call.Add(_result);
  635. // add name:
  636. call.Add(CreateSymbol("[]"));
  637. // add arguments:
  638. AddArguments(call, node.Arguments);
  639. // TODO: 1.9: add block:
  640. // call.Add(node.Block);
  641. _result = call;
  642. } else {
  643. var isRhsArg = _rhs.IsRhsArg;
  644. _rhs.IsRhsArg = true;
  645. var assignment = MakeNode(NodeKind.attrasgn, 2 + SizeOf(node.Arguments));
  646. UsingRhs(null, () => {
  647. Walk(node.Array);
  648. assignment.Add(_result);
  649. });
  650. assignment.Add(CreateSymbol("[]="));
  651. AddArguments(assignment, node.Arguments);
  652. _rhs.IsRhsArg = isRhsArg;
  653. _result = assignment;
  654. }
  655. return false;
  656. }
  657. // [:attrasgn, QUALIFIER, :NAME=, [:array, RHS]]
  658. public override bool Enter(AttributeAccess/*!*/ node) {
  659. Debug.Assert(_rhs != null);
  660. var assignment = MakeNode(NodeKind.attrasgn, 3);
  661. // qualifier:
  662. UsingRhs(null, () => {
  663. Walk(node.Qualifier);
  664. assignment.Add(_result);
  665. });
  666. // name:
  667. assignment.Add(CreateSymbol(node.Name));
  668. // rhs array:
  669. object rhsValue;
  670. if (TryGetRhsValue(out rhsValue)) {
  671. assignment.Add(MakeNode(NodeKind.array, rhsValue));
  672. }
  673. _result = assignment;
  674. return false;
  675. }
  676. public override bool Enter(AssignmentExpression/*!*/ node) {
  677. throw Assert.Unreachable;
  678. }
  679. #endregion
  680. #region CompoundLeftValue
  681. public override bool Enter(CompoundLeftValue/*!*/ node) {
  682. Debug.Assert(_rhs != null);
  683. if (node.UnsplattedValue == null) {
  684. if (node.LeftValues.Length == 0) {
  685. Debug.Assert(_rhs == BlockRhs);
  686. _result = ScriptingRuntimeHelpers.Int32ToObject(0);
  687. return false;
  688. }
  689. if (node.LeftValues.Length == 1) {
  690. Walk(node.LeftValues[0]);
  691. return false;
  692. }
  693. }
  694. bool isTop = _rhs.InTopCompoundLhs;
  695. _rhs.InTopCompoundLhs = false;
  696. var assignment = MakeNode(NodeKind.masgn,
  697. (node.LeftValues.Length > 1 ? 1 : 0) +
  698. (node.UnsplattedValue != null ? 1 : 0) +
  699. (_rhs != null ? 1 : 0) +
  700. (isTop ? 1 : 0) // outer most gets RHS
  701. );
  702. // TODO: 1.9: leading-l-values, *, trailing-l-values
  703. if (node.LeftValues.Length > 1) {
  704. assignment.Add(
  705. AddRange(MakeNode(NodeKind.array, node.LeftValues.Length), node.LeftValues)
  706. );
  707. }
  708. if (node.UnsplattedValue != null) {
  709. if (node.UnsplattedValue is Placeholder) {
  710. assignment.Add(MakeNode(NodeKind.splat));
  711. } else {
  712. Walk(node.UnsplattedValue);
  713. assignment.Add(_result);
  714. }
  715. }
  716. if (_rhs.InCompoundLhs && isTop) {
  717. assignment.Add(_rhs.Value);
  718. }
  719. _rhs.InTopCompoundLhs = isTop;
  720. _result = assignment;
  721. return false;
  722. }
  723. //MemberAssignmentExpression
  724. //SimpleAssignmentExpression
  725. //
  726. #endregion
  727. #region Alias, Undefine, Defined?, Self, Initializer, Finalizer
  728. public override bool Enter(AliasStatement/*!*/ node) {
  729. if (node.IsGlobalVariableAlias) {
  730. _result = MakeNode(NodeKind.valias,
  731. CreateSymbol("$" + node.NewName),
  732. CreateSymbol("$" + node.OldName)
  733. );
  734. } else {
  735. // TODO: handle constructed symbols
  736. _result = MakeNode(NodeKind.alias,
  737. MakeNode(NodeKind.lit, CreateSymbol((string)node.NewName.Value)),
  738. MakeNode(NodeKind.lit, CreateSymbol((string)node.OldName.Value))
  739. );
  740. }
  741. return false;
  742. }
  743. public override bool Enter(UndefineStatement/*!*/ node) {
  744. if (node.Items.Count == 1) {
  745. // TODO: handle constructed symbols
  746. _result = MakeNode(NodeKind.undef, MakeNode(NodeKind.lit, CreateSymbol((string)node.Items[0].Value)));
  747. } else {
  748. var block = MakeNode(NodeKind.block, node.Items.Count);
  749. foreach (var item in node.Items) {
  750. // TODO: handle constructed symbols
  751. block.Add(MakeNode(NodeKind.undef, MakeNode(NodeKind.lit, CreateSymbol((string)item.Value))));
  752. }
  753. _result = block;
  754. }
  755. return false;
  756. }
  757. public override bool Enter(IsDefinedExpression/*!*/ node) {
  758. var def = MakeNode(NodeKind.defined, 1);
  759. Walk(node.Expression);
  760. def.Add(_result);
  761. _result = def;
  762. return false;
  763. }
  764. public override bool Enter(SelfReference/*!*/ node) {
  765. _result = MakeNode(NodeKind.self);
  766. return false;
  767. }
  768. public override bool Enter(FileInitializerStatement/*!*/ node) {
  769. // TODO:
  770. throw new NotImplementedException();
  771. }
  772. public override bool Enter(ShutdownHandlerStatement/*!*/ node) {
  773. // TODO:
  774. throw new NotImplementedException();
  775. }
  776. #endregion
  777. #region Boolean Expressions
  778. private bool EnterBooleanExpression(Expression/*!*/ left, Expression/*!*/ right, NodeKind kind) {
  779. var b = MakeNode(kind, 2);
  780. Walk(left);
  781. b.Add(_result);
  782. Walk(right);
  783. b.Add(_result);
  784. _result = b;
  785. return false;
  786. }
  787. public override bool Enter(AndExpression/*!*/ node) {
  788. return EnterBooleanExpression(node.Left, node.Right, NodeKind.and);
  789. }
  790. public override bool Enter(OrExpression/*!*/ node) {
  791. return EnterBooleanExpression(node.Left, node.Right, NodeKind.or);
  792. }
  793. public override bool Enter(NotExpression/*!*/ node) {
  794. var b = MakeNode(NodeKind.not, 1);
  795. Walk(node.Expression);
  796. b.Add(_result);
  797. _result = b;
  798. return false;
  799. }
  800. #endregion
  801. #region JumpStatements
  802. private bool EnterJumpStatement(JumpStatement/*!*/ node, NodeKind kind) {
  803. var jmp = MakeNode(kind, SizeOf(node.Arguments));
  804. // add arguments:
  805. AddArguments(jmp, node.Arguments); // TODO: splat [:array, value]
  806. _result = jmp;
  807. return false;
  808. }
  809. public override bool Enter(BreakStatement/*!*/ node) {
  810. return EnterJumpStatement(node, NodeKind.@break);
  811. }
  812. public override bool Enter(NextStatement/*!*/ node) {
  813. return EnterJumpStatement(node, NodeKind.next);
  814. }
  815. public override bool Enter(ReturnStatement/*!*/ node) {
  816. return EnterJumpStatement(node, NodeKind.@return);
  817. }
  818. public override bool Enter(RetryStatement/*!*/ node) {
  819. return EnterJumpStatement(node, NodeKind.retry);
  820. }
  821. public override bool Enter(RedoStatement/*!*/ node) {
  822. return EnterJumpStatement(node, NodeKind.redo);
  823. }
  824. #endregion
  825. #region Body (EH)
  826. public override bool Enter(BlockExpression/*!*/ node) {
  827. _result = MakeBlock(node.Statements);
  828. return false;
  829. }
  830. public override bool Enter(Body/*!*/ node) {
  831. var begin = MakeNode(NodeKind.begin, 5);
  832. AddBody(begin, node);
  833. _result = begin;
  834. return false;
  835. }
  836. private RubyArray/*!*/ AddBody(RubyArray/*!*/ list, Body/*!*/ node) {
  837. RubyArray current;
  838. if (node.EnsureStatements != null) {
  839. list.Add(current = MakeNode(NodeKind.ensure, 2));
  840. } else {
  841. current = list;
  842. }
  843. if (node.RescueClauses != null) {
  844. var rescue = MakeNode(NodeKind.rescue);
  845. rescue.Add(MakeBlock(node.Statements));
  846. AddRescueBody(rescue, node);
  847. AddRange(rescue, node.ElseStatements);
  848. current.Add(rescue);
  849. } else {
  850. current.Add(MakeBlock(node.Statements));
  851. }
  852. AddRange(current, node.EnsureStatements);
  853. return list;
  854. }
  855. /// <code>
  856. /// rescue
  857. /// 2
  858. /// rescue A => e
  859. /// 3
  860. /// rescue A,B => e
  861. /// 4
  862. /// rescue A
  863. /// 5
  864. /// rescue A,B
  865. /// 6
  866. /// end
  867. ///
  868. /// [:resbody,
  869. /// nil,
  870. /// [:lit, 2],
  871. /// [:resbody,
  872. /// [:array, [:const, :A]],
  873. /// [:block,
  874. /// [:lasgn, :e, [:gvar, :$!]],
  875. /// [:lit, 3]
  876. /// ],
  877. /// [:resbody,
  878. /// [:array, [:const, :A], [:const, :B]],
  879. /// [:block,
  880. /// [:lasgn, :e, [:gvar, :$!]],
  881. /// [:lit, 4]
  882. /// ],
  883. /// [:resbody,
  884. /// [:array, [:const, :A]],
  885. /// [:lit, 5],
  886. /// [:resbody,
  887. /// [:array, [:const, :A], [:const, :B]],
  888. /// [:lit, 6]
  889. /// ]
  890. /// ]
  891. /// ]
  892. /// ]
  893. /// ]
  894. /// </code>
  895. private void AddRescueBody(RubyArray/*!*/ current, Body/*!*/ node) {
  896. foreach (var clause in node.RescueClauses) {
  897. var resbody = MakeNode(NodeKind.resbody, 3);
  898. if (clause.Types != null) {
  899. resbody.Add(AddRange(MakeNode(NodeKind.array, clause.Types.Length), clause.Types));
  900. } else {
  901. resbody.Add(null);
  902. }
  903. if (clause.Target != null) {
  904. UsingRhs(new Rhs { Value = MakeNode(NodeKind.gvar, CreateSymbol("$!")) }, () => {
  905. Walk(clause.Target);
  906. });
  907. var assignment = _result;
  908. var block = MakeNode(NodeKind.block, 1 + (clause.Statements != null ? clause.Statements.Count : 0));
  909. block.Add(assignment);
  910. AddRange(block, clause.Statements);
  911. resbody.Add(block);
  912. } else {
  913. AddRange(resbody, clause.Statements);
  914. }
  915. current.Add(resbody);
  916. current = resbody;
  917. }
  918. }
  919. public override bool Enter(RescueClause/*!*/ node) {
  920. throw Assert.Unreachable;
  921. }
  922. public override bool Enter(RescueExpression/*!*/ node) {
  923. var rescue = MakeNode(NodeKind.rescue, 2);
  924. Walk(node.GuardedExpression);
  925. rescue.Add(_result);
  926. var resbody = MakeNode(NodeKind.resbody, 2);
  927. resbody.Add(null);
  928. Walk(node.RescueClauseStatement);
  929. resbody.Add(_result);
  930. rescue.Add(resbody);
  931. _result = rescue;
  932. return false;
  933. }
  934. #endregion
  935. #region Flow
  936. private object MakeBlock(Statements statements) {
  937. var block = MakeBlockOpt(statements);
  938. return (block != Skip) ? block : MakeNode(NodeKind.nil);
  939. }
  940. private RubyArray/*!*/ AddBlock(RubyArray/*!*/ list, Statements statements) {
  941. var block = MakeBlockOpt(statements);
  942. if (block != Skip) {
  943. list.Add(block);
  944. }
  945. return list;
  946. }
  947. private object MakeBlockOpt(Statements statements) {
  948. if (statements == null || statements.Count == 0) {
  949. return Skip;
  950. } else if (statements.Count == 1) {
  951. Walk(statements.First);
  952. return _result;
  953. } else {
  954. return AddRange(MakeNode(NodeKind.block, statements.Count), statements);
  955. }
  956. }
  957. public override bool Enter(IfExpression/*!*/ node) {
  958. RubyArray @if;
  959. RubyArray current = @if = MakeNode(NodeKind.@if, 3);
  960. Walk(node.Condition);
  961. current.Add(_result);
  962. current.Add(MakeBlock(node.Body));
  963. if (node.ElseIfClauses != null && node.ElseIfClauses.Count != 0) {
  964. foreach (var clause in node.ElseIfClauses) {
  965. if (clause.Condition != null) {
  966. // elsif cond
  967. current.Add(current = MakeNode(NodeKind.@if, 3));
  968. Walk(clause.Condition);
  969. current.Add(_result);
  970. }
  971. current.Add(MakeBlock(clause.Statements));
  972. }
  973. if (node.ElseIfClauses[node.ElseIfClauses.Count - 1].Condition != null) {
  974. current.Add(null);
  975. }
  976. } else {
  977. current.Add(null);
  978. }
  979. _result = @if;
  980. return false;
  981. }
  982. public override bool Enter(UnlessExpression/*!*/ node) {
  983. var @if = MakeNode(NodeKind.@if, 3);
  984. Walk(node.Condition);
  985. @if.Add(_result);
  986. if (node.ElseClause != null) {
  987. Debug.Assert(node.ElseClause.Condition == null);
  988. @if.Add(MakeBlock(node.ElseClause.Statements));
  989. } else {
  990. @if.Add(null);
  991. }
  992. @if.Add(MakeBlock(node.Statements));
  993. _result = @if;
  994. return false;
  995. }
  996. public override bool Enter(ElseIfClause/*!*/ node) {
  997. throw Assert.Unreachable;
  998. }
  999. private bool EnterTernary(NodeKind kind, Expression/*!*/ expr1, Expression expr2, Expression expr3) {
  1000. var result = MakeNode(NodeKind.@if, 3);
  1001. Walk(expr1);
  1002. result.Add(_result);
  1003. if (expr2 != null) {
  1004. Walk(expr2);
  1005. result.Add(_result);
  1006. } else {
  1007. result.Add(null);
  1008. }
  1009. if (expr3 != null) {
  1010. Walk(expr3);
  1011. result.Add(_result);
  1012. } else {
  1013. result.Add(null);
  1014. }
  1015. _result = result;
  1016. return false;
  1017. }
  1018. public override bool Enter(ConditionalExpression/*!*/ node) {
  1019. return EnterTernary(NodeKind.@if, node.Condition, node.TrueExpression, node.FalseExpression);
  1020. }
  1021. public override bool Enter(ConditionalJumpExpression/*!*/

Large files files are truncated, but you can click here to view the full file