Esempio n. 1
0
        private static SourceUnit ParseFile(
            TextWriter consoleOutput,
            PhpParseOptions parseOptions,
            PhpParseOptions scriptParseOptions,
            SourceText content,
            CommandLineSourceFile file)
        {
            // TODO: new parser implementation based on Roslyn

            // TODO: file.IsScript ? scriptParseOptions : parseOptions
            var tree = CodeSourceUnit.ParseCode(content.ToString(), file.Path);

            return(tree);
        }
Esempio n. 2
0
        private SourceUnit ParseFile(
            TextWriter consoleOutput,
            PhpParseOptions parseOptions,
            PhpParseOptions scriptParseOptions,
            ref bool hadErrors,
            CommandLineSourceFile file,
            ErrorLogger errorLogger)
        {
            var fileReadDiagnostics = new List <DiagnosticInfo>();
            var content             = ReadFileContent(file, fileReadDiagnostics);

            if (content == null)
            {
                ReportErrors(fileReadDiagnostics, consoleOutput, errorLogger);
                fileReadDiagnostics.Clear();
                hadErrors = true;
                return(null);
            }
            else
            {
                return(ParseFile(consoleOutput, parseOptions, scriptParseOptions, content, file));
            }
        }
        internal override CommandLineArguments CommonParse(IEnumerable <string> args, string baseDirectory, string sdkDirectoryOpt, string additionalReferenceDirectories)
        {
            List <Diagnostic> diagnostics   = new List <Diagnostic>();
            List <string>     flattenedArgs = new List <string>();
            List <string>     scriptArgs    = IsScriptRunner ? new List <string>() : null;

            FlattenArgs(args, diagnostics, flattenedArgs, scriptArgs, baseDirectory);

            var                    sourceFiles = new List <CommandLineSourceFile>();
            var                    metadataReferences = new List <CommandLineReference>();
            var                    analyzers = new List <CommandLineAnalyzerReference>();
            var                    additionalFiles = new List <CommandLineSourceFile>();
            var                    managedResources = new List <ResourceDescription>();
            var                    defines = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            string                 outputDirectory = baseDirectory;
            string                 outputFileName = null;
            string                 documentationPath = null;
            string                 moduleName = null;
            string                 runtimeMetadataVersion = null; // will be read from cor library if not specified in cmd
            string                 compilationName = null;
            string                 versionString = null;
            bool                   optimize = false;
            bool                   concurrentBuild = true;
            var                    diagnosticOptions = new Dictionary <string, ReportDiagnostic>();
            PhpDocTypes            phpdocTypes = PhpDocTypes.None;
            OutputKind             outputKind = OutputKind.ConsoleApplication;
            bool                   optionsEnded = false;
            bool                   displayHelp = false, displayLogo = true;
            bool                   emitPdb = true, debugPlus = false;
            string                 mainTypeName = null, pdbPath = null;
            Version                languageVersion             = null;
            bool?                  delaySignSetting            = null;
            string                 keyFileSetting              = null;
            string                 keyContainerSetting         = null;
            bool                   publicSign                  = false;
            bool                   shortOpenTags               = false;
            bool                   resourcesOrModulesSpecified = false;
            DebugInformationFormat debugInformationFormat      = DebugInformationFormat.Pdb;
            List <string>          referencePaths              = new List <string>();
            List <string>          keyFileSearchPaths          = new List <string>();

            if (sdkDirectoryOpt != null)
            {
                referencePaths.Add(sdkDirectoryOpt);
            }
            if (!string.IsNullOrEmpty(additionalReferenceDirectories))
            {
                referencePaths.AddRange(additionalReferenceDirectories.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
            }

            foreach (string arg in flattenedArgs)
            {
                Debug.Assert(optionsEnded || !arg.StartsWith("@", StringComparison.Ordinal));

                string name, value;
                if (optionsEnded || !TryParseOption2(arg, out name, out value))
                {
                    sourceFiles.AddRange(ExpandFileArgument(arg, baseDirectory, diagnostics));
                    continue;
                }

                switch (name)
                {
                case "?":
                case "help":
                    displayHelp = true;
                    continue;

                case "d":
                case "define":
                    ParseDefine(value, defines);
                    continue;

                case "r":
                case "reference":
                    metadataReferences.AddRange(ParseAssemblyReferences(arg, value, diagnostics, embedInteropTypes: false));
                    continue;

                case "debug":
                    emitPdb = true;

                    // unused, parsed for backward compat only
                    if (!string.IsNullOrEmpty(value))
                    {
                        switch (value.ToLower())
                        {
                        case "full":
                        case "pdbonly":
                            debugInformationFormat = DebugInformationFormat.Pdb;
                            break;

                        case "portable":
                            debugInformationFormat = DebugInformationFormat.PortablePdb;
                            break;

                        case "embedded":
                            debugInformationFormat = DebugInformationFormat.Embedded;
                            break;

                        default:
                            //AddDiagnostic(diagnostics, ErrorCode.ERR_BadDebugType, value);
                            break;
                        }
                    }
                    continue;

                case "debug+":
                    //guard against "debug+:xx"
                    if (value != null)
                    {
                        break;
                    }

                    emitPdb   = true;
                    debugPlus = true;
                    continue;

                case "debug-":
                    if (value != null)
                    {
                        break;
                    }

                    emitPdb   = false;
                    debugPlus = false;
                    continue;

                case "o":
                case "optimize":
                case "o+":
                case "optimize+":
                    if (value != null)
                    {
                        break;
                    }

                    optimize = true;
                    continue;

                case "o-":
                case "optimize-":
                    if (value != null)
                    {
                        break;
                    }

                    optimize = false;
                    continue;

                case "p":
                case "parallel":
                case "p+":
                case "parallel+":
                    if (value != null)
                    {
                        break;
                    }

                    concurrentBuild = true;
                    continue;

                case "p-":
                case "parallel-":
                    if (value != null)
                    {
                        break;
                    }

                    concurrentBuild = false;
                    continue;

                case "nowarn":
                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        foreach (var warn in value.Split(new char[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            diagnosticOptions[warn] = ReportDiagnostic.Suppress;
                        }
                    }
                    continue;

                case "langversion":
                    value = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else if (string.Equals(value, "default", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "latest", StringComparison.OrdinalIgnoreCase))
                    {
                        languageVersion = null;     // latest
                    }
                    else if (!Version.TryParse(value, out languageVersion))
                    {
                        throw new ArgumentException("langversion");
                        //AddDiagnostic(diagnostics, ErrorCode.ERR_BadCompatMode, value);
                    }
                    continue;

                case "delaysign":
                case "delaysign+":
                    if (value != null)
                    {
                        break;
                    }

                    delaySignSetting = true;
                    continue;

                case "delaysign-":
                    if (value != null)
                    {
                        break;
                    }

                    delaySignSetting = false;
                    continue;

                case "publicsign":
                case "publicsign+":
                    if (value != null)
                    {
                        break;
                    }

                    publicSign = true;
                    continue;

                case "publicsign-":
                    if (value != null)
                    {
                        break;
                    }

                    publicSign = false;
                    continue;

                case "keyfile":
                    value = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                        // TODO: AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, "keyfile");
                    }
                    else
                    {
                        keyFileSetting = value;
                    }
                    // NOTE: Dev11/VB also clears "keycontainer", see also:
                    //
                    // MSDN: In case both /keyfile and /keycontainer are specified (either by command line option or by
                    // MSDN: custom attribute) in the same compilation, the compiler will first try the key container.
                    // MSDN: If that succeeds, then the assembly is signed with the information in the key container.
                    // MSDN: If the compiler does not find the key container, it will try the file specified with /keyfile.
                    // MSDN: If that succeeds, the assembly is signed with the information in the key file and the key
                    // MSDN: information will be installed in the key container (similar to sn -i) so that on the next
                    // MSDN: compilation, the key container will be valid.
                    continue;

                case "keycontainer":
                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        keyContainerSetting = value;
                    }
                    // NOTE: Dev11/VB also clears "keyfile", see also:
                    //
                    // MSDN: In case both /keyfile and /keycontainer are specified (either by command line option or by
                    // MSDN: custom attribute) in the same compilation, the compiler will first try the key container.
                    // MSDN: If that succeeds, then the assembly is signed with the information in the key container.
                    // MSDN: If the compiler does not find the key container, it will try the file specified with /keyfile.
                    // MSDN: If that succeeds, the assembly is signed with the information in the key file and the key
                    // MSDN: information will be installed in the key container (similar to sn -i) so that on the next
                    // MSDN: compilation, the key container will be valid.
                    continue;

                case "shortopentag":
                    shortOpenTags = string.IsNullOrEmpty(value) || (RemoveQuotesAndSlashes(value).ToLowerInvariant() == "true");
                    continue;

                case "shortopentag+":
                    shortOpenTags = true;
                    continue;

                case "shortopentag-":
                    shortOpenTags = false;
                    continue;

                case "nologo":
                    displayLogo = false;
                    continue;

                case "m":
                case "main":
                    // Remove any quotes for consistent behavior as MSBuild can return quoted or
                    // unquoted main.
                    var unquoted = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(unquoted))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        mainTypeName = unquoted;
                    }
                    continue;

                case "pdb":
                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        pdbPath = ParsePdbPath(value, diagnostics, baseDirectory);
                    }
                    continue;

                case "out":
                    if (string.IsNullOrWhiteSpace(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        ParseOutputFile(value, diagnostics, baseDirectory, out outputFileName, out outputDirectory);
                    }

                    continue;

                case "t":
                case "target":
                    if (value == null)
                    {
                        break;     // force 'unrecognized option'
                    }

                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        outputKind = ParseTarget(value, diagnostics);
                    }

                    continue;

                case "xmldoc":
                case "doc":
                    documentationPath = value ?? string.Empty;
                    break;

                case "phpdoctypes+":
                    phpdocTypes = PhpDocTypes.All;
                    break;

                case "phpdoctypes-":
                    phpdocTypes = PhpDocTypes.None;
                    break;

                case "phpdoctypes":
                    if (value == null)
                    {
                        phpdocTypes = PhpDocTypes.All;
                    }
                    else
                    {
                        phpdocTypes = (PhpDocTypes)Enum.Parse(typeof(PhpDocTypes), value);
                    }
                    break;

                case "modulename":
                    var unquotedModuleName = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(unquotedModuleName))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        moduleName = unquotedModuleName;
                    }

                    continue;

                case "version":
                case "v":
                    versionString = RemoveQuotesAndSlashes(value);
                    continue;

                case "runtimemetadataversion":
                    unquoted = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(unquoted))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        runtimeMetadataVersion = unquoted;
                    }
                    continue;

                case "res":
                case "resource":
                    if (value == null)
                    {
                        break;     // Dev11 reports unrecognized option
                    }

                    var embeddedResource = ParseResourceDescription(arg, value, baseDirectory, diagnostics, embedded: true);
                    if (embeddedResource != null)
                    {
                        managedResources.Add(embeddedResource);
                        resourcesOrModulesSpecified = true;
                    }

                    continue;

                case "linkres":
                case "linkresource":
                    if (value == null)
                    {
                        break;     // Dev11 reports unrecognized option
                    }

                    var linkedResource = ParseResourceDescription(arg, value, baseDirectory, diagnostics, embedded: false);
                    if (linkedResource != null)
                    {
                        managedResources.Add(linkedResource);
                        resourcesOrModulesSpecified = true;
                    }

                    continue;

                default:
                    break;
                }
            }

            GetCompilationAndModuleNames(diagnostics, outputKind, sourceFiles, sourceFiles.Count != 0, /*moduleAssemblyName*/ null, ref outputFileName, ref moduleName, out compilationName);

            //
            if (sourceFiles.Count == 0 && !IsScriptRunner && (outputKind.IsNetModule() || !resourcesOrModulesSpecified))
            {
                // warning: no source files specified
                diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.WRN_NoSourceFiles, Location.None));
            }

            // XML Documentation path
            if (documentationPath != null)
            {
                if (documentationPath.Length == 0)
                {
                    // default xmldoc file name
                    documentationPath = compilationName + ".xml";
                }

                // resolve path
                documentationPath = PathUtilities.CombinePossiblyRelativeAndRelativePaths(outputDirectory, documentationPath);
            }

            // Dev11 searches for the key file in the current directory and assembly output directory.
            // We always look to base directory and then examine the search paths.
            keyFileSearchPaths.Add(baseDirectory);
            if (baseDirectory != outputDirectory)
            {
                keyFileSearchPaths.Add(outputDirectory);
            }

            // Public sign doesn't use the legacy search path settings
            if (publicSign && !string.IsNullOrWhiteSpace(keyFileSetting))
            {
                keyFileSetting = ParseGenericPathToFile(keyFileSetting, diagnostics, baseDirectory);
            }

            var parseOptions = new PhpParseOptions
                               (
                documentationMode: DocumentationMode.Diagnose, // always diagnose
                kind: SourceCodeKind.Regular,
                languageVersion: languageVersion,
                shortOpenTags: shortOpenTags,
                features: ImmutableDictionary <string, string> .Empty, // features: parsedFeatures
                defines: defines.ToImmutableDictionary()
                               );

            var scriptParseOptions = parseOptions.WithKind(SourceCodeKind.Script);

            //// We want to report diagnostics with source suppression in the error log file.
            //// However, these diagnostics won't be reported on the command line.
            //var reportSuppressedDiagnostics = errorLogPath != null;

            var options = new PhpCompilationOptions
                          (
                outputKind: outputKind,
                baseDirectory: baseDirectory,
                sdkDirectory: sdkDirectoryOpt,
                moduleName: moduleName,
                mainTypeName: mainTypeName,
                scriptClassName: WellKnownMemberNames.DefaultScriptClassName,
                versionString: versionString,
                phpdocTypes: phpdocTypes,
                parseOptions: parseOptions,
                diagnostics: diagnostics.AsImmutable(),
                specificDiagnosticOptions: diagnosticOptions,
                //usings: usings,
                optimizationLevel: optimize ? OptimizationLevel.Release : OptimizationLevel.Debug,
                checkOverflow: false, // checkOverflow,
                                      //deterministic: deterministic,
                concurrentBuild: concurrentBuild,
                cryptoKeyContainer: keyContainerSetting,
                cryptoKeyFile: keyFileSetting,
                delaySign: delaySignSetting,
                platform: Platform.AnyCpu,
                //generalDiagnosticOption: generalDiagnosticOption,
                //warningLevel: warningLevel,
                //specificDiagnosticOptions: diagnosticOptions,
                //reportSuppressedDiagnostics: reportSuppressedDiagnostics,
                publicSign: publicSign
                          );

            if (debugPlus)
            {
                options = options.WithDebugPlusMode(debugPlus);
            }

            var emitOptions = new EmitOptions
                              (
                metadataOnly: false,
                debugInformationFormat: debugInformationFormat,
                pdbFilePath: null,        // to be determined later
                outputNameOverride: null, // to be determined later
                //baseAddress: baseAddress,
                //highEntropyVirtualAddressSpace: highEntropyVA,
                //fileAlignment: fileAlignment,
                //subsystemVersion: subsystemVersion,
                runtimeMetadataVersion: runtimeMetadataVersion
                              );

            return(new PhpCommandLineArguments()
            {
                // TODO: parsed arguments
                IsScriptRunner = IsScriptRunner,
                //InteractiveMode = interactiveMode || IsScriptRunner && sourceFiles.Count == 0,
                BaseDirectory = baseDirectory,
                //PathMap = pathMap,
                Errors = ImmutableArray <Diagnostic> .Empty,
                Utf8Output = true,
                CompilationName = compilationName,
                OutputFileName = outputFileName,
                PdbPath = pdbPath,
                EmitPdb = emitPdb,
                OutputDirectory = outputDirectory,
                DocumentationPath = documentationPath,
                //ErrorLogPath = errorLogPath,
                //AppConfigPath = appConfigPath,
                SourceFiles = sourceFiles.AsImmutable(),
                Encoding = Encoding.UTF8,
                ChecksumAlgorithm = SourceHashAlgorithm.Sha1, // checksumAlgorithm,
                MetadataReferences = metadataReferences.AsImmutable(),
                AnalyzerReferences = analyzers.AsImmutable(),
                AdditionalFiles = additionalFiles.AsImmutable(),
                ReferencePaths = referencePaths.AsImmutable(),
                SourcePaths = ImmutableArray <string> .Empty, //sourcePaths.AsImmutable(),
                KeyFileSearchPaths = keyFileSearchPaths.AsImmutable(),
                //Win32ResourceFile = win32ResourceFile,
                //Win32Icon = win32IconFile,
                //Win32Manifest = win32ManifestFile,
                //NoWin32Manifest = noWin32Manifest,
                DisplayLogo = displayLogo,
                DisplayHelp = displayHelp,
                ManifestResources = managedResources.AsImmutable(),
                CompilationOptions = options,
                ParseOptions = IsScriptRunner ? scriptParseOptions : parseOptions,
                EmitOptions = emitOptions,
                //ScriptArguments = scriptArgs.AsImmutableOrEmpty(),
                //TouchedFilesPath = touchedFilesPath,
                //PrintFullPaths = printFullPaths,
                //ShouldIncludeErrorEndLocation = errorEndLocation,
                //PreferredUILang = preferredUILang,
                //SqmSessionGuid = sqmSessionGuid,
                //ReportAnalyzer = reportAnalyzer
            });
        }
Esempio n. 4
0
        private ParsedSource ParseFile(
            TextWriter consoleOutput,
            PhpParseOptions parseOptions,
            PhpParseOptions scriptParseOptions,
            ref bool hadErrors,
            CommandLineSourceFile file,
            ErrorLogger errorLogger)
        {
            if (file.Path.IsPharFile())
            {
                // phar file archive
                var phar = Devsense.PHP.Phar.PharFile.OpenPharFile(file.Path); // TODO: report exception

                // treat the stub as a regular source code:
                var stub = PhpSyntaxTree.ParseCode(SourceText.From(GetPharStub(phar), Encoding.UTF8), parseOptions, scriptParseOptions, file.Path);

                // TODO: ConcurrentBuild -> Parallel

                var prefix  = PhpFileUtilities.NormalizeSlashes(PhpFileUtilities.GetRelativePath(file.Path, Arguments.BaseDirectory));
                var trees   = new List <PhpSyntaxTree>();
                var content = new List <Devsense.PHP.Phar.Entry>();

                foreach (var entry in phar.Manifest.Entries.Values)
                {
                    var entryName = PhpFileUtilities.NormalizeSlashes(entry.Name);

                    if (entry.IsCompileEntry())
                    {
                        var tree = PhpSyntaxTree.ParseCode(SourceText.From(entry.Code, Encoding.UTF8), parseOptions, scriptParseOptions, prefix + "/" + entryName);
                        tree.PharStubFile = stub;
                        trees.Add(tree);
                    }
                    else
                    {
                        content.Add(entry);
                    }
                }

                // create resource file
                var resources = new ResourceDescription($"phar://{prefix}.resources", () =>
                {
                    var stream = new MemoryStream();
                    var writer = new System.Resources.ResourceWriter(stream);

                    foreach (var entry in content)
                    {
                        var entryName = PhpFileUtilities.NormalizeSlashes(entry.Name);
                        writer.AddResource(entryName, entry.Code);
                    }

                    //
                    writer.Generate();
                    stream.Position = 0;
                    return(stream);
                }, isPublic: true);

                // TODO: report errors if any

                return(new ParsedSource {
                    SyntaxTree = stub, Manifest = phar.Manifest, Trees = trees, Resources = resources,
                });
            }
            else
            {
                // single source file

                var diagnosticInfos = new List <DiagnosticInfo>();
                var content         = TryReadFileContent(file, diagnosticInfos);

                if (diagnosticInfos.Count != 0)
                {
                    ReportErrors(diagnosticInfos, consoleOutput, errorLogger);
                    hadErrors = true;
                }

                PhpSyntaxTree result = null;

                if (content != null)
                {
                    result = PhpSyntaxTree.ParseCode(content, parseOptions, scriptParseOptions, file.Path);
                }

                if (result != null && result.Diagnostics.HasAnyErrors())
                {
                    ReportErrors(result.Diagnostics, consoleOutput, errorLogger);
                    hadErrors = true;
                }

                return(new ParsedSource {
                    SyntaxTree = result
                });
            }
        }
        internal override CommandLineArguments CommonParse(IEnumerable <string> args, string baseDirectory, string sdkDirectoryOpt, string additionalReferenceDirectories)
        {
            List <Diagnostic> diagnostics   = new List <Diagnostic>();
            List <string>     flattenedArgs = new List <string>();
            List <string>     scriptArgs    = IsScriptRunner ? new List <string>() : null;

            FlattenArgs(args, diagnostics, flattenedArgs, scriptArgs, baseDirectory);

            var                    sourceFiles            = new List <CommandLineSourceFile>();
            var                    metadataReferences     = new List <CommandLineReference>();
            var                    analyzers              = new List <CommandLineAnalyzerReference>();
            var                    additionalFiles        = new List <CommandLineSourceFile>();
            var                    managedResources       = new List <ResourceDescription>();
            string                 outputDirectory        = baseDirectory;
            string                 outputFileName         = null;
            string                 documentationPath      = null;
            string                 moduleName             = null;
            string                 runtimeMetadataVersion = null; // will be read from cor library if not specified in cmd
            string                 compilationName        = null;
            bool                   optimize = false;
            bool                   concurrentBuild = true;
            PhpDocTypes            phpdocTypes = PhpDocTypes.None;
            OutputKind             outputKind = OutputKind.ConsoleApplication;
            bool                   optionsEnded = false;
            bool                   displayHelp = false, displayLogo = true;
            bool                   emitPdb = true, debugPlus = false;
            string                 mainTypeName = null, pdbPath = null;
            DebugInformationFormat debugInformationFormat = DebugInformationFormat.Pdb;
            List <string>          referencePaths         = new List <string>();

            if (sdkDirectoryOpt != null)
            {
                referencePaths.Add(sdkDirectoryOpt);
            }
            if (!string.IsNullOrEmpty(additionalReferenceDirectories))
            {
                referencePaths.AddRange(additionalReferenceDirectories.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
            }

            foreach (string arg in flattenedArgs)
            {
                Debug.Assert(optionsEnded || !arg.StartsWith("@", StringComparison.Ordinal));

                string name, value;
                if (optionsEnded || !TryParseOption2(arg, out name, out value))
                {
                    sourceFiles.AddRange(ExpandFileArgument(arg, baseDirectory, diagnostics));
                    continue;
                }

                switch (name)
                {
                case "?":
                case "help":
                    displayHelp = true;
                    continue;

                case "r":
                case "reference":
                    metadataReferences.AddRange(ParseAssemblyReferences(arg, value, diagnostics, embedInteropTypes: false));
                    continue;

                case "debug":
                    emitPdb = true;

                    // unused, parsed for backward compat only
                    if (!string.IsNullOrEmpty(value))
                    {
                        switch (value.ToLower())
                        {
                        case "full":
                        case "pdbonly":
                            debugInformationFormat = DebugInformationFormat.Pdb;
                            break;

                        case "portable":
                            debugInformationFormat = DebugInformationFormat.PortablePdb;
                            break;

                        case "embedded":
                            debugInformationFormat = DebugInformationFormat.Embedded;
                            break;

                        default:
                            //AddDiagnostic(diagnostics, ErrorCode.ERR_BadDebugType, value);
                            break;
                        }
                    }
                    continue;

                case "debug+":
                    //guard against "debug+:xx"
                    if (value != null)
                    {
                        break;
                    }

                    emitPdb   = true;
                    debugPlus = true;
                    continue;

                case "debug-":
                    if (value != null)
                    {
                        break;
                    }

                    emitPdb   = false;
                    debugPlus = false;
                    continue;

                case "o":
                case "optimize":
                case "o+":
                case "optimize+":
                    if (value != null)
                    {
                        break;
                    }

                    optimize = true;
                    continue;

                case "o-":
                case "optimize-":
                    if (value != null)
                    {
                        break;
                    }

                    optimize = false;
                    continue;

                case "p":
                case "parallel":
                case "p+":
                case "parallel+":
                    if (value != null)
                    {
                        break;
                    }

                    concurrentBuild = true;
                    continue;

                case "p-":
                case "parallel-":
                    if (value != null)
                    {
                        break;
                    }

                    concurrentBuild = false;
                    continue;

                case "nologo":
                    displayLogo = false;
                    continue;

                case "m":
                case "main":
                    // Remove any quotes for consistent behavior as MSBuild can return quoted or
                    // unquoted main.
                    var unquoted = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(unquoted))
                    {
                        //AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "<text>", name);
                        //continue;
                        throw new ArgumentException("main");        // TODO: ErrorCode
                    }

                    mainTypeName = unquoted;
                    continue;

                case "pdb":
                    if (string.IsNullOrEmpty(value))
                    {
                        //AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
                        throw new ArgumentException("pdb");     // TODO: ErrorCode
                    }
                    else
                    {
                        pdbPath = ParsePdbPath(value, diagnostics, baseDirectory);
                    }
                    continue;

                case "out":
                    if (string.IsNullOrWhiteSpace(value))
                    {
                        //AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
                        throw new ArgumentException("out");     // TODO: ErrorCode
                    }
                    else
                    {
                        ParseOutputFile(value, diagnostics, baseDirectory, out outputFileName, out outputDirectory);
                    }

                    continue;

                case "t":
                case "target":
                    if (value == null)
                    {
                        break;     // force 'unrecognized option'
                    }

                    if (string.IsNullOrEmpty(value))
                    {
                        //AddDiagnostic(diagnostics, ErrorCode.FTL_InvalidTarget);
                        throw new ArgumentException("target");     // TODO: ErrorCode
                    }
                    else
                    {
                        outputKind = ParseTarget(value, diagnostics);
                    }

                    continue;

                case "xmldoc":
                case "doc":
                    documentationPath = value ?? string.Empty;
                    break;

                case "phpdoctypes+":
                    phpdocTypes = PhpDocTypes.All;
                    break;

                case "phpdoctypes-":
                    phpdocTypes = PhpDocTypes.None;
                    break;

                case "phpdoctypes":
                    if (value == null)
                    {
                        phpdocTypes = PhpDocTypes.All;
                    }
                    else
                    {
                        phpdocTypes = (PhpDocTypes)Enum.Parse(typeof(PhpDocTypes), value);
                    }
                    break;

                case "modulename":
                    var unquotedModuleName = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(unquotedModuleName))
                    {
                        //AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), "modulename");
                        //continue;
                        throw new ArgumentException("modulename");     // TODO: ErrorCode
                    }
                    else
                    {
                        moduleName = unquotedModuleName;
                    }

                    continue;

                case "runtimemetadataversion":
                    unquoted = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(unquoted))
                    {
                        //AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "<text>", name);
                        //continue;
                        throw new ArgumentException("runtimemetadataversion");     // TODO: ErrorCode
                    }

                    runtimeMetadataVersion = unquoted;
                    continue;

                default:
                    break;
                }
            }

            GetCompilationAndModuleNames(diagnostics, outputKind, sourceFiles, sourceFiles.Count != 0, /*moduleAssemblyName*/ null, ref outputFileName, ref moduleName, out compilationName);

            // XML Documentation path
            if (documentationPath != null)
            {
                if (documentationPath.Length == 0)
                {
                    // default xmldoc file name
                    documentationPath = compilationName + ".xml";
                }

                // resolve path
                documentationPath = PathUtilities.CombinePossiblyRelativeAndRelativePaths(outputDirectory, documentationPath);
            }

            var parseOptions = new PhpParseOptions
                               (
                //languageVersion: languageVersion,
                //preprocessorSymbols: defines.ToImmutableAndFree(),
                documentationMode: DocumentationMode.Diagnose, // always diagnose
                kind: SourceCodeKind.Regular                   //,
                                                               //features: parsedFeatures
                               );

            var scriptParseOptions = parseOptions.WithKind(SourceCodeKind.Script);

            //// We want to report diagnostics with source suppression in the error log file.
            //// However, these diagnostics won't be reported on the command line.
            //var reportSuppressedDiagnostics = errorLogPath != null;

            var options = new PhpCompilationOptions
                          (
                outputKind: outputKind,
                baseDirectory: baseDirectory,
                sdkDirectory: sdkDirectoryOpt,
                moduleName: moduleName,
                mainTypeName: mainTypeName,
                scriptClassName: WellKnownMemberNames.DefaultScriptClassName,
                phpdocTypes: phpdocTypes,
                //usings: usings,
                optimizationLevel: optimize ? OptimizationLevel.Release : OptimizationLevel.Debug,
                checkOverflow: false, // checkOverflow,
                                      //deterministic: deterministic,
                concurrentBuild: concurrentBuild,
                //cryptoKeyContainer: keyContainerSetting,
                //cryptoKeyFile: keyFileSetting,
                //delaySign: delaySignSetting,
                platform: Platform.AnyCpu // platform,
                                          //generalDiagnosticOption: generalDiagnosticOption,
                                          //warningLevel: warningLevel,
                                          //specificDiagnosticOptions: diagnosticOptions,
                                          //reportSuppressedDiagnostics: reportSuppressedDiagnostics,
                                          //publicSign: publicSign
                          );

            if (debugPlus)
            {
                options = options.WithDebugPlusMode(debugPlus);
            }

            var emitOptions = new EmitOptions
                              (
                metadataOnly: false,
                debugInformationFormat: debugInformationFormat,
                //pdbFilePath: null, // to be determined later
                //outputNameOverride: null, // to be determined later
                //baseAddress: baseAddress,
                //highEntropyVirtualAddressSpace: highEntropyVA,
                //fileAlignment: fileAlignment,
                //subsystemVersion: subsystemVersion,
                runtimeMetadataVersion: runtimeMetadataVersion
                              );

            return(new PhpCommandLineArguments()
            {
                // TODO: parsed arguments
                IsScriptRunner = IsScriptRunner,
                //InteractiveMode = interactiveMode || IsScriptRunner && sourceFiles.Count == 0,
                BaseDirectory = baseDirectory,
                //PathMap = pathMap,
                Errors = ImmutableArray <Diagnostic> .Empty,
                Utf8Output = true,
                CompilationName = compilationName,
                OutputFileName = outputFileName,
                PdbPath = pdbPath,
                EmitPdb = emitPdb,
                OutputDirectory = outputDirectory,
                DocumentationPath = documentationPath,
                //ErrorLogPath = errorLogPath,
                //AppConfigPath = appConfigPath,
                SourceFiles = sourceFiles.AsImmutable(),
                Encoding = Encoding.UTF8,
                ChecksumAlgorithm = SourceHashAlgorithm.Sha1, // checksumAlgorithm,
                MetadataReferences = metadataReferences.AsImmutable(),
                AnalyzerReferences = analyzers.AsImmutable(),
                AdditionalFiles = additionalFiles.AsImmutable(),
                ReferencePaths = referencePaths.AsImmutable(),
                SourcePaths = ImmutableArray <string> .Empty, //sourcePaths.AsImmutable(),
                //KeyFileSearchPaths = keyFileSearchPaths.AsImmutable(),
                //Win32ResourceFile = win32ResourceFile,
                //Win32Icon = win32IconFile,
                //Win32Manifest = win32ManifestFile,
                //NoWin32Manifest = noWin32Manifest,
                DisplayLogo = displayLogo,
                DisplayHelp = displayHelp,
                ManifestResources = managedResources.AsImmutable(),
                CompilationOptions = options,
                ParseOptions = IsScriptRunner ? scriptParseOptions : parseOptions,
                EmitOptions = emitOptions,
                //ScriptArguments = scriptArgs.AsImmutableOrEmpty(),
                //TouchedFilesPath = touchedFilesPath,
                //PrintFullPaths = printFullPaths,
                //ShouldIncludeErrorEndLocation = errorEndLocation,
                //PreferredUILang = preferredUILang,
                //SqmSessionGuid = sqmSessionGuid,
                //ReportAnalyzer = reportAnalyzer
            });
        }
Esempio n. 6
0
        internal override CommandLineArguments CommonParse(IEnumerable <string> args, string baseDirectory, string sdkDirectoryOpt, string additionalReferenceDirectories)
        {
            List <Diagnostic> diagnostics   = new List <Diagnostic>();
            List <string>     flattenedArgs = new List <string>();
            List <string>     scriptArgs    = IsScriptCommandLineParser ? new List <string>() : null;

            FlattenArgs(args, diagnostics, flattenedArgs, scriptArgs, baseDirectory);

            var                    sourceFiles = new List <CommandLineSourceFile>();
            var                    metadataReferences = new List <CommandLineReference>();
            var                    analyzers = new List <CommandLineAnalyzerReference>();
            var                    analyzerConfigPaths = new List <string>();
            var                    additionalFiles = new List <CommandLineSourceFile>();
            var                    embeddedFiles = new List <CommandLineSourceFile>();
            var                    managedResources = new List <ResourceDescription>();
            var                    defines = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            string                 outputDirectory = baseDirectory;
            string                 subDirectory = null;
            string                 targetFramework = null;
            string                 outputFileName = null;
            string                 documentationPath = null;
            string                 moduleName = null;
            string                 runtimeMetadataVersion = null; // will be read from cor library if not specified in cmd
            string                 compilationName = null;
            string                 versionString = null;
            Encoding               codepage = null;
            bool                   embedAllSourceFiles = false;
            PhpOptimizationLevel   optimization = PhpOptimizationLevel.Debug;
            bool                   concurrentBuild = true;
            var                    diagnosticOptions = new Dictionary <string, ReportDiagnostic>();
            PhpDocTypes            phpdocTypes = PhpDocTypes.None;
            OutputKind             outputKind = OutputKind.ConsoleApplication;
            bool                   optionsEnded = false;
            bool                   displayHelp = false, displayLogo = true;
            bool                   emitPdb = true, debugPlus = false;
            string                 sourceLink = null;
            string                 mainTypeName = null, pdbPath = null;
            Version                languageVersion             = null;
            bool?                  delaySignSetting            = null;
            string                 keyFileSetting              = null;
            string                 keyContainerSetting         = null;
            bool                   publicSign                  = false;
            bool                   shortOpenTags               = false;
            bool                   printFullPaths              = false;
            bool                   resourcesOrModulesSpecified = false;
            DebugInformationFormat debugInformationFormat      = DebugInformationFormat.Pdb;
            List <string>          referencePaths              = new List <string>();
            List <string>          keyFileSearchPaths          = new List <string>();
            var                    autoload_classmapfiles      = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase);
            var                    autoload_files              = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase);
            var                    autoload_psr4               = new List <(string prefix, string path)>();

            if (sdkDirectoryOpt != null)
            {
                referencePaths.Add(sdkDirectoryOpt);
            }
            if (!string.IsNullOrEmpty(additionalReferenceDirectories))
            {
                referencePaths.AddRange(additionalReferenceDirectories.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
            }

            foreach (string arg in flattenedArgs)
            {
                Debug.Assert(optionsEnded || !arg.StartsWith("@", StringComparison.Ordinal));

                string name, value;
                if (optionsEnded || !TryParseOption2(arg, out name, out value))
                {
                    sourceFiles.AddRange(ExpandFileArgument(arg, baseDirectory, diagnostics));
                    continue;
                }

                switch (name)
                {
                case "?":
                case "help":
                    displayHelp = true;
                    continue;

                case "d":
                case "define":
                    ParseDefine(value, defines);
                    continue;

                case "codepage":
                    value = RemoveQuotesAndSlashes(value);
                    if (value == null)
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                        continue;
                    }

                    var encoding = TryParseEncodingName(value);
                    if (encoding == null)
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.FTL_BadCodepage, Location.None, value));
                        continue;
                    }

                    codepage = encoding;
                    continue;

                case "r":
                case "reference":
                    metadataReferences.AddRange(ParseAssemblyReferences(arg, value, diagnostics, embedInteropTypes: false));
                    continue;

                case "sourcelink":
                    value = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(value))
                    {
                        //diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.no
                        //AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
                    }
                    else
                    {
                        sourceLink = ParseGenericPathToFile(value, diagnostics, baseDirectory);
                    }
                    continue;

                case "debug":
                case "debug-type":
                    emitPdb = true;

                    // unused, parsed for backward compat only
                    if (!string.IsNullOrEmpty(value))
                    {
                        switch (value.ToLower())
                        {
                        case "full":
                        case "pdbonly":
                            debugInformationFormat = DebugInformationFormat.Pdb;
                            break;

                        case "portable":
                            debugInformationFormat = DebugInformationFormat.PortablePdb;
                            break;

                        case "embedded":
                            debugInformationFormat = DebugInformationFormat.Embedded;
                            break;

                        default:
                            //AddDiagnostic(diagnostics, ErrorCode.ERR_BadDebugType, value);
                            break;
                        }
                    }
                    continue;

                case "debug+":
                    //guard against "debug+:xx"
                    if (value != null)
                    {
                        break;
                    }

                    emitPdb   = true;
                    debugPlus = true;
                    continue;

                case "debug-":
                    if (value != null)
                    {
                        break;
                    }

                    emitPdb   = false;
                    debugPlus = false;
                    continue;

                case "o":
                case "optimize":
                case "o+":
                case "optimize+":
                    if (value == null)
                    {
                        optimization = PhpOptimizationLevel.Release;
                    }
                    else if (bool.TryParse(value, out var optimizationBool))
                    {
                        optimization = optimizationBool ? PhpOptimizationLevel.Release : PhpOptimizationLevel.Debug;
                    }
                    else if (int.TryParse(value, out var optimizationNumber) && Enum.IsDefined(typeof(PhpOptimizationLevel), optimizationNumber))
                    {
                        optimization = (PhpOptimizationLevel)optimizationNumber;
                    }
                    else if (Enum.TryParse(value, true, out optimization))
                    {
                        //
                    }
                    else
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_BadCompilationOptionValue, Location.None, name, value));
                    }

                    continue;

                case "o-":
                case "optimize-":
                    if (value != null)
                    {
                        break;
                    }

                    optimization = PhpOptimizationLevel.Debug;
                    continue;

                case "p":
                case "parallel":
                case "p+":
                case "parallel+":
                    if (value != null)
                    {
                        break;
                    }

                    concurrentBuild = true;
                    continue;

                case "p-":
                case "parallel-":
                    if (value != null)
                    {
                        break;
                    }

                    concurrentBuild = false;
                    continue;

                case "nowarn":
                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        foreach (var warn in value.Split(new char[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            diagnosticOptions[warn] = ReportDiagnostic.Suppress;
                        }
                    }
                    continue;

                case "langversion":
                    value = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else if (string.Equals(value, "default", StringComparison.OrdinalIgnoreCase))
                    {
                        languageVersion = PhpSyntaxTree.DefaultLanguageVersion;
                    }
                    else if (string.Equals(value, "latest", StringComparison.OrdinalIgnoreCase))
                    {
                        languageVersion = PhpSyntaxTree.LatestLanguageVersion;
                    }
                    else if (!Version.TryParse(value, out languageVersion))
                    {
                        throw new ArgumentException("langversion");
                        //AddDiagnostic(diagnostics, ErrorCode.ERR_BadCompatMode, value);
                    }
                    continue;

                case "delaysign":
                case "delaysign+":
                    if (value != null)
                    {
                        break;
                    }

                    delaySignSetting = true;
                    continue;

                case "delaysign-":
                    if (value != null)
                    {
                        break;
                    }

                    delaySignSetting = false;
                    continue;

                case "publicsign":
                case "publicsign+":
                    if (value != null)
                    {
                        break;
                    }

                    publicSign = true;
                    continue;

                case "publicsign-":
                    if (value != null)
                    {
                        break;
                    }

                    publicSign = false;
                    continue;

                case "keyfile":
                    value = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                        // TODO: AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, "keyfile");
                    }
                    else
                    {
                        keyFileSetting = value;
                    }
                    // NOTE: Dev11/VB also clears "keycontainer", see also:
                    //
                    // MSDN: In case both /keyfile and /keycontainer are specified (either by command line option or by
                    // MSDN: custom attribute) in the same compilation, the compiler will first try the key container.
                    // MSDN: If that succeeds, then the assembly is signed with the information in the key container.
                    // MSDN: If the compiler does not find the key container, it will try the file specified with /keyfile.
                    // MSDN: If that succeeds, the assembly is signed with the information in the key file and the key
                    // MSDN: information will be installed in the key container (similar to sn -i) so that on the next
                    // MSDN: compilation, the key container will be valid.
                    continue;

                case "keycontainer":
                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        keyContainerSetting = value;
                    }
                    // NOTE: Dev11/VB also clears "keyfile", see also:
                    //
                    // MSDN: In case both /keyfile and /keycontainer are specified (either by command line option or by
                    // MSDN: custom attribute) in the same compilation, the compiler will first try the key container.
                    // MSDN: If that succeeds, then the assembly is signed with the information in the key container.
                    // MSDN: If the compiler does not find the key container, it will try the file specified with /keyfile.
                    // MSDN: If that succeeds, the assembly is signed with the information in the key file and the key
                    // MSDN: information will be installed in the key container (similar to sn -i) so that on the next
                    // MSDN: compilation, the key container will be valid.
                    continue;

                case "shortopentag":
                    if (string.IsNullOrEmpty(value))
                    {
                        shortOpenTags = true;
                    }
                    else if (!bool.TryParse(RemoveQuotesAndSlashes(value), out shortOpenTags))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_BadCompilationOptionValue, Location.None, name, value));
                    }
                    continue;

                case "shortopentag+":
                    shortOpenTags = true;
                    continue;

                case "shortopentag-":
                    shortOpenTags = false;
                    continue;

                case "nologo":
                    displayLogo = false;
                    continue;

                case "m":
                case "main":
                    // Remove any quotes for consistent behavior as MSBuild can return quoted or
                    // unquoted main.
                    var unquoted = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(unquoted))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        mainTypeName = unquoted;
                    }
                    continue;

                case "fullpaths":
                    if (value != null)
                    {
                        if (!bool.TryParse(RemoveQuotesAndSlashes(value), out printFullPaths))
                        {
                            diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_BadCompilationOptionValue, Location.None, name, value));
                        }
                    }
                    else
                    {
                        printFullPaths = true;
                    }
                    continue;

                case "pdb":
                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        pdbPath = ParsePdbPath(value, diagnostics, baseDirectory);
                    }
                    continue;

                case "out":
                    if (string.IsNullOrWhiteSpace(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        ParseOutputFile(value, diagnostics, baseDirectory, out outputFileName, out outputDirectory);
                    }

                    continue;

                case "t":
                case "target":
                    if (value == null)
                    {
                        break;     // force 'unrecognized option'
                    }

                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        outputKind = ParseTarget(value, diagnostics);
                    }

                    continue;

                case "target-framework":
                    if (string.IsNullOrEmpty(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        targetFramework = value;
                    }
                    continue;

                case "xmldoc":
                case "doc":
                    documentationPath = value ?? string.Empty;
                    break;

                case "phpdoctypes+":
                    phpdocTypes = PhpDocTypes.All;
                    break;

                case "phpdoctypes-":
                    phpdocTypes = PhpDocTypes.None;
                    break;

                case "phpdoctypes":
                    if (value == null)
                    {
                        phpdocTypes = PhpDocTypes.All;
                    }
                    else
                    {
                        phpdocTypes = (PhpDocTypes)Enum.Parse(typeof(PhpDocTypes), value);
                    }
                    break;

                case "modulename":
                    var unquotedModuleName = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(unquotedModuleName))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        moduleName = unquotedModuleName;
                    }

                    continue;

                case "version":
                case "v":
                    versionString = RemoveQuotesAndSlashes(value);
                    continue;

                case "runtimemetadataversion":
                    unquoted = RemoveQuotesAndSlashes(value);
                    if (string.IsNullOrEmpty(unquoted))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                    }
                    else
                    {
                        runtimeMetadataVersion = unquoted;
                    }
                    continue;

                case "res":
                case "resource":
                    if (value == null)
                    {
                        break;     // Dev11 reports unrecognized option
                    }

                    var embeddedResource = ParseResourceDescription(arg, value, baseDirectory, diagnostics, embedded: true);
                    if (embeddedResource != null)
                    {
                        managedResources.Add(embeddedResource);
                        resourcesOrModulesSpecified = true;
                    }

                    continue;

                case "linkres":
                case "linkresource":
                    if (value == null)
                    {
                        break;     // Dev11 reports unrecognized option
                    }

                    var linkedResource = ParseResourceDescription(arg, value, baseDirectory, diagnostics, embedded: false);
                    if (linkedResource != null)
                    {
                        managedResources.Add(linkedResource);
                        resourcesOrModulesSpecified = true;
                    }

                    continue;

                case "subdir":
                    if (!string.IsNullOrEmpty(value))
                    {
                        // TODO: check value
                        subDirectory = Utilities.PhpFileUtilities.NormalizeSlashes(RemoveQuotesAndSlashes(value));
                    }
                    continue;

                case "embed":
                    if (string.IsNullOrEmpty(value))
                    {
                        embedAllSourceFiles = true;
                        continue;
                    }

                    foreach (var path in ParseSeparatedFileArgument(value, baseDirectory, diagnostics))
                    {
                        embeddedFiles.Add(ToCommandLineSourceFile(path));
                    }
                    continue;

                case "autoload":
                    if (string.IsNullOrWhiteSpace(value))
                    {
                        diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_SwitchNeedsValue, Location.None, name));
                        break;
                    }

                    const string classmapprefix = "classmap,";
                    const string psr4prefix     = "psr-4,";
                    const string filesprefix    = "files,";

                    if (value.StartsWith(classmapprefix, StringComparison.OrdinalIgnoreCase))
                    {
                        // "classmap,<fullfilename>"
                        autoload_classmapfiles.Add(value.Substring(classmapprefix.Length));
                        break;
                    }
                    else if (value.StartsWith(psr4prefix, StringComparison.OrdinalIgnoreCase))
                    {
                        // "psr-4,<prefix>,<path>"
                        var prefix_dir = value.Substring(psr4prefix.Length);
                        var comma      = prefix_dir.IndexOf(',');
                        if (comma >= 0)
                        {
                            autoload_psr4.Add((prefix_dir.Remove(comma), prefix_dir.Substring(comma + 1)));
                        }

                        break;
                    }
                    else if (value.StartsWith(filesprefix, StringComparison.OrdinalIgnoreCase))
                    {
                        // "files,<fullfilename>"
                        autoload_files.Add(value.Substring(filesprefix.Length));
                        break;
                    }

                    // not handled
                    diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_BadCompilationOptionValue, Location.None, name, value));
                    break;

                default:
                    break;
                }
            }

            GetCompilationAndModuleNames(diagnostics, outputKind, sourceFiles, sourceFiles.Count != 0, /*moduleAssemblyName*/ null, ref outputFileName, ref moduleName, out compilationName);

            //
            if (sourceFiles.Count == 0 && !IsScriptCommandLineParser && (outputKind.IsNetModule() || !resourcesOrModulesSpecified))
            {
                // warning: no source files specified
                diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.WRN_NoSourceFiles, Location.None));
            }

            // XML Documentation path
            if (documentationPath != null)
            {
                if (documentationPath.Length == 0)
                {
                    // default xmldoc file name
                    documentationPath = PathUtilities.CombinePossiblyRelativeAndRelativePaths(outputDirectory, compilationName + ".xml");
                }
                else
                {
                    // resolve path
                    documentationPath = PathUtilities.CombinePossiblyRelativeAndRelativePaths(baseDirectory, documentationPath);
                }
            }

            // sanitize autoload paths, prefix them with subdir
            for (int i = 0; i < autoload_psr4.Count; i++)
            {
                var value = autoload_psr4[i];
                var path  = subDirectory == null
                    ? value.path
                    : PathUtilities.CombinePathsUnchecked(subDirectory, value.path);

                autoload_psr4[i] = (value.prefix, PhpFileUtilities.NormalizeSlashes(path));
            }

            autoload_classmapfiles = new HashSet <string>(
                autoload_classmapfiles.Select(path => PhpFileUtilities.NormalizeSlashes(subDirectory == null ? path : PathUtilities.CombinePathsUnchecked(subDirectory, path))),
                autoload_classmapfiles.Comparer);

            autoload_files = new HashSet <string>(
                autoload_files.Select(path => PhpFileUtilities.NormalizeSlashes(subDirectory == null ? path : PathUtilities.CombinePathsUnchecked(subDirectory, path))),
                autoload_files.Comparer);

            // event source // TODO: change to EventSource
            var evetsources = new[] { CreateObserver("Peachpie.Compiler.Diagnostics.Observer,Peachpie.Compiler.Diagnostics", moduleName) }.WhereNotNull();

#if TRACE
            evetsources = evetsources.Concat(new CompilationTrackerExtension.TraceObserver());
#endif

            // Dev11 searches for the key file in the current directory and assembly output directory.
            // We always look to base directory and then examine the search paths.
            keyFileSearchPaths.Add(baseDirectory);
            if (baseDirectory != outputDirectory)
            {
                keyFileSearchPaths.Add(outputDirectory);
            }

            // Public sign doesn't use the legacy search path settings
            if (publicSign && !string.IsNullOrWhiteSpace(keyFileSetting))
            {
                keyFileSetting = ParseGenericPathToFile(keyFileSetting, diagnostics, baseDirectory);
            }

            if (sourceLink != null && !emitPdb)
            {
                //AddDiagnostic(diagnostics, ErrorCode.ERR_SourceLinkRequiresPdb);
            }

            if (embedAllSourceFiles)
            {
                embeddedFiles.AddRange(sourceFiles);
            }

            if (embeddedFiles.Count > 0 && !emitPdb)
            {
                diagnostics.Add(Errors.MessageProvider.Instance.CreateDiagnostic(Errors.ErrorCode.ERR_CannotEmbedWithoutPdb, Location.None));
            }

            var parseOptions = new PhpParseOptions
                               (
                documentationMode: DocumentationMode.Diagnose, // always diagnose
                kind: SourceCodeKind.Regular,
                languageVersion: languageVersion,
                shortOpenTags: shortOpenTags,
                features: ImmutableDictionary <string, string> .Empty // features: parsedFeatures
                               );

            var scriptParseOptions = parseOptions.WithKind(SourceCodeKind.Script);

            //// We want to report diagnostics with source suppression in the error log file.
            //// However, these diagnostics won't be reported on the command line.
            //var reportSuppressedDiagnostics = errorLogPath != null;

            var options = new PhpCompilationOptions
                          (
                outputKind: outputKind,
                baseDirectory: baseDirectory,
                sdkDirectory: sdkDirectoryOpt,
                subDirectory: subDirectory,
                targetFramework: targetFramework,
                moduleName: moduleName,
                mainTypeName: mainTypeName,
                scriptClassName: WellKnownMemberNames.DefaultScriptClassName,
                versionString: versionString,
                phpdocTypes: phpdocTypes,
                parseOptions: parseOptions,
                defines: defines.ToImmutableDictionary(),
                diagnostics: diagnostics.AsImmutable(),
                specificDiagnosticOptions: diagnosticOptions,
                //usings: usings,
                optimizationLevel: optimization,
                checkOverflow: false, // checkOverflow,
                                      //deterministic: deterministic,
                concurrentBuild: concurrentBuild,
                cryptoKeyContainer: keyContainerSetting,
                cryptoKeyFile: keyFileSetting,
                delaySign: delaySignSetting,
                platform: Platform.AnyCpu,
                //generalDiagnosticOption: generalDiagnosticOption,
                //warningLevel: warningLevel,
                //specificDiagnosticOptions: diagnosticOptions,
                //reportSuppressedDiagnostics: reportSuppressedDiagnostics,
                publicSign: publicSign
                          )
            {
                EventSources           = evetsources.AsImmutableOrEmpty(),
                Autoload_PSR4          = autoload_psr4,
                Autoload_ClassMapFiles = autoload_classmapfiles,
                Autoload_Files         = autoload_files,
            };

            if (debugPlus)
            {
                options = options.WithDebugPlusMode(debugPlus);
            }

            var emitOptions = new EmitOptions
                              (
                metadataOnly: false,
                debugInformationFormat: debugInformationFormat,
                pdbFilePath: null,        // to be determined later
                pdbChecksumAlgorithm: System.Security.Cryptography.HashAlgorithmName.SHA1,
                outputNameOverride: null, // to be determined later
                                          //baseAddress: baseAddress,
                                          //highEntropyVirtualAddressSpace: highEntropyVA,
                                          //fileAlignment: fileAlignment,
                                          //subsystemVersion: subsystemVersion,
                runtimeMetadataVersion: runtimeMetadataVersion
                              );

            return(new PhpCommandLineArguments()
            {
                // TODO: parsed arguments
                IsScriptRunner = IsScriptCommandLineParser,
                //InteractiveMode = interactiveMode || IsScriptRunner && sourceFiles.Count == 0,
                BaseDirectory = baseDirectory,
                //PathMap = pathMap,
                Errors = ImmutableArray <Diagnostic> .Empty,
                Utf8Output = true,
                CompilationName = compilationName,
                OutputFileName = outputFileName,
                PdbPath = pdbPath,
                EmitPdb = emitPdb,
                SourceLink = sourceLink,
                OutputDirectory = outputDirectory,
                DocumentationPath = documentationPath,
                //ErrorLogPath = errorLogPath,
                //AppConfigPath = appConfigPath,
                SourceFiles = sourceFiles.AsImmutable(),
                Encoding = codepage,                          // Encoding.UTF8,
                ChecksumAlgorithm = SourceHashAlgorithm.Sha1, // checksumAlgorithm,
                MetadataReferences = metadataReferences.AsImmutable(),
                AnalyzerReferences = analyzers.AsImmutable(),
                AnalyzerConfigPaths = analyzerConfigPaths.AsImmutable(),
                AdditionalFiles = additionalFiles.AsImmutable(),
                ReferencePaths = referencePaths.AsImmutable(),
                SourcePaths = ImmutableArray <string> .Empty, //sourcePaths.AsImmutable(),
                KeyFileSearchPaths = keyFileSearchPaths.AsImmutable(),
                //Win32ResourceFile = win32ResourceFile,
                //Win32Icon = win32IconFile,
                //Win32Manifest = win32ManifestFile,
                //NoWin32Manifest = noWin32Manifest,
                DisplayLogo = displayLogo,
                DisplayHelp = displayHelp,
                ManifestResources = managedResources.AsImmutable(),
                CompilationOptions = options,
                ParseOptions = IsScriptCommandLineParser ? scriptParseOptions : parseOptions,
                EmitOptions = emitOptions,
                //ScriptArguments = scriptArgs.AsImmutableOrEmpty(),
                //TouchedFilesPath = touchedFilesPath,
                PrintFullPaths = printFullPaths,
                //ShouldIncludeErrorEndLocation = errorEndLocation,
                //PreferredUILang = preferredUILang,
                //SqmSessionGuid = sqmSessionGuid,
                //ReportAnalyzer = reportAnalyzer
                EmbeddedFiles = embeddedFiles.AsImmutable(),
            });
        }
Esempio n. 7
0
        internal override CommandLineArguments CommonParse(IEnumerable<string> args, string baseDirectory, string sdkDirectoryOpt, string additionalReferenceDirectories)
        {
            List<Diagnostic> diagnostics = new List<Diagnostic>();
            List<string> flattenedArgs = new List<string>();
            List<string> scriptArgs = IsScriptRunner ? new List<string>() : null;
            FlattenArgs(args, diagnostics, flattenedArgs, scriptArgs, baseDirectory);

            var sourceFiles = new List<CommandLineSourceFile>();
            var metadataReferences = new List<CommandLineReference>();
            var analyzers = new List<CommandLineAnalyzerReference>();
            var additionalFiles = new List<CommandLineSourceFile>();
            var managedResources = new List<ResourceDescription>();
            string outputDirectory = baseDirectory;
            string outputFileName = null;
            string moduleName = null;
            string runtimeMetadataVersion = null; // will be read from cor library if not specified in cmd
            string compilationName = null;
            bool optimize = false;
            OutputKind outputKind = OutputKind.ConsoleApplication;
            bool optionsEnded = false;
            bool displayHelp = false, displayLogo = true;
            bool emitPdb = true, debugPlus = false;
            string mainTypeName = null, pdbPath = null;
            DebugInformationFormat debugInformationFormat = DebugInformationFormat.Pdb;
            List<string> referencePaths = new List<string>();
            if (sdkDirectoryOpt != null) referencePaths.Add(sdkDirectoryOpt);
            if (!string.IsNullOrEmpty(additionalReferenceDirectories)) referencePaths.AddRange(additionalReferenceDirectories.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));

            foreach (string arg in flattenedArgs)
            {
                Debug.Assert(optionsEnded || !arg.StartsWith("@", StringComparison.Ordinal));

                string name, value;
                if (optionsEnded || !TryParseOption2(arg, out name, out value))
                {
                    sourceFiles.AddRange(ParseFileArgument(arg, baseDirectory, diagnostics));
                    continue;
                }

                switch (name)
                {
                    case "?":
                    case "help":
                        displayHelp = true;
                        continue;

                    case "r":
                    case "reference":
                        metadataReferences.AddRange(ParseAssemblyReferences(arg, value, diagnostics, embedInteropTypes: false));
                        continue;

                    case "debug":
                        emitPdb = true;
                        
                        // unused, parsed for backward compat only
                        if (!string.IsNullOrEmpty(value))
                        {
                            switch (value.ToLower())
                            {
                                case "full":
                                case "pdbonly":
                                    debugInformationFormat = DebugInformationFormat.Pdb;
                                    break;
                                case "portable":
                                    debugInformationFormat = DebugInformationFormat.PortablePdb;
                                    break;
                                case "embedded":
                                    debugInformationFormat = DebugInformationFormat.Embedded;
                                    break;
                                default:
                                    //AddDiagnostic(diagnostics, ErrorCode.ERR_BadDebugType, value);
                                    break;
                            }
                        }
                        continue;

                    case "debug+":
                        //guard against "debug+:xx"
                        if (value != null)
                            break;

                        emitPdb = true;
                        debugPlus = true;
                        continue;

                    case "debug-":
                        if (value != null)
                            break;

                        emitPdb = false;
                        debugPlus = false;
                        continue;

                    case "o":
                    case "optimize":
                    case "o+":
                    case "optimize+":
                        if (value != null)
                            break;

                        optimize = true;
                        continue;

                    case "o-":
                    case "optimize-":
                        if (value != null)
                            break;

                        optimize = false;
                        continue;

                    case "nologo":
                        displayLogo = false;
                        continue;

                    case "m":
                    case "main":
                        // Remove any quotes for consistent behavior as MSBuild can return quoted or 
                        // unquoted main.    
                        var unquoted = RemoveQuotesAndSlashes(value);
                        if (string.IsNullOrEmpty(unquoted))
                        {
                            //AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "<text>", name);
                            //continue;
                            throw new ArgumentException("main");    // TODO: ErrorCode
                        }

                        mainTypeName = unquoted;
                        continue;

                    case "pdb":
                        if (string.IsNullOrEmpty(value))
                        {
                            //AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
                            throw new ArgumentException("pdb"); // TODO: ErrorCode
                        }
                        else
                        {
                            pdbPath = ParsePdbPath(value, diagnostics, baseDirectory);
                        }
                        continue;

                    case "out":
                        if (string.IsNullOrWhiteSpace(value))
                        {
                            //AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
                            throw new ArgumentException("out"); // TODO: ErrorCode
                        }
                        else
                        {
                            ParseOutputFile(value, diagnostics, baseDirectory, out outputFileName, out outputDirectory);
                        }

                        continue;

                    case "t":
                    case "target":
                        if (value == null)
                        {
                            break; // force 'unrecognized option'
                        }

                        if (string.IsNullOrEmpty(value))
                        {
                            //AddDiagnostic(diagnostics, ErrorCode.FTL_InvalidTarget);
                            throw new ArgumentException("target"); // TODO: ErrorCode
                        }
                        else
                        {
                            outputKind = ParseTarget(value, diagnostics);
                        }

                        continue;

                    case "modulename":
                        var unquotedModuleName = RemoveQuotesAndSlashes(value);
                        if (string.IsNullOrEmpty(unquotedModuleName))
                        {
                            //AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), "modulename");
                            //continue;
                            throw new ArgumentException("modulename"); // TODO: ErrorCode
                        }
                        else
                        {
                            moduleName = unquotedModuleName;
                        }

                        continue;

                    case "runtimemetadataversion":
                        unquoted = RemoveQuotesAndSlashes(value);
                        if (string.IsNullOrEmpty(unquoted))
                        {
                            //AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "<text>", name);
                            //continue;
                            throw new ArgumentException("runtimemetadataversion"); // TODO: ErrorCode
                        }

                        runtimeMetadataVersion = unquoted;
                        continue;

                    default:
                        break;
                }
            }

            GetCompilationAndModuleNames(diagnostics, outputKind, sourceFiles, sourceFiles.Count != 0, /*moduleAssemblyName*/null, ref outputFileName, ref moduleName, out compilationName);

            var parseOptions = new PhpParseOptions
            (
                //languageVersion: languageVersion,
                //preprocessorSymbols: defines.ToImmutableAndFree(),
                //documentationMode: parseDocumentationComments ? DocumentationMode.Diagnose : DocumentationMode.None,
                kind: SourceCodeKind.Regular//,
                                            //features: parsedFeatures
            );

            var scriptParseOptions = parseOptions.WithKind(SourceCodeKind.Script);

            //// We want to report diagnostics with source suppression in the error log file.
            //// However, these diagnostics won't be reported on the command line.
            //var reportSuppressedDiagnostics = errorLogPath != null;

            var options = new PhpCompilationOptions
            (
                outputKind: outputKind,
                baseDirectory: baseDirectory,
                sdkDirectory: sdkDirectoryOpt,
                moduleName: moduleName,
                mainTypeName: mainTypeName,
                scriptClassName: WellKnownMemberNames.DefaultScriptClassName,
                //usings: usings,
                optimizationLevel: optimize ? OptimizationLevel.Release : OptimizationLevel.Debug,
                checkOverflow: false, // checkOverflow,
                                      //deterministic: deterministic,
                concurrentBuild: false, //concurrentBuild,  // TODO: true in Release
                                        //cryptoKeyContainer: keyContainerSetting,
                                        //cryptoKeyFile: keyFileSetting,
                                        //delaySign: delaySignSetting,
                platform: Platform.AnyCpu //, // platform,
                                          //generalDiagnosticOption: generalDiagnosticOption,
                                          //warningLevel: warningLevel,
                                          //specificDiagnosticOptions: diagnosticOptions,
                                          //reportSuppressedDiagnostics: reportSuppressedDiagnostics,
                                          //publicSign: publicSign
            );

            if (debugPlus)
            {
                options = options.WithDebugPlusMode(debugPlus);
            }

            var emitOptions = new EmitOptions
            (
                //metadataOnly: false,
                debugInformationFormat: debugInformationFormat,
                //pdbFilePath: null, // to be determined later
                //outputNameOverride: null, // to be determined later
                //baseAddress: baseAddress,
                //highEntropyVirtualAddressSpace: highEntropyVA,
                //fileAlignment: fileAlignment,
                //subsystemVersion: subsystemVersion,
                runtimeMetadataVersion: runtimeMetadataVersion
            );

            return new PhpCommandLineArguments()
            {
                // TODO: parsed arguments
                IsScriptRunner = IsScriptRunner,
                //InteractiveMode = interactiveMode || IsScriptRunner && sourceFiles.Count == 0,
                BaseDirectory = baseDirectory,
                //PathMap = pathMap,
                Errors = ImmutableArray<Diagnostic>.Empty,
                Utf8Output = true,
                CompilationName = compilationName,
                OutputFileName = outputFileName,
                PdbPath = pdbPath,
                EmitPdb = emitPdb,
                OutputDirectory = outputDirectory,
                //DocumentationPath = documentationPath,
                //ErrorLogPath = errorLogPath,
                //AppConfigPath = appConfigPath,
                SourceFiles = sourceFiles.AsImmutable(),
                Encoding = Encoding.UTF8,
                ChecksumAlgorithm = SourceHashAlgorithm.Sha1, // checksumAlgorithm,
                MetadataReferences = metadataReferences.AsImmutable(),
                AnalyzerReferences = analyzers.AsImmutable(),
                AdditionalFiles = additionalFiles.AsImmutable(),
                ReferencePaths = referencePaths.AsImmutable(),
                SourcePaths = ImmutableArray<string>.Empty, //sourcePaths.AsImmutable(),
                //KeyFileSearchPaths = keyFileSearchPaths.AsImmutable(),
                //Win32ResourceFile = win32ResourceFile,
                //Win32Icon = win32IconFile,
                //Win32Manifest = win32ManifestFile,
                //NoWin32Manifest = noWin32Manifest,
                DisplayLogo = displayLogo,
                DisplayHelp = displayHelp,
                ManifestResources = managedResources.AsImmutable(),
                CompilationOptions = options,
                ParseOptions = IsScriptRunner ? scriptParseOptions : parseOptions,
                EmitOptions = emitOptions,
                //ScriptArguments = scriptArgs.AsImmutableOrEmpty(),
                //TouchedFilesPath = touchedFilesPath,
                //PrintFullPaths = printFullPaths,
                //ShouldIncludeErrorEndLocation = errorEndLocation,
                //PreferredUILang = preferredUILang,
                //SqmSessionGuid = sqmSessionGuid,
                //ReportAnalyzer = reportAnalyzer
            };
        }