Files
yallie 9fa3874800 Added the contents of the archive.
Moved the original file to the archive subfolder.
2017-11-20 16:11:42 +03:00

164 lines
7.3 KiB
C#

// ==++==
//
//
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
// ==--==
namespace Microsoft.JScript
{
using Microsoft.JScript.Vsa;
using System;
using System.Reflection;
using System.Reflection.Emit;
public sealed class FunctionExpression : AST{
private FunctionObject func;
private String name;
private JSVariableField field;
private LocalBuilder func_local;
private static int uniqueNumber = 0;
internal FunctionExpression(Context context, AST id, ParameterDeclaration[] formal_parameters, TypeExpression return_type, Block body, FunctionScope own_scope, FieldAttributes attributes)
: base(context){
if (attributes != (FieldAttributes)0){
this.context.HandleError(JSError.SyntaxError);
attributes = (FieldAttributes)0;
}
ScriptObject enclosingScope = Globals.ScopeStack.Peek();
this.name = id.ToString();
if (this.name.Length == 0)
this.name = "anonymous "+(uniqueNumber++).ToString();
else
this.AddNameTo(enclosingScope);
this.func = new FunctionObject(this.name, formal_parameters, return_type, body, own_scope, enclosingScope, this.context, MethodAttributes.Static|MethodAttributes.Public);
}
void AddNameTo(ScriptObject enclosingScope){
while (enclosingScope is WithObject) //Can only happen at run time and only if there is an eval
enclosingScope = enclosingScope.GetParent();
FieldInfo field = ((IActivationObject)enclosingScope).GetLocalField(this.name);
if (field != null) return;
if (enclosingScope is ActivationObject)
if (enclosingScope is FunctionScope)
field = ((ActivationObject)enclosingScope).AddNewField(this.name, null, FieldAttributes.Public);
else
field = ((ActivationObject)enclosingScope).AddNewField(this.name, null, FieldAttributes.Public|FieldAttributes.Static);
else
field = ((StackFrame)enclosingScope).AddNewField(this.name, null, FieldAttributes.Public);
JSLocalField lfield = field as JSLocalField;
if (lfield != null){
// emit debug info for the local only if this block of code is in a section that has debug set
lfield.debugOn = this.context.document.debugOn;
lfield.isDefined = true;
}
this.field = (JSVariableField)field;
}
internal override Object Evaluate(){
if( VsaEngine.executeForJSEE )
throw new JScriptException(JSError.NonSupportedInDebugger);
ScriptObject enclosingScope = Globals.ScopeStack.Peek();
this.func.own_scope.SetParent(enclosingScope);
Closure result = new Closure(this.func);
if (this.field != null)
this.field.value = result;
return result;
}
internal override IReflect InferType(JSField inference_target){
return Typeob.ScriptFunction;
}
public static FunctionObject JScriptFunctionExpression(RuntimeTypeHandle handle, String name, String method_name, String[] formal_params, JSLocalField[] fields,
bool must_save_stack_locals, bool hasArgumentsObject, String text, VsaEngine engine){
Type t = Type.GetTypeFromHandle(handle);
FunctionObject result = new FunctionObject(t, name, method_name, formal_params, fields, must_save_stack_locals, hasArgumentsObject, text, engine);
return result;
}
internal override AST PartiallyEvaluate(){
ScriptObject enclosingScope = Globals.ScopeStack.Peek();
ScriptObject scope = enclosingScope;
while (scope is WithObject || scope is BlockScope) scope = scope.GetParent();
FunctionScope fscope = scope as FunctionScope;
if (fscope != null) fscope.closuresMightEscape = true;
if (scope != enclosingScope)
//cut out scopes of outer functions. Early binding to locals in these scope will not work
this.func.own_scope.SetParent(new WithObject(new JSObject(), this.func.own_scope.GetGlobalScope()));
this.func.PartiallyEvaluate();
return this;
}
internal override void TranslateToIL(ILGenerator il, Type rtype){
//This is executed every time the function expression is executed and constructs a new closure for every execution.
if (rtype == Typeob.Void)
return;
il.Emit(OpCodes.Ldloc, this.func_local);
il.Emit(OpCodes.Newobj, CompilerGlobals.closureConstructor);
Convert.Emit(this, il, typeof(Closure), rtype);
if (this.field != null){
il.Emit(OpCodes.Dup);
Object tok = this.field.GetMetaData();
if (tok is LocalBuilder)
il.Emit(OpCodes.Stloc, (LocalBuilder)tok);
else
il.Emit(OpCodes.Stsfld, (FieldInfo)tok);
}
}
internal override void TranslateToILInitializer(ILGenerator il){
//This is executed only once for a given scope. It creates a FunctionObject and stores it in a private local.
//The FunctionObject is then used to construct a new closure every time the function expression is evaluated.
//This way, what is a method to IL, ends up as a ScriptFunction object that behaves just like an ECMAScript function.
this.func.TranslateToIL(compilerGlobals);
this.func_local = il.DeclareLocal(typeof(FunctionObject));
il.Emit(OpCodes.Ldtoken, compilerGlobals.classwriter);
il.Emit(OpCodes.Ldstr, this.name);
il.Emit(OpCodes.Ldstr, this.func.GetName());
int n = this.func.formal_parameters.Length;
ConstantWrapper.TranslateToILInt(il, n);
il.Emit(OpCodes.Newarr, Typeob.String);
for (int i = 0; i < n; i++){
il.Emit(OpCodes.Dup);
ConstantWrapper.TranslateToILInt(il, i);
il.Emit(OpCodes.Ldstr, this.func.formal_parameters[i]);
il.Emit(OpCodes.Stelem_Ref);
}
n = this.func.fields.Length;
ConstantWrapper.TranslateToILInt(il, n);
il.Emit(OpCodes.Newarr, CompilerGlobals.jsLocalFieldClass);
for (int i = 0; i < n; i++){
JSLocalField field = this.func.fields[i];
il.Emit(OpCodes.Dup);
ConstantWrapper.TranslateToILInt(il, i);
il.Emit(OpCodes.Ldstr, field.Name);
il.Emit(OpCodes.Ldtoken, field.FieldType);
ConstantWrapper.TranslateToILInt(il, field.slotNumber);
il.Emit(OpCodes.Newobj, CompilerGlobals.jsLocalFieldConstructor);
il.Emit(OpCodes.Stelem_Ref);
}
if (this.func.must_save_stack_locals)
il.Emit(OpCodes.Ldc_I4_1);
else
il.Emit(OpCodes.Ldc_I4_0);
if (this.func.hasArgumentsObject)
il.Emit(OpCodes.Ldc_I4_1);
else
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldstr, this.func.ToString());
this.EmitILToLoadEngine(il);
il.Emit(OpCodes.Call, CompilerGlobals.jScriptFunctionExpressionMethod);
il.Emit(OpCodes.Stloc, this.func_local);
}
}
}