Engine.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  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.Array;
  8. using Jint.Native.Boolean;
  9. using Jint.Native.Date;
  10. using Jint.Native.Error;
  11. using Jint.Native.Function;
  12. using Jint.Native.Global;
  13. using Jint.Native.Json;
  14. using Jint.Native.Math;
  15. using Jint.Native.Number;
  16. using Jint.Native.Object;
  17. using Jint.Native.RegExp;
  18. using Jint.Native.String;
  19. using Jint.Native.Symbol;
  20. using Jint.Pooling;
  21. using Jint.Runtime;
  22. using Jint.Runtime.CallStack;
  23. using Jint.Runtime.Debugger;
  24. using Jint.Runtime.Descriptors;
  25. using Jint.Runtime.Environments;
  26. using Jint.Runtime.Interop;
  27. using Jint.Runtime.References;
  28. namespace Jint
  29. {
  30. public class Engine
  31. {
  32. private static readonly ParserOptions DefaultParserOptions = new ParserOptions
  33. {
  34. AdaptRegexp = true,
  35. Tolerant = false,
  36. Loc = true
  37. };
  38. private readonly ExpressionInterpreter _expressions;
  39. private readonly StatementInterpreter _statements;
  40. private readonly Stack<ExecutionContext> _executionContexts;
  41. private JsValue _completionValue = JsValue.Undefined;
  42. private int _statementsCount;
  43. private long _timeoutTicks;
  44. private INode _lastSyntaxNode = null;
  45. public ITypeConverter ClrTypeConverter;
  46. // cache of types used when resolving CLR type names
  47. internal Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
  48. internal static Dictionary<Type, Func<Engine, object, JsValue>> TypeMappers = new Dictionary<Type, Func<Engine, object, JsValue>>
  49. {
  50. { typeof(bool), (Engine engine, object v) => (bool) v ? JsBoolean.True : JsBoolean.False },
  51. { typeof(byte), (Engine engine, object v) => JsNumber.Create((byte)v) },
  52. { typeof(char), (Engine engine, object v) => JsString.Create((char)v) },
  53. { typeof(DateTime), (Engine engine, object v) => engine.Date.Construct((DateTime)v) },
  54. { typeof(DateTimeOffset), (Engine engine, object v) => engine.Date.Construct((DateTimeOffset)v) },
  55. { typeof(decimal), (Engine engine, object v) => (JsValue) (double)(decimal)v },
  56. { typeof(double), (Engine engine, object v) => (JsValue)(double)v },
  57. { typeof(Int16), (Engine engine, object v) => JsNumber.Create((Int16)v) },
  58. { typeof(Int32), (Engine engine, object v) => JsNumber.Create((Int32)v) },
  59. { typeof(Int64), (Engine engine, object v) => (JsValue)(Int64)v },
  60. { typeof(SByte), (Engine engine, object v) => JsNumber.Create((SByte)v) },
  61. { typeof(Single), (Engine engine, object v) => (JsValue)(Single)v },
  62. { typeof(string), (Engine engine, object v) => (JsValue) (string)v },
  63. { typeof(UInt16), (Engine engine, object v) => JsNumber.Create((UInt16)v) },
  64. { typeof(UInt32), (Engine engine, object v) => JsNumber.Create((UInt32)v) },
  65. { typeof(UInt64), (Engine engine, object v) => JsNumber.Create((UInt64)v) },
  66. { typeof(System.Text.RegularExpressions.Regex), (Engine engine, object v) => engine.RegExp.Construct((System.Text.RegularExpressions.Regex)v, "") }
  67. };
  68. internal JintCallStack CallStack = new JintCallStack();
  69. public Engine() : this(null)
  70. {
  71. }
  72. public Engine(Action<Options> options)
  73. {
  74. _executionContexts = new Stack<ExecutionContext>();
  75. Global = GlobalObject.CreateGlobalObject(this);
  76. Object = ObjectConstructor.CreateObjectConstructor(this);
  77. Function = FunctionConstructor.CreateFunctionConstructor(this);
  78. Symbol = SymbolConstructor.CreateSymbolConstructor(this);
  79. Array = ArrayConstructor.CreateArrayConstructor(this);
  80. String = StringConstructor.CreateStringConstructor(this);
  81. RegExp = RegExpConstructor.CreateRegExpConstructor(this);
  82. Number = NumberConstructor.CreateNumberConstructor(this);
  83. Boolean = BooleanConstructor.CreateBooleanConstructor(this);
  84. Date = DateConstructor.CreateDateConstructor(this);
  85. Math = MathInstance.CreateMathObject(this);
  86. Json = JsonInstance.CreateJsonObject(this);
  87. Error = ErrorConstructor.CreateErrorConstructor(this, "Error");
  88. EvalError = ErrorConstructor.CreateErrorConstructor(this, "EvalError");
  89. RangeError = ErrorConstructor.CreateErrorConstructor(this, "RangeError");
  90. ReferenceError = ErrorConstructor.CreateErrorConstructor(this, "ReferenceError");
  91. SyntaxError = ErrorConstructor.CreateErrorConstructor(this, "SyntaxError");
  92. TypeError = ErrorConstructor.CreateErrorConstructor(this, "TypeError");
  93. UriError = ErrorConstructor.CreateErrorConstructor(this, "URIError");
  94. GlobalSymbolRegistry = new GlobalSymbolRegistry();
  95. // Because the properties might need some of the built-in object
  96. // their configuration is delayed to a later step
  97. Global.Configure();
  98. Object.Configure();
  99. Object.PrototypeObject.Configure();
  100. Symbol.Configure();
  101. Symbol.PrototypeObject.Configure();
  102. Function.Configure();
  103. Function.PrototypeObject.Configure();
  104. Array.Configure();
  105. Array.PrototypeObject.Configure();
  106. String.Configure();
  107. String.PrototypeObject.Configure();
  108. RegExp.Configure();
  109. RegExp.PrototypeObject.Configure();
  110. Number.Configure();
  111. Number.PrototypeObject.Configure();
  112. Boolean.Configure();
  113. Boolean.PrototypeObject.Configure();
  114. Date.Configure();
  115. Date.PrototypeObject.Configure();
  116. Math.Configure();
  117. Json.Configure();
  118. Error.Configure();
  119. Error.PrototypeObject.Configure();
  120. // create the global environment http://www.ecma-international.org/ecma-262/5.1/#sec-10.2.3
  121. GlobalEnvironment = LexicalEnvironment.NewObjectEnvironment(this, Global, null, false);
  122. // create the global execution context http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.1.1
  123. EnterExecutionContext(GlobalEnvironment, GlobalEnvironment, Global);
  124. Options = new Options();
  125. options?.Invoke(Options);
  126. ReferencePool = new ReferencePool();
  127. CompletionPool = new CompletionPool();
  128. ArgumentsInstancePool = new ArgumentsInstancePool(this);
  129. JsValueArrayPool = new JsValueArrayPool();
  130. Eval = new EvalFunctionInstance(this, System.Array.Empty<string>(), LexicalEnvironment.NewDeclarativeEnvironment(this, ExecutionContext.LexicalEnvironment), StrictModeScope.IsStrictModeCode);
  131. Global.FastAddProperty("eval", Eval, true, false, true);
  132. _statements = new StatementInterpreter(this);
  133. _expressions = new ExpressionInterpreter(this);
  134. if (Options._IsClrAllowed)
  135. {
  136. Global.FastAddProperty("System", new NamespaceReference(this, "System"), false, false, false);
  137. Global.FastAddProperty("importNamespace", new ClrFunctionInstance(this, (thisObj, arguments) =>
  138. {
  139. return new NamespaceReference(this, TypeConverter.ToString(arguments.At(0)));
  140. }), false, false, false);
  141. }
  142. ClrTypeConverter = new DefaultTypeConverter(this);
  143. BreakPoints = new List<BreakPoint>();
  144. DebugHandler = new DebugHandler(this);
  145. }
  146. public LexicalEnvironment GlobalEnvironment { get; }
  147. public GlobalObject Global { get; }
  148. public ObjectConstructor Object { get; }
  149. public FunctionConstructor Function { get; }
  150. public ArrayConstructor Array { get; }
  151. public StringConstructor String { get; }
  152. public RegExpConstructor RegExp { get; }
  153. public BooleanConstructor Boolean { get; }
  154. public NumberConstructor Number { get; }
  155. public DateConstructor Date { get; }
  156. public MathInstance Math { get; }
  157. public JsonInstance Json { get; }
  158. public SymbolConstructor Symbol { get; }
  159. public EvalFunctionInstance Eval { get; }
  160. public ErrorConstructor Error { get; }
  161. public ErrorConstructor EvalError { get; }
  162. public ErrorConstructor SyntaxError { get; }
  163. public ErrorConstructor TypeError { get; }
  164. public ErrorConstructor RangeError { get; }
  165. public ErrorConstructor ReferenceError { get; }
  166. public ErrorConstructor UriError { get; }
  167. public ExecutionContext ExecutionContext => _executionContexts.Peek();
  168. public GlobalSymbolRegistry GlobalSymbolRegistry { get; }
  169. internal Options Options { get; }
  170. internal ReferencePool ReferencePool { get; }
  171. internal CompletionPool CompletionPool { get; }
  172. internal ArgumentsInstancePool ArgumentsInstancePool { get; }
  173. internal JsValueArrayPool JsValueArrayPool { get; }
  174. #region Debugger
  175. public delegate StepMode DebugStepDelegate(object sender, DebugInformation e);
  176. public delegate StepMode BreakDelegate(object sender, DebugInformation e);
  177. public event DebugStepDelegate Step;
  178. public event BreakDelegate Break;
  179. internal DebugHandler DebugHandler { get; private set; }
  180. public List<BreakPoint> BreakPoints { get; private set; }
  181. internal StepMode? InvokeStepEvent(DebugInformation info)
  182. {
  183. return Step?.Invoke(this, info);
  184. }
  185. internal StepMode? InvokeBreakEvent(DebugInformation info)
  186. {
  187. return Break?.Invoke(this, info);
  188. }
  189. #endregion
  190. public ExecutionContext EnterExecutionContext(LexicalEnvironment lexicalEnvironment, LexicalEnvironment variableEnvironment, JsValue thisBinding)
  191. {
  192. var executionContext = new ExecutionContext
  193. {
  194. LexicalEnvironment = lexicalEnvironment,
  195. VariableEnvironment = variableEnvironment,
  196. ThisBinding = thisBinding
  197. };
  198. _executionContexts.Push(executionContext);
  199. return executionContext;
  200. }
  201. public Engine SetValue(string name, Delegate value)
  202. {
  203. Global.FastAddProperty(name, new DelegateWrapper(this, value), true, false, true);
  204. return this;
  205. }
  206. public Engine SetValue(string name, string value)
  207. {
  208. return SetValue(name, (JsValue) value);
  209. }
  210. public Engine SetValue(string name, double value)
  211. {
  212. return SetValue(name, JsNumber.Create(value));
  213. }
  214. public Engine SetValue(string name, int value)
  215. {
  216. return SetValue(name, JsNumber.Create(value));
  217. }
  218. public Engine SetValue(string name, bool value)
  219. {
  220. return SetValue(name, value ? JsBoolean.True : JsBoolean.False);
  221. }
  222. public Engine SetValue(string name, JsValue value)
  223. {
  224. Global.Put(name, value, false);
  225. return this;
  226. }
  227. public Engine SetValue(string name, object obj)
  228. {
  229. return SetValue(name, JsValue.FromObject(this, obj));
  230. }
  231. public void LeaveExecutionContext()
  232. {
  233. _executionContexts.Pop();
  234. }
  235. /// <summary>
  236. /// Initializes the statements count
  237. /// </summary>
  238. public void ResetStatementsCount()
  239. {
  240. _statementsCount = 0;
  241. }
  242. public void ResetTimeoutTicks()
  243. {
  244. var timeoutIntervalTicks = Options._TimeoutInterval.Ticks;
  245. _timeoutTicks = timeoutIntervalTicks > 0 ? DateTime.UtcNow.Ticks + timeoutIntervalTicks : 0;
  246. }
  247. /// <summary>
  248. /// Initializes list of references of called functions
  249. /// </summary>
  250. public void ResetCallStack()
  251. {
  252. CallStack.Clear();
  253. }
  254. public Engine Execute(string source)
  255. {
  256. return Execute(source, DefaultParserOptions);
  257. }
  258. public Engine Execute(string source, ParserOptions parserOptions)
  259. {
  260. var parser = new JavaScriptParser(source, parserOptions);
  261. return Execute(parser.ParseProgram());
  262. }
  263. public Engine Execute(Program program)
  264. {
  265. ResetStatementsCount();
  266. ResetTimeoutTicks();
  267. ResetLastStatement();
  268. ResetCallStack();
  269. using (new StrictModeScope(Options._IsStrict || program.Strict))
  270. {
  271. DeclarationBindingInstantiation(DeclarationBindingType.GlobalCode, program.HoistingScope.FunctionDeclarations, program.HoistingScope.VariableDeclarations, null, null);
  272. var result = _statements.ExecuteProgram(program);
  273. if (result.Type == Completion.Throw)
  274. {
  275. var ex = new JavaScriptException(result.GetValueOrDefault()).SetCallstack(this, result.Location);
  276. CompletionPool.Return(result);
  277. throw ex;
  278. }
  279. _completionValue = result.GetValueOrDefault();
  280. CompletionPool.Return(result);
  281. }
  282. return this;
  283. }
  284. private void ResetLastStatement()
  285. {
  286. _lastSyntaxNode = null;
  287. }
  288. /// <summary>
  289. /// Gets the last evaluated statement completion value
  290. /// </summary>
  291. public JsValue GetCompletionValue()
  292. {
  293. return _completionValue;
  294. }
  295. public Completion ExecuteStatement(Statement statement)
  296. {
  297. var maxStatements = Options._MaxStatements;
  298. if (maxStatements > 0 && _statementsCount++ > maxStatements)
  299. {
  300. throw new StatementsCountOverflowException();
  301. }
  302. if (_timeoutTicks > 0 && _timeoutTicks < DateTime.UtcNow.Ticks)
  303. {
  304. throw new TimeoutException();
  305. }
  306. _lastSyntaxNode = statement;
  307. if (Options._IsDebugMode)
  308. {
  309. DebugHandler.OnStep(statement);
  310. }
  311. switch (statement.Type)
  312. {
  313. case Nodes.BlockStatement:
  314. return _statements.ExecuteBlockStatement(statement.As<BlockStatement>());
  315. case Nodes.ReturnStatement:
  316. return _statements.ExecuteReturnStatement(statement.As<ReturnStatement>());
  317. case Nodes.VariableDeclaration:
  318. return _statements.ExecuteVariableDeclaration(statement.As<VariableDeclaration>());
  319. case Nodes.BreakStatement:
  320. return _statements.ExecuteBreakStatement(statement.As<BreakStatement>());
  321. case Nodes.ContinueStatement:
  322. return _statements.ExecuteContinueStatement(statement.As<ContinueStatement>());
  323. case Nodes.DoWhileStatement:
  324. return _statements.ExecuteDoWhileStatement(statement.As<DoWhileStatement>());
  325. case Nodes.EmptyStatement:
  326. return _statements.ExecuteEmptyStatement(statement.As<EmptyStatement>());
  327. case Nodes.ExpressionStatement:
  328. return _statements.ExecuteExpressionStatement(statement.As<ExpressionStatement>());
  329. case Nodes.ForStatement:
  330. return _statements.ExecuteForStatement(statement.As<ForStatement>());
  331. case Nodes.ForInStatement:
  332. return _statements.ExecuteForInStatement(statement.As<ForInStatement>());
  333. case Nodes.IfStatement:
  334. return _statements.ExecuteIfStatement(statement.As<IfStatement>());
  335. case Nodes.LabeledStatement:
  336. return _statements.ExecuteLabeledStatement(statement.As<LabeledStatement>());
  337. case Nodes.SwitchStatement:
  338. return _statements.ExecuteSwitchStatement(statement.As<SwitchStatement>());
  339. case Nodes.FunctionDeclaration:
  340. return Completion.Empty;
  341. case Nodes.ThrowStatement:
  342. return _statements.ExecuteThrowStatement(statement.As<ThrowStatement>());
  343. case Nodes.TryStatement:
  344. return _statements.ExecuteTryStatement(statement.As<TryStatement>());
  345. case Nodes.WhileStatement:
  346. return _statements.ExecuteWhileStatement(statement.As<WhileStatement>());
  347. case Nodes.WithStatement:
  348. return _statements.ExecuteWithStatement(statement.As<WithStatement>());
  349. case Nodes.DebuggerStatement:
  350. return _statements.ExecuteDebuggerStatement(statement.As<DebuggerStatement>());
  351. case Nodes.Program:
  352. return _statements.ExecuteProgram(statement.As<Program>());
  353. default:
  354. throw new ArgumentOutOfRangeException();
  355. }
  356. }
  357. public object EvaluateExpression(INode expression)
  358. {
  359. _lastSyntaxNode = expression;
  360. switch (expression.Type)
  361. {
  362. case Nodes.AssignmentExpression:
  363. return _expressions.EvaluateAssignmentExpression(expression.As<AssignmentExpression>());
  364. case Nodes.ArrayExpression:
  365. return _expressions.EvaluateArrayExpression(expression.As<ArrayExpression>());
  366. case Nodes.BinaryExpression:
  367. return _expressions.EvaluateBinaryExpression(expression.As<BinaryExpression>());
  368. case Nodes.CallExpression:
  369. return _expressions.EvaluateCallExpression(expression.As<CallExpression>());
  370. case Nodes.ConditionalExpression:
  371. return _expressions.EvaluateConditionalExpression(expression.As<ConditionalExpression>());
  372. case Nodes.FunctionExpression:
  373. return _expressions.EvaluateFunctionExpression(expression.As<IFunction>());
  374. case Nodes.Identifier:
  375. return _expressions.EvaluateIdentifier(expression.As<Identifier>());
  376. case Nodes.Literal:
  377. return _expressions.EvaluateLiteral(expression.As<Literal>());
  378. case Nodes.LogicalExpression:
  379. return _expressions.EvaluateLogicalExpression(expression.As<BinaryExpression>());
  380. case Nodes.MemberExpression:
  381. return _expressions.EvaluateMemberExpression(expression.As<MemberExpression>());
  382. case Nodes.NewExpression:
  383. return _expressions.EvaluateNewExpression(expression.As<NewExpression>());
  384. case Nodes.ObjectExpression:
  385. return _expressions.EvaluateObjectExpression(expression.As<ObjectExpression>());
  386. case Nodes.SequenceExpression:
  387. return _expressions.EvaluateSequenceExpression(expression.As<SequenceExpression>());
  388. case Nodes.ThisExpression:
  389. return _expressions.EvaluateThisExpression(expression.As<ThisExpression>());
  390. case Nodes.UpdateExpression:
  391. return _expressions.EvaluateUpdateExpression(expression.As<UpdateExpression>());
  392. case Nodes.UnaryExpression:
  393. return _expressions.EvaluateUnaryExpression(expression.As<UnaryExpression>());
  394. default:
  395. throw new ArgumentOutOfRangeException();
  396. }
  397. }
  398. /// <summary>
  399. /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.7.1
  400. /// </summary>
  401. /// <param name="value"></param>
  402. /// <returns></returns>
  403. public JsValue GetValue(object value)
  404. {
  405. return GetValue(value, false);
  406. }
  407. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  408. internal JsValue GetValue(object value, bool returnReferenceToPool)
  409. {
  410. if (value is JsValue jsValue)
  411. {
  412. return jsValue;
  413. }
  414. var reference = value as Reference;
  415. if (reference == null)
  416. {
  417. if (value is Completion completion)
  418. {
  419. return GetValue(completion.Value, returnReferenceToPool);
  420. }
  421. }
  422. if (reference.IsUnresolvableReference())
  423. {
  424. if (Options._ReferenceResolver != null &&
  425. Options._ReferenceResolver.TryUnresolvableReference(this, reference, out JsValue val))
  426. {
  427. return val;
  428. }
  429. throw new JavaScriptException(ReferenceError, reference.GetReferencedName() + " is not defined");
  430. }
  431. var baseValue = reference.GetBase();
  432. if (reference.IsPropertyReference())
  433. {
  434. if (Options._ReferenceResolver != null &&
  435. Options._ReferenceResolver.TryPropertyReference(this, reference, ref baseValue))
  436. {
  437. return baseValue;
  438. }
  439. var referencedName = reference.GetReferencedName();
  440. if (returnReferenceToPool)
  441. {
  442. ReferencePool.Return(reference);
  443. }
  444. if (reference.HasPrimitiveBase() == false)
  445. {
  446. var o = TypeConverter.ToObject(this, baseValue);
  447. var v = o.Get(referencedName);
  448. return v;
  449. }
  450. else
  451. {
  452. var o = TypeConverter.ToObject(this, baseValue);
  453. var desc = o.GetProperty(referencedName);
  454. if (desc == PropertyDescriptor.Undefined)
  455. {
  456. return JsValue.Undefined;
  457. }
  458. if (desc.IsDataDescriptor())
  459. {
  460. return desc.Value;
  461. }
  462. var getter = desc.Get;
  463. if (ReferenceEquals(getter, Undefined.Instance))
  464. {
  465. return Undefined.Instance;
  466. }
  467. var callable = (ICallable)getter.AsObject();
  468. return callable.Call(baseValue, Arguments.Empty);
  469. }
  470. }
  471. var record = (EnvironmentRecord) baseValue;
  472. if (record == null)
  473. {
  474. throw new ArgumentException();
  475. }
  476. var bindingValue = record.GetBindingValue(reference.GetReferencedName(), reference.IsStrict());
  477. if (returnReferenceToPool)
  478. {
  479. ReferencePool.Return(reference);
  480. }
  481. return bindingValue;
  482. }
  483. /// <summary>
  484. /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.7.2
  485. /// </summary>
  486. /// <param name="reference"></param>
  487. /// <param name="value"></param>
  488. public void PutValue(Reference reference, JsValue value)
  489. {
  490. if (reference.IsUnresolvableReference())
  491. {
  492. if (reference.IsStrict())
  493. {
  494. throw new JavaScriptException(ReferenceError);
  495. }
  496. Global.Put(reference.GetReferencedName(), value, false);
  497. }
  498. else if (reference.IsPropertyReference())
  499. {
  500. var baseValue = reference.GetBase();
  501. if (!reference.HasPrimitiveBase())
  502. {
  503. baseValue.AsObject().Put(reference.GetReferencedName(), value, reference.IsStrict());
  504. }
  505. else
  506. {
  507. PutPrimitiveBase(baseValue, reference.GetReferencedName(), value, reference.IsStrict());
  508. }
  509. }
  510. else
  511. {
  512. var baseValue = reference.GetBase();
  513. var record = baseValue as EnvironmentRecord;
  514. if (record == null)
  515. {
  516. throw new ArgumentNullException();
  517. }
  518. record.SetMutableBinding(reference.GetReferencedName(), value, reference.IsStrict());
  519. }
  520. }
  521. /// <summary>
  522. /// Used by PutValue when the reference has a primitive base value
  523. /// </summary>
  524. /// <param name="b"></param>
  525. /// <param name="name"></param>
  526. /// <param name="value"></param>
  527. /// <param name="throwOnError"></param>
  528. public void PutPrimitiveBase(JsValue b, string name, JsValue value, bool throwOnError)
  529. {
  530. var o = TypeConverter.ToObject(this, b);
  531. if (!o.CanPut(name))
  532. {
  533. if (throwOnError)
  534. {
  535. throw new JavaScriptException(TypeError);
  536. }
  537. return;
  538. }
  539. var ownDesc = o.GetOwnProperty(name);
  540. if (ownDesc.IsDataDescriptor())
  541. {
  542. if (throwOnError)
  543. {
  544. throw new JavaScriptException(TypeError);
  545. }
  546. return;
  547. }
  548. var desc = o.GetProperty(name);
  549. if (desc.IsAccessorDescriptor())
  550. {
  551. var setter = (ICallable)desc.Set.AsObject();
  552. setter.Call(b, new[] { value });
  553. }
  554. else
  555. {
  556. if (throwOnError)
  557. {
  558. throw new JavaScriptException(TypeError);
  559. }
  560. }
  561. }
  562. /// <summary>
  563. /// Invoke the current value as function.
  564. /// </summary>
  565. /// <param name="propertyName">The name of the function to call.</param>
  566. /// <param name="arguments">The arguments of the function call.</param>
  567. /// <returns>The value returned by the function call.</returns>
  568. public JsValue Invoke(string propertyName, params object[] arguments)
  569. {
  570. return Invoke(propertyName, null, arguments);
  571. }
  572. /// <summary>
  573. /// Invoke the current value as function.
  574. /// </summary>
  575. /// <param name="propertyName">The name of the function to call.</param>
  576. /// <param name="thisObj">The this value inside the function call.</param>
  577. /// <param name="arguments">The arguments of the function call.</param>
  578. /// <returns>The value returned by the function call.</returns>
  579. public JsValue Invoke(string propertyName, object thisObj, object[] arguments)
  580. {
  581. var value = GetValue(propertyName);
  582. return Invoke(value, thisObj, arguments);
  583. }
  584. /// <summary>
  585. /// Invoke the current value as function.
  586. /// </summary>
  587. /// <param name="value">The function to call.</param>
  588. /// <param name="arguments">The arguments of the function call.</param>
  589. /// <returns>The value returned by the function call.</returns>
  590. public JsValue Invoke(JsValue value, params object[] arguments)
  591. {
  592. return Invoke(value, null, arguments);
  593. }
  594. /// <summary>
  595. /// Invoke the current value as function.
  596. /// </summary>
  597. /// <param name="value">The function to call.</param>
  598. /// <param name="thisObj">The this value inside the function call.</param>
  599. /// <param name="arguments">The arguments of the function call.</param>
  600. /// <returns>The value returned by the function call.</returns>
  601. public JsValue Invoke(JsValue value, object thisObj, object[] arguments)
  602. {
  603. var callable = value.TryCast<ICallable>();
  604. if (callable == null)
  605. {
  606. throw new ArgumentException("Can only invoke functions");
  607. }
  608. var items = JsValueArrayPool.RentArray(arguments.Length);
  609. for (int i = 0; i < arguments.Length; ++i)
  610. {
  611. items[i] = JsValue.FromObject(this, arguments[i]);
  612. }
  613. var result = callable.Call(JsValue.FromObject(this, thisObj), items);
  614. JsValueArrayPool.ReturnArray(items);
  615. return result;
  616. }
  617. /// <summary>
  618. /// Gets a named value from the Global scope.
  619. /// </summary>
  620. /// <param name="propertyName">The name of the property to return.</param>
  621. public JsValue GetValue(string propertyName)
  622. {
  623. return GetValue(Global, propertyName);
  624. }
  625. /// <summary>
  626. /// Gets the last evaluated <see cref="INode"/>.
  627. /// </summary>
  628. public INode GetLastSyntaxNode()
  629. {
  630. return _lastSyntaxNode;
  631. }
  632. /// <summary>
  633. /// Gets a named value from the specified scope.
  634. /// </summary>
  635. /// <param name="scope">The scope to get the property from.</param>
  636. /// <param name="propertyName">The name of the property to return.</param>
  637. public JsValue GetValue(JsValue scope, string propertyName)
  638. {
  639. if (string.IsNullOrEmpty(propertyName))
  640. {
  641. throw new ArgumentException("propertyName");
  642. }
  643. var reference = ReferencePool.Rent(scope, propertyName, Options._IsStrict);
  644. var jsValue = GetValue(reference);
  645. ReferencePool.Return(reference);
  646. return jsValue;
  647. }
  648. // http://www.ecma-international.org/ecma-262/5.1/#sec-10.5
  649. internal bool DeclarationBindingInstantiation(
  650. DeclarationBindingType declarationBindingType,
  651. List<FunctionDeclaration> functionDeclarations,
  652. List<VariableDeclaration> variableDeclarations,
  653. FunctionInstance functionInstance,
  654. JsValue[] arguments)
  655. {
  656. var env = ExecutionContext.VariableEnvironment.Record;
  657. bool configurableBindings = declarationBindingType == DeclarationBindingType.EvalCode;
  658. var strict = StrictModeScope.IsStrictModeCode;
  659. if (declarationBindingType == DeclarationBindingType.FunctionCode)
  660. {
  661. var parameters = functionInstance.FormalParameters;
  662. for (var i = 0; i < parameters.Length; i++)
  663. {
  664. var argName = parameters[i];
  665. var v = i + 1 > arguments.Length ? Undefined.Instance : arguments[i];
  666. var argAlreadyDeclared = env.HasBinding(argName);
  667. if (!argAlreadyDeclared)
  668. {
  669. env.CreateMutableBinding(argName, v);
  670. }
  671. env.SetMutableBinding(argName, v, strict);
  672. }
  673. }
  674. var functionDeclarationsCount = functionDeclarations.Count;
  675. for (var i = 0; i < functionDeclarationsCount; i++)
  676. {
  677. var f = functionDeclarations[i];
  678. var fn = f.Id.Name;
  679. var fo = Function.CreateFunctionObject(f);
  680. var funcAlreadyDeclared = env.HasBinding(fn);
  681. if (!funcAlreadyDeclared)
  682. {
  683. env.CreateMutableBinding(fn, configurableBindings);
  684. }
  685. else
  686. {
  687. if (env == GlobalEnvironment.Record)
  688. {
  689. var go = Global;
  690. var existingProp = go.GetProperty(fn);
  691. if (existingProp.Configurable.Value)
  692. {
  693. go.DefineOwnProperty(fn,
  694. new PropertyDescriptor(
  695. value: Undefined.Instance,
  696. writable: true,
  697. enumerable: true,
  698. configurable: configurableBindings
  699. ), true);
  700. }
  701. else
  702. {
  703. if (existingProp.IsAccessorDescriptor() || (!existingProp.Enumerable.Value))
  704. {
  705. throw new JavaScriptException(TypeError);
  706. }
  707. }
  708. }
  709. }
  710. env.SetMutableBinding(fn, fo, strict);
  711. }
  712. bool canReleaseArgumentsInstance = false;
  713. if (declarationBindingType == DeclarationBindingType.FunctionCode && !env.HasBinding("arguments"))
  714. {
  715. var argsObj = ArgumentsInstancePool.Rent(functionInstance, functionInstance.FormalParameters, arguments, env, strict);
  716. canReleaseArgumentsInstance = true;
  717. if (strict)
  718. {
  719. var declEnv = env as DeclarativeEnvironmentRecord;
  720. if (declEnv == null)
  721. {
  722. throw new ArgumentException();
  723. }
  724. declEnv.CreateImmutableBinding("arguments", argsObj);
  725. }
  726. else
  727. {
  728. env.CreateMutableBinding("arguments", argsObj);
  729. }
  730. }
  731. // process all variable declarations in the current parser scope
  732. var variableDeclarationsCount = variableDeclarations.Count;
  733. for (var i = 0; i < variableDeclarationsCount; i++)
  734. {
  735. var variableDeclaration = variableDeclarations[i];
  736. var declarationsCount = variableDeclaration.Declarations.Count;
  737. for (var j = 0; j < declarationsCount; j++)
  738. {
  739. var d = variableDeclaration.Declarations[j];
  740. var dn = d.Id.As<Identifier>().Name;
  741. var varAlreadyDeclared = env.HasBinding(dn);
  742. if (!varAlreadyDeclared)
  743. {
  744. env.CreateMutableBinding(dn, Undefined.Instance);
  745. }
  746. }
  747. }
  748. return canReleaseArgumentsInstance;
  749. }
  750. }
  751. }