ExpressionIntepreter.cs 34 KB

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