Exemple #1
0
        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;
        }
        /// <summary>
        /// When trying to access variables, functions, classes, etc.. we need to pass the member's name through the VBScriptNameRewriter. In
        /// most cases this token will be a NameToken which we can pass straight in, but in some cases it may be another type (perhaps a key
        /// word type) and so will have to be wrapped in a NameToken instance before passing through the name rewriter. This extension
        /// method should be used in all places where the VBScriptNameRewriter is used by the CSharpWriter since it allows us to override
        /// its behaviour where required - eg. by using a DoNotRenameNameToken
        /// </summary>
        public static string GetMemberAccessTokenName(this VBScriptNameRewriter nameRewriter, IToken token)
        {
            if (nameRewriter == null)
            {
                throw new ArgumentNullException("nameRewriter");
            }
            if (token == null)
            {
                throw new ArgumentNullException("token");
            }

            // A TargetCurrentClassToken indicates a "Me" (eg. "Me.Name") which can always be translated directly into "this". In VBScript,
            // "Me" is valid even when not explicitly within a VBScript class (it refers to the outermost scope, so "Me.F1()" will try to
            // call a function "F1" in the outermost scope). When the code IS explicitly within a VBScript class, the "Me" reference is
            // the instance of that class. In the translated code, both cases are fine to translate straight into whatever "this" is
            // at runtime.
            if (token is TargetCurrentClassToken)
            {
                return("this");
            }

            var nameToken = (token as NameToken) ?? new ForRenamingNameToken(token.Content, token.LineIndex);

            if (nameToken is DoNotRenameNameToken)
            {
                return(nameToken.Content);
            }
            return(nameRewriter(nameToken).Name);
        }
        /// <summary>
        /// Where variables must be stored in temporary references in order to be accessed within lambas (which is the case for variables that are "ref" arguments of the containing function, the common cases
        /// where lambdas may be required are for passing as REF into an IProvideCallArguments implementation or when accessed within a HANDLEERROR call), the temporary references must be defined and a try
        /// opened before the work attempted. After the work is completed, in a finally, the aliases values must be mapped back onto the source values - this is what the CloseByRefReplacementDefinitionWork
        /// method is for.
        /// </summary>
        public static ByRefReplacementTranslationResultDetails OpenByRefReplacementDefinitionWork(
            this NonNullImmutableList <FuncByRefMapping> byRefArgumentsToRewrite,
            TranslationResult translationResult,
            int indentationDepth,
            VBScriptNameRewriter nameRewriter)
        {
            if (byRefArgumentsToRewrite == null)
            {
                throw new ArgumentNullException("byRefArgumentsToRewrite");
            }
            if (translationResult == null)
            {
                throw new ArgumentNullException("translationResult");
            }
            if (indentationDepth < 0)
            {
                throw new ArgumentOutOfRangeException("indentationDepth");
            }
            if (nameRewriter == null)
            {
                throw new ArgumentNullException("nameRewriter");
            }

            // Originally, this would throw an exception if there were no by-ref arguments (why bother calling this if there are no by-ref arguments to deal with; does this indicate an error in the calling
            // code?) but in some cases it's easier to be able to call it without having check whether there were any value that need rewriting and the cases where being so strict may catch unintentional
            // calls are few
            if (!byRefArgumentsToRewrite.Any())
            {
                return(new ByRefReplacementTranslationResultDetails(translationResult, 0));
            }

            var lineIndexForStartOfContent = byRefArgumentsToRewrite.Min(a => a.From.LineIndex);

            translationResult = translationResult.Add(new TranslatedStatement(
                                                          string.Format(
                                                              "object {0};",
                                                              string.Join(
                                                                  ", ",
                                                                  byRefArgumentsToRewrite.Select(r => r.To.Name + " = " + nameRewriter(r.From).Name)
                                                                  )
                                                              ),
                                                          indentationDepth,
                                                          lineIndexForStartOfContent
                                                          ));

            if (byRefArgumentsToRewrite.All(mapping => mapping.MappedValueIsReadOnly))
            {
                return(new ByRefReplacementTranslationResultDetails(translationResult, distanceToIndentCodeWithMappedValues: 0));
            }

            return(new ByRefReplacementTranslationResultDetails(
                       translationResult
                       .Add(new TranslatedStatement("try", indentationDepth, lineIndexForStartOfContent))
                       .Add(new TranslatedStatement("{", indentationDepth, lineIndexForStartOfContent)),
                       distanceToIndentCodeWithMappedValues: 1
                       ));
        }
        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;
        }
Exemple #5
0
 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 FuncByRefArgumentMapper(VBScriptNameRewriter nameRewriter, TempValueNameGenerator tempNameGenerator, ILogInformation logger)
        {
            if (tempNameGenerator == null)
            {
                throw new ArgumentNullException("tempNameGenerator");
            }
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }

            _nameRewriter      = nameRewriter;
            _tempNameGenerator = tempNameGenerator;
            _logger            = logger;
        }
        public static bool AreNamesEquivalent(this VBScriptNameRewriter nameRewriter, NameToken x, NameToken y)
        {
            if (nameRewriter == null)
            {
                throw new ArgumentNullException("nameRewriter");
            }
            if (x == null)
            {
                throw new ArgumentNullException("x");
            }
            if (y == null)
            {
                throw new ArgumentNullException("y");
            }

            return(nameRewriter.GetMemberAccessTokenName(x) == nameRewriter.GetMemberAccessTokenName(y));
        }
Exemple #8
0
        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;
        }
Exemple #9
0
        /// <summary>
        /// This will never be null
        /// </summary>
        public static NonNullImmutableList <NameToken> GetUndeclaredVariablesAccessed(
            this TranslatedStatementContentDetails source,
            ScopeAccessInformation scopeAccessInformation,
            VBScriptNameRewriter nameRewriter)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (scopeAccessInformation == null)
            {
                throw new ArgumentNullException("scopeAccessInformation");
            }
            if (nameRewriter == null)
            {
                throw new ArgumentNullException("nameRewriter");
            }

            return(source.VariablesAccessed
                   .Where(v => !scopeAccessInformation.IsDeclaredReference(v, nameRewriter))
                   .ToNonNullImmutableList());
        }
        public static Statement RewriteStatementUsingByRefArgumentMappings(this NonNullImmutableList <FuncByRefMapping> byRefArgumentsToRewrite, Statement statementBlock, VBScriptNameRewriter nameRewriter)
        {
            if (byRefArgumentsToRewrite == null)
            {
                throw new ArgumentNullException("byRefArgumentsToRewrite");
            }
            if (statementBlock == null)
            {
                throw new ArgumentNullException("statementBlock");
            }
            if (nameRewriter == null)
            {
                throw new ArgumentNullException("nameRewriter");
            }

            // Originally, this would throw an exception if there were no by-ref arguments (why bother calling this if there are no by-ref arguments to deal with; does this indicate an error in the calling
            // code?) but in some cases it's easier to be able to call it without having check whether there were any value that need rewriting and the cases where being so strict may catch unintentional
            // calls are few
            if (!byRefArgumentsToRewrite.Any())
            {
                return(statementBlock);
            }

            return(new Statement(
                       statementBlock.Tokens.Select(t =>
            {
                var nameToken = t as NameToken;
                if (nameToken == null)
                {
                    return t;
                }
                var referenceRewriteDetailsIfApplicable = byRefArgumentsToRewrite.FirstOrDefault(
                    r => nameRewriter.GetMemberAccessTokenName(r.From) == nameRewriter.GetMemberAccessTokenName(nameToken)
                    );
                return (referenceRewriteDetailsIfApplicable == null) ? t : new DoNotRenameNameToken(referenceRewriteDetailsIfApplicable.To.Name, t.LineIndex);
            }),
                       statementBlock.CallPrefix
                       ));
        }
        /// <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()
                       ));
        }
Exemple #12
0
        public static bool IsDeclaredReference(this ScopeAccessInformation scopeInformation, NameToken target, VBScriptNameRewriter nameRewriter)
        {
            if (scopeInformation == null)
            {
                throw new ArgumentNullException("scopeInformation");
            }
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }
            if (nameRewriter == null)
            {
                throw new ArgumentNullException("nameRewriter");
            }

            // TargetCurrentClassToken indicates a "Me" reference, which is always valid - TODO: Move this into TryToGetDeclaredReferenceDetails?
            if (target is TargetCurrentClassToken)
            {
                return(true);
            }

            return(TryToGetDeclaredReferenceDetails(scopeInformation, target, nameRewriter) != null);
        }
Exemple #13
0
        /// <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);
        }
Exemple #14
0
        /// <summary>
        /// Try to retrieve information about a name token. If there is nothing matching it in the current scope then null will be returned.
        /// </summary>
        public static DeclaredReferenceDetails TryToGetDeclaredReferenceDetails(
            this ScopeAccessInformation scopeInformation,
            NameToken target,
            VBScriptNameRewriter nameRewriter)
        {
            if (scopeInformation == null)
            {
                throw new ArgumentNullException("scopeInformation");
            }
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }
            if (nameRewriter == null)
            {
                throw new ArgumentNullException("nameRewriter");
            }

            // If the target corresponds to the containing "WITH" reference (if any) then use that ("WITH a: .Go: END WITH" is translated
            // approximately into "var w123 = a; w123.Go();" where the "w123" is the DirectedWithReferenceIfAny and so we don't need to
            // check for other variables or functions that may apply, it's the local variable WITH construct target.
            var rewrittenTargetName = nameRewriter(target).Name;

            if (scopeInformation.DirectedWithReferenceIfAny != null)
            {
                // Note that WithinFunctionOrPropertyOrWith is always specified here for the scope location since the WITH target should
                // not be part of the "outer most scope" variable set like variables declared in that scope in the source script - this
                // target reference is not something that can be altered, it is set in the current scope and accessed directly.
                if (nameRewriter.GetMemberAccessTokenName(scopeInformation.DirectedWithReferenceIfAny.AsToken()) == rewrittenTargetName)
                {
                    return(new DeclaredReferenceDetails(ReferenceTypeOptions.Variable, ScopeLocationOptions.WithinFunctionOrPropertyOrWith));
                }
            }

            if (scopeInformation.ScopeDefiningParent != null)
            {
                if (scopeInformation.ScopeDefiningParent.ExplicitScopeAdditions.Any(t => nameRewriter.GetMemberAccessTokenName(t) == rewrittenTargetName))
                {
                    // ExplicitScopeAdditions should be things such as function arguments, so they will share the same ScopeLocation as the
                    // current scopeInformation reference
                    return(new DeclaredReferenceDetails(ReferenceTypeOptions.Variable, scopeInformation.ScopeDefiningParent.Scope));
                }
            }

            var firstExternalDependencyMatch = scopeInformation.ExternalDependencies
                                               .FirstOrDefault(t => nameRewriter.GetMemberAccessTokenName(t) == rewrittenTargetName);

            if (firstExternalDependencyMatch != null)
            {
                return(new DeclaredReferenceDetails(ReferenceTypeOptions.ExternalDependency, ScopeLocationOptions.OutermostScope));
            }

            var scopedNameTokens =
                scopeInformation.Classes.Select(t => Tuple.Create(t, ReferenceTypeOptions.Class))
                .Concat(scopeInformation.Functions.Select(t => Tuple.Create(t, ReferenceTypeOptions.Function)))
                .Concat(scopeInformation.Properties.Select(t => Tuple.Create(t, ReferenceTypeOptions.Property)))
                .Concat(scopeInformation.Constants.Select(t => Tuple.Create(t, ReferenceTypeOptions.Constant)))
                .Concat(scopeInformation.Variables.Select(t => Tuple.Create(t, ReferenceTypeOptions.Variable)));

            // There could be references matching the requested name in multiple scopes, start from the closest and work outwards
            var possibleScopes = new[]
            {
                ScopeLocationOptions.WithinFunctionOrPropertyOrWith,
                ScopeLocationOptions.WithinClass,
                ScopeLocationOptions.OutermostScope
            };

            foreach (var scope in possibleScopes)
            {
                var firstMatch = scopedNameTokens
                                 .Where(t => t.Item1.ScopeLocation == scope)
                                 .FirstOrDefault(t => nameRewriter.GetMemberAccessTokenName(t.Item1) == rewrittenTargetName);
                if (firstMatch != null)
                {
                    return(new DeclaredReferenceDetails(firstMatch.Item2, firstMatch.Item1.ScopeLocation));
                }
            }
            return(null);
        }