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; })); }
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); } } } }
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 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)); return withField; })); }
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 SourceContext 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); }
public override JSVariableField CreateField(JSVariableField outerField) { // when we create a field inside a with-scope, it's ALWAYS a with-field, no matter // what type the outer reference is. return(new JSVariableField(FieldType.WithField, outerField)); }
public override JSVariableField CreateField(JSVariableField outerField) { // should NEVER try to create an inner field in a global scope throw new NotImplementedException(); }
public JSNamedFunctionExpressionField(JSVariableField variableField) : base(variableField) { CanCrunch = true; IsFunction = true; }
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(); }
private static void GetFieldScopeType(JSVariableField variableField, out string scope, out string type) { // default scope is blank scope = string.Empty; switch (variableField.FieldType) { case FieldType.Argument: type = NUglify.MemberInfoTypeArgument; if (variableField.IsOuterReference) { scope = NUglify.MemberInfoScopeOuter; } break; case FieldType.Arguments: type = NUglify.MemberInfoTypeArguments; if (variableField.IsOuterReference) { scope = NUglify.MemberInfoScopeOuter; } break; case FieldType.CatchError: type = NUglify.MemberInfoTypeCatchEror; if (variableField.IsOuterReference) { scope = NUglify.MemberInfoScopeOuter; } break; case FieldType.Super: type = NUglify.MemberInfoTypeSuper; if (variableField.IsOuterReference) { scope = NUglify.MemberInfoScopeOuter; } break; case FieldType.GhostCatch: case FieldType.GhostFunction: default: // ghost fields -- ignore type = string.Empty; break; case FieldType.Global: case FieldType.UndefinedGlobal: 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 = NUglify.MemberInfoPossiblyUndefined; } else if (variableField.FieldValue is FunctionObject && variableField.GhostedField != null) { type = NUglify.MemberInfoFunctionExpression; } else { goto case FieldType.Local; } break; case FieldType.Local: // type string if (variableField.FieldValue is FunctionObject) { if (variableField.GhostedField == null) { type = NUglify.MemberInfoFunction; } else { type = NUglify.MemberInfoFunctionExpression; } } else if (variableField.FieldValue is ClassNode) { type = NUglify.MemberInfoClass; } else if (variableField.IsLiteral) { type = NUglify.MemberInfoLiteral; } else if (variableField.InitializationOnly) { type = NUglify.MemberInfoConst; } else { type = NUglify.MemberInfoVar; } // scope string if (variableField.IsOuterReference) { scope = NUglify.MemberInfoScopeOuter; } else if (variableField.FieldType == FieldType.Global || variableField.FieldType == FieldType.UndefinedGlobal) { scope = NUglify.MemberInfoScopeGlobal; } else { scope = NUglify.MemberInfoScopeLocal; } break; case FieldType.Predefined: scope = NUglify.MemberInfoScopeGlobalObject; type = variableField.IsFunction ? NUglify.MemberInfoBuiltInMethod : NUglify.MemberInfoBuiltInProperty; break; case FieldType.WithField: type = NUglify.MemberInfoWithField; if (variableField.IsOuterReference) { scope = NUglify.MemberInfoScopeOuter; } break; } if (variableField.IsExported) { scope = NUglify.MemberInfoScopeExported + scope; } }
// NAME [SCOPE TYPE] [crunched to CRUNCH] // // SCOPE: global, local, outer, '' // TYPE: var, function, argument, arguments array, possibly undefined private void WriteMemberReport(JSVariableField variableField) { // don't report arguments fields that aren't referenced because // we add those fields to the function scopes automatically if (variableField.FieldType != FieldType.Arguments || variableField.RefCount > 0) { 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 if (variableField.CrunchedName != null) { crunched = NUglify.CrunchedTo.FormatInvariant(variableField.CrunchedName, variableField.RefCount); } else { crunched = NUglify.MemberInfoReferences.FormatInvariant(variableField.RefCount); } // get the field's default scope and type GetFieldScopeType(variableField, out scope, out type); if (variableField.FieldType == FieldType.WithField) { // 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 if (variableField.OuterField != null) { // make sure we get the OUTERMOST outer ield var outerField = variableField.OuterField; while (outerField.OuterField != null) { outerField = outerField.OuterField; } string outerScope; string outerType; GetFieldScopeType(outerField, out outerScope, out outerType); if (!outerScope.IsNullOrWhiteSpace() || !outerType.IsNullOrWhiteSpace()) { crunched = NUglify.MemberInfoWithPossibly.FormatInvariant(outerScope, outerType); } } else { // no outer field. Then it must be a lexically-declared field inside the with-statement's // block. These are tricky! At run-time if you try to declare a function, const, or let // inside the with-scope, and the with-object already has a property with that name, the // declaration will throw a run-time error. crunched = variableField.IsFunction ? NUglify.MemberInfoWithLexFunc : NUglify.MemberInfoWithLexDecl; } } var definedLocation = string.Empty; var definedContext = GetFirstDeclaration(variableField); if (definedContext != null) { definedLocation = NUglify.MemberInfoDefinedLocation.FormatInvariant(definedContext.StartLineNumber, definedContext.StartColumn + 1); } // format the entire string WriteProgress(NUglify.MemberInfoFormat.FormatInvariant( name, scope, type, crunched, definedLocation )); } }