/// <summary> /// Binds this function to an instance of a class, /// allowing it to access the instance's 'this' variable. /// </summary> /// <param name="instance">Instance to bind to.</param> /// <returns>The bound function.</returns> public Function Bind(Instance instance) { var environment = new EnvironmentState(outerEnvironment: _closure); environment.Define("this", instance); return(new Function(_declaration, environment, _name, _isInit)); }
/// <summary> /// Calls the function. /// </summary> /// <param name="interpreter">Interpreter calling the function.</param> /// <param name="arguments">Arguments to pass to the function.</param> /// <returns>The result of the function call.</returns> public object Call(Interpreter interpreter, IEnumerable <object> arguments) { // each call gets its own scope so that it can keep track of its individual state var environment = new EnvironmentState(outerEnvironment: _closure); // combine the params and the arguments into one collection var paramArguments = _declaration.Params.Zip(arguments, (param, argument) => new { Name = param.WrappedSource, Value = argument }); // define scoped variables for each param/argument foreach (var item in paramArguments) { environment.Define(item.Name, item.Value); } try { // execute the function body with the new scope we just created interpreter.ExecuteBlock(_declaration.Body, environment); } catch (ReturnException ex) { return(_isInit ? _closure.GetValue("this", 0) : ex.Value); } // constructors will always return 'this' return(_isInit ? _closure.GetValue("this", 0) : null); }
/// <summary> /// Initialize a <see cref="Function"/> with the /// <see cref="FunctionStatement"/> declaration it originated from. /// </summary> /// <param name="declaration">Parsed source of the function.</param> public Function(FunctionExpression declaration, EnvironmentState closure, Token name = null, bool isInit = false) { _declaration = declaration; _closure = closure; _name = name; _isInit = isInit; ParamCount = _declaration.Params.Count(); }
/// <summary> /// Interprets and executes the given statements. /// </summary> /// <param name="statements">Statements to execute.</param> public void Interpret(IEnumerable <StatementBase> statements) { RuntimeExceptionThrown = false; _environment = GlobalState; PrepareGlobalScope(); try { foreach (var statement in statements) { Execute(statement); } } catch (RuntimeException ex) { RuntimeExceptionThrown = true; ErrorReporter.ReportRuntimeException(ex); } }
/// <summary> /// <see cref="Execute(StatementBase)"/>s all statements in a block. /// </summary> /// <param name="statements">Statements to execute.</param> /// <param name="environment">The block's environment.</param> public void ExecuteBlock(IEnumerable <StatementBase> statements, EnvironmentState environment) { // hang on to the current scope var outerEnvironment = _environment; try { // our scope is now this block's scope _environment = environment; foreach (var statement in statements) { Execute(statement); } } finally { // restore to the first scope _environment = outerEnvironment; } }
/// <summary> /// Initializes an <see cref="EnvironmentState"/>, optionally with an enclosing environment. /// </summary> /// <param name="outerEnvironment">The <see cref="EnvironmentState"/> enclosing this one.</param> public EnvironmentState(EnvironmentState outerEnvironment = null) { OuterEnvironment = outerEnvironment; }