Beispiel #1
0
        private static EvaluationResult Write(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            var outputFilePath    = Args.AsPath(args, 0);
            var obj               = Args.AsObjectLiteral(args, 1);
            var quoteChar         = Args.AsStringOptional(args, 2) ?? "\'";
            var tags              = Args.AsStringArrayOptional(args, 3);
            var description       = Args.AsStringOptional(args, 4);
            var additionalOptions = GetAdditionalOptions(context.FrontEndContext, Args.AsObjectLiteralOptional(args, 5));

            using (var pipDataBuilderWrapper = context.FrontEndContext.GetPipDataBuilder())
            {
                var pipData = CreatePipData(context.StringTable, obj, quoteChar, pipDataBuilderWrapper.Instance);
                if (!pipData.IsValid)
                {
                    return(EvaluationResult.Error);
                }

                FileArtifact result;
                if (!context.GetPipConstructionHelper().TryWriteFile(outputFilePath, pipData, WriteFileEncoding.Utf8, tags, description, out result, GetWriteFileOption(additionalOptions)))
                {
                    // Error has been logged
                    return(EvaluationResult.Error);
                }

                return(new EvaluationResult(result));
            }
        }
Beispiel #2
0
        private static EvaluationResult ReadGraphFragment(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            var file        = Args.AsFile(args, 0);
            var deps        = Args.AsArrayLiteral(args, 1).Values.Select(v => (AbsolutePath)v.Value).ToArray();
            var description = Args.AsStringOptional(args, 2) ?? file.Path.ToString(context.PathTable);

            if (!file.IsSourceFile)
            {
                // Do not read output file.
                throw new FileOperationException(
                          new Exception(
                              I($"Failed adding pip graph fragment file '{file.Path.ToString(context.PathTable)}' because the file is not a source file")));
            }

            if (!context.FrontEndContext.FileSystem.Exists(file.Path))
            {
                throw new FileOperationException(new FileNotFoundException(I($"File '{file.Path.ToString(context.PathTable)}' does not exist")));
            }

            // Record the file, so that its content is tracked by input tracker.
            context.FrontEndHost.Engine.RecordFrontEndFile(file.Path, "DScript");

            int id = Interlocked.Increment(ref s_uniqueFragmentId);
            var readFragmentResult = context.FrontEndHost.PipGraphFragmentManager.AddFragmentFileToGraph(file, description, deps);

            if (!readFragmentResult)
            {
                return(EvaluationResult.Error);
            }

            return(EvaluationResult.Create(file.Path));
        }
Beispiel #3
0
        private static EvaluationResult SealDirectoryHelper(Context context, ModuleLiteral env, EvaluationStackFrame args, SealDirectoryKind sealDirectoryKind)
        {
            AbsolutePath path        = Args.AsPath(args, 0, false);
            ArrayLiteral contents    = Args.AsArrayLiteral(args, 1);
            var          tags        = Args.AsStringArrayOptional(args, 2);
            var          description = Args.AsStringOptional(args, 3);
            // Only do scrub for fully seal directory
            var scrub = sealDirectoryKind.IsFull() ? Args.AsBoolOptional(args, 4) : false;

            var fileContents = new FileArtifact[contents.Length];

            for (int i = 0; i < contents.Length; ++i)
            {
                fileContents[i] = Converter.ExpectFile(contents[i], strict: false, context: new ConversionContext(pos: i, objectCtx: contents));
            }

            var sortedFileContents = SortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer> .CloneAndSort(fileContents, OrdinalFileArtifactComparer.Instance);

            DirectoryArtifact sealedDirectoryArtifact;

            if (!context.GetPipConstructionHelper().TrySealDirectory(path, sortedFileContents, sealDirectoryKind, tags, description, null, out sealedDirectoryArtifact, scrub))
            {
                // Error has been logged
                return(EvaluationResult.Error);
            }

            var result = new StaticDirectory(sealedDirectoryArtifact, sealDirectoryKind, sortedFileContents.WithCompatibleComparer(OrdinalPathOnlyFileArtifactComparer.Instance));

            return(new EvaluationResult(result));
        }
Beispiel #4
0
        private static EvaluationResult Write(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            var outputFilePath = Args.AsPath(args, 0);
            var obj            = Args.AsObjectLiteral(args, 1);
            // Options don't have any settings yet, just here for future convenience
            var tags        = Args.AsStringArrayOptional(args, 3);
            var description = Args.AsStringOptional(args, 4);

            using (var pipDataBuilderWrapper = context.FrontEndContext.GetPipDataBuilder())
            {
                var pipData = CreatePipData(context.StringTable, obj, pipDataBuilderWrapper.Instance);
                if (!pipData.IsValid)
                {
                    return(EvaluationResult.Error);
                }

                FileArtifact result;
                if (!context.GetPipConstructionHelper().TryWriteFile(outputFilePath, pipData, WriteFileEncoding.Utf8, tags, description, out result))
                {
                    // Error has been logged
                    return(EvaluationResult.Error);
                }

                return(new EvaluationResult(result));
            }
        }
        private static EvaluationResult WriteFileHelper(Context context, ModuleLiteral env, EvaluationStackFrame args, WriteFileMode mode)
        {
            var path        = Args.AsPath(args, 0, false);
            var tags        = Args.AsStringArrayOptional(args, 2);
            var description = Args.AsStringOptional(args, 3);

            PipData pipData;

            switch (mode)
            {
            case WriteFileMode.WriteFile:
                var fileContent = Args.AsIs(args, 1);
                // WriteFile has a separator argument with default newline
                var separator = Args.AsStringOptional(args, 3) ?? Environment.NewLine;
                description = Args.AsStringOptional(args, 4);

                pipData = CreatePipDataForWriteFile(context, fileContent, separator);
                break;

            case WriteFileMode.WriteData:
                var data = Args.AsIs(args, 1);
                pipData = DataProcessor.ProcessData(context, context.FrontEndContext.PipDataBuilderPool, EvaluationResult.Create(data), new ConversionContext(pos: 1));
                break;

            case WriteFileMode.WriteAllLines:
                var lines   = Args.AsArrayLiteral(args, 1);
                var entry   = context.TopStack;
                var newData = ObjectLiteral.Create(
                    new List <Binding>
                {
                    new Binding(context.Names.DataSeparator, Environment.NewLine, entry.InvocationLocation),
                    new Binding(context.Names.DataContents, lines, entry.InvocationLocation),
                },
                    lines.Location,
                    entry.Path);

                pipData = DataProcessor.ProcessData(context, context.FrontEndContext.PipDataBuilderPool, EvaluationResult.Create(newData), new ConversionContext(pos: 1));
                break;

            case WriteFileMode.WriteAllText:
                var text = Args.AsString(args, 1);
                pipData = DataProcessor.ProcessData(context, context.FrontEndContext.PipDataBuilderPool, EvaluationResult.Create(text), new ConversionContext(pos: 1));
                break;

            default:
                throw Contract.AssertFailure("Unknown WriteFileMode.");
            }

            FileArtifact result;

            if (!context.GetPipConstructionHelper().TryWriteFile(path, pipData, WriteFileEncoding.Utf8, tags, description, out result))
            {
                // Error has been logged
                return(EvaluationResult.Error);
            }

            return(new EvaluationResult(result));
        }
Beispiel #6
0
        private static EvaluationResult DumpCallStack(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            var message  = Args.AsStringOptional(args, 0) ?? string.Empty;
            var location = context.TopStack.InvocationLocation.AsUniversalLocation(env, context);
            var stack    = context.GetStackTraceAsString(location);

            context.Logger.DebugDumpCallStack(context.FrontEndContext.LoggingContext, location.AsLoggingLocation(), message, stack);
            return(EvaluationResult.Undefined);
        }
Beispiel #7
0
        private static EvaluationResult IsFalse(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            var condition = Args.AsBool(args, 0);
            var message   = Args.AsStringOptional(args, 1);

            Assert.False(condition, message);

            return(EvaluationResult.Undefined);
        }
        private EvaluationResult SealSourceDirectory(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            AbsolutePath      path;
            SealDirectoryKind sealDirectoryKind;

            string[] tags;
            string   description;

            string[] patterns;

            if (args.Length > 0 && args[0].Value is ObjectLiteral)
            {
                var obj       = Args.AsObjectLiteral(args, 0);
                var directory = Converter.ExtractDirectory(obj, m_sealRoot, allowUndefined: false);
                path = directory.Path;

                var include = Converter.ExtractStringLiteral(obj, m_sealInclude, s_includeMap.Keys, allowUndefined: true);
                sealDirectoryKind = include != null
                    ? s_includeMap[include]
                    : SealDirectoryKind.SourceTopDirectoryOnly;
                tags        = Converter.ExtractStringArray(obj, m_sealTags, allowUndefined: true);
                description = Converter.ExtractString(obj, m_sealDescription, allowUndefined: true);
                patterns    = Converter.ExtractStringArray(obj, m_sealPatterns, allowUndefined: true);
            }
            else
            {
                path = Args.AsPath(args, 0, false);
                var optionAsEnumValue = Args.AsNumberOrEnumValueOptional(args, 1);
                var option            = optionAsEnumValue.HasValue ? (SealSourceDirectoryOption)optionAsEnumValue.Value : SealSourceDirectoryOption.TopDirectoryOnly;
                sealDirectoryKind = option == SealSourceDirectoryOption.AllDirectories ? SealDirectoryKind.SourceAllDirectories : SealDirectoryKind.SourceTopDirectoryOnly;

                tags        = Args.AsStringArrayOptional(args, 2);
                description = Args.AsStringOptional(args, 3);
                patterns    = Args.AsStringArrayOptional(args, 4);
            }

            DirectoryArtifact sealedDirectoryArtifact;

            if (!context.GetPipConstructionHelper().TrySealDirectory(
                    directoryRoot: path,
                    contents: s_emptySealContents,
                    outputDirectorycontents: s_emptyOutputDirectoryContents,
                    kind: sealDirectoryKind,
                    tags: tags,
                    description: description,
                    patterns: patterns,
                    sealedDirectory: out sealedDirectoryArtifact))
            {
                // Error has been logged
                return(EvaluationResult.Error);
            }

            var result = new StaticDirectory(sealedDirectoryArtifact, sealDirectoryKind, s_emptySealContents.WithCompatibleComparer(OrdinalPathOnlyFileArtifactComparer.Instance));

            return(new EvaluationResult(result));
        }
Beispiel #9
0
        private static EvaluationResult Assert(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            bool   predicate = Args.AsBool(args, 0);
            string message   = Args.AsStringOptional(args, 1) ?? string.Empty;

            if (!predicate)
            {
                throw new ContractAssertException(message);
            }

            return(EvaluationResult.Undefined);
        }
        private EvaluationResult SealDirectoryHelper(Context context, ModuleLiteral env, EvaluationStackFrame args, SealDirectoryKind sealDirectoryKind)
        {
            AbsolutePath path;
            ArrayLiteral contents;

            string[] tags;
            string   description;
            bool     scrub;

            if (args.Length > 0 && args[0].Value is ObjectLiteral)
            {
                var obj       = Args.AsObjectLiteral(args, 0);
                var directory = Converter.ExtractDirectory(obj, m_sealRoot, allowUndefined: false);
                path        = directory.Path;
                contents    = Converter.ExtractArrayLiteral(obj, m_sealFiles, allowUndefined: false);
                tags        = Converter.ExtractStringArray(obj, m_sealTags, allowUndefined: true);
                description = Converter.ExtractString(obj, m_sealDescription, allowUndefined: true);
                scrub       = sealDirectoryKind.IsFull()
                    ? Converter.ExtractOptionalBoolean(obj, m_sealScrub) ?? false
                    : false;
            }
            else
            {
                path        = Args.AsPath(args, 0, false);
                contents    = Args.AsArrayLiteral(args, 1);
                tags        = Args.AsStringArrayOptional(args, 2);
                description = Args.AsStringOptional(args, 3);
                // Only do scrub for fully seal directory
                scrub = sealDirectoryKind.IsFull() ? Args.AsBoolOptional(args, 4) : false;
            }

            var fileContents = new FileArtifact[contents.Length];

            for (int i = 0; i < contents.Length; ++i)
            {
                fileContents[i] = Converter.ExpectFile(contents[i], strict: false, context: new ConversionContext(pos: i, objectCtx: contents));
            }

            var sortedFileContents = SortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer> .CloneAndSort(fileContents, OrdinalFileArtifactComparer.Instance);

            DirectoryArtifact sealedDirectoryArtifact;

            if (!context.GetPipConstructionHelper().TrySealDirectory(path, sortedFileContents, sealDirectoryKind, tags, description, null, out sealedDirectoryArtifact, scrub))
            {
                // Error has been logged
                return(EvaluationResult.Error);
            }

            var result = new StaticDirectory(sealedDirectoryArtifact, sealDirectoryKind, sortedFileContents.WithCompatibleComparer(OrdinalPathOnlyFileArtifactComparer.Instance));

            return(new EvaluationResult(result));
        }
Beispiel #11
0
        private EvaluationResult GlobFolders(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            var dirPath   = Args.AsPath(args, 0, false);
            var pathTable = context.FrontEndContext.PathTable;
            var path      = dirPath.ToString(pathTable);

            // TODO:ST: add different set of function that will distinguish optional from required arguments!
            string pattern   = Args.AsStringOptional(args, 1) ?? "*";
            bool   recursive = Args.AsBoolOptional(args, 2);

            var resultPaths = EnumerateFilesOrDirectories(context, path, pattern, directoriesToSkipRecursively: 0, isRecursive: recursive, enumerateDirectory: true);

            var entry = context.TopStack;

            return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(resultPaths, entry.InvocationLocation, entry.Path)));
        }
        private static EvaluationResult ReadGraphFragment(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            var file        = Args.AsFile(args, 0);
            var deps        = Args.AsArrayLiteral(args, 1).Values.Select(v => (int)v.Value).ToArray();
            var description = Args.AsStringOptional(args, 2) ?? file.Path.ToString(context.PathTable);

            if (!file.IsSourceFile)
            {
                // Do not read output file.
                throw new FileOperationException(
                          new Exception(
                              I($"Failed adding pip graph fragment file '{file.Path.ToString(context.PathTable)}' because the file is not a source file")));
            }

            Contract.Assert(context.FrontEndContext.FileSystem.Exists(file.Path), "Fragment file does not exist");
            int id = Interlocked.Increment(ref s_uniqueFragmentId);
            var readFragmentTask = context.FrontEndHost.PipGraphFragmentManager.AddFragmentFileToGraph(id, file, deps, description);

            return(EvaluationResult.Create(id));
        }
Beispiel #13
0
        private static EvaluationResult SealSourceDirectory(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            AbsolutePath path = Args.AsPath(args, 0, false);
            var          optionAsEnumValue = Args.AsNumberOrEnumValueOptional(args, 1);
            var          option            = optionAsEnumValue.HasValue ? (SealSourceDirectoryOption)optionAsEnumValue.Value : SealSourceDirectoryOption.TopDirectoryOnly;
            var          tags        = Args.AsStringArrayOptional(args, 2);
            var          description = Args.AsStringOptional(args, 3);
            var          patterns    = Args.AsStringArrayOptional(args, 4);

            var sealDirectoryKind = option == SealSourceDirectoryOption.AllDirectories ? SealDirectoryKind.SourceAllDirectories : SealDirectoryKind.SourceTopDirectoryOnly;

            DirectoryArtifact sealedDirectoryArtifact;

            if (!context.GetPipConstructionHelper().TrySealDirectory(path, s_emptySealContents, sealDirectoryKind, tags, description, patterns, out sealedDirectoryArtifact))
            {
                // Error has been logged
                return(EvaluationResult.Error);
            }

            var result = new StaticDirectory(sealedDirectoryArtifact, sealDirectoryKind, s_emptySealContents.WithCompatibleComparer(OrdinalPathOnlyFileArtifactComparer.Instance));

            return(new EvaluationResult(result));
        }
Beispiel #14
0
        private EvaluationResult GlobImpl(Context context, EvaluationStackFrame args, SearchOption searchOption)
        {
            AbsolutePath dirPath   = Args.AsPath(args, 0, false);
            var          pathTable = context.FrontEndContext.PathTable;
            var          path      = dirPath.ToString(pathTable);

            string pattern = Args.AsStringOptional(args, 1) ?? "*";

            uint directoriesToSkipRecursively = 0;

            if (pattern.Length > 2)
            {
                if (pattern[0] == '*' &&
                    pattern[1] == '/' || pattern[1] == '\\')
                {
                    pattern = pattern.Substring(2);
                    directoriesToSkipRecursively = 1;
                }
            }

            var sw = Stopwatch.StartNew();

            var resultPaths = EnumerateFilesOrDirectories(
                context,
                path,
                pattern,
                directoriesToSkipRecursively,
                searchOption == SearchOption.AllDirectories,
                enumerateDirectory: false);

            sw.Stop();
            Interlocked.Add(ref context.Statistics.TotalGlobTimeInTicks, sw.Elapsed.Ticks);

            var entry = context.TopStack;

            return(EvaluationResult.Create(ArrayLiteral.CreateWithoutCopy(resultPaths, entry.InvocationLocation, entry.Path)));
        }
        private static EvaluationResult ComposeSharedOpaqueDirectories(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            AbsolutePath root        = Args.AsPath(args, 0, false);
            ArrayLiteral contents    = Args.AsArrayLiteral(args, 1);
            var          tags        = Args.AsStringArrayOptional(args, 2);
            var          description = Args.AsStringOptional(args, 3);

            var directories = new DirectoryArtifact[contents.Length];

            for (int i = 0; i < contents.Length; ++i)
            {
                directories[i] = Converter.ExpectSharedOpaqueDirectory(contents[i], context: new ConversionContext(pos: i, objectCtx: contents)).Root;
            }

            if (!context.GetPipConstructionHelper().TryComposeSharedOpaqueDirectory(root, directories, description, tags, out var compositeSharedOpaque))
            {
                // Error should have been logged
                return(EvaluationResult.Error);
            }

            var result = new StaticDirectory(compositeSharedOpaque, SealDirectoryKind.SharedOpaque, s_emptySealContents.WithCompatibleComparer(OrdinalPathOnlyFileArtifactComparer.Instance));

            return(new EvaluationResult(result));
        }
Beispiel #16
0
        private static EvaluationResult CopyFile(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            var source      = Args.AsFile(args, 0);
            var destination = Args.AsPath(args, 1);
            var tags        = Args.AsStringArrayOptional(args, 2);
            var description = Args.AsStringOptional(args, 3);
            var writable    = Args.AsBoolOptional(args, 4);

            CopyFile.Options options = default;
            if (writable)
            {
                options = BuildXL.Pips.Operations.CopyFile.Options.OutputsMustRemainWritable;
            }

            FileArtifact result;

            if (!context.GetPipConstructionHelper().TryCopyFile(source, destination, options, tags, description, out result))
            {
                // Error has been logged
                return(EvaluationResult.Error);
            }

            return(new EvaluationResult(result));
        }
Beispiel #17
0
        private EvaluationResult GetKeyForm(Context context, ModuleLiteral env, EvaluationStackFrame args)
        {
            var keyFormDll     = Args.AsFile(args, 0);
            var arch           = Args.AsString(args, 1);
            var name           = Args.AsString(args, 2);
            var version        = Args.AsString(args, 3);
            var publicKeyToken = Args.AsString(args, 4);
            var versionScope   = Args.AsStringOptional(args, 5);
            var culture        = Args.AsStringOptional(args, 6);
            var type           = Args.AsStringOptional(args, 7);

            var handler = m_handlers.GetOrAdd(
                keyFormDll.Path,
                _ =>
            {
                var keyFormDllPath = keyFormDll.Path.ToString(context.PathTable);
                var fileName       = Path.GetFileName(keyFormDllPath);
                if (!string.Equals(KeyFormFileName, fileName, StringComparison.OrdinalIgnoreCase))
                {
                    throw new KeyFormDllWrongFileNameException(keyFormDllPath, KeyFormFileName, new ErrorContext(pos: 1));
                }

                if (!File.Exists(keyFormDllPath))
                {
                    throw new KeyFormDllNotFoundException(keyFormDllPath, new ErrorContext(pos: 1));
                }

                IntPtr moduleHandle = NativeMethods.LoadLibraryW(keyFormDllPath);
                if (moduleHandle == IntPtr.Zero)
                {
                    var lasterror = Marshal.GetLastWin32Error();
                    var ex        = new Win32Exception(lasterror);
                    throw new KeyFormDllLoadException(keyFormDllPath, lasterror, ex.Message, new ErrorContext(pos: 1));
                }

                IntPtr procHandle = NativeMethods.GetProcAddress(moduleHandle, KeyFormFunction);
                if (procHandle == IntPtr.Zero)
                {
                    var lasterror = Marshal.GetLastWin32Error();
                    var ex        = new Win32Exception(lasterror);
                    throw new KeyFormDllLoadException(keyFormDllPath, lasterror, ex.Message, new ErrorContext(pos: 1));
                }

                return(Marshal.GetDelegateForFunctionPointer <GetKeyFormHandler>(procHandle));
            });

            using (var pooledBuilder = m_stringBuilderCache.GetInstance())
            {
                var builder = pooledBuilder.Instance;
                try
                {
                    // Since this is native code hardening our process against threading issues
                    // in the native code by ensuring we only access from single thread.

                    // WIP: experimental. Removing locking for key form.
                    // lock (m_keyFormLock)
                    {
                        handler(arch, name, version, publicKeyToken, versionScope, culture, type, builder, (uint)builder.Capacity);
                    }
                }
                catch (Exception e)
                {
                    // I know it is bad to catch all exceptions, but this is going into native code of which we
                    // don't have control and this code doesn't handle weird input properly.
                    var keyFormDllPath = keyFormDll.Path.ToString(context.PathTable);
                    throw new KeyFormNativeFailureException(keyFormDllPath, e, new ErrorContext(pos: 1));
                }

                return(EvaluationResult.Create(builder.ToString()));
            }
        }
Beispiel #18
0
        private EvaluationResult WriteFileHelper(Context context, ModuleLiteral env, EvaluationStackFrame args, WriteFileMode mode)
        {
            AbsolutePath path;

            string[] tags;
            string   description;
            PipData  pipData;

            if (args.Length > 0 && args[0].Value is ObjectLiteral)
            {
                var obj = Args.AsObjectLiteral(args, 0);
                path        = Converter.ExtractPath(obj, m_writeOutputPath, allowUndefined: false);
                tags        = Converter.ExtractStringArray(obj, m_writeTags, allowUndefined: true);
                description = Converter.ExtractString(obj, m_writeDescription, allowUndefined: true);
                switch (mode)
                {
                case WriteFileMode.WriteData:
                    var data = obj[m_writeContents];
                    pipData = ProcessData(context, data, new ConversionContext(pos: 1));
                    break;

                case WriteFileMode.WriteAllLines:
                    var lines   = Converter.ExtractArrayLiteral(obj, m_writeLines);
                    var entry   = context.TopStack;
                    var newData = ObjectLiteral.Create(
                        new List <Binding>
                    {
                        new Binding(m_dataSeparator, Environment.NewLine, entry.InvocationLocation),
                        new Binding(m_dataContents, lines, entry.InvocationLocation),
                    },
                        lines.Location,
                        entry.Path);

                    pipData = ProcessData(context, EvaluationResult.Create(newData), new ConversionContext(pos: 1));
                    break;

                case WriteFileMode.WriteAllText:
                    var text = Converter.ExtractString(obj, m_writeText);
                    pipData = ProcessData(context, EvaluationResult.Create(text), new ConversionContext(pos: 1));
                    break;

                default:
                    throw Contract.AssertFailure("Unknown WriteFileMode.");
                }
            }
            else
            {
                path        = Args.AsPath(args, 0, false);
                tags        = Args.AsStringArrayOptional(args, 2);
                description = Args.AsStringOptional(args, 3);

                switch (mode)
                {
                case WriteFileMode.WriteFile:
                    var fileContent = Args.AsIs(args, 1);
                    // WriteFile has a separator argument with default newline
                    var separator = Args.AsStringOptional(args, 3) ?? Environment.NewLine;
                    description = Args.AsStringOptional(args, 4);

                    pipData = CreatePipDataForWriteFile(context, fileContent, separator);
                    break;

                case WriteFileMode.WriteData:
                    var data = Args.AsIs(args, 1);
                    pipData = ProcessData(context, EvaluationResult.Create(data), new ConversionContext(pos: 1));
                    break;

                case WriteFileMode.WriteAllLines:
                    var lines   = Args.AsArrayLiteral(args, 1);
                    var entry   = context.TopStack;
                    var newData = ObjectLiteral.Create(
                        new List <Binding>
                    {
                        new Binding(m_dataSeparator, Environment.NewLine, entry.InvocationLocation),
                        new Binding(m_dataContents, lines, entry.InvocationLocation),
                    },
                        lines.Location,
                        entry.Path);

                    pipData = ProcessData(context, EvaluationResult.Create(newData), new ConversionContext(pos: 1));
                    break;

                case WriteFileMode.WriteAllText:
                    var text = Args.AsString(args, 1);
                    pipData = ProcessData(context, EvaluationResult.Create(text), new ConversionContext(pos: 1));
                    break;

                default:
                    throw Contract.AssertFailure("Unknown WriteFileMode.");
                }
            }

            FileArtifact result;

            if (!context.GetPipConstructionHelper().TryWriteFile(path, pipData, WriteFileEncoding.Utf8, tags, description, out result))
            {
                // Error has been logged
                return(EvaluationResult.Error);
            }

            return(new EvaluationResult(result));
        }