ExpressionIntepreter.cs 36 KB

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