public static ScopeAccessInformation AddStructureExitPoints( this ScopeAccessInformation scopeInformation, CSharpName structureExitFlagNameIfAny, ScopeAccessInformation.ExitableNonScopeDefiningConstructOptions structureExitType) { if (scopeInformation == null) { throw new ArgumentNullException("scopeInformation"); } if (!Enum.IsDefined(typeof(ScopeAccessInformation.ExitableNonScopeDefiningConstructOptions), structureExitType)) { throw new ArgumentOutOfRangeException("structureExitType"); } return(new ScopeAccessInformation( scopeInformation.Parent, scopeInformation.ScopeDefiningParent, scopeInformation.ParentReturnValueNameIfAny, scopeInformation.ErrorRegistrationTokenIfAny, scopeInformation.DirectedWithReferenceIfAny, scopeInformation.ExternalDependencies, scopeInformation.Classes, scopeInformation.Functions, scopeInformation.Properties, scopeInformation.Constants, scopeInformation.Variables, scopeInformation.StructureExitPoints .Add(new ScopeAccessInformation.ExitableNonScopeDefiningConstructDetails( structureExitFlagNameIfAny, structureExitType )) )); }
public ForEachBlockTranslator( CSharpName supportRefName, CSharpName envClassName, CSharpName envRefName, CSharpName outerClassName, CSharpName outerRefName, VBScriptNameRewriter nameRewriter, TempValueNameGenerator tempNameGenerator, ITranslateIndividualStatements statementTranslator, ITranslateValueSettingsStatements valueSettingStatementTranslator, ILogInformation logger) : base(supportRefName, envClassName, envRefName, outerClassName, outerRefName, nameRewriter, tempNameGenerator, statementTranslator, valueSettingStatementTranslator, logger) { if (statementTranslator == null) { throw new ArgumentNullException("statementTranslator"); } if (logger == null) { throw new ArgumentNullException("logger"); } _statementTranslator = statementTranslator; _logger = logger; }
public OuterScopeBlockTranslator( CSharpName startNamespace, CSharpName startClassName, CSharpName startMethodName, CSharpName runtimeDateLiteralValidatorClassName, CSharpName supportRefName, CSharpName envClassName, CSharpName envRefName, CSharpName outerClassName, CSharpName outerRefName, VBScriptNameRewriter nameRewriter, TempValueNameGenerator tempNameGenerator, ITranslateIndividualStatements statementTranslator, ITranslateValueSettingsStatements valueSettingStatementTranslator, NonNullImmutableList <NameToken> externalDependencies, OutputTypeOptions outputType, ILogInformation logger) : base(supportRefName, envClassName, envRefName, outerClassName, outerRefName, nameRewriter, tempNameGenerator, statementTranslator, valueSettingStatementTranslator, logger) { if (startNamespace == null) { throw new ArgumentNullException("startNamespace"); } if (startClassName == null) { throw new ArgumentNullException("startClassName"); } if (startMethodName == null) { throw new ArgumentNullException("startMethodName"); } if (runtimeDateLiteralValidatorClassName == null) { throw new ArgumentNullException("runtimeDateLiteralValidatorClassName"); } if (externalDependencies == null) { throw new ArgumentNullException("externalDependencies"); } if (!Enum.IsDefined(typeof(OutputTypeOptions), outputType)) { throw new ArgumentOutOfRangeException("outputType"); } if (logger == null) { throw new ArgumentNullException("logger"); } _startNamespace = startNamespace; _startClassName = startClassName; _startMethodName = startMethodName; _runtimeDateLiteralValidatorClassName = runtimeDateLiteralValidatorClassName; _externalDependencies = externalDependencies; _outputType = outputType; _logger = logger; }
public ClassBlockTranslator( CSharpName supportRefName, CSharpName envClassName, CSharpName envRefName, CSharpName outerClassName, CSharpName outerRefName, VBScriptNameRewriter nameRewriter, TempValueNameGenerator tempNameGenerator, ITranslateIndividualStatements statementTranslator, ITranslateValueSettingsStatements valueSettingStatementTranslator, ILogInformation logger) : base(supportRefName, envClassName, envRefName, outerClassName, outerRefName, nameRewriter, tempNameGenerator, statementTranslator, valueSettingStatementTranslator, logger) { }
public FuncByRefMapping(NameToken from, CSharpName to, bool mappedValueIsReadOnly) { if (from == null) { throw new ArgumentNullException("from"); } if (to == null) { throw new ArgumentNullException("to"); } From = from; To = to; MappedValueIsReadOnly = mappedValueIsReadOnly; }
public ValueSettingStatementsTranslator( CSharpName supportRefName, CSharpName envRefName, CSharpName outerRefName, VBScriptNameRewriter nameRewriter, ITranslateIndividualStatements statementTranslator, ILogInformation logger) { if (supportRefName == null) { throw new ArgumentNullException("supportRefName"); } if (envRefName == null) { throw new ArgumentNullException("envRefName"); } if (outerRefName == null) { throw new ArgumentNullException("outerRefName"); } if (nameRewriter == null) { throw new ArgumentNullException("nameRewriter"); } if (statementTranslator == null) { throw new ArgumentNullException("statementTranslator"); } if (logger == null) { throw new ArgumentNullException("logger"); } _supportRefName = supportRefName; _envRefName = envRefName; _outerRefName = outerRefName; _nameRewriter = nameRewriter; _statementTranslator = statementTranslator; _logger = logger; }
private TranslationResult Translate( NonNullImmutableList <ICodeBlock> blocks, ScopeAccessInformation scopeAccessInformation, bool supportsExit, CSharpName earlyExitNameIfAny, int indentationDepth) { if (blocks == null) { throw new ArgumentNullException("block"); } if (scopeAccessInformation == null) { throw new ArgumentNullException("scopeAccessInformation"); } if (!supportsExit && (earlyExitNameIfAny != null)) { throw new ArgumentException("earlyExitNameIfAny should always be null if supportsExit is false"); } if (indentationDepth < 0) { throw new ArgumentOutOfRangeException("indentationDepth", "must be zero or greater"); } // Add a StructureExitPoint entry for the current loop so that the "early-exit" logic described in the Translate method above is possible if (supportsExit) { scopeAccessInformation = scopeAccessInformation.AddStructureExitPoints( earlyExitNameIfAny, ScopeAccessInformation.ExitableNonScopeDefiningConstructOptions.Do ); } return(base.TranslateCommon( base.GetWithinFunctionBlockTranslators(), blocks, scopeAccessInformation, indentationDepth )); }
/// <summary> /// If the parent is scope-defining then both the parent and scopeDefiningParent references will be set to it, this is a convenience method to /// save having to specify it explicitly for both /// </summary> public static ScopeAccessInformation Extend( this ScopeAccessInformation scopeInformation, IDefineScope parent, CSharpName parentReturnValueNameIfAny, CSharpName errorRegistrationTokenIfAny, NonNullImmutableList <ICodeBlock> blocks) { if (scopeInformation == null) { throw new ArgumentNullException("scopeInformation"); } if (parent == null) { throw new ArgumentNullException("parent"); } if (blocks == null) { throw new ArgumentNullException("blocks"); } return(Extend(scopeInformation, parent, parent, parentReturnValueNameIfAny, errorRegistrationTokenIfAny, blocks)); }
private IEnumerable <TranslatedStatement> TranslateFunctionHeader(AbstractFunctionBlock functionBlock, ScopeAccessInformation scopeAccessInformation, CSharpName returnValueNameIfAny, int indentationDepth) { if (functionBlock == null) { throw new ArgumentNullException("functionBlock"); } if (functionBlock.HasReturnValue && (returnValueNameIfAny == null)) { throw new ArgumentException("returnValueNameIfAny must not be null if functionBlock.HasReturnValue is true"); } if (scopeAccessInformation == null) { throw new ArgumentNullException("scopeAccessInformation"); } if (indentationDepth < 0) { throw new ArgumentOutOfRangeException("indentationDepth", "must be zero or greater"); } var content = new StringBuilder(); content.Append(functionBlock.IsPublic ? "public" : "private"); content.Append(" "); content.Append(functionBlock.HasReturnValue ? "object" : "void"); content.Append(" "); content.Append(_nameRewriter.GetMemberAccessTokenName(functionBlock.Name)); content.Append("("); var numberOfParameters = functionBlock.Parameters.Count(); for (var index = 0; index < numberOfParameters; index++) { var parameter = functionBlock.Parameters.ElementAt(index); if (parameter.ByRef) { content.Append("ref "); } content.Append("object "); content.Append(_nameRewriter.GetMemberAccessTokenName(parameter.Name)); if (index < (numberOfParameters - 1)) { content.Append(", "); } } content.Append(")"); var translatedStatements = new List <TranslatedStatement>(); if (functionBlock.IsDefault) { translatedStatements.Add(new TranslatedStatement("[" + typeof(IsDefault).FullName + "]", indentationDepth, functionBlock.Name.LineIndex)); } var property = functionBlock as PropertyBlock; if (property != null) { // All property blocks that are translated into C# methods needs to be decorated with the [TranslatedProperty] attribute. The [TranslatedProperty] attribute // was originally intended only for indexed properties (which C# can only support one of per class but VBScript classes can have as many as they like) but // a class with an indexed property will be emitted to inherit from TranslatedPropertyIReflectImplementation, which will try to identify properties based // upon the presence of [TranslatedProperty] attributes - if some (ie. indexed properties) have these and others (non-indexed properties) don't then it // will result in runtime failures. So we could apply the attribute to indexed properties and all properties within classes that have at least one // indexed property but that feels like complications for little benefit so I think it's easier to just put it on ALL from-property methods. translatedStatements.Add( new TranslatedStatement( string.Format( "[TranslatedProperty({0})]", // Note: Safe to assume that using statements are present for the namespace that contains TranslatedProperty property.Name.Content.ToLiteral() ), indentationDepth, functionBlock.Name.LineIndex ) ); } translatedStatements.Add(new TranslatedStatement(content.ToString(), indentationDepth, functionBlock.Name.LineIndex)); translatedStatements.Add(new TranslatedStatement("{", indentationDepth, functionBlock.Name.LineIndex)); if (functionBlock.HasReturnValue && functionBlock.Statements.Any() && !IsSingleReturnValueStatementFunctionWithoutAnyByRefMappings(functionBlock, scopeAccessInformation)) { translatedStatements.Add(new TranslatedStatement( base.TranslateVariableInitialisation( new VariableDeclaration( new DoNotRenameNameToken( returnValueNameIfAny.Name, functionBlock.Name.LineIndex ), VariableDeclarationScopeOptions.Private, null // Not declared as an array ), ScopeLocationOptions.WithinFunctionOrPropertyOrWith ), indentationDepth + 1, functionBlock.Name.LineIndex )); } return(translatedStatements); }
public static ScopeAccessInformation Extend( this ScopeAccessInformation scopeInformation, IHaveNestedContent parent, IDefineScope scopeDefiningParent, CSharpName parentReturnValueNameIfAny, CSharpName errorRegistrationTokenIfAny, NonNullImmutableList <ICodeBlock> blocks) { if (parent == null) { throw new ArgumentNullException("parent"); } if (scopeDefiningParent == null) { throw new ArgumentNullException("scopeDefiningParent"); } if (scopeInformation == null) { throw new ArgumentNullException("scopeInformation"); } if (blocks == null) { throw new ArgumentNullException("blocks"); } var blocksScopeLocation = scopeDefiningParent.Scope; blocks = FlattenAllAccessibleBlockLevelCodeBlocks(blocks); var variables = scopeInformation.Variables.AddRange( blocks .OfType <DimStatement>() // This covers DIM, REDIM, PRIVATE and PUBLIC (they may all be considered the same for these purposes) .SelectMany(d => d.Variables.Select(v => new ScopedNameToken( v.Name.Content, v.Name.LineIndex, blocksScopeLocation ))) ); if (scopeDefiningParent != null) { variables = variables.AddRange( scopeDefiningParent.ExplicitScopeAdditions .Select(v => new ScopedNameToken( v.Content, v.LineIndex, blocksScopeLocation ) ) ); } var constants = scopeInformation.Constants.AddRange( blocks .OfType <ConstStatement>() .SelectMany(c => c.Values.Select(v => new ScopedNameToken( v.Name.Content, v.Name.LineIndex, blocksScopeLocation ))) ); return(new ScopeAccessInformation( parent, scopeDefiningParent, parentReturnValueNameIfAny, errorRegistrationTokenIfAny, scopeInformation.DirectedWithReferenceIfAny, scopeInformation.ExternalDependencies, scopeInformation.Classes.AddRange( blocks .Where(b => b is ClassBlock) .Cast <ClassBlock>() .Select(c => new ScopedNameToken(c.Name.Content, c.Name.LineIndex, ScopeLocationOptions.OutermostScope)) // These are always OutermostScope ), scopeInformation.Functions.AddRange( blocks .Where(b => (b is FunctionBlock) || (b is SubBlock)) .Cast <AbstractFunctionBlock>() .Select(b => new ScopedNameToken(b.Name.Content, b.Name.LineIndex, blocksScopeLocation)) ), scopeInformation.Properties.AddRange( blocks .Where(b => b is PropertyBlock) .Cast <PropertyBlock>() .Select(p => new ScopedNameToken(p.Name.Content, p.Name.LineIndex, ScopeLocationOptions.WithinClass)) // These are always WithinClass ), constants, variables, scopeInformation.StructureExitPoints )); }
/// <summary> /// This Translate signature is what the others call into - it doesn't try to hide the fact that externalDependencies should be a NonNullImmutableList /// of strings and it requires an ILogInformation implementation to deal with logging warnings /// </summary> public static NonNullImmutableList <TranslatedStatement> Translate( string scriptContent, NonNullImmutableList <string> externalDependencies, OuterScopeBlockTranslator.OutputTypeOptions outputType, ILogInformation logger) { if (scriptContent == null) { throw new ArgumentNullException("scriptContent"); } if (externalDependencies == null) { throw new ArgumentNullException("externalDependencies"); } if ((outputType != OuterScopeBlockTranslator.OutputTypeOptions.Executable) && (outputType != OuterScopeBlockTranslator.OutputTypeOptions.WithoutScaffolding)) { throw new ArgumentOutOfRangeException("outputType"); } if (logger == null) { throw new ArgumentNullException("logger"); } var startNamespace = new CSharpName("TranslatedProgram"); var startClassName = new CSharpName("Runner"); var startMethodName = new CSharpName("Go"); var runtimeDateLiteralValidatorClassName = new CSharpName("RuntimeDateLiteralValidator"); var supportRefName = new CSharpName("_"); var envClassName = new CSharpName("EnvironmentReferences"); var envRefName = new CSharpName("_env"); var outerClassName = new CSharpName("GlobalReferences"); var outerRefName = new CSharpName("_outer"); VBScriptNameRewriter nameRewriter = name => new CSharpName(DefaultRuntimeSupportClassFactory.DefaultNameRewriter(name.Content)); var tempNameGeneratorNextNumber = 0; TempValueNameGenerator tempNameGenerator = (optionalPrefix, scopeAccessInformation) => { // To get unique names for any given translation, a running counter is maintained and appended to the end of the generated // name. This is only run during translation (this code is not used during execution) so there will be a finite number of // times that this is called (so there should be no need to worry about the int value overflowing!) return(new CSharpName(((optionalPrefix == null) ? "temp" : optionalPrefix.Name) + (++tempNameGeneratorNextNumber).ToString())); }; var statementTranslator = new StatementTranslator(supportRefName, envRefName, outerRefName, nameRewriter, tempNameGenerator, logger); var codeBlockTranslator = new OuterScopeBlockTranslator( startNamespace, startClassName, startMethodName, runtimeDateLiteralValidatorClassName, supportRefName, envClassName, envRefName, outerClassName, outerRefName, nameRewriter, tempNameGenerator, statementTranslator, new ValueSettingStatementsTranslator(supportRefName, envRefName, outerRefName, nameRewriter, statementTranslator, logger), externalDependencies.Select(name => new NameToken(name, 0)).ToNonNullImmutableList(), outputType, logger ); return(codeBlockTranslator.Translate( Parse(scriptContent).ToNonNullImmutableList() )); }
public static ScopeAccessInformation SetErrorRegistrationToken(this ScopeAccessInformation scopeAccessInformation, CSharpName errorRegistrationTokenIfAny) { if (scopeAccessInformation == null) { throw new ArgumentNullException("scopeAccessInformation"); } return(new ScopeAccessInformation( scopeAccessInformation.Parent, scopeAccessInformation.ScopeDefiningParent, scopeAccessInformation.ParentReturnValueNameIfAny, errorRegistrationTokenIfAny, scopeAccessInformation.DirectedWithReferenceIfAny, scopeAccessInformation.ExternalDependencies, scopeAccessInformation.Classes, scopeAccessInformation.Functions, scopeAccessInformation.Properties, scopeAccessInformation.Constants, scopeAccessInformation.Variables, scopeAccessInformation.StructureExitPoints )); }
/// <summary> /// Get the name of the containing reference where applicable. For outermost scope variable references, the target container will be the reference to the /// outer most scope (aka. Global References) instance. For undeclared variables, it will be the Environment References instance when in the outermost scope /// but undeclared variables within functions or properties are implicitly declared within that function or property, and so need no target container to be /// specified. This will return null if no container is required to locate the specified target. /// </summary> public static CSharpName GetNameOfTargetContainerIfAnyRequired( this ScopeAccessInformation scopeAccessInformation, NameToken target, CSharpName envRefName, CSharpName outerRefName, VBScriptNameRewriter nameRewriter) { if (scopeAccessInformation == null) { throw new ArgumentNullException("scopeAccessInformation"); } if (target == null) { throw new ArgumentNullException("target"); } if (envRefName == null) { throw new ArgumentNullException("envRefName"); } if (outerRefName == null) { throw new ArgumentNullException("outerRefName"); } if (nameRewriter == null) { throw new ArgumentNullException("nameRewriter"); } // TargetCurrentClassToken indicates a "Me" reference, which never requires a target container - it is always valid where it is (even in the // outermost scope, VBScript doesn't require that "Me" be used only within a VBScript class) if (target is TargetCurrentClassToken) { return(null); } // Similarly, if the target is a NameToken that comes from content that was partially processed and then rewritten then we can assume that // it does not need any target-container logic re-applying if (target is ProcessedNameToken) { return(null); } var rewrittenTargetName = nameRewriter(target).Name; var targetReferenceDetailsIfAvailable = scopeAccessInformation.TryToGetDeclaredReferenceDetails(target, nameRewriter); if (targetReferenceDetailsIfAvailable == null) { if (scopeAccessInformation.ScopeDefiningParent.Scope == ScopeLocationOptions.WithinFunctionOrPropertyOrWith) { // If an undeclared variable is accessed within a function (or property) then it is treated as if it was declared to be restricted // to the current scope, so the nameOfTargetContainerIfRequired should be null in this case (this means that the UndeclaredVariables // data returned from this process should be translated into locally-scoped DIM statements at the top of the function / property). return(null); } return(envRefName); } else if (targetReferenceDetailsIfAvailable.ReferenceType == ReferenceTypeOptions.ExternalDependency) { return(envRefName); } else if (targetReferenceDetailsIfAvailable.ScopeLocation == ScopeLocationOptions.OutermostScope) { // 2014-01-06 DWR: Used to only apply this logic if the target reference was in the OutermostScope and we were currently inside a // class but I'm restructuring the outer scope so that declared variables and functions are inside a class that the outermost scope // references in an identical manner to the class functions (and properties) so the outerRefName should used every time that an // OutermostScope reference is accessed return(outerRefName); } return(null); }