PageRenderTime 60ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/Runtime/Samples/sympl/csharp/ETGen.cs

http://github.com/IronLanguages/main
C# | 730 lines | 578 code | 64 blank | 88 comment | 113 complexity | f4c2cd9752eb25e73ffe9651e18f0032 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. using System;
  2. using System.Dynamic;
  3. using System.Linq.Expressions;
  4. using System.Linq;
  5. using System.Collections.Generic;
  6. namespace SymplSample {
  7. internal static class ETGen {
  8. public static Expression AnalyzeExpr(SymplExpr expr, AnalysisScope scope) {
  9. if (expr is SymplImportExpr) {
  10. return AnalyzeImportExpr((SymplImportExpr)expr, scope);
  11. } else if (expr is SymplFunCallExpr) {
  12. return AnalyzeFunCallExpr((SymplFunCallExpr)expr, scope);
  13. } else if (expr is SymplDefunExpr) {
  14. return AnalyzeDefunExpr((SymplDefunExpr)expr, scope);
  15. } else if (expr is SymplLambdaExpr) {
  16. return AnalyzeLambdaExpr((SymplLambdaExpr)expr, scope);
  17. } else if (expr is SymplIdExpr) {
  18. return AnalyzeIdExpr((SymplIdExpr)expr, scope);
  19. } else if (expr is SymplQuoteExpr) {
  20. return AnalyzeQuoteExpr((SymplQuoteExpr)expr, scope);
  21. } else if (expr is SymplLiteralExpr) {
  22. return Expression.Constant(((SymplLiteralExpr)expr).Value);
  23. } else if (expr is SymplAssignExpr) {
  24. return AnalyzeAssignExpr((SymplAssignExpr)expr, scope);
  25. } else if (expr is SymplLetStarExpr) {
  26. return AnalyzeLetStarExpr((SymplLetStarExpr)expr, scope);
  27. } else if (expr is SymplBlockExpr) {
  28. return AnalyzeBlockExpr((SymplBlockExpr)expr, scope);
  29. } else if (expr is SymplEqExpr) {
  30. return AnalyzeEqExpr((SymplEqExpr)expr, scope);
  31. } else if (expr is SymplConsExpr) {
  32. return AnalyzeConsExpr((SymplConsExpr)expr, scope);
  33. } else if (expr is SymplListCallExpr) {
  34. return AnalyzeListCallExpr((SymplListCallExpr)expr, scope);
  35. } else if (expr is SymplIfExpr) {
  36. return AnalyzeIfExpr((SymplIfExpr)expr, scope);
  37. } else if (expr is SymplDottedExpr) {
  38. return AnalyzeDottedExpr((SymplDottedExpr)expr, scope);
  39. } else if (expr is SymplNewExpr) {
  40. return AnalyzeNewExpr((SymplNewExpr)expr, scope);
  41. } else if (expr is SymplLoopExpr) {
  42. return AnalyzeLoopExpr((SymplLoopExpr)expr, scope);
  43. } else if (expr is SymplBreakExpr) {
  44. return AnalyzeBreakExpr((SymplBreakExpr)expr, scope);
  45. } else if (expr is SymplEltExpr) {
  46. return AnalyzeEltExpr((SymplEltExpr)expr, scope);
  47. } else if (expr is SymplBinaryExpr) {
  48. return AnalyzeBinaryExpr((SymplBinaryExpr)expr, scope);
  49. } else if (expr is SymplUnaryExpr) {
  50. return AnalyzeUnaryExpr((SymplUnaryExpr)expr, scope);
  51. } else {
  52. throw new InvalidOperationException(
  53. "Internal: no expression to analyze.");
  54. }
  55. }
  56. public static Expression AnalyzeImportExpr(SymplImportExpr expr,
  57. AnalysisScope scope) {
  58. if (!scope.IsModule) {
  59. throw new InvalidOperationException(
  60. "Import expression must be a top level expression.");
  61. }
  62. return Expression.Call(
  63. typeof(RuntimeHelpers).GetMethod("SymplImport"),
  64. scope.RuntimeExpr,
  65. scope.ModuleExpr,
  66. Expression.Constant(expr.NamespaceExpr.Select(id => id.Name)
  67. .ToArray()),
  68. Expression.Constant(expr.MemberNames.Select(id => id.Name)
  69. .ToArray()),
  70. Expression.Constant(expr.Renames.Select(id => id.Name)
  71. .ToArray()));
  72. }
  73. public static DynamicExpression AnalyzeDefunExpr(SymplDefunExpr expr,
  74. AnalysisScope scope) {
  75. if (!scope.IsModule) {
  76. throw new InvalidOperationException(
  77. "Use Defmethod or Lambda when not defining top-level function.");
  78. }
  79. return Expression.Dynamic(
  80. scope.GetRuntime().GetSetMemberBinder(expr.Name),
  81. typeof(object),
  82. scope.ModuleExpr,
  83. AnalyzeLambdaDef(expr.Params, expr.Body, scope,
  84. "defun " + expr.Name));
  85. }
  86. public static LambdaExpression AnalyzeLambdaExpr(SymplLambdaExpr expr,
  87. AnalysisScope scope) {
  88. return (LambdaExpression)AnalyzeLambdaDef(expr.Params, expr.Body,
  89. scope, "lambda");
  90. }
  91. private static Expression AnalyzeLambdaDef
  92. (IdOrKeywordToken[] parms, SymplExpr[] body,
  93. AnalysisScope scope, string description) {
  94. var funscope = new AnalysisScope(scope, description);
  95. funscope.IsLambda = true; // needed for return support.
  96. var paramsInOrder = new List<ParameterExpression>();
  97. foreach (var p in parms) {
  98. var pe = Expression.Parameter(typeof(object), p.Name);
  99. paramsInOrder.Add(pe);
  100. funscope.Names[p.Name.ToLower()] = pe;
  101. }
  102. // No need to add fun name to module scope since recursive call just looks
  103. // up global name late bound. For lambdas,to get the effect of flet to
  104. // support recursion, bind a variable to nil and then set it to a lambda.
  105. // Then the lambda's body can refer to the let bound var in its def.
  106. var bodyexprs = new List<Expression>();
  107. foreach (var e in body) {
  108. bodyexprs.Add(AnalyzeExpr(e, funscope));
  109. }
  110. // Set up the Type arg array for the delegate type. Must include
  111. // the return type as the last Type, which is object for Sympl defs.
  112. var funcTypeArgs = new List<Type>();
  113. for (int i = 0; i < parms.Length + 1; i++) {
  114. funcTypeArgs.Add(typeof(object));
  115. }
  116. return Expression.Lambda(
  117. Expression.GetFuncType(funcTypeArgs.ToArray()),
  118. Expression.Block(bodyexprs),
  119. paramsInOrder);
  120. }
  121. // Returns a dynamic InvokeMember or Invoke expression, depending on the
  122. // Function expression.
  123. //
  124. public static DynamicExpression AnalyzeFunCallExpr(
  125. SymplFunCallExpr expr, AnalysisScope scope) {
  126. if (expr.Function is SymplDottedExpr) {
  127. SymplDottedExpr dottedExpr = (SymplDottedExpr)expr.Function;
  128. Expression objExpr;
  129. int length = dottedExpr.Exprs.Length;
  130. if (length > 1) {
  131. objExpr = AnalyzeDottedExpr(
  132. // create a new dot expression for the object that doesn't
  133. // include the last part
  134. new SymplDottedExpr(
  135. dottedExpr.ObjectExpr,
  136. RuntimeHelpers.RemoveLast(dottedExpr.Exprs)),
  137. scope
  138. );
  139. } else {
  140. objExpr = AnalyzeExpr(dottedExpr.ObjectExpr, scope);
  141. }
  142. List<Expression> args = new List<Expression>();
  143. args.Add(objExpr);
  144. args.AddRange(expr.Arguments.Select(a => AnalyzeExpr(a, scope)));
  145. // last expr must be an id
  146. var lastExpr = (SymplIdExpr)(dottedExpr.Exprs.Last());
  147. return Expression.Dynamic(
  148. scope.GetRuntime().GetInvokeMemberBinder(
  149. new InvokeMemberBinderKey(
  150. lastExpr.IdToken.Name,
  151. new CallInfo(expr.Arguments.Length))),
  152. typeof(object),
  153. args
  154. );
  155. } else {
  156. var fun = AnalyzeExpr(expr.Function, scope);
  157. List<Expression> args = new List<Expression>();
  158. args.Add(fun);
  159. args.AddRange(expr.Arguments.Select(a => AnalyzeExpr(a, scope)));
  160. // Use DynExpr so that I don't always have to have a delegate to call,
  161. // such as what happens with IPy interop.
  162. return Expression.Dynamic(
  163. scope.GetRuntime()
  164. .GetInvokeBinder(new CallInfo(expr.Arguments.Length)),
  165. typeof(object),
  166. args
  167. );
  168. }
  169. }
  170. // Returns a chain of GetMember and InvokeMember dynamic expressions for
  171. // the dotted expr.
  172. //
  173. public static Expression AnalyzeDottedExpr(SymplDottedExpr expr,
  174. AnalysisScope scope) {
  175. var curExpr = AnalyzeExpr(expr.ObjectExpr, scope);
  176. foreach (var e in expr.Exprs) {
  177. if (e is SymplIdExpr) {
  178. curExpr = Expression.Dynamic(
  179. scope.GetRuntime()
  180. .GetGetMemberBinder(((SymplIdExpr)e).IdToken.Name),
  181. typeof(object),
  182. curExpr
  183. );
  184. } else if (e is SymplFunCallExpr) {
  185. var call = (SymplFunCallExpr)e;
  186. List<Expression> args = new List<Expression>();
  187. args.Add(curExpr);
  188. args.AddRange(call.Arguments.Select(a => AnalyzeExpr(a, scope)));
  189. curExpr = Expression.Dynamic(
  190. // Dotted exprs must be simple invoke members, a.b.(c ...)
  191. scope.GetRuntime().GetInvokeMemberBinder(
  192. new InvokeMemberBinderKey(
  193. ((SymplIdExpr)call.Function).IdToken.Name,
  194. new CallInfo(call.Arguments.Length))),
  195. typeof(object),
  196. args
  197. );
  198. } else {
  199. throw new InvalidOperationException(
  200. "Internal: dotted must be IDs or Funs.");
  201. }
  202. }
  203. return curExpr;
  204. }
  205. // AnalyzeAssignExpr handles IDs, indexing, and member sets. IDs are either
  206. // lexical or dynamic exprs on the module scope. Everything
  207. // else is dynamic.
  208. //
  209. public static Expression AnalyzeAssignExpr(SymplAssignExpr expr,
  210. AnalysisScope scope) {
  211. if (expr.Location is SymplIdExpr) {
  212. var idExpr = (SymplIdExpr)(expr.Location);
  213. var lhs = AnalyzeExpr(expr.Location, scope);
  214. var val = AnalyzeExpr(expr.Value, scope);
  215. var param = FindIdDef(idExpr.IdToken.Name, scope);
  216. if (param != null) {
  217. // Assign returns value stored.
  218. return Expression.Assign(
  219. lhs,
  220. Expression.Convert(val, param.Type));
  221. } else {
  222. var tmp = Expression.Parameter(typeof(object),
  223. "assignTmpForRes");
  224. // Ensure stored value is returned. Had some erroneous
  225. // MOs come through here and left the code for example.
  226. return Expression.Block(
  227. new[] { tmp },
  228. Expression.Assign(
  229. tmp,
  230. Expression.Convert(val, typeof(object))),
  231. Expression.Dynamic(
  232. scope.GetRuntime()
  233. .GetSetMemberBinder(idExpr.IdToken.Name),
  234. typeof(object),
  235. scope.GetModuleExpr(),
  236. tmp),
  237. tmp);
  238. }
  239. } else if (expr.Location is SymplEltExpr) {
  240. var eltExpr = (SymplEltExpr)(expr.Location);
  241. var args = new List<Expression>();
  242. args.Add(AnalyzeExpr(eltExpr.ObjectExpr, scope));
  243. args.AddRange(eltExpr.Indexes.Select(e => AnalyzeExpr(e, scope)));
  244. args.Add(AnalyzeExpr(expr.Value, scope));
  245. // Trusting MO convention to return stored values.
  246. return Expression.Dynamic(
  247. scope.GetRuntime().GetSetIndexBinder(
  248. new CallInfo(eltExpr.Indexes.Length)),
  249. typeof(object),
  250. args);
  251. } else if (expr.Location is SymplDottedExpr) {
  252. // For now, one dot only. Later, pick oflast dotted member
  253. // access (like AnalyzeFunctionCall), and use a temp and block.
  254. var dottedExpr = (SymplDottedExpr)(expr.Location);
  255. if (dottedExpr.Exprs.Length > 1) {
  256. throw new InvalidOperationException(
  257. "Don't support assigning with more than simple dotted " +
  258. "expression, o.foo.");
  259. }
  260. if (!(dottedExpr.Exprs[0] is SymplIdExpr)) {
  261. throw new InvalidOperationException(
  262. "Only support unindexed field or property when assigning " +
  263. "dotted expression location.");
  264. }
  265. var id = (SymplIdExpr)(dottedExpr.Exprs[0]);
  266. // Trusting MOs convention to return stored values.
  267. return Expression.Dynamic(
  268. scope.GetRuntime().GetSetMemberBinder(id.IdToken.Name),
  269. typeof(object),
  270. AnalyzeExpr(dottedExpr.ObjectExpr, scope),
  271. AnalyzeExpr(expr.Value, scope)
  272. );
  273. }
  274. throw new InvalidOperationException("Invalid left hand side type.");
  275. }
  276. // Return an Expression for referencing the ID. If we find the name in the
  277. // scope chain, then we just return the stored ParamExpr. Otherwise, the
  278. // reference is a dynamic member lookup on the root scope, a module object.
  279. //
  280. public static Expression AnalyzeIdExpr(SymplIdExpr expr,
  281. AnalysisScope scope) {
  282. if (expr.IdToken.IsKeywordToken) {
  283. if (expr.IdToken == KeywordToken.Nil)
  284. return Expression.Constant(null, typeof(object));
  285. else if (expr.IdToken == KeywordToken.True)
  286. return Expression.Constant(true);
  287. else if (expr.IdToken == KeywordToken.False)
  288. return Expression.Constant(false);
  289. else
  290. throw new InvalidOperationException(
  291. "Internal: unrecognized keyword literal constant.");
  292. } else {
  293. var param = FindIdDef(expr.IdToken.Name, scope);
  294. if (param != null) {
  295. return param;
  296. } else {
  297. return Expression.Dynamic(
  298. scope.GetRuntime().GetGetMemberBinder(expr.IdToken.Name),
  299. typeof(object),
  300. scope.GetModuleExpr()
  301. );
  302. }
  303. }
  304. }
  305. // _findIdDef returns the ParameterExpr for the name by searching the scopes,
  306. // or it returns None.
  307. //
  308. private static Expression FindIdDef(string name, AnalysisScope scope) {
  309. var curscope = scope;
  310. name = name.ToLower();
  311. ParameterExpression res;
  312. while (curscope != null && !curscope.IsModule) {
  313. if (curscope.Names.TryGetValue(name, out res)) {
  314. return res;
  315. } else {
  316. curscope = curscope.Parent;
  317. }
  318. }
  319. if (scope == null) {
  320. throw new InvalidOperationException(
  321. "Got bad AnalysisScope chain with no module at end.");
  322. }
  323. return null;
  324. }
  325. // AnalyzeLetStar returns a Block with vars, each initialized in the order
  326. // they appear. Each var's init expr can refer to vars initialized before it.
  327. // The Block's body is the Let*'s body.
  328. //
  329. public static Expression AnalyzeLetStarExpr(SymplLetStarExpr expr,
  330. AnalysisScope scope) {
  331. var letscope = new AnalysisScope(scope, "let*");
  332. // Analyze bindings.
  333. List<Expression> inits = new List<Expression>();
  334. List<ParameterExpression> varsInOrder = new List<ParameterExpression>();
  335. foreach (var b in expr.Bindings) {
  336. // Need richer logic for mvbind
  337. var v = Expression.Parameter(typeof(object), b.Variable.Name);
  338. varsInOrder.Add(v);
  339. inits.Add(
  340. Expression.Assign(
  341. v,
  342. Expression.Convert(AnalyzeExpr(b.Value, letscope), v.Type))
  343. );
  344. // Add var to scope after analyzing init value so that init value
  345. // references to the same ID do not bind to his uninitialized var.
  346. letscope.Names[b.Variable.Name.ToLower()] = v;
  347. }
  348. List<Expression> body = new List<Expression>();
  349. foreach (var e in expr.Body) {
  350. body.Add(AnalyzeExpr(e, letscope));
  351. }
  352. // Order of vars to BlockExpr don't matter semantically, but may as well
  353. // keep them in the order the programmer specified in case they look at the
  354. // Expr Trees in the debugger or for meta-programming.
  355. inits.AddRange(body);
  356. return Expression.Block(typeof(object), varsInOrder.ToArray(), inits);
  357. }
  358. // AnalyzeBlockExpr returns a Block with the body exprs.
  359. //
  360. public static Expression AnalyzeBlockExpr(SymplBlockExpr expr,
  361. AnalysisScope scope) {
  362. List<Expression> body = new List<Expression>();
  363. foreach (var e in expr.Body) {
  364. body.Add(AnalyzeExpr(e, scope));
  365. }
  366. return Expression.Block(typeof(object), body);
  367. }
  368. // AnalyzeQuoteExpr converts a list, literal, or id expr to a runtime quoted
  369. // literal and returns the Constant expression for it.
  370. //
  371. public static Expression AnalyzeQuoteExpr(SymplQuoteExpr expr,
  372. AnalysisScope scope) {
  373. return Expression.Constant(MakeQuoteConstant(
  374. expr.Expr, scope.GetRuntime()));
  375. }
  376. private static object MakeQuoteConstant(object expr, Sympl symplRuntime) {
  377. if (expr is SymplListExpr) {
  378. SymplListExpr listexpr = (SymplListExpr)expr;
  379. int len = listexpr.Elements.Length;
  380. var exprs = new object[len];
  381. for (int i = 0; i < len; i++) {
  382. exprs[i] = MakeQuoteConstant(listexpr.Elements[i], symplRuntime);
  383. }
  384. return Cons._List(exprs);
  385. } else if (expr is IdOrKeywordToken) {
  386. return symplRuntime.MakeSymbol(((IdOrKeywordToken)expr).Name);
  387. } else if (expr is LiteralToken) {
  388. return ((LiteralToken)expr).Value;
  389. } else {
  390. throw new InvalidOperationException(
  391. "Internal: quoted list has -- " + expr.ToString());
  392. }
  393. }
  394. public static Expression AnalyzeEqExpr (SymplEqExpr expr,
  395. AnalysisScope scope) {
  396. var mi = typeof(RuntimeHelpers).GetMethod("SymplEq");
  397. return Expression.Call(mi, Expression.Convert(
  398. AnalyzeExpr(expr.Left, scope),
  399. typeof(object)),
  400. Expression.Convert(
  401. AnalyzeExpr(expr.Right, scope),
  402. typeof(object)));
  403. }
  404. public static Expression AnalyzeConsExpr (SymplConsExpr expr,
  405. AnalysisScope scope) {
  406. var mi = typeof(RuntimeHelpers).GetMethod("MakeCons");
  407. return Expression.Call(mi, Expression.Convert(
  408. AnalyzeExpr(expr.Left, scope),
  409. typeof(object)),
  410. Expression.Convert(
  411. AnalyzeExpr(expr.Right, scope),
  412. typeof(object)));
  413. }
  414. public static Expression AnalyzeListCallExpr (SymplListCallExpr expr,
  415. AnalysisScope scope) {
  416. var mi = typeof(Cons).GetMethod("_List");
  417. int len = expr.Elements.Length;
  418. var args = new Expression[len];
  419. for (int i = 0; i < len; i++) {
  420. args[i] = Expression.Convert(AnalyzeExpr(expr.Elements[i], scope),
  421. typeof(object));
  422. }
  423. return Expression.Call(mi, Expression
  424. .NewArrayInit(typeof(object), args));
  425. }
  426. public static Expression AnalyzeIfExpr (SymplIfExpr expr,
  427. AnalysisScope scope) {
  428. Expression alt = null;
  429. if (expr.Alternative != null) {
  430. alt = AnalyzeExpr(expr.Alternative, scope);
  431. } else {
  432. alt = Expression.Constant(false);
  433. }
  434. return Expression.Condition(
  435. WrapBooleanTest(AnalyzeExpr(expr.Test, scope)),
  436. Expression.Convert(AnalyzeExpr(expr.Consequent, scope),
  437. typeof(object)),
  438. Expression.Convert(alt, typeof(object)));
  439. }
  440. private static Expression WrapBooleanTest (Expression expr) {
  441. var tmp = Expression.Parameter(typeof(object), "testtmp");
  442. return Expression.Block(
  443. new ParameterExpression[] { tmp },
  444. new Expression[]
  445. {Expression.Assign(tmp, Expression
  446. .Convert(expr, typeof(object))),
  447. Expression.Condition(
  448. Expression.TypeIs(tmp, typeof(bool)),
  449. Expression.Convert(tmp, typeof(bool)),
  450. Expression.NotEqual(
  451. tmp,
  452. Expression.Constant(null, typeof(object))))});
  453. }
  454. public static Expression AnalyzeLoopExpr (SymplLoopExpr expr,
  455. AnalysisScope scope) {
  456. var loopscope = new AnalysisScope(scope, "loop ");
  457. loopscope.IsLoop = true; // needed for break and continue
  458. loopscope.LoopBreak = Expression.Label(typeof(object), "loop break");
  459. int len = expr.Body.Length;
  460. var body = new Expression[len];
  461. for (int i = 0; i < len; i++) {
  462. body[i] = AnalyzeExpr(expr.Body[i], loopscope);
  463. }
  464. return Expression.Loop(Expression.Block(typeof(object), body),
  465. loopscope.LoopBreak);
  466. }
  467. public static Expression AnalyzeBreakExpr (SymplBreakExpr expr,
  468. AnalysisScope scope) {
  469. var loopscope = _findFirstLoop(scope);
  470. if (loopscope == null)
  471. throw new InvalidOperationException(
  472. "Call to Break not inside loop.");
  473. Expression value;
  474. if (expr.Value == null)
  475. value = Expression.Constant(null, typeof(object));
  476. else
  477. // Ok if value jumps to break label.
  478. value = AnalyzeExpr(expr.Value, loopscope);
  479. // Need final type=object arg because the Goto is in a value returning
  480. // position, and the Break factory doesn't set the GotoExpr.Type property
  481. // to the type of the LoopBreak label target's type. For example, removing
  482. // this would cause the Convert to object for an If branch to throw because
  483. // the Goto is void without this last arg.
  484. return Expression.Break(loopscope.LoopBreak, value, typeof(object));
  485. }
  486. // _findFirstLoop returns the first loop AnalysisScope or None.
  487. //
  488. private static AnalysisScope _findFirstLoop (AnalysisScope scope) {
  489. var curscope = scope;
  490. while (curscope != null) {
  491. if (curscope.IsLoop)
  492. return curscope;
  493. else
  494. curscope = curscope.Parent;
  495. }
  496. return null;
  497. }
  498. public static Expression AnalyzeNewExpr(SymplNewExpr expr,
  499. AnalysisScope scope) {
  500. List<Expression> args = new List<Expression>();
  501. args.Add(AnalyzeExpr(expr.Type, scope));
  502. args.AddRange(expr.Arguments.Select(a => AnalyzeExpr(a, scope)));
  503. return Expression.Dynamic(
  504. scope.GetRuntime().GetCreateInstanceBinder(
  505. new CallInfo(expr.Arguments.Length)),
  506. typeof(object),
  507. args
  508. );
  509. }
  510. public static Expression AnalyzeBinaryExpr(SymplBinaryExpr expr,
  511. AnalysisScope scope) {
  512. // The language has the following special logic to handle And and Or
  513. // x And y == if x then y
  514. // x Or y == if x then x else (if y then y)
  515. if (expr.Operation == ExpressionType.And) {
  516. return AnalyzeIfExpr(
  517. new SymplIfExpr(
  518. expr.Left, expr.Right, null),
  519. scope);
  520. } else if (expr.Operation == ExpressionType.Or) {
  521. // Use (LetStar (tmp expr) (if tmp tmp)) to represent (if expr expr)
  522. // to remore duplicate evaluation.
  523. // So x Or y is translated into
  524. // (Let* (tmp1 x)
  525. // (If tmp1 tmp1
  526. // (Let* (tmp2 y) (If tmp2 tmp2))))
  527. //
  528. IdOrKeywordToken tmp2 = new IdOrKeywordToken(
  529. // Real implementation needs to ensure unique ID in scope chain.
  530. "__tmpLetVariable2");
  531. var tmpExpr2 = new SymplIdExpr(tmp2);
  532. var binding2 = new LetBinding(tmp2, expr.Right); ;
  533. var ifExpr2 = new SymplIfExpr(
  534. tmpExpr2, tmpExpr2, null);
  535. var letExpr2 = new SymplLetStarExpr(
  536. new[] { binding2 },
  537. new[] { ifExpr2 });
  538. IdOrKeywordToken tmp1 = new IdOrKeywordToken(
  539. // Real implementation needs to ensure unique ID in scope chain.
  540. "__tmpLetVariable1");
  541. var tmpExpr1 = new SymplIdExpr(tmp1);
  542. LetBinding binding1 = new LetBinding(tmp1, expr.Left); ;
  543. SymplExpr ifExpr1 = new SymplIfExpr(
  544. tmpExpr1, tmpExpr1, letExpr2);
  545. return AnalyzeLetStarExpr(
  546. new SymplLetStarExpr(
  547. new[] { binding1 },
  548. new[] { ifExpr1 }
  549. ),
  550. scope
  551. );
  552. }
  553. return Expression.Dynamic(
  554. scope.GetRuntime().GetBinaryOperationBinder(expr.Operation),
  555. typeof(object),
  556. AnalyzeExpr(expr.Left, scope),
  557. AnalyzeExpr(expr.Right, scope)
  558. );
  559. }
  560. public static Expression AnalyzeUnaryExpr(SymplUnaryExpr expr,
  561. AnalysisScope scope) {
  562. if (expr.Operation == ExpressionType.Not) {
  563. return Expression.Not(WrapBooleanTest(AnalyzeExpr(expr.Operand,
  564. scope)));
  565. }
  566. // Example purposes only, we should never get here since we only have Not.
  567. return Expression.Dynamic(
  568. scope.GetRuntime().GetUnaryOperationBinder(expr.Operation),
  569. typeof(object),
  570. AnalyzeExpr(expr.Operand, scope)
  571. );
  572. }
  573. // AnalyzeEltExpr returns and Expression for accessing an element of an
  574. // aggregate structure. This also works for .NET objs with indexer Item
  575. // properties. We handle analyzing Elt for assignment in AnalyzeAssignExpr.
  576. //
  577. public static Expression AnalyzeEltExpr(SymplEltExpr expr,
  578. AnalysisScope scope) {
  579. List<Expression> args = new List<Expression>();
  580. args.Add(AnalyzeExpr(expr.ObjectExpr, scope));
  581. args.AddRange(expr.Indexes.Select(e => AnalyzeExpr(e, scope)));
  582. return Expression.Dynamic(
  583. scope.GetRuntime().GetGetIndexBinder(
  584. new CallInfo(expr.Indexes.Length)),
  585. typeof(object),
  586. args
  587. );
  588. }
  589. } // ETGen
  590. // AnalysisScope holds identifier information so that we can do name binding
  591. // during analysis. It manages a map from names to ParameterExprs so ET
  592. // definition locations and reference locations can alias the same variable.
  593. //
  594. // These chain from inner most BlockExprs, through LambdaExprs, to the root
  595. // which models a file or top-level expression. The root has non-None
  596. // ModuleExpr and RuntimeExpr, which are ParameterExprs.
  597. //
  598. internal class AnalysisScope {
  599. private AnalysisScope _parent;
  600. private string _name;
  601. // Need runtime for interning Symbol constants at code gen time.
  602. private Sympl _runtime;
  603. private ParameterExpression _runtimeParam;
  604. private ParameterExpression _moduleParam;
  605. // Need IsLambda when support return to find tightest closing fun.
  606. private bool _isLambda = false;
  607. private bool _isLoop = false;
  608. private LabelTarget _loopBreak = null;
  609. //private LabelTarget _continueBreak = null;
  610. private Dictionary<string, ParameterExpression> _names;
  611. public AnalysisScope(AnalysisScope parent, string name)
  612. : this(parent, name, null, null, null) { }
  613. public AnalysisScope(AnalysisScope parent,
  614. string name,
  615. Sympl runtime,
  616. ParameterExpression runtimeParam,
  617. ParameterExpression moduleParam) {
  618. _parent = parent;
  619. _name = name;
  620. _runtime = runtime;
  621. _runtimeParam = runtimeParam;
  622. _moduleParam = moduleParam;
  623. _names = new Dictionary<string, ParameterExpression>();
  624. _isLambda = false;
  625. }
  626. public AnalysisScope Parent { get { return _parent; } }
  627. public ParameterExpression ModuleExpr { get { return _moduleParam; } }
  628. public ParameterExpression RuntimeExpr { get { return _runtimeParam; } }
  629. public Sympl Runtime { get { return _runtime; } }
  630. public bool IsModule { get { return _moduleParam != null; } }
  631. public bool IsLambda {
  632. get { return _isLambda; }
  633. set { _isLambda = value; }
  634. }
  635. public bool IsLoop {
  636. get { return _isLoop; }
  637. set { _isLoop = value; }
  638. }
  639. public LabelTarget LoopBreak {
  640. get { return _loopBreak; }
  641. set { _loopBreak = value; }
  642. }
  643. public LabelTarget LoopContinue {
  644. get { return _loopBreak; }
  645. set { _loopBreak = value; }
  646. }
  647. public Dictionary<string, ParameterExpression> Names {
  648. get { return _names; }
  649. set { _names = value; }
  650. }
  651. public ParameterExpression GetModuleExpr() {
  652. var curScope = this;
  653. while (!curScope.IsModule) {
  654. curScope = curScope.Parent;
  655. }
  656. return curScope.ModuleExpr;
  657. }
  658. public Sympl GetRuntime() {
  659. var curScope = this;
  660. while (curScope.Runtime == null) {
  661. curScope = curScope.Parent;
  662. }
  663. return curScope.Runtime;
  664. }
  665. } //AnalysisScope
  666. } // Namespace