ExpressionIntepreter.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. using System;
  2. using System.Linq;
  3. using Jint.Native;
  4. using Jint.Native.Errors;
  5. using Jint.Native.Function;
  6. using Jint.Parser.Ast;
  7. using Jint.Runtime.Descriptors;
  8. using Jint.Runtime.Environments;
  9. using Jint.Runtime.References;
  10. namespace Jint.Runtime
  11. {
  12. public class ExpressionInterpreter
  13. {
  14. private readonly Engine _engine;
  15. public ExpressionInterpreter(Engine engine)
  16. {
  17. _engine = engine;
  18. }
  19. private object EvaluateExpression(Expression expression)
  20. {
  21. return _engine.EvaluateExpression(expression);
  22. }
  23. public object EvaluateConditionalExpression(ConditionalExpression conditionalExpression)
  24. {
  25. var test = _engine.EvaluateExpression(conditionalExpression.Test);
  26. var evaluate = TypeConverter.ToBoolean(test) ? conditionalExpression.Consequent : conditionalExpression.Alternate;
  27. return _engine.EvaluateExpression(evaluate);
  28. }
  29. public object EvaluateAssignmentExpression(AssignmentExpression assignmentExpression)
  30. {
  31. object rval = _engine.GetValue(EvaluateExpression(assignmentExpression.Right));
  32. var lref = EvaluateExpression(assignmentExpression.Left) as Reference;
  33. if (assignmentExpression.Operator == "=")
  34. {
  35. if(lref != null && lref.IsStrict() && lref.GetBase() is EnvironmentRecord && (lref.GetReferencedName() == "eval" || lref.GetReferencedName() == "arguments"))
  36. {
  37. throw new SyntaxError();
  38. }
  39. _engine.PutValue(lref, rval);
  40. return rval;
  41. }
  42. object lval = _engine.GetValue(lref);
  43. var type = TypeConverter.GetType(lval);
  44. switch (assignmentExpression.Operator)
  45. {
  46. case "+=":
  47. switch (type)
  48. {
  49. case TypeCode.String:
  50. lval = TypeConverter.ToString(_engine.GetValue(lref)) + rval;
  51. break;
  52. case TypeCode.Double:
  53. lval = TypeConverter.ToNumber(_engine.GetValue(lref)) + TypeConverter.ToNumber(rval);
  54. break;
  55. }
  56. break;
  57. case "-=":
  58. switch (type)
  59. {
  60. case TypeCode.Double:
  61. lval = TypeConverter.ToNumber(_engine.GetValue(lref)) + TypeConverter.ToNumber(rval);
  62. break;
  63. }
  64. break;
  65. case "*=":
  66. switch (type)
  67. {
  68. case TypeCode.Double:
  69. lval = TypeConverter.ToNumber(_engine.GetValue(lref)) *TypeConverter.ToNumber(rval);
  70. break;
  71. }
  72. break;
  73. case "/=":
  74. switch (type)
  75. {
  76. case TypeCode.Double:
  77. lval = TypeConverter.ToNumber(_engine.GetValue(lref)) / TypeConverter.ToNumber(rval);
  78. break;
  79. }
  80. break;
  81. case "%=":
  82. switch (type)
  83. {
  84. case TypeCode.Double:
  85. lval = TypeConverter.ToNumber(_engine.GetValue(lref)) % TypeConverter.ToNumber(rval);
  86. break;
  87. }
  88. break;
  89. case "&=":
  90. switch (type)
  91. {
  92. case TypeCode.Double:
  93. lval = TypeConverter.ToInt32(_engine.GetValue(lref)) & TypeConverter.ToInt32(rval);
  94. break;
  95. }
  96. break;
  97. case "|=":
  98. switch (type)
  99. {
  100. case TypeCode.Double:
  101. lval = TypeConverter.ToInt32(_engine.GetValue(lref)) | TypeConverter.ToInt32(rval);
  102. break;
  103. }
  104. break;
  105. case "^=":
  106. switch (type)
  107. {
  108. case TypeCode.Double:
  109. lval = TypeConverter.ToInt32(_engine.GetValue(lref)) ^ TypeConverter.ToInt32(rval);
  110. break;
  111. }
  112. break;
  113. case "<<=":
  114. switch (type)
  115. {
  116. case TypeCode.Double:
  117. lval = TypeConverter.ToInt32(_engine.GetValue(lref)) << (int)(TypeConverter.ToUint32(rval) & 0x1F);
  118. break;
  119. }
  120. break;
  121. case ">>>=":
  122. switch (type)
  123. {
  124. case TypeCode.Double:
  125. lval = (uint)TypeConverter.ToInt32(_engine.GetValue(lref)) >> (int)(TypeConverter.ToUint32(rval) & 0x1F);
  126. break;
  127. }
  128. break;
  129. }
  130. _engine.PutValue(lref, lval);
  131. return lval;
  132. }
  133. public object EvaluateBinaryExpression(BinaryExpression expression)
  134. {
  135. object left = _engine.GetValue(EvaluateExpression(expression.Left));
  136. object right = _engine.GetValue(EvaluateExpression(expression.Right));
  137. object value = Undefined.Instance;
  138. var type = TypeConverter.GetType(left);
  139. switch (expression.Operator)
  140. {
  141. case "+":
  142. switch (type)
  143. {
  144. case TypeCode.String:
  145. value = TypeConverter.ToString(left) + right;
  146. break;
  147. case TypeCode.Double:
  148. value = TypeConverter.ToNumber(left) + TypeConverter.ToNumber(right);
  149. break;
  150. }
  151. break;
  152. case "-":
  153. switch (type)
  154. {
  155. case TypeCode.Double:
  156. value = TypeConverter.ToNumber(left) - TypeConverter.ToNumber(right);
  157. break;
  158. }
  159. break;
  160. case "*":
  161. switch (type)
  162. {
  163. case TypeCode.Double:
  164. value = TypeConverter.ToNumber(left) * TypeConverter.ToNumber(right);
  165. break;
  166. }
  167. break;
  168. case "/":
  169. switch (type)
  170. {
  171. case TypeCode.Double:
  172. value = TypeConverter.ToNumber(left) / TypeConverter.ToNumber(right);
  173. break;
  174. }
  175. break;
  176. case "%":
  177. switch (type)
  178. {
  179. case TypeCode.Double:
  180. value = TypeConverter.ToNumber(left) % TypeConverter.ToNumber(right);
  181. break;
  182. }
  183. break;
  184. case "==":
  185. value = left.Equals(right);
  186. break;
  187. case "!=":
  188. value = !left.Equals(right);
  189. break;
  190. case ">":
  191. switch (type)
  192. {
  193. case TypeCode.Double:
  194. value = TypeConverter.ToNumber(left) > TypeConverter.ToNumber(right);
  195. break;
  196. }
  197. break;
  198. case ">=":
  199. switch (type)
  200. {
  201. case TypeCode.Double:
  202. value = TypeConverter.ToNumber(left) >= TypeConverter.ToNumber(right);
  203. break;
  204. }
  205. break;
  206. case "<":
  207. switch (type)
  208. {
  209. case TypeCode.Double:
  210. value = TypeConverter.ToNumber(left) < TypeConverter.ToNumber(right);
  211. break;
  212. }
  213. break;
  214. case "<=":
  215. switch (type)
  216. {
  217. case TypeCode.Double:
  218. value = TypeConverter.ToNumber(left) <= TypeConverter.ToNumber(right);
  219. break;
  220. }
  221. break;
  222. case "===":
  223. return StriclyEqual(left, right);
  224. case "!==":
  225. return !StriclyEqual(left, right);
  226. case "&":
  227. return TypeConverter.ToInt32(left) & TypeConverter.ToInt32(right);
  228. case "|":
  229. return TypeConverter.ToInt32(left) | TypeConverter.ToInt32(right);
  230. case "^":
  231. return TypeConverter.ToInt32(left) ^ TypeConverter.ToInt32(right);
  232. case "<<":
  233. return TypeConverter.ToInt32(left) << (int)(TypeConverter.ToUint32(right) & 0x1F);
  234. case ">>":
  235. return TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F);
  236. case ">>>":
  237. return (uint)TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F);
  238. case "instanceof":
  239. var f = (FunctionInstance)right;
  240. value = f.HasInstance(left);
  241. break;
  242. default:
  243. throw new NotImplementedException();
  244. }
  245. return value;
  246. }
  247. public static bool StriclyEqual(object x, object y)
  248. {
  249. var typea = TypeConverter.GetType(x);
  250. var typeb = TypeConverter.GetType(y);
  251. if (typea != typeb)
  252. {
  253. return false;
  254. }
  255. if (typea == TypeCode.Empty)
  256. {
  257. return true;
  258. }
  259. if (typea == TypeCode.Double)
  260. {
  261. var nx = TypeConverter.ToNumber(x);
  262. var ny = TypeConverter.ToNumber(y);
  263. if (double.IsNaN(nx) || double.IsNaN(ny))
  264. {
  265. return false;
  266. }
  267. if (nx == ny)
  268. {
  269. return true;
  270. }
  271. return false;
  272. }
  273. if (typea == TypeCode.String)
  274. {
  275. return TypeConverter.ToString(x) == TypeConverter.ToString(y);
  276. }
  277. if (typea == TypeCode.Boolean)
  278. {
  279. return TypeConverter.ToBoolean(x) == TypeConverter.ToBoolean(y);
  280. }
  281. return x == y;
  282. }
  283. public object EvaluateIdentifier(Identifier identifier)
  284. {
  285. return _engine.ExecutionContext.LexicalEnvironment.GetIdentifierReference(identifier.Name, _engine.Options.IsStrict());
  286. }
  287. public object EvaluateLiteral(Literal literal)
  288. {
  289. return literal.Value ?? Null.Instance;
  290. }
  291. public object EvaluateObjectExpression(ObjectExpression objectExpression)
  292. {
  293. var value = _engine.Object.Construct(Arguments.Empty);
  294. foreach (var property in objectExpression.Properties)
  295. {
  296. switch (property.Kind)
  297. {
  298. case PropertyKind.Data:
  299. value.DefineOwnProperty(property.Key.GetKey(), new DataDescriptor(property.Value), false);
  300. break;
  301. case PropertyKind.Get:
  302. throw new NotImplementedException();
  303. break;
  304. case PropertyKind.Set:
  305. throw new NotImplementedException();
  306. break;
  307. default:
  308. throw new ArgumentOutOfRangeException();
  309. }
  310. }
  311. return value;
  312. }
  313. public object EvaluateMemberExpression(MemberExpression memberExpression)
  314. {
  315. var baseValue = _engine.GetValue(EvaluateExpression(memberExpression.Object));
  316. string propertyName =
  317. !memberExpression.Computed
  318. ? memberExpression.Property.As<Identifier>().Name // o.foo
  319. : EvaluateExpression(memberExpression.Property).ToString(); // o['foo']
  320. return new Reference(baseValue, propertyName, false);
  321. }
  322. public object EvaluateFunctionExpression(FunctionExpression functionExpression)
  323. {
  324. string identifier = functionExpression.Id != null ? functionExpression.Id.Name : null;
  325. return new ScriptFunctionInstance(
  326. _engine,
  327. functionExpression.Body,
  328. identifier,
  329. functionExpression.Parameters.ToArray(),
  330. _engine.Function.Prototype,
  331. _engine.Object.Construct(Arguments.Empty),
  332. LexicalEnvironment.NewDeclarativeEnvironment(_engine.ExecutionContext.LexicalEnvironment),
  333. functionExpression.Strict
  334. );
  335. }
  336. public object EvaluateCallExpression(CallExpression callExpression)
  337. {
  338. /// todo: read the spec as this is made up
  339. var callee = EvaluateExpression(callExpression.Callee);
  340. var func = _engine.GetValue(callee);
  341. object thisObject;
  342. // todo: implement as in http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
  343. var arguments = callExpression.Arguments.Select(EvaluateExpression).Select(_engine.GetValue).ToArray();
  344. if (TypeConverter.GetType(func) != TypeCode.Object)
  345. {
  346. throw new TypeError();
  347. }
  348. var callable = func as ICallable;
  349. if (callable == null)
  350. {
  351. throw new TypeError();
  352. }
  353. var r = callee as Reference;
  354. if (r != null)
  355. {
  356. if (r.IsPropertyReference())
  357. {
  358. thisObject = r.GetBase();
  359. }
  360. else
  361. {
  362. var env = r.GetBase() as EnvironmentRecord;
  363. thisObject = env.ImplicitThisValue();
  364. }
  365. }
  366. else
  367. {
  368. thisObject = Undefined.Instance;
  369. }
  370. return callable.Call(thisObject, arguments);
  371. }
  372. public object EvaluateSequenceExpression(SequenceExpression sequenceExpression)
  373. {
  374. foreach (var expression in sequenceExpression.Expressions)
  375. {
  376. _engine.EvaluateExpression(expression);
  377. }
  378. return Undefined.Instance;
  379. }
  380. public object EvaluateUpdateExpression(UpdateExpression updateExpression)
  381. {
  382. var r = EvaluateExpression(updateExpression.Argument) as Reference;
  383. var value = _engine.GetValue(r);
  384. var old = value;
  385. switch (updateExpression.Operator)
  386. {
  387. case "++" :
  388. value = TypeConverter.ToNumber(value) + 1;
  389. break;
  390. case "--":
  391. value = TypeConverter.ToNumber(value) - 1;
  392. break;
  393. default:
  394. throw new ArgumentException();
  395. }
  396. _engine.PutValue(r, value);
  397. return updateExpression.Prefix ? value : old;
  398. }
  399. public object EvaluateThisExpression(ThisExpression thisExpression)
  400. {
  401. return _engine.ExecutionContext.ThisBinding;
  402. }
  403. public object EvaluateNewExpression(NewExpression newExpression)
  404. {
  405. var arguments = newExpression.Arguments.Select(EvaluateExpression).ToArray();
  406. // todo: optimize by defining a common abstract class or interface
  407. var callee = (IConstructor)_engine.GetValue(EvaluateExpression(newExpression.Callee));
  408. // construct the new instance using the Function's constructor method
  409. var instance = callee.Construct(arguments);
  410. // initializes the new instance by executing the Function
  411. callee.Call(instance, arguments.ToArray());
  412. return instance;
  413. }
  414. public object EvaluateArrayExpression(ArrayExpression arrayExpression)
  415. {
  416. var arguments = arrayExpression.Elements.Select(EvaluateExpression).ToArray();
  417. // construct the new instance using the Function's constructor method
  418. var instance = _engine.Array.Construct(arguments);
  419. return instance;
  420. }
  421. public object EvaluateUnaryExpression(UnaryExpression unaryExpression)
  422. {
  423. var value = _engine.EvaluateExpression(unaryExpression.Argument);
  424. Reference r;
  425. switch (unaryExpression.Operator)
  426. {
  427. case "++" :
  428. r = value as Reference;
  429. if(r != null
  430. && r.IsStrict()
  431. && (r.GetBase() is EnvironmentRecord )
  432. && (Array.IndexOf(new []{"eval", "arguments"}, r.GetReferencedName()) != -1) )
  433. {
  434. throw new SyntaxError();
  435. }
  436. var oldValue = _engine.GetValue(value);
  437. var newValue = TypeConverter.ToNumber(value) + 1;
  438. _engine.PutValue(r, newValue);
  439. return unaryExpression.Prefix ? newValue : oldValue;
  440. case "--":
  441. r = value as Reference;
  442. if(r != null
  443. && r.IsStrict()
  444. && (r.GetBase() is EnvironmentRecord )
  445. && (Array.IndexOf(new []{"eval", "arguments"}, r.GetReferencedName()) != -1) )
  446. {
  447. throw new SyntaxError();
  448. }
  449. oldValue = _engine.GetValue(value);
  450. newValue = TypeConverter.ToNumber(value) - 1;
  451. _engine.PutValue(r, newValue);
  452. return unaryExpression.Prefix ? newValue : oldValue;
  453. case "+":
  454. return TypeConverter.ToNumber(_engine.GetValue(value));
  455. case "-":
  456. var n = TypeConverter.ToNumber(_engine.GetValue(value));
  457. return double.IsNaN(n) ? double.NaN : n*-1;
  458. case "~":
  459. return ~TypeConverter.ToInt32(_engine.GetValue(value));
  460. case "!":
  461. return !TypeConverter.ToBoolean(_engine.GetValue(value));
  462. case "delete":
  463. r = value as Reference;
  464. if (r == null)
  465. {
  466. return true;
  467. }
  468. if (r.IsUnresolvableReference())
  469. {
  470. if (r.IsStrict())
  471. {
  472. throw new SyntaxError();
  473. }
  474. return true;
  475. }
  476. if (r.IsPropertyReference())
  477. {
  478. var o = TypeConverter.ToObject(_engine, r.GetBase());
  479. return o.Delete(r.GetReferencedName(), r.IsStrict());
  480. }
  481. if (r.IsStrict())
  482. {
  483. throw new SyntaxError();
  484. }
  485. var bindings = r.GetBase() as EnvironmentRecord;
  486. return bindings.DeleteBinding(r.GetReferencedName());
  487. case "void":
  488. _engine.GetValue(value);
  489. return Undefined.Instance;
  490. case "typeof":
  491. r = value as Reference;
  492. if (r != null)
  493. {
  494. if (r.IsUnresolvableReference())
  495. {
  496. return "undefined";
  497. }
  498. }
  499. var v = _engine.GetValue(value);
  500. if (v == Undefined.Instance)
  501. {
  502. return "undefined";
  503. }
  504. if (v == Null.Instance)
  505. {
  506. return "object";
  507. }
  508. switch (TypeConverter.GetType(v))
  509. {
  510. case TypeCode.Boolean: return "boolean";
  511. case TypeCode.Double: return "number";
  512. case TypeCode.String: return "string";
  513. }
  514. if (v is ICallable)
  515. {
  516. return "function";
  517. }
  518. return "object";
  519. default:
  520. throw new ArgumentException();
  521. }
  522. }
  523. }
  524. }