using Esprima;
using Esprima.Ast;
using Jint.Runtime.Environments;
using Jint.Runtime.Interpreter;
using Jint.Runtime.Interpreter.Expressions;
namespace Jint;
public partial class Engine
{
///
/// Prepares a script for the engine that includes static analysis data to speed up execution during run-time.
///
///
/// Returned instance is reusable and thread-safe. You should prepare scripts only once and then reuse them.
///
public static Script PrepareScript(string script, string? source = null, bool strict = false)
{
var astAnalyzer = new AstAnalyzer();
var options = ParserOptions.Default with
{
AllowReturnOutsideFunction = true,
OnNodeCreated = astAnalyzer.NodeVisitor
};
return new JavaScriptParser(options).ParseScript(script, source, strict);
}
///
/// Prepares a module for the engine that includes static analysis data to speed up execution during run-time.
///
///
/// Returned instance is reusable and thread-safe. You should prepare modules only once and then reuse them.
///
public static Module PrepareModule(string script, string? source = null)
{
var astAnalyzer = new AstAnalyzer();
var options = ParserOptions.Default with { OnNodeCreated = astAnalyzer.NodeVisitor };
return new JavaScriptParser(options).ParseModule(script, source);
}
private sealed class AstAnalyzer
{
private readonly Dictionary _bindingNames = new();
public void NodeVisitor(Node node)
{
switch (node.Type)
{
case Nodes.Identifier:
{
var name = ((Identifier) node).Name;
if (!_bindingNames.TryGetValue(name, out var bindingName))
{
_bindingNames[name] = bindingName = new EnvironmentRecord.BindingName(name);
}
node.AssociatedData = bindingName;
break;
}
case Nodes.Literal:
node.AssociatedData = JintLiteralExpression.ConvertToJsValue((Literal) node);
break;
case Nodes.ArrowFunctionExpression:
case Nodes.FunctionDeclaration:
case Nodes.FunctionExpression:
var function = (IFunction) node;
node.AssociatedData = JintFunctionDefinition.BuildState(function);
break;
}
}
}
}