ExpressionIntepreter.cs 37 KB

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