ExpressionIntepreter.cs 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. using System;
  2. using System.Linq;
  3. using Jint.Native;
  4. using Jint.Native.Function;
  5. using Jint.Native.Number;
  6. using Jint.Native.Object;
  7. using Jint.Parser.Ast;
  8. using Jint.Runtime.Descriptors;
  9. using Jint.Runtime.Environments;
  10. using Jint.Runtime.Interop;
  11. using Jint.Runtime.References;
  12. namespace Jint.Runtime
  13. {
  14. public class ExpressionInterpreter
  15. {
  16. private readonly Engine _engine;
  17. public ExpressionInterpreter(Engine engine)
  18. {
  19. _engine = engine;
  20. }
  21. private object EvaluateExpression(Expression expression)
  22. {
  23. return _engine.EvaluateExpression(expression);
  24. }
  25. public JsValue EvaluateConditionalExpression(ConditionalExpression conditionalExpression)
  26. {
  27. var lref = _engine.EvaluateExpression(conditionalExpression.Test);
  28. if (TypeConverter.ToBoolean(_engine.GetValue(lref)))
  29. {
  30. var trueRef = _engine.EvaluateExpression(conditionalExpression.Consequent);
  31. return _engine.GetValue(trueRef);
  32. }
  33. else
  34. {
  35. var falseRef = _engine.EvaluateExpression(conditionalExpression.Alternate);
  36. return _engine.GetValue(falseRef);
  37. }
  38. }
  39. public JsValue EvaluateAssignmentExpression(AssignmentExpression assignmentExpression)
  40. {
  41. var lref = EvaluateExpression(assignmentExpression.Left) as Reference;
  42. JsValue rval = _engine.GetValue(EvaluateExpression(assignmentExpression.Right));
  43. if (lref == null)
  44. {
  45. throw new JavaScriptException(_engine.ReferenceError);
  46. }
  47. if (assignmentExpression.Operator == AssignmentOperator.Assign) // "="
  48. {
  49. if(lref.IsStrict() && lref.GetBase().TryCast<EnvironmentRecord>() != null && (lref.GetReferencedName() == "eval" || lref.GetReferencedName() == "arguments"))
  50. {
  51. throw new JavaScriptException(_engine.SyntaxError);
  52. }
  53. _engine.PutValue(lref, rval);
  54. return rval;
  55. }
  56. JsValue lval = _engine.GetValue(lref);
  57. switch (assignmentExpression.Operator)
  58. {
  59. case AssignmentOperator.PlusAssign:
  60. var lprim = TypeConverter.ToPrimitive(lval);
  61. var rprim = TypeConverter.ToPrimitive(rval);
  62. if (lprim.IsString() || rprim.IsString())
  63. {
  64. lval = TypeConverter.ToString(lprim) + TypeConverter.ToString(rprim);
  65. }
  66. else
  67. {
  68. lval = TypeConverter.ToNumber(lprim) + TypeConverter.ToNumber(rprim);
  69. }
  70. break;
  71. case AssignmentOperator.MinusAssign:
  72. lval = TypeConverter.ToNumber(lval) - TypeConverter.ToNumber(rval);
  73. break;
  74. case AssignmentOperator.TimesAssign:
  75. if (lval == Undefined.Instance || rval == Undefined.Instance)
  76. {
  77. lval = Undefined.Instance;
  78. }
  79. else
  80. {
  81. lval = TypeConverter.ToNumber(lval) * TypeConverter.ToNumber(rval);
  82. }
  83. break;
  84. case AssignmentOperator.DivideAssign:
  85. lval = Divide(lval, rval);
  86. break;
  87. case AssignmentOperator.ModuloAssign:
  88. if (lval == Undefined.Instance || rval == Undefined.Instance)
  89. {
  90. lval = Undefined.Instance;
  91. }
  92. else
  93. {
  94. lval = TypeConverter.ToNumber(lval) % TypeConverter.ToNumber(rval);
  95. }
  96. break;
  97. case AssignmentOperator.BitwiseAndAssign:
  98. lval = TypeConverter.ToInt32(lval) & TypeConverter.ToInt32(rval);
  99. break;
  100. case AssignmentOperator.BitwiseOrAssign:
  101. lval = TypeConverter.ToInt32(lval) | TypeConverter.ToInt32(rval);
  102. break;
  103. case AssignmentOperator.BitwiseXOrAssign:
  104. lval = TypeConverter.ToInt32(lval) ^ TypeConverter.ToInt32(rval);
  105. break;
  106. case AssignmentOperator.LeftShiftAssign:
  107. lval = TypeConverter.ToInt32(lval) << (int)(TypeConverter.ToUint32(rval) & 0x1F);
  108. break;
  109. case AssignmentOperator.RightShiftAssign:
  110. lval = TypeConverter.ToInt32(lval) >> (int)(TypeConverter.ToUint32(rval) & 0x1F);
  111. break;
  112. case AssignmentOperator.UnsignedRightShiftAssign:
  113. lval = (uint)TypeConverter.ToInt32(lval) >> (int)(TypeConverter.ToUint32(rval) & 0x1F);
  114. break;
  115. default:
  116. throw new NotImplementedException();
  117. }
  118. _engine.PutValue(lref, lval);
  119. return lval;
  120. }
  121. private JsValue Divide(JsValue lval, JsValue rval)
  122. {
  123. if (lval == Undefined.Instance || rval == Undefined.Instance)
  124. {
  125. return Undefined.Instance;
  126. }
  127. else
  128. {
  129. var lN = TypeConverter.ToNumber(lval);
  130. var rN = TypeConverter.ToNumber(rval);
  131. if (double.IsNaN(rN) || double.IsNaN(lN))
  132. {
  133. return double.NaN;
  134. }
  135. if (double.IsInfinity(lN) && double.IsInfinity(rN))
  136. {
  137. return double.NaN;
  138. }
  139. if (double.IsInfinity(lN) && rN.Equals(0))
  140. {
  141. if (NumberInstance.IsNegativeZero(rN))
  142. {
  143. return -lN;
  144. }
  145. return lN;
  146. }
  147. if (lN.Equals(0) && rN.Equals(0))
  148. {
  149. return double.NaN;
  150. }
  151. if (rN.Equals(0))
  152. {
  153. if (NumberInstance.IsNegativeZero(rN))
  154. {
  155. return lN > 0 ? -double.PositiveInfinity : -double.NegativeInfinity;
  156. }
  157. return lN > 0 ? double.PositiveInfinity : double.NegativeInfinity;
  158. }
  159. return lN/rN;
  160. }
  161. }
  162. public JsValue EvaluateBinaryExpression(BinaryExpression expression)
  163. {
  164. var leftExpression = EvaluateExpression(expression.Left);
  165. JsValue left = _engine.GetValue(leftExpression);
  166. var rightExpression = EvaluateExpression(expression.Right);
  167. JsValue right = _engine.GetValue(rightExpression);
  168. JsValue value;
  169. switch (expression.Operator)
  170. {
  171. case BinaryOperator.Plus:
  172. var lprim = TypeConverter.ToPrimitive(left);
  173. var rprim = TypeConverter.ToPrimitive(right);
  174. if (lprim.IsString() || rprim.IsString())
  175. {
  176. value = TypeConverter.ToString(lprim) + TypeConverter.ToString(rprim);
  177. }
  178. else
  179. {
  180. value = TypeConverter.ToNumber(lprim) + TypeConverter.ToNumber(rprim);
  181. }
  182. break;
  183. case BinaryOperator.Minus:
  184. value = TypeConverter.ToNumber(left) - TypeConverter.ToNumber(right);
  185. break;
  186. case BinaryOperator.Times:
  187. if (left == Undefined.Instance || right == Undefined.Instance)
  188. {
  189. value = Undefined.Instance;
  190. }
  191. else
  192. {
  193. value = TypeConverter.ToNumber(left) * TypeConverter.ToNumber(right);
  194. }
  195. break;
  196. case BinaryOperator.Divide:
  197. value = Divide(left, right);
  198. break;
  199. case BinaryOperator.Modulo:
  200. if (left == Undefined.Instance || right == Undefined.Instance)
  201. {
  202. value = Undefined.Instance;
  203. }
  204. else
  205. {
  206. value = TypeConverter.ToNumber(left) % TypeConverter.ToNumber(right);
  207. }
  208. break;
  209. case BinaryOperator.Equal:
  210. value = Equal(left, right);
  211. break;
  212. case BinaryOperator.NotEqual:
  213. value = !Equal(left, right);
  214. break;
  215. case BinaryOperator.Greater:
  216. value = Compare(right, left, false);
  217. if (value == Undefined.Instance)
  218. {
  219. value = false;
  220. }
  221. break;
  222. case BinaryOperator.GreaterOrEqual:
  223. value = Compare(left, right);
  224. if (value == Undefined.Instance || value.AsBoolean())
  225. {
  226. value = false;
  227. }
  228. else
  229. {
  230. value = true;
  231. }
  232. break;
  233. case BinaryOperator.Less:
  234. value = Compare(left, right);
  235. if (value == Undefined.Instance)
  236. {
  237. value = false;
  238. }
  239. break;
  240. case BinaryOperator.LessOrEqual:
  241. value = Compare(right, left, false);
  242. if (value == Undefined.Instance || value.AsBoolean())
  243. {
  244. value = false;
  245. }
  246. else
  247. {
  248. value = true;
  249. }
  250. break;
  251. case BinaryOperator.StrictlyEqual:
  252. return StrictlyEqual(left, right);
  253. case BinaryOperator.StricltyNotEqual:
  254. return !StrictlyEqual(left, right);
  255. case BinaryOperator.BitwiseAnd:
  256. return TypeConverter.ToInt32(left) & TypeConverter.ToInt32(right);
  257. case BinaryOperator.BitwiseOr:
  258. return TypeConverter.ToInt32(left) | TypeConverter.ToInt32(right);
  259. case BinaryOperator.BitwiseXOr:
  260. return TypeConverter.ToInt32(left) ^ TypeConverter.ToInt32(right);
  261. case BinaryOperator.LeftShift:
  262. return TypeConverter.ToInt32(left) << (int)(TypeConverter.ToUint32(right) & 0x1F);
  263. case BinaryOperator.RightShift:
  264. return TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F);
  265. case BinaryOperator.UnsignedRightShift:
  266. return (uint)TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F);
  267. case BinaryOperator.InstanceOf:
  268. var f = right.TryCast<FunctionInstance>();
  269. if (f == null)
  270. {
  271. throw new JavaScriptException(_engine.TypeError, "instanceof can only be used with a function object");
  272. }
  273. value = f.HasInstance(left);
  274. break;
  275. case BinaryOperator.In:
  276. if (!right.IsObject())
  277. {
  278. throw new JavaScriptException(_engine.TypeError, "in can only be used with an object");
  279. }
  280. value = right.AsObject().HasProperty(TypeConverter.ToString(left));
  281. break;
  282. default:
  283. throw new NotImplementedException();
  284. }
  285. return value;
  286. }
  287. public JsValue EvaluateLogicalExpression(LogicalExpression logicalExpression)
  288. {
  289. var left = _engine.GetValue(EvaluateExpression(logicalExpression.Left));
  290. switch (logicalExpression.Operator)
  291. {
  292. case LogicalOperator.LogicalAnd:
  293. if (!TypeConverter.ToBoolean(left))
  294. {
  295. return left;
  296. }
  297. return _engine.GetValue(EvaluateExpression(logicalExpression.Right));
  298. case LogicalOperator.LogicalOr:
  299. if (TypeConverter.ToBoolean(left))
  300. {
  301. return left;
  302. }
  303. return _engine.GetValue(EvaluateExpression(logicalExpression.Right));
  304. default:
  305. throw new NotImplementedException();
  306. }
  307. }
  308. public static bool Equal(JsValue x, JsValue y)
  309. {
  310. var typex = x.Type;
  311. var typey = y.Type;
  312. if (typex == typey)
  313. {
  314. return StrictlyEqual(x, y);
  315. }
  316. if (x == Null.Instance && y == Undefined.Instance)
  317. {
  318. return true;
  319. }
  320. if (x == Undefined.Instance && y == Null.Instance)
  321. {
  322. return true;
  323. }
  324. if (typex == Types.Number && typey == Types.String)
  325. {
  326. return Equal(x, TypeConverter.ToNumber(y));
  327. }
  328. if (typex == Types.String && typey == Types.Number)
  329. {
  330. return Equal(TypeConverter.ToNumber(x), y);
  331. }
  332. if (typex == Types.Boolean)
  333. {
  334. return Equal(TypeConverter.ToNumber(x), y);
  335. }
  336. if (typey == Types.Boolean)
  337. {
  338. return Equal(x, TypeConverter.ToNumber(y));
  339. }
  340. if (typey == Types.Object && (typex == Types.String || typex == Types.Number))
  341. {
  342. return Equal(x, TypeConverter.ToPrimitive(y));
  343. }
  344. if (typex == Types.Object && (typey == Types.String || typey == Types.Number))
  345. {
  346. return Equal(TypeConverter.ToPrimitive(x), y);
  347. }
  348. return false;
  349. }
  350. public static bool StrictlyEqual(JsValue x, JsValue y)
  351. {
  352. var typea = x.Type;
  353. var typeb = y.Type;
  354. if (typea != typeb)
  355. {
  356. return false;
  357. }
  358. if (typea == Types.Undefined || typea == Types.Null)
  359. {
  360. return true;
  361. }
  362. if (typea == Types.None)
  363. {
  364. return true;
  365. }
  366. if (typea == Types.Number)
  367. {
  368. var nx = x.AsNumber();
  369. var ny = y.AsNumber();
  370. if (double.IsNaN(nx) || double.IsNaN(ny))
  371. {
  372. return false;
  373. }
  374. if (nx.Equals(ny))
  375. {
  376. return true;
  377. }
  378. return false;
  379. }
  380. if (typea == Types.String)
  381. {
  382. return x.AsString() == y.AsString();
  383. }
  384. if (typea == Types.Boolean)
  385. {
  386. return x.AsBoolean() == y.AsBoolean();
  387. }
  388. if (typea == Types.Object)
  389. {
  390. var xw = x.AsObject() as IObjectWrapper;
  391. if (xw != null)
  392. {
  393. var yw = y.AsObject() as IObjectWrapper;
  394. return Object.Equals(xw.Target, yw.Target);
  395. }
  396. }
  397. return x == y;
  398. }
  399. public static bool SameValue(JsValue x, JsValue y)
  400. {
  401. var typea = TypeConverter.GetPrimitiveType(x);
  402. var typeb = TypeConverter.GetPrimitiveType(y);
  403. if (typea != typeb)
  404. {
  405. return false;
  406. }
  407. if (typea == Types.None)
  408. {
  409. return true;
  410. }
  411. if (typea == Types.Number)
  412. {
  413. var nx = TypeConverter.ToNumber(x);
  414. var ny = TypeConverter.ToNumber(y);
  415. if (double.IsNaN(nx) && double.IsNaN(ny))
  416. {
  417. return true;
  418. }
  419. if (nx.Equals(ny))
  420. {
  421. if (nx.Equals(0))
  422. {
  423. // +0 !== -0
  424. return NumberInstance.IsNegativeZero(nx) == NumberInstance.IsNegativeZero(ny);
  425. }
  426. return true;
  427. }
  428. return false;
  429. }
  430. if (typea == Types.String)
  431. {
  432. return TypeConverter.ToString(x) == TypeConverter.ToString(y);
  433. }
  434. if (typea == Types.Boolean)
  435. {
  436. return TypeConverter.ToBoolean(x) == TypeConverter.ToBoolean(y);
  437. }
  438. return x == y;
  439. }
  440. public static JsValue Compare(JsValue x, JsValue y, bool leftFirst = true)
  441. {
  442. JsValue px, py;
  443. if (leftFirst)
  444. {
  445. px = TypeConverter.ToPrimitive(x, Types.Number);
  446. py = TypeConverter.ToPrimitive(y, Types.Number);
  447. }
  448. else
  449. {
  450. py = TypeConverter.ToPrimitive(y, Types.Number);
  451. px = TypeConverter.ToPrimitive(x, Types.Number);
  452. }
  453. var typea = px.Type;
  454. var typeb = py.Type;
  455. if (typea != Types.String || typeb != Types.String)
  456. {
  457. var nx = TypeConverter.ToNumber(px);
  458. var ny = TypeConverter.ToNumber(py);
  459. if (double.IsNaN(nx) || double.IsNaN(ny))
  460. {
  461. return Undefined.Instance;
  462. }
  463. if (nx.Equals(ny))
  464. {
  465. return false;
  466. }
  467. if (double.IsPositiveInfinity(nx))
  468. {
  469. return false;
  470. }
  471. if (double.IsPositiveInfinity(ny))
  472. {
  473. return true;
  474. }
  475. if (double.IsNegativeInfinity(ny))
  476. {
  477. return false;
  478. }
  479. if (double.IsNegativeInfinity(nx))
  480. {
  481. return true;
  482. }
  483. return nx < ny;
  484. }
  485. else
  486. {
  487. return String.CompareOrdinal(TypeConverter.ToString(x), TypeConverter.ToString(y)) < 0;
  488. }
  489. }
  490. public Reference EvaluateIdentifier(Identifier identifier)
  491. {
  492. var env = _engine.ExecutionContext.LexicalEnvironment;
  493. var strict = StrictModeScope.IsStrictModeCode;
  494. return LexicalEnvironment.GetIdentifierReference(env, identifier.Name, strict);
  495. }
  496. public JsValue EvaluateLiteral(Literal literal)
  497. {
  498. if(literal.Cached)
  499. {
  500. return literal.CachedValue;
  501. }
  502. if (literal.Type == SyntaxNodes.RegularExpressionLiteral)
  503. {
  504. var regexp = _engine.RegExp.Construct(literal.Raw);
  505. if (regexp.Global)
  506. {
  507. // A Global regexp literal can't be cached or its state would evolve
  508. return regexp;
  509. }
  510. literal.CachedValue = regexp;
  511. }
  512. else
  513. {
  514. literal.CachedValue = JsValue.FromObject(_engine, literal.Value);
  515. }
  516. literal.Cached = true;
  517. return literal.CachedValue;
  518. }
  519. public JsValue EvaluateObjectExpression(ObjectExpression objectExpression)
  520. {
  521. // http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5
  522. var obj = _engine.Object.Construct(Arguments.Empty);
  523. foreach (var property in objectExpression.Properties)
  524. {
  525. var propName = property.Key.GetKey();
  526. var previous = obj.GetOwnProperty(propName);
  527. PropertyDescriptor propDesc;
  528. switch (property.Kind)
  529. {
  530. case PropertyKind.Data:
  531. var exprValue = _engine.EvaluateExpression(property.Value);
  532. var propValue = _engine.GetValue(exprValue);
  533. propDesc = new PropertyDescriptor(propValue, true, true, true);
  534. break;
  535. case PropertyKind.Get:
  536. var getter = property.Value as FunctionExpression;
  537. if (getter == null)
  538. {
  539. throw new JavaScriptException(_engine.SyntaxError);
  540. }
  541. ScriptFunctionInstance get;
  542. using (new StrictModeScope(getter.Strict))
  543. {
  544. get = new ScriptFunctionInstance(
  545. _engine,
  546. getter,
  547. _engine.ExecutionContext.LexicalEnvironment,
  548. StrictModeScope.IsStrictModeCode
  549. );
  550. }
  551. propDesc = new PropertyDescriptor(get: get, set: null, enumerable: true, configurable:true);
  552. break;
  553. case PropertyKind.Set:
  554. var setter = property.Value as FunctionExpression;
  555. if (setter == null)
  556. {
  557. throw new JavaScriptException(_engine.SyntaxError);
  558. }
  559. ScriptFunctionInstance set;
  560. using (new StrictModeScope(setter.Strict))
  561. {
  562. set = new ScriptFunctionInstance(
  563. _engine,
  564. setter,
  565. _engine.ExecutionContext.LexicalEnvironment,
  566. StrictModeScope.IsStrictModeCode
  567. );
  568. }
  569. propDesc = new PropertyDescriptor(get:null, set: set, enumerable: true, configurable: true);
  570. break;
  571. default:
  572. throw new ArgumentOutOfRangeException();
  573. }
  574. if (previous != PropertyDescriptor.Undefined)
  575. {
  576. if (StrictModeScope.IsStrictModeCode && previous.IsDataDescriptor() && propDesc.IsDataDescriptor())
  577. {
  578. throw new JavaScriptException(_engine.SyntaxError);
  579. }
  580. if (previous.IsDataDescriptor() && propDesc.IsAccessorDescriptor())
  581. {
  582. throw new JavaScriptException(_engine.SyntaxError);
  583. }
  584. if (previous.IsAccessorDescriptor() && propDesc.IsDataDescriptor())
  585. {
  586. throw new JavaScriptException(_engine.SyntaxError);
  587. }
  588. if (previous.IsAccessorDescriptor() && propDesc.IsAccessorDescriptor())
  589. {
  590. if (propDesc.Set != null && previous.Set != null)
  591. {
  592. throw new JavaScriptException(_engine.SyntaxError);
  593. }
  594. if (propDesc.Get != null && previous.Get != null)
  595. {
  596. throw new JavaScriptException(_engine.SyntaxError);
  597. }
  598. }
  599. }
  600. obj.DefineOwnProperty(propName, propDesc, false);
  601. }
  602. return obj;
  603. }
  604. /// <summary>
  605. /// http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.1
  606. /// </summary>
  607. /// <param name="memberExpression"></param>
  608. /// <returns></returns>
  609. public Reference EvaluateMemberExpression(MemberExpression memberExpression)
  610. {
  611. var baseReference = EvaluateExpression(memberExpression.Object);
  612. var baseValue = _engine.GetValue(baseReference);
  613. Expression expression = memberExpression.Property;
  614. if (!memberExpression.Computed) // index accessor ?
  615. {
  616. expression = new Literal { Type = SyntaxNodes.Literal, Value = memberExpression.Property.As<Identifier>().Name };
  617. }
  618. var propertyNameReference = EvaluateExpression(expression);
  619. var propertyNameValue = _engine.GetValue(propertyNameReference);
  620. TypeConverter.CheckObjectCoercible(_engine, baseValue, memberExpression, baseReference);
  621. var propertyNameString = TypeConverter.ToString(propertyNameValue);
  622. return new Reference(baseValue, propertyNameString, StrictModeScope.IsStrictModeCode);
  623. }
  624. public JsValue EvaluateFunctionExpression(FunctionExpression functionExpression)
  625. {
  626. var funcEnv = LexicalEnvironment.NewDeclarativeEnvironment(_engine, _engine.ExecutionContext.LexicalEnvironment);
  627. var envRec = (DeclarativeEnvironmentRecord)funcEnv.Record;
  628. if (functionExpression.Id != null && !String.IsNullOrEmpty(functionExpression.Id.Name))
  629. {
  630. envRec.CreateMutableBinding(functionExpression.Id.Name);
  631. }
  632. var closure = new ScriptFunctionInstance(
  633. _engine,
  634. functionExpression,
  635. funcEnv,
  636. functionExpression.Strict
  637. );
  638. if (functionExpression.Id != null && !String.IsNullOrEmpty(functionExpression.Id.Name))
  639. {
  640. envRec.InitializeImmutableBinding(functionExpression.Id.Name, closure);
  641. }
  642. return closure;
  643. }
  644. public JsValue EvaluateCallExpression(CallExpression callExpression)
  645. {
  646. var callee = EvaluateExpression(callExpression.Callee);
  647. if (_engine.Options._IsDebugMode)
  648. {
  649. _engine.DebugHandler.AddToDebugCallStack(callExpression);
  650. }
  651. JsValue thisObject;
  652. // todo: implement as in http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
  653. JsValue[] arguments;
  654. if (callExpression.Cached)
  655. {
  656. arguments = callExpression.CachedArguments;
  657. }
  658. else
  659. {
  660. arguments = callExpression.Arguments.Select(EvaluateExpression).Select(_engine.GetValue).ToArray();
  661. if (callExpression.CanBeCached)
  662. {
  663. // The arguments array can be cached if they are all literals
  664. if (callExpression.Arguments.All(x => x is Literal))
  665. {
  666. callExpression.CachedArguments = arguments;
  667. callExpression.Cached = true;
  668. }
  669. else
  670. {
  671. callExpression.CanBeCached = false;
  672. }
  673. }
  674. }
  675. var func = _engine.GetValue(callee);
  676. var r = callee as Reference;
  677. if (_engine.Options._MaxRecursionDepth >= 0)
  678. {
  679. var stackItem = new CallStackElement(callExpression, func, r != null ? r.GetReferencedName() : "anonymous function");
  680. var recursionDepth = _engine.CallStack.Push(stackItem);
  681. if (recursionDepth > _engine.Options._MaxRecursionDepth)
  682. {
  683. _engine.CallStack.Pop();
  684. throw new RecursionDepthOverflowException(_engine.CallStack, stackItem.ToString());
  685. }
  686. }
  687. if (func == Undefined.Instance)
  688. {
  689. throw new JavaScriptException(_engine.TypeError, r == null ? "" : string.Format("Object has no method '{0}'", r.GetReferencedName()));
  690. }
  691. if (!func.IsObject())
  692. {
  693. if (_engine.Options._ReferenceResolver == null ||
  694. !_engine.Options._ReferenceResolver.TryGetCallable(_engine, callee, out func))
  695. {
  696. throw new JavaScriptException(_engine.TypeError,
  697. r == null ? "" : string.Format("Property '{0}' of object is not a function", r.GetReferencedName()));
  698. }
  699. }
  700. var callable = func.TryCast<ICallable>();
  701. if (callable == null)
  702. {
  703. throw new JavaScriptException(_engine.TypeError);
  704. }
  705. if (r != null)
  706. {
  707. if (r.IsPropertyReference())
  708. {
  709. thisObject = r.GetBase();
  710. }
  711. else
  712. {
  713. var env = r.GetBase().TryCast<EnvironmentRecord>();
  714. thisObject = env.ImplicitThisValue();
  715. }
  716. }
  717. else
  718. {
  719. thisObject = Undefined.Instance;
  720. }
  721. // is it a direct call to eval ? http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.1.1
  722. if (r != null && r.GetReferencedName() == "eval" && callable is EvalFunctionInstance)
  723. {
  724. return ((EvalFunctionInstance) callable).Call(thisObject, arguments, true);
  725. }
  726. var result = callable.Call(thisObject, arguments);
  727. if (_engine.Options._IsDebugMode)
  728. {
  729. _engine.DebugHandler.PopDebugCallStack();
  730. }
  731. if (_engine.Options._MaxRecursionDepth >= 0)
  732. {
  733. _engine.CallStack.Pop();
  734. }
  735. return result;
  736. }
  737. public JsValue EvaluateSequenceExpression(SequenceExpression sequenceExpression)
  738. {
  739. var result = Undefined.Instance;
  740. foreach (var expression in sequenceExpression.Expressions)
  741. {
  742. result = _engine.GetValue(_engine.EvaluateExpression(expression));
  743. }
  744. return result;
  745. }
  746. public JsValue EvaluateUpdateExpression(UpdateExpression updateExpression)
  747. {
  748. var value = _engine.EvaluateExpression(updateExpression.Argument);
  749. Reference r;
  750. switch (updateExpression.Operator)
  751. {
  752. case UnaryOperator.Increment:
  753. r = value as Reference;
  754. if (r != null
  755. && r.IsStrict()
  756. && (r.GetBase().TryCast<EnvironmentRecord>() != null)
  757. && (Array.IndexOf(new[] { "eval", "arguments" }, r.GetReferencedName()) != -1))
  758. {
  759. throw new JavaScriptException(_engine.SyntaxError);
  760. }
  761. var oldValue = TypeConverter.ToNumber(_engine.GetValue(value));
  762. var newValue = oldValue + 1;
  763. _engine.PutValue(r, newValue);
  764. return updateExpression.Prefix ? newValue : oldValue;
  765. case UnaryOperator.Decrement:
  766. r = value as Reference;
  767. if (r != null
  768. && r.IsStrict()
  769. && (r.GetBase().TryCast<EnvironmentRecord>() != null)
  770. && (Array.IndexOf(new[] { "eval", "arguments" }, r.GetReferencedName()) != -1))
  771. {
  772. throw new JavaScriptException(_engine.SyntaxError);
  773. }
  774. oldValue = TypeConverter.ToNumber(_engine.GetValue(value));
  775. newValue = oldValue - 1;
  776. _engine.PutValue(r, newValue);
  777. return updateExpression.Prefix ? newValue : oldValue;
  778. default:
  779. throw new ArgumentException();
  780. }
  781. }
  782. public JsValue EvaluateThisExpression(ThisExpression thisExpression)
  783. {
  784. return _engine.ExecutionContext.ThisBinding;
  785. }
  786. public JsValue EvaluateNewExpression(NewExpression newExpression)
  787. {
  788. var arguments = newExpression.Arguments.Select(EvaluateExpression).Select(_engine.GetValue).ToArray();
  789. // todo: optimize by defining a common abstract class or interface
  790. var callee = _engine.GetValue(EvaluateExpression(newExpression.Callee)).TryCast<IConstructor>();
  791. if (callee == null)
  792. {
  793. throw new JavaScriptException(_engine.TypeError, "The object can't be used as constructor.");
  794. }
  795. // construct the new instance using the Function's constructor method
  796. var instance = callee.Construct(arguments);
  797. return instance;
  798. }
  799. public JsValue EvaluateArrayExpression(ArrayExpression arrayExpression)
  800. {
  801. var a = _engine.Array.Construct(new JsValue[] { arrayExpression.Elements.Count() });
  802. var n = 0;
  803. foreach (var expr in arrayExpression.Elements)
  804. {
  805. if (expr != null)
  806. {
  807. var value = _engine.GetValue(EvaluateExpression(expr));
  808. a.DefineOwnProperty(n.ToString(),
  809. new PropertyDescriptor(value, true, true, true), false);
  810. }
  811. n++;
  812. }
  813. return a;
  814. }
  815. public JsValue EvaluateUnaryExpression(UnaryExpression unaryExpression)
  816. {
  817. var value = _engine.EvaluateExpression(unaryExpression.Argument);
  818. Reference r;
  819. switch (unaryExpression.Operator)
  820. {
  821. case UnaryOperator.Plus:
  822. return TypeConverter.ToNumber(_engine.GetValue(value));
  823. case UnaryOperator.Minus:
  824. var n = TypeConverter.ToNumber(_engine.GetValue(value));
  825. return double.IsNaN(n) ? double.NaN : n*-1;
  826. case UnaryOperator.BitwiseNot:
  827. return ~TypeConverter.ToInt32(_engine.GetValue(value));
  828. case UnaryOperator.LogicalNot:
  829. return !TypeConverter.ToBoolean(_engine.GetValue(value));
  830. case UnaryOperator.Delete:
  831. r = value as Reference;
  832. if (r == null)
  833. {
  834. return true;
  835. }
  836. if (r.IsUnresolvableReference())
  837. {
  838. if (r.IsStrict())
  839. {
  840. throw new JavaScriptException(_engine.SyntaxError);
  841. }
  842. return true;
  843. }
  844. if (r.IsPropertyReference())
  845. {
  846. var o = TypeConverter.ToObject(_engine, r.GetBase());
  847. return o.Delete(r.GetReferencedName(), r.IsStrict());
  848. }
  849. if (r.IsStrict())
  850. {
  851. throw new JavaScriptException(_engine.SyntaxError);
  852. }
  853. var bindings = r.GetBase().TryCast<EnvironmentRecord>();
  854. return bindings.DeleteBinding(r.GetReferencedName());
  855. case UnaryOperator.Void:
  856. _engine.GetValue(value);
  857. return Undefined.Instance;
  858. case UnaryOperator.TypeOf:
  859. r = value as Reference;
  860. if (r != null)
  861. {
  862. if (r.IsUnresolvableReference())
  863. {
  864. return "undefined";
  865. }
  866. }
  867. var v = _engine.GetValue(value);
  868. if (v == Undefined.Instance)
  869. {
  870. return "undefined";
  871. }
  872. if (v == Null.Instance)
  873. {
  874. return "object";
  875. }
  876. switch (v.Type)
  877. {
  878. case Types.Boolean: return "boolean";
  879. case Types.Number: return "number";
  880. case Types.String: return "string";
  881. }
  882. if (v.TryCast<ICallable>() != null)
  883. {
  884. return "function";
  885. }
  886. return "object";
  887. default:
  888. throw new ArgumentException();
  889. }
  890. }
  891. }
  892. }