2
0

ExpressionIntepreter.cs 34 KB

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