internal JSWithField(JSVariableField outerField) : base(outerField) { // with-fields cannot be crunced because they might // need to reference a property on the with object CanCrunch = false; }
private void DefineParameters() { var functionObject = (FunctionObject)Owner; if (functionObject.ParameterDeclarations != null) { // for each parameter... foreach (ParameterDeclaration parameter in functionObject.ParameterDeclarations) { foreach (var nameDeclaration in BindingsVisitor.Bindings(parameter.Binding)) { // see if it's already defined var argumentField = this[nameDeclaration.Name]; if (argumentField == null) { // not already defined -- create a field now argumentField = new JSVariableField(FieldType.Argument, nameDeclaration.Name, 0, null) { Position = parameter.Position, OriginalContext = parameter.Context, CanCrunch = !nameDeclaration.RenameNotAllowed }; this.AddField(argumentField); } // make the parameter reference the field and the field reference // the parameter as its declaration nameDeclaration.VariableField = argumentField; argumentField.Declarations.Add(nameDeclaration); } } } }
public override JSVariableField this[string name] { get { // check the name table JSVariableField variableField = base[name]; if (variableField == null) { // not found so far, check the window object variableField = m_windowObject.GetField(name); } if (variableField == null) { // not found so far, check the global object variableField = m_globalObject.GetField(name); } if (variableField == null) { // see if this value is provided in our "assumed" global list specified on the command line if (m_assumedGlobals != null && m_assumedGlobals.Count > 0) { foreach (string globalName in m_assumedGlobals) { if (string.Compare(name, globalName.Trim(), StringComparison.Ordinal) == 0) { variableField = CreateField(name, null, 0); break; } } } } return(variableField); } }
public void DetachFromOuterField(bool leaveInnerPointingToOuter) { // we're going to change the reference from the outer variable to the inner variable // save the inner variable field JSNamedFunctionExpressionField nfeField = m_variableField.NamedFunctionExpression; // break the connection from the outer to the inner m_variableField.NamedFunctionExpression = null; if (!leaveInnerPointingToOuter) { // detach the inner from the outer nfeField.Detach(); } // the outer field no longer points to the function object m_variableField.FieldValue = null; // but the inner field should nfeField.FieldValue = this; // our variable field is now the inner field m_variableField = nfeField; // and so is out identifier m_identifier.VariableField = nfeField; }
internal void SetOuterLocalField(ActivationObject parentScope) { // if we're trying to set the outer local field using a global scope, // then ignore this request. This should only do something for scopes with // local variables if (!(parentScope is GlobalScope)) { // get the field reference for this lookup value JSVariableField variableField = parentScope.FindReference(m_name); if (variableField != null) { // see if this scope already points to this name if (parentScope[m_name] == null) { // create an inner reference so we don't keep walking up the scope chain for this name variableField = parentScope.CreateInnerField(variableField); } // save the local field VariableField = variableField as JSLocalField; // add a reference if (VariableField != null) { VariableField.AddReference(parentScope); } } } }
public override JSVariableField CreateInnerField(JSVariableField outerField) { return(outerField.IfNotNull(o => { // blindly create an inner reference field for with scopes, no matter what it // is. globals and predefined values can be hijacked by object properties in // this scope. var withField = AddField(CreateField(outerField)); // and we need to make sure that any field that may be referenced from inside // a with-statement does not get automatically renamed outerField.CanCrunch = false; // if the outer field is an undefined global, then we want to flag it with a // special attribute that tells us that it might not actually be an undefined global, // because it might just be a property reference on the with-object. if (outerField.FieldType == FieldType.UndefinedGlobal) { do { outerField.Attributes |= FieldAttributes.RTSpecialName; } while ((outerField = outerField.OuterField) != null); } return withField; })); }
/// <summary> /// returns true if the fields point to the same ultimate reference object. /// Needs to walk up the outer-reference chain for each field in order to /// find the ultimate reference /// </summary> /// <param name="otherField"></param> /// <returns></returns> public bool IsSameField(JSVariableField otherField) { // shortcuts -- if they are already the same object, we're done; // and if the other field is null, then we are NOT the same object. if (this == otherField) { return(true); } else if (otherField == null) { return(false); } // get the ultimate field for this field var thisOuter = OuterField != null ? OuterField : this; while (thisOuter.OuterField != null) { thisOuter = thisOuter.OuterField; } // get the ultimate field for the other field var otherOuter = otherField.OuterField != null ? otherField.OuterField : otherField; while (otherOuter.OuterField != null) { otherOuter = otherOuter.OuterField; } // now that we have the same outer fields, check to see if they are the same return(thisOuter == otherOuter); }
/*public override BlockScope Clone() * { * return new WithScope(Parser.ScopeStack.Peek(), Context, Parser); * }*/ public override JSVariableField FindReference(string name) { // call the base class, which will walk up the chain to find wherever the name lives JSVariableField variableField = base.FindReference(name); if (variableField != null) { // it exists, but is it in our with scope? if (this[name] == null) { // it's not. We need to create an inner field pointing to this outer // field so we can make sure the name doesn't get crunched variableField = CreateInnerField(variableField); } } else { // because this is a with scope, if something isn't defined anywhere, we // don't want to throw an error because we very well may be referencing // a property on the object of the with scope. // So add a global field to our scope and return that instead, and use the // RTSpecialName flag to indicate that we don't really know what this thing could be. JSVariableField globalField = Parser.GlobalScope.AddField( new JSGlobalField(name, null, FieldAttributes.RTSpecialName) ); variableField = CreateInnerField(globalField); } return(variableField); }
public override JSVariableField CreateInnerField(JSVariableField outerField) { // blindly create an inner reference field for with scopes, no matter what it // is. globals and predefined values can be hijacked by object properties in // this scope. JSVariableField innerField = CreateField(outerField); AddField(innerField); return(innerField); }
internal JSLocalField(JSVariableField outerField) : base(outerField) { JSLocalField outerLocalField = outerField as JSLocalField; if (outerLocalField != null) { // copy some properties m_isDefined = outerLocalField.m_isDefined; m_isGenerated = outerLocalField.m_isGenerated; } }
private JSVariableField ResolveFromCollection(string name, HashSet <string> collection, FieldType fieldType, bool isFunction) { if (collection.Contains(name)) { var variableField = new JSVariableField(fieldType, name, 0, null); variableField.IsFunction = isFunction; return(AddField(variableField)); } return(null); }
public virtual JSVariableField FindReference(string name) { // see if we have it JSVariableField variableField = this[name]; // if we didn't find anything and this scope has a parent if (variableField == null && Parent != null) { // recursively go up the scope chain variableField = Parent.FindReference(name); } return(variableField); }
//public abstract BlockScope Clone(); public override JSVariableField this[string name] { get { // check this name table JSVariableField variableField = base[name]; if (variableField == null) { // we need to keep checking until we hit a non-block scope? } return(variableField); } }
// NAME [SCOPE TYPE] [crunched to CRUNCH] // // SCOPE: global, local, outer, '' // TYPE: var, function, argument, arguments array, possibly undefined private void WriteMemberReport(JSVariableField variableField, ActivationObject immediateScope) { // skip any *unreferenced* named-function-expression fields JSNamedFunctionExpressionField namedFuncExpr = variableField as JSNamedFunctionExpressionField; if (namedFuncExpr == null || namedFuncExpr.RefCount > 0 || !m_removeFunctionExpressionNames) { string scope = string.Empty; string type = string.Empty; string crunched = string.Empty; string name = variableField.Name; if (variableField.IsLiteral) { name = variableField.FieldValue.ToString(); } // calculate the crunched label JSLocalField localField = variableField as JSLocalField; if (localField != null) { if (localField.CrunchedName != null) { crunched = StringMgr.GetString("CrunchedTo", localField.CrunchedName, localField.RefCount); } } // get the field's default scope and type GetFieldScopeType(variableField, immediateScope, out scope, out type); if (variableField is JSWithField) { // if the field is a with field, we won't be using the crunched field (since // those fields can't be crunched), so let's overload it with what the field // could POSSIBLY be if the with object doesn't have a property of that name string outerScope; string outerType; GetFieldScopeType(variableField.OuterField, immediateScope, out outerScope, out outerType); crunched = StringMgr.GetString("MemberInfoWithPossibly", outerScope, outerType); } // format the entire string WriteProgress(StringMgr.GetString( "MemberInfoFormat", name, scope, type, crunched )); } }
internal override void AnalyzeScope() { if (Context != null) { // get the parent global/function scope where variables defined within our // scope are REALLY defined ActivationObject definingScope = this; do { definingScope = definingScope.Parent; } while (definingScope is BlockScope); // see if there is a variable already defined in that scope with the same name JSVariableField outerField = definingScope[m_name]; if (outerField != null) { // there is one defined already!!! // but if it isn't referenced, it's safe to just use it // as the outer field for our catch variable so our names // stay in sync when we rename stuff if (outerField.IsReferenced) { // but the outer field IS referenced somewhere! We have a possible ambiguous // catch variable problem that behaves differently in IE and non-IE browsers. Context.HandleError(JSError.AmbiguousCatchVar); } } else { // there isn't one defined -- add one and hook it to our argument // field as the outer reference so the name doesn't collide with any // other fields in that scope if we are renaming fields outerField = definingScope.CreateField(m_name, null, 0); outerField.IsPlaceholder = true; definingScope.AddField(outerField); } // point our inner catch variable to the outer variable this[m_name].OuterField = outerField; } base.AnalyzeScope(); }
public virtual JSVariableField CreateInnerField(JSVariableField outerField) { JSVariableField innerField; if (outerField is JSGlobalField || outerField is JSPredefinedField) { // if this is a global or predefined field, then just add the field itself // to the local scope. We don't want to create a local reference. innerField = outerField; } else { // create a new inner field to be added to our scope innerField = CreateField(outerField); } // add the field to our scope and return it AddField(innerField); return(innerField); }
internal JSVariableField(FieldType fieldType, JSVariableField outerField) { if (outerField == null) { throw new ArgumentNullException("outerField"); } m_referenceTable = new HashSet <INameReference>(); m_declarationTable = new HashSet <INameDeclaration>(); // set values based on the outer field OuterField = outerField; Name = outerField.Name; Attributes = outerField.Attributes; FieldValue = outerField.FieldValue; IsGenerated = outerField.IsGenerated; // and set some other fields on our object based on the type we are SetFieldsBasedOnType(fieldType); }
public override JSVariableField FindReference(string name) { JSVariableField variableField = this[name]; if (variableField == null) { // didn't find a field in this scope. // special to function scopes: check to see if this is the arguments object if (string.Compare(name, "arguments", StringComparison.Ordinal) == 0) { // this is a reference to the arguments object, so add the // arguments field to the scope and return it variableField = AddArgumentsField(); } else { // recurse up the parent chain variableField = Parent.FindReference(name); } } return(variableField); }
public override JSVariableField this[string name] { get { // check the name table JSVariableField variableField = base[name]; // not found so far, check the global properties if (variableField == null) { variableField = ResolveFromCollection(name, m_globalProperties, FieldType.Predefined, false); } // not found so far, check the global properties if (variableField == null) { variableField = ResolveFromCollection(name, m_globalFunctions, FieldType.Predefined, true); } // if not found so far, check to see if this value is provided in our "assumed" // global list specified on the command line if (variableField == null) { variableField = ResolveFromCollection(name, m_assumedGlobals, FieldType.Global, false); } // if it's not something explicitly defined so far, check to see if it // matches the browser-specific pattern (prefixes followed by Pascal-cased identifiers). // Plus, most browsers expose dozens of DOM elements prefixed by "HTML" // (eg: HTMLAnchorElement and HTMLTableColElement). if (variableField == null && s_blanketPrefixes.IsMatch(name)) { variableField = new JSVariableField(FieldType.Predefined, name, 0, null); AddField(variableField); } return(variableField); } }
private static Context GetFirstDeclaration(JSVariableField variableField) { // only local fields that actually correspond to a declaration get the declaration // added to the declarations collection -- inner references don't get the declaration, // and neither do ghosted variables. So starting from this variable, walk up the // outer-reference chain until we find on with at least one declaration. If we don't // find one, that's fine -- there probably isn't a declaration for it (predefined, for example). while (variableField != null && variableField.Declarations.Count == 0) { variableField = variableField.OuterField; } if (variableField != null) { foreach (var declaration in variableField.Declarations) { // we only care about the FIRST declaration, so return the context of the name return(declaration.Context); } } // if we get here, there were no declarations return(null); }
internal override void AnalyzeNode() { // get the field -- it should have been generated when the scope was analyzed if (CatchBlock != null && !string.IsNullOrEmpty(m_catchVarName)) { m_catchVariable = CatchBlock.BlockScope[m_catchVarName]; } // anaylze the blocks base.AnalyzeNode(); // if the try block is empty, then set it to null if (TryBlock != null && TryBlock.Count == 0) { TryBlock = null; } // eliminate an empty finally block UNLESS there is no catch block. if (FinallyBlock != null && FinallyBlock.Count == 0 && CatchBlock != null && Parser.Settings.IsModificationAllowed(TreeModifications.RemoveEmptyFinally)) { FinallyBlock = null; } }
internal JSVariableField AddField(JSVariableField variableField) { m_nameTable[variableField.Name] = variableField; m_fieldTable.Add(variableField); return variableField; }
public FunctionObject(Lookup identifier, JSParser parser, FunctionType functionType, ParameterDeclaration[] parameterDeclarations, Block bodyBlock, Context functionContext, FunctionScope functionScope) : base(functionContext, parser) { FunctionType = functionType; m_functionScope = functionScope; if (functionScope != null) { functionScope.FunctionObject = this; } m_name = string.Empty; m_identifier = identifier; if (m_identifier != null) { m_identifier.Parent = this; } // make sure the parameter array is never null so we don't have to keep checking it m_parameterDeclarations = parameterDeclarations ?? new ParameterDeclaration[0]; Body = bodyBlock; if (bodyBlock != null) { bodyBlock.Parent = this; } // now we need to make sure that the enclosing scope has the name of this function defined // so that any references get properly resolved once we start analyzing the parent scope // see if this is not anonymnous AND not a getter/setter bool isGetterSetter = (FunctionType == FunctionType.Getter || FunctionType == FunctionType.Setter); if (m_identifier != null && !isGetterSetter) { // yes -- add the function name to the current enclosing // check whether the function name is in use already // shouldn't be any duplicate names ActivationObject enclosingScope = m_functionScope.Parent; // functions aren't owned by block scopes while (enclosingScope is BlockScope) { enclosingScope = enclosingScope.Parent; } // if the enclosing scope already contains this name, then we know we have a dup string functionName = m_identifier.Name; m_variableField = enclosingScope[functionName]; if (m_variableField != null) { // it's pointing to a function m_variableField.IsFunction = true; if (FunctionType == FunctionType.Expression) { // if the containing scope is itself a named function expression, then just // continue on as if everything is fine. It will chain and be good. if (!(m_variableField is JSNamedFunctionExpressionField)) { if (m_variableField.NamedFunctionExpression != null) { // we have a second named function expression in the same scope // with the same name. Not an error unless someone actually references // it. // we are now ambiguous. m_variableField.IsAmbiguous = true; // BUT because this field now points to multiple function object, we // need to break the connection. We'll leave the inner NFEs pointing // to this field as the outer field so the names all align, however. DetachFromOuterField(true); // create a new NFE pointing to the existing field as the outer so // the names stay in sync, and with a value of our function object. JSNamedFunctionExpressionField namedExpressionField = new JSNamedFunctionExpressionField(m_variableField); namedExpressionField.FieldValue = this; m_functionScope.AddField(namedExpressionField); // hook our function object up to the named field m_variableField = namedExpressionField; m_identifier.VariableField = namedExpressionField; // we're done; quit. return; } else if (m_variableField.IsAmbiguous) { // we're pointing to a field that is already marked as ambiguous. // just create our own NFE pointing to this one, and hook us up. JSNamedFunctionExpressionField namedExpressionField = new JSNamedFunctionExpressionField(m_variableField); namedExpressionField.FieldValue = this; m_functionScope.AddField(namedExpressionField); // hook our function object up to the named field m_variableField = namedExpressionField; m_identifier.VariableField = namedExpressionField; // we're done; quit. return; } else { // we are a named function expression in a scope that has already // defined a local variable of the same name. Not good. Throw the // error but keep them attached because the names have to be synced // to keep the same meaning in all browsers. m_identifier.Context.HandleError(JSError.AmbiguousNamedFunctionExpression, true); // if we are preserving function names, then we need to mark this field // as not crunchable if (Parser.Settings.PreserveFunctionNames) { m_variableField.CanCrunch = false; } } } /*else * { * // it's okay; just chain the NFEs as normal and everything will work out * // and the names will be properly synced. * }*/ } else { // function declaration -- duplicate name m_identifier.Context.HandleError(JSError.DuplicateName, false); } } else { // doesn't exist -- create it now m_variableField = enclosingScope.DeclareField(functionName, this, 0); // and it's a pointing to a function object m_variableField.IsFunction = true; } // set the identifier variable field now. We *know* what the field is now, and during // Analyze mode we aren't going to recurse into the identifier because that would add // a reference to it. m_identifier.VariableField = m_variableField; // if we're here, we have a name. if this is a function expression, then we have // a named function expression and we need to do a little more work to prepare for // the ambiguities of named function expressions in various browsers. if (FunctionType == FunctionType.Expression) { // now add a field within the function scope that indicates that it's okay to reference // this named function expression from WITHIN the function itself. // the inner field points to the outer field since we're going to want to catch ambiguous // references in the future JSNamedFunctionExpressionField namedExpressionField = new JSNamedFunctionExpressionField(m_variableField); m_functionScope.AddField(namedExpressionField); m_variableField.NamedFunctionExpression = namedExpressionField; } else { // function declarations are declared by definition m_variableField.IsDeclared = true; } } }
internal JSVariableField AddField(JSVariableField variableField) { m_nameTable[variableField.Name] = variableField; m_fieldTable.Add(variableField); return(variableField); }
public override JSVariableField CreateField(JSVariableField outerField) { return new JSLocalField(outerField); }
public abstract JSVariableField CreateField(JSVariableField outerField);
internal JSVariableField(JSVariableField outerField) : this(outerField.Name, outerField.Attributes, outerField.FieldValue) { m_outerField = outerField; }
public FunctionObject(Lookup identifier, JSParser parser, FunctionType functionType, ParameterDeclaration[] parameterDeclarations, Block bodyBlock, Context functionContext, FunctionScope functionScope) : base(functionContext, parser) { FunctionType = functionType; m_functionScope = functionScope; if (functionScope != null) { functionScope.FunctionObject = this; } m_name = string.Empty; Identifier = identifier; if (Identifier != null) { Identifier.Parent = this; } m_parameterDeclarations = parameterDeclarations; Body = bodyBlock; if (bodyBlock != null) { bodyBlock.Parent = this; } // now we need to make sure that the enclosing scope has the name of this function defined // so that any references get properly resolved once we start analyzing the parent scope // see if this is not anonymnous AND not a getter/setter bool isGetterSetter = (FunctionType == FunctionType.Getter || FunctionType == FunctionType.Setter); if (Identifier != null && !isGetterSetter) { // yes -- add the function name to the current enclosing // check whether the function name is in use already // shouldn't be any duplicate names ActivationObject enclosingScope = m_functionScope.Parent; // functions aren't owned by block scopes while (enclosingScope is BlockScope) { enclosingScope = enclosingScope.Parent; } // if the enclosing scope already contains this name, then we know we have a dup string functionName = Identifier.Name; m_variableField = enclosingScope[functionName]; if (m_variableField != null) { // it's pointing to a function m_variableField.IsFunction = true; if (FunctionType == FunctionType.Expression) { // if the containing scope is itself a named function expression, then just // continue on as if everything is fine. It will chain and be good. if (!(m_variableField is JSNamedFunctionExpressionField)) { if (m_variableField.NamedFunctionExpression != null) { // we have a second named function expression in the same scope // with the same name. Not an error unless someone actually references // it. // we are now ambiguous. m_variableField.IsAmbiguous = true; // BUT because this field now points to multiple function object, we // need to break the connection. We'll leave the inner NFEs pointing // to this field as the outer field so the names all align, however. DetachFromOuterField(true); // create a new NFE pointing to the existing field as the outer so // the names stay in sync, and with a value of our function object. JSNamedFunctionExpressionField namedExpressionField = new JSNamedFunctionExpressionField(m_variableField); namedExpressionField.FieldValue = this; m_functionScope.AddField(namedExpressionField); // hook our function object up to the named field m_variableField = namedExpressionField; Identifier.VariableField = namedExpressionField; // we're done; quit. return; } else if (m_variableField.IsAmbiguous) { // we're pointing to a field that is already marked as ambiguous. // just create our own NFE pointing to this one, and hook us up. JSNamedFunctionExpressionField namedExpressionField = new JSNamedFunctionExpressionField(m_variableField); namedExpressionField.FieldValue = this; m_functionScope.AddField(namedExpressionField); // hook our function object up to the named field m_variableField = namedExpressionField; Identifier.VariableField = namedExpressionField; // we're done; quit. return; } else { // we are a named function expression in a scope that has already // defined a local variable of the same name. Not good. Throw the // error but keep them attached because the names have to be synced // to keep the same meaning in all browsers. Identifier.Context.HandleError(JSError.AmbiguousNamedFunctionExpression, false); // if we are preserving function names, then we need to mark this field // as not crunchable if (Parser.Settings.PreserveFunctionNames) { m_variableField.CanCrunch = false; } } } /*else { // it's okay; just chain the NFEs as normal and everything will work out // and the names will be properly synced. }*/ } else { // function declaration -- duplicate name Identifier.Context.HandleError(JSError.DuplicateName, false); } } else { // doesn't exist -- create it now m_variableField = enclosingScope.DeclareField(functionName, this, 0); // and it's a pointing to a function object m_variableField.IsFunction = true; } // set the identifier variable field now. We *know* what the field is now, and during // Analyze mode we aren't going to recurse into the identifier because that would add // a reference to it. Identifier.VariableField = m_variableField; // if we're here, we have a name. if this is a function expression, then we have // a named function expression and we need to do a little more work to prepare for // the ambiguities of named function expressions in various browsers. if (FunctionType == FunctionType.Expression) { // now add a field within the function scope that indicates that it's okay to reference // this named function expression from WITHIN the function itself. // the inner field points to the outer field since we're going to want to catch ambiguous // references in the future JSNamedFunctionExpressionField namedExpressionField = new JSNamedFunctionExpressionField(m_variableField); m_functionScope.AddField(namedExpressionField); m_variableField.NamedFunctionExpression = namedExpressionField; } else { // function declarations are declared by definition m_variableField.IsDeclared = true; } } }
/*public override BlockScope Clone() * { * return new CatchScope(Parser.ScopeStack.Peek(), Context, Parser); * }*/ public override JSVariableField CreateField(JSVariableField outerField) { return(new JSLocalField(outerField)); }
private static void GetFieldScopeType(JSVariableField variableField, ActivationObject immediateScope, out string scope, out string type) { JSLocalField localField = variableField as JSLocalField; JSPredefinedField predefinedField = variableField as JSPredefinedField; JSNamedFunctionExpressionField namedFuncExpr = variableField as JSNamedFunctionExpressionField; // default scope is blank scope = string.Empty; if (variableField is JSArgumentField) { type = StringMgr.GetString("MemberInfoTypeArgument"); } else if (variableField is JSArgumentsField) { type = StringMgr.GetString("MemberInfoTypeArguments"); } else if (predefinedField != null) { switch (predefinedField.GlobalObject) { case GlobalObjectInstance.GlobalObject: scope = StringMgr.GetString("MemberInfoScopeGlobalObject"); break; case GlobalObjectInstance.WindowObject: scope = StringMgr.GetString("MemberInfoScopeWindowObject"); break; case GlobalObjectInstance.Other: scope = StringMgr.GetString("MemberInfoScopeOtherObject"); break; } switch (predefinedField.MemberType) { case MemberTypes.Method: type = StringMgr.GetString("MemberInfoBuiltInMethod"); break; case MemberTypes.Property: type = StringMgr.GetString("MemberInfoBuiltInProperty"); break; default: type = StringMgr.GetString("MemberInfoBuiltInObject"); break; } } else if (variableField is JSGlobalField) { if ((variableField.Attributes & FieldAttributes.RTSpecialName) == FieldAttributes.RTSpecialName) { // this is a special "global." It might not be a global, but something referenced // in a with scope somewhere down the line. type = StringMgr.GetString("MemberInfoPossiblyUndefined"); } else if (variableField.FieldValue is FunctionObject) { if (variableField.NamedFunctionExpression == null) { type = StringMgr.GetString("MemberInfoGlobalFunction"); } else { type = StringMgr.GetString("MemberInfoFunctionExpression"); } } else { type = StringMgr.GetString("MemberInfoGlobalVar"); } } else if (variableField is JSWithField) { type = StringMgr.GetString("MemberInfoWithField"); } else if (namedFuncExpr != null) { type = StringMgr.GetString("MemberInfoSelfFuncExpr"); } else if (localField != null) { // type string if (localField.FieldValue is FunctionObject) { if (localField.NamedFunctionExpression == null) { type = StringMgr.GetString("MemberInfoLocalFunction"); } else { type = StringMgr.GetString("MemberInfoFunctionExpression"); } } else if (localField.IsLiteral) { type = StringMgr.GetString("MemberInfoLocalLiteral"); } else { type = StringMgr.GetString("MemberInfoLocalVar"); } // scope string // this is a local variable, so there MUST be a non-null function scope passed // to us. That function scope will be the scope we are expecting local variables // to be defined in. If the field is defined in that scope, it's local -- otherwise // it must be an outer variable. JSVariableField scopeField = immediateScope[variableField.Name]; if (scopeField == null || scopeField.OuterField != null) { scope = StringMgr.GetString("MemberInfoScopeOuter"); } else { scope = StringMgr.GetString("MemberInfoScopeLocal"); } } else { type = StringMgr.GetString("MemberInfoBuiltInObject"); } }
public void SetCatchVariable(JSVariableField field) { m_catchVariable = field; }
public JSVariableField(JSVariableField outerField) : this(outerField.Name, outerField.Attributes, outerField.FieldValue) { m_outerField = outerField; }
public override JSVariableField CreateField(JSVariableField outerField) { // should NEVER try to create an inner field in a global scope throw new NotImplementedException(); }
private void ProcessField(JSVariableField field, bool isDefined) { // save THIS field's refcount value because we will // be adjusting hte field pointer to be the outermost field // and we want to report THIS field's refcount, not the overall. var refCount = field.RefCount; var isGhost = false; // make sure we're at the outer-most field var isOuter = false; if (!isDefined) { while (field.OuterField != null) { isOuter = true; field = field.OuterField; } } m_writer.WriteStartElement("field"); if (field.IsExported) { m_writer.WriteAttributeString("exported", "true"); } var typeValue = field.FieldType.ToString(); switch (field.FieldType) { case FieldType.Argument: case FieldType.CatchError: case FieldType.WithField: if (isOuter) { typeValue = "Outer " + typeValue; } break; case FieldType.Local: if (isOuter) { typeValue = "Outer "; } else { typeValue = string.Empty; if (field.IsPlaceholder || !field.IsDeclared) { isGhost = true; } } if (field.IsFunction) { typeValue += "Function"; } else { typeValue += "Variable"; } break; case FieldType.Arguments: case FieldType.Global: case FieldType.UndefinedGlobal: case FieldType.GhostCatch: case FieldType.GhostFunction: case FieldType.Predefined: case FieldType.Super: break; } m_writer.WriteAttributeString("type", typeValue.ToLowerInvariant()); m_writer.WriteAttributeString("src", field.Name); if (field.CrunchedName != null) { m_writer.WriteAttributeString("min", field.CrunchedName); } OutputContextPosition(field.OriginalContext); if (m_useReferenceCounts) { m_writer.WriteAttributeString("refcount", refCount.ToStringInvariant()); } if (field.IsAmbiguous) { m_writer.WriteAttributeString("ambiguous", "true"); } if (field.IsGenerated) { m_writer.WriteAttributeString("generated", "true"); } if (isGhost) { m_writer.WriteAttributeString("ghost", "true"); } m_writer.WriteEndElement(); }
public void DetachFromOuterField(bool leaveInnerPointingToOuter) { // we're going to change the reference from the outer variable to the inner variable // save the inner variable field JSNamedFunctionExpressionField nfeField = m_variableField.NamedFunctionExpression; // break the connection from the outer to the inner m_variableField.NamedFunctionExpression = null; if (!leaveInnerPointingToOuter) { // detach the inner from the outer nfeField.Detach(); } // the outer field no longer points to the function object m_variableField.FieldValue = null; // but the inner field should nfeField.FieldValue = this; // our variable field is now the inner field m_variableField = nfeField; // and so is out identifier Identifier.VariableField = nfeField; }
public virtual JSVariableField CreateInnerField(JSVariableField outerField) { JSVariableField innerField; if (outerField is JSGlobalField || outerField is JSPredefinedField) { // if this is a global or predefined field, then just add the field itself // to the local scope. We don't want to create a local reference. innerField = outerField; } else { // create a new inner field to be added to our scope innerField = CreateField(outerField); } // add the field to our scope and return it AddField(innerField); return innerField; }
public VariableDeclaration(Context context, JSParser parser, string identifier, Context idContext, AstNode initializer, FieldAttributes fieldAttributes, bool ignoreDuplicates) : base(context, parser) { // identifier cannot be null m_identifier = identifier; // initializer may be null m_initializer = initializer; if (m_initializer != null) { m_initializer.Parent = this; } // we'll need to do special stuff if the initializer if a function expression, // so try the conversion now FunctionObject functionValue = m_initializer as FunctionObject; string name = m_identifier.ToString(); ActivationObject currentScope = ScopeStack.Peek(); ActivationObject definingScope = currentScope; if (definingScope is BlockScope) { // block scope -- the variable is ACTUALLY defined in the containing function/global scope, // so we need to check THERE for duplicate defines. do { definingScope = definingScope.Parent; } while (definingScope is BlockScope); } JSVariableField field = definingScope[name]; if (field != null && (functionValue == null || functionValue != field.FieldValue)) { // this is a declaration that already has a field declared. // if the field is a named function expression, we want to fire an // ambiguous named function expression error -- and we know it's an NFE // if the FieldValue is a function object OR if the field // has already been marked ambiguous if (field.IsAmbiguous || field.FieldValue is FunctionObject) { if (idContext != null) { idContext.HandleError( JSError.AmbiguousNamedFunctionExpression, true ); } else if (context != null) { // not identifier context???? Try the whole statment context. // if neither context is set, then we don't get an error! context.HandleError( JSError.AmbiguousNamedFunctionExpression, true ); } // if we are preserving function names, then we need to mark this field // as not crunchable if (Parser.Settings.PreserveFunctionNames) { field.CanCrunch = false; } } else if (!ignoreDuplicates) { if (idContext != null) { // otherwise just a normal duplicate error idContext.HandleError( JSError.DuplicateName, field.IsLiteral ); } else if (context != null) { // otherwise just a normal duplicate error context.HandleError( JSError.DuplicateName, field.IsLiteral ); } } } bool isLiteral = ((fieldAttributes & FieldAttributes.Literal) != 0); // normally the value will be null. // but if there is no initializer, we'll use Missing so we can tell the difference. // and if this is a literal, we'll set it to the actual literal astnode object val = null; if (m_initializer == null) { val = Missing.Value; } else if (isLiteral || (functionValue != null)) { val = m_initializer; } m_field = currentScope.DeclareField( m_identifier, val, fieldAttributes ); m_field.OriginalContext = idContext; // we are now declared by a var statement m_field.IsDeclared = true; // if we are declaring a variable inside a with statement, then we will be declaring // a local variable in the enclosing scope if the with object doesn't have a property // of that name. But if it does, we won't actually be creating a variable field -- we'll // just use the property. So if we use an initializer in this declaration, then we will // actually be referencing the value. // SO, if this is a with-scope and this variable declaration has an initializer, we're going // to go ahead and bump up the reference. if (currentScope is WithScope && m_initializer != null) { m_field.AddReference(currentScope); } // special case the ambiguous function expression test. If we are var-ing a variable // with the same name as the function expression, then it's okay. We won't have an ambiguous // reference and it will be okay to use the name to reference the function expression if (functionValue != null && string.CompareOrdinal(m_identifier, functionValue.Name) == 0) { // null out the link to the named function expression // and make the function object point to the PROPER variable: the local within its own scope // and the inner is not pointing to the outer. functionValue.DetachFromOuterField(false); m_field.IsFunction = false; } }
/// <summary> /// returns true if the fields point to the same ultimate reference object. /// Needs to walk up the outer-reference chain for each field in order to /// find the ultimate reference /// </summary> /// <param name="otherField"></param> /// <returns></returns> public bool IsSameField(JSVariableField otherField) { // shortcuts -- if they are already the same object, we're done; // and if the other field is null, then we are NOT the same object. if (this == otherField) { return true; } else if (otherField == null) { return false; } // get the ultimate field for this field var thisOuter = OuterField != null ? OuterField : this; while (thisOuter.OuterField != null) { thisOuter = thisOuter.OuterField; } // get the ultimate field for the other field var otherOuter = otherField.OuterField != null ? otherField.OuterField : otherField; while (otherOuter.OuterField != null) { otherOuter = otherOuter.OuterField; } // now that we have the same outer fields, check to see if they are the same return thisOuter == otherOuter; }