/// <summary>
 /// Registers an API with the module.
 /// </summary>
 /// <param name="routeBuilder">
 /// The route builder to register a route with.
 /// </param>
 /// <param name="apiRoute">
 /// The route to register.
 /// </param>
 /// <param name="useUser">
 /// A function that uses the user.
 /// </param>
 private void RegisterUserApi <T>(
     RouteBuilder routeBuilder,
     string apiRoute,
     Func <dynamic, User, Task <T> > useUser)
 {
     routeBuilder[apiRoute, true] = async(args, ct) =>
     {
         User user;
         if (!User.TryGetByToken(args.token, out user))
         {
             Program.GlobalLog.Log(
                 new LogEntry(
                     Severity.Warning,
                     "malformed request",
                     Quotation.QuoteEvenInBold(
                         "token ",
                         args.token,
                         " does not exist.")));
             return(HttpStatusCode.BadRequest);
         }
         else if (user.IsAuthenticated)
         {
             return(await useUser(args, user));
         }
         else
         {
             return(HttpStatusCode.Unauthorized);
         }
     };
 }
Пример #2
0
        /// <summary>
        /// Hosts an instance of UnSHACLed on the local host.
        /// </summary>
        /// <param name="port">The port to host UnSHACLed on.</param>
        /// <param name="log">A log to send errors to.</param>
        /// <returns>
        /// The host process if it can be launched; otherwise, <c>null</c>.
        /// An error is logged by this function in the latter case.
        /// </returns>
        private static Process HostUnSHACLed(int port, ILog log)
        {
            // If nobody bothered to specify a URL, then we'll just have to
            // host it ourselves.
            string procName      = "serve";
            string procArgs      = "-s build -p " + port;
            var    serverProcess = StartUnSHACLedProcess(procName, procArgs, true);

            if (serverProcess == null)
            {
                log.Log(
                    new Pixie.LogEntry(
                        Severity.Error,
                        "cannot host",
                        Quotation.QuoteEvenInBold(
                            "command ",
                            procName + " " + procArgs,
                            " failed to launch; do you have ",
                            procName,
                            " installed? If not, try ",
                            "npm install -g " + procName + "@6.5.3",
                            ".")));
                return(null);
            }

            string expectedServerOutput = "serve: Running on port " + port;
            var    serverOutput         = serverProcess.StandardOutput.ReadLine();

            if (serverOutput == expectedServerOutput)
            {
                return(serverProcess);
            }
            else
            {
                if (!serverProcess.HasExited)
                {
                    serverProcess.Kill();
                }
                serverProcess.Dispose();
                log.Log(
                    new Pixie.LogEntry(
                        Severity.Error,
                        "cannot host",
                        Quotation.QuoteEvenInBold(
                            "expected ",
                            procName,
                            " to reply with ",
                            expectedServerOutput,
                            " but instead it said ",
                            serverOutput,
                            "; assuming that something went terribly wrong.")));
                return(null);
            }
        }
Пример #3
0
        private static Flame.Compiler.MethodBody GetInitialMethodBody(IMethod method, TypeEnvironment typeSystem)
        {
            // TODO: deduplicate this logic (it also appears in IL2LLVM and ILOpt)

            var body = OnDemandOptimizer.GetInitialMethodBodyDefault(method);

            if (body == null)
            {
                return(null);
            }

            // Validate the method body.
            var errors = body.Validate();

            if (errors.Count > 0)
            {
                var sourceIr     = FormatIr(body);
                var exceptionLog = new TestLog(new[] { Severity.Error }, NullLog.Instance);
                exceptionLog.Log(
                    new LogEntry(
                        Severity.Error,
                        "invalid IR",
                        Quotation.QuoteEvenInBold(
                            "the Flame IR produced by the CIL analyzer for ",
                            method.FullName.ToString(),
                            " is erroneous."),

                        CreateRemark(
                            "errors in IR:",
                            new BulletedList(errors.Select(x => new Text(x)).ToArray())),

                        CreateRemark(
                            "generated Flame IR:",
                            new Paragraph(new WrapBox(sourceIr, 0, -sourceIr.Length)))));
                return(null);
            }

            // Register some analyses and clean up the CFG before we actually start to optimize it.
            return(body.WithImplementation(
                       body.Implementation
                       .WithAnalysis(
                           new ConstantAnalysis <SubtypingRules>(
                               typeSystem.Subtyping))
                       .WithAnalysis(
                           new ConstantAnalysis <PermissiveExceptionDelayability>(
                               PermissiveExceptionDelayability.Instance))
                       .Transform(
                           AllocaToRegister.Instance,
                           CopyPropagation.Instance,
                           new ConstantPropagation(),
                           CanonicalizeDelegates.Instance,
                           InstructionSimplification.Instance)));
        }
Пример #4
0
 /// <summary>
 /// Asserts that a value cannot be <c>null</c>.
 /// </summary>
 /// <param name="value">The value to check.</param>
 /// <param name="valueName">The name of the value to check.</param>
 public static void IsNotNull(object value, string valueName)
 {
     IsTrue(
         value != null,
         Quotation.QuoteEvenInBold(
             "expected a non-",
             "null",
             " value for ",
             valueName,
             ", but got ",
             "null",
             " anyway."));
 }
Пример #5
0
 /// <summary>
 /// Asserts that two values are equal.
 /// </summary>
 /// <param name="actual">The left-hand side of the equality.</param>
 /// <param name="expected">The right-hand side of the equality.</param>
 public static void AreEqual(
     object actual,
     object expected)
 {
     AreEqual(
         actual,
         expected,
         Quotation.QuoteEvenInBold(
             "values are not equal; expected ",
             expected.ToString(),
             " but got ",
             actual.ToString(),
             "."));
 }
Пример #6
0
 /// <summary>
 /// Asserts that two values are not equal.
 /// </summary>
 /// <param name="actual">The left-hand side of the equality.</param>
 /// <param name="expected">The right-hand side of the equality.</param>
 public static void AreNotEqual(
     object actual,
     object expected)
 {
     AreNotEqual(
         actual,
         expected,
         Quotation.QuoteEvenInBold(
             "values are equal; expected anything but ",
             expected.ToString(),
             " but got it anyway (",
             actual.ToString(),
             ")."));
 }
Пример #7
0
        /// <summary>
        /// Parses a list of browser names to use.
        /// </summary>
        /// <param name="names">The names to parse.</param>
        /// <param name="log">A log for sending errors to.</param>
        /// <returns>A list of web driver builders.</returns>
        private static IReadOnlyDictionary <string, Func <IWebDriver> > ParseBrowserNames(
            IEnumerable <string> names, ILog log)
        {
            var browsersToUse = new Dictionary <string, Func <IWebDriver> >();

            foreach (var name in names.Distinct())
            {
                if (Drivers.ContainsKey(name))
                {
                    browsersToUse[name] = Drivers[name];
                }
                else
                {
                    // Try to guess what the user meant.
                    var suggestion = NameSuggestion.SuggestName(name, Drivers.Keys);
                    if (suggestion == null)
                    {
                        // Log an error if we couldn't find a reasonable guess.
                        log.Log(
                            new Pixie.LogEntry(
                                Severity.Error,
                                "unknown browser",
                                Quotation.QuoteEvenInBold(
                                    "specified browser ",
                                    name,
                                    " is not a known browser.")));
                    }
                    else
                    {
                        // Give the user a hand otherwise.
                        var diff = Diff.Create(name, suggestion);
                        log.Log(
                            new Pixie.LogEntry(
                                Severity.Error,
                                "unknown browser",
                                Quotation.QuoteEvenInBold(
                                    "specified browser ",
                                    TextDiff.RenderDeletions(diff),
                                    " is not a known browser; did you mean ",
                                    TextDiff.RenderInsertions(diff),
                                    "?")));
                    }
                }
            }
            return(browsersToUse);
        }
 /// <summary>
 /// Checks that a mandatory string-valued option actually
 /// has an argument.
 /// </summary>
 /// <param name="option">The mandatory string-valued option.</param>
 /// <param name="parsedOptions">Parsed command-line arguments.</param>
 /// <param name="log">A log to send errors to.</param>
 private static void CheckMandatoryStringOptionHasArg(
     Option option,
     OptionSet parsedOptions,
     ILog log)
 {
     if (string.IsNullOrWhiteSpace(parsedOptions.GetValue <string>(option)))
     {
         log.Log(
             new Pixie.LogEntry(
                 Severity.Error,
                 "missing option",
                 Quotation.QuoteEvenInBold(
                     "option ",
                     option.Forms[0].ToString(),
                     " is mandatory but left blank.")));
     }
 }
Пример #9
0
        private static void OptimizeMethod(
            Mono.Cecil.MethodDefinition methodDefinition,
            ClrAssembly parentAssembly,
            Func <ClrMethodDefinition, MethodBody> optimizeBody)
        {
            if (methodDefinition.HasBody)
            {
                var flameMethod = (ClrMethodDefinition)parentAssembly.Resolve(methodDefinition);
                var irBody      = flameMethod.Body;

                var errors = irBody.Validate();
                if (errors.Count > 0)
                {
                    var sourceIr = FormatIr(irBody);
                    log.Log(
                        new LogEntry(
                            Severity.Warning,
                            "invalid IR",
                            Quotation.QuoteEvenInBold(
                                "the Flame IR produced by the CIL analyzer for ",
                                flameMethod.FullName.ToString(),
                                " is erroneous; skipping it."),

                            CreateRemark(
                                "errors in IR:",
                                new BulletedList(errors.Select(x => new Text(x)).ToArray())),

                            CreateRemark(
                                "generated Flame IR:",
                                new Paragraph(new WrapBox(sourceIr, 0, -sourceIr.Length)))));
                    return;
                }

                var optBody = optimizeBody(flameMethod);
                var emitter = new ClrMethodBodyEmitter(
                    methodDefinition,
                    optBody,
                    parentAssembly.Resolver.TypeEnvironment);
                var newCilBody = emitter.Compile();
                methodDefinition.Body = newCilBody;
            }
        }
Пример #10
0
 /// <summary>
 /// Runs this test case against a web driver.
 /// </summary>
 /// <param name="driver">A web driver to use.</param>
 /// <param name="driverName">The name of the driver being used.</param>
 /// <param name="log">A log to send messages to.</param>
 /// <returns>
 /// <c>true</c> if the test was successful; otherwise, <c>false</c>.
 /// </returns>
 public bool Run(IWebDriver driver, string driverName, ILog log)
 {
     try
     {
         impl(driver, log);
         return(true);
     }
     catch (TestFailedException ex)
     {
         log.Log(
             new Pixie.LogEntry(
                 Severity.Error,
                 new Diagnostic(
                     driverName,
                     "error",
                     Colors.Red,
                     new Quotation(Description, 2),
                     ex.FormattedMessage)));
         return(false);
     }
     catch (Exception ex)
     {
         log.Log(
             new Pixie.LogEntry(
                 Severity.Error,
                 new Diagnostic(
                     driverName,
                     "error",
                     Colors.Red,
                     new Quotation(Description, 2),
                     new Sequence(
                         Quotation.QuoteEvenInBold(
                             "unhandled exception of type ",
                             ex.GetType().FullName,
                             "."),
                         new Paragraph(ex.ToString())))));
         return(false);
     }
 }
        /// <summary>
        /// Parse the domain names as an array of URIs.
        /// </summary>
        /// <param name="parsedOptions">The set of all parsed options.</param>
        /// <param name="log">A log to send errors to.</param>
        /// <returns>An array of URIs.</returns>
        private static Uri[] ParseDomains(OptionSet parsedOptions, ILog log)
        {
            var domainUris = new List <Uri>();

            var domainNames = parsedOptions.GetValue <IReadOnlyList <string> >(Options.Domains);

            if (domainNames.Count == 0)
            {
                // Zero domains doesn't make no sense. Make the user pick a domain.
                log.Log(
                    new LogEntry(
                        Severity.Error,
                        "no domain",
                        "at least one URI must be specified as a base domain for the server."));
                return(domainUris.ToArray());
            }

            foreach (var name in domainNames)
            {
                Uri domainUri;
                if (Uri.TryCreate(name, UriKind.Absolute, out domainUri))
                {
                    domainUris.Add(domainUri);
                }
                else
                {
                    log.Log(
                        new LogEntry(
                            Severity.Error,
                            "bad domain",
                            Quotation.QuoteEvenInBold(
                                "all domains must be well-formed absolute URIs, but ",
                                name,
                                " is not a well-formed URI.")));
                }
            }
            return(domainUris.ToArray());
        }
Пример #12
0
 private static T CheckSingleCandidate <T>(
     T[] candidates,
     LNode parentType,
     LNode signature,
     string memberKind,
     DecoderState state)
     where T : class
 {
     if (candidates.Length == 0)
     {
         state.Log.LogSyntaxError(
             signature,
             Quotation.QuoteEvenInBold(
                 "type ",
                 FeedbackHelpers.Print(parentType),
                 " does not define a " + memberKind + " ",
                 FeedbackHelpers.Print(signature),
                 "."));
         return(null);
     }
     else if (candidates.Length > 1)
     {
         state.Log.LogSyntaxError(
             signature,
             Quotation.QuoteEvenInBold(
                 "type ",
                 FeedbackHelpers.Print(parentType),
                 " defines more than one " + memberKind + " ",
                 FeedbackHelpers.Print(signature),
                 "."));
         return(null);
     }
     else
     {
         return(candidates[0]);
     }
 }
Пример #13
0
        public static int Main(string[] args)
        {
            // Acquire a log.
            var rawLog = TerminalLog.Acquire();

            log = new TransformLog(
                rawLog,
                new Func <LogEntry, LogEntry>[]
            {
                MakeDiagnostic
            });

            // Parse command-line options.
            var parser = new GnuOptionSetParser(
                Options.All, Options.Input);

            var recLog        = new RecordingLog(log);
            var parsedOptions = parser.Parse(args, recLog);

            if (recLog.Contains(Severity.Error))
            {
                // Stop the program if the command-line arguments
                // are half baked.
                return(1);
            }

            if (parsedOptions.GetValue <bool>(Options.Help))
            {
                // Wrap the help message into a log entry and send it to the log.
                TerminalLog.AcquireStandardOutput().Log(
                    new LogEntry(
                        Severity.Info,
                        new HelpMessage(
                            "il2llvm is a command-line tool that compiles CIL assemblies to LLVM modules.",
                            "il2llvm path [options...]",
                            Options.All)));
                return(0);
            }

            var inputPath = parsedOptions.GetValue <string>(Options.Input);

            if (string.IsNullOrEmpty(inputPath))
            {
                log.Log(
                    new LogEntry(
                        Severity.Error,
                        "nothing to compile",
                        "no input file"));
                return(1);
            }

            var outputPath = parsedOptions.GetValue <string>(Options.Output);

            if (string.IsNullOrEmpty(outputPath))
            {
                outputPath = Path.GetFileNameWithoutExtension(inputPath) + ".ll";
            }

            var printIr = parsedOptions.GetValue <bool>(Options.PrintIr);

            // Read the assembly from disk.
            Mono.Cecil.AssemblyDefinition cecilAsm;
            try
            {
                cecilAsm = Mono.Cecil.AssemblyDefinition.ReadAssembly(
                    inputPath,
                    new Mono.Cecil.ReaderParameters
                {
                    ReadWrite = false
                });
            }
            catch (Exception)
            {
                log.Log(
                    new LogEntry(
                        Severity.Error,
                        "unreadable assembly",
                        Quotation.QuoteEvenInBold(
                            "cannot read assembly at ",
                            inputPath,
                            ".")));
                return(1);
            }

            if (cecilAsm.EntryPoint == null)
            {
                log.Log(
                    new LogEntry(
                        Severity.Error,
                        "unsuitable assembly",
                        "input assembly does not define an entry point."));
                return(1);
            }

            try
            {
                // Wrap the CIL assembly in a Flame assembly.
                var flameAsm = ClrAssembly.Wrap(cecilAsm);

                // Compile the assembly to an LLVM module.
                var module = CompileAsync(flameAsm).Result;

                // Write the LLVM module to disk.
                string error;
                if (LLVM.PrintModuleToFile(module, outputPath, out error))
                {
                    log.Log(new LogEntry(Severity.Error, "cannot write module", error));
                }

                LLVM.DisposeModule(module);
            }
            finally
            {
                // Be sure to dispose the assembly after we've used it.
                cecilAsm.Dispose();
            }

            return(0);
        }
Пример #14
0
 /// <summary>
 /// Quotes even (second, fourth, sixth, ...) markup elements in bold
 /// and wraps the result in a sequence node.
 /// </summary>
 /// <param name="nodes">The nodes to process.</param>
 /// <returns>A sequence container node.</returns>
 public static Sequence QuoteEven(params MarkupNode[] nodes)
 {
     return(Quotation.QuoteEvenInBold(nodes));
 }
Пример #15
0
        private IReadOnlyList <object> RunAction(SExpression expression, bool reportExceptions = true)
        {
            if (expression.IsCallTo("invoke"))
            {
                var tail     = expression.Tail;
                var moduleId = Assembler.AssembleLabelOrNull(ref tail);
                var name     = Assembler.AssembleString(tail[0], Log);
                var args     = tail.Skip(1);

                if (moduleId == null)
                {
                    foreach (var inst in Enumerable.Reverse(moduleInstances))
                    {
                        if (TryInvokeNamedFunction(inst, name, args, expression, out IReadOnlyList <object> results, reportExceptions))
                        {
                            return(results);
                        }
                    }

                    Log.Log(
                        new LogEntry(
                            Severity.Error,
                            "undefined function",
                            Quotation.QuoteEvenInBold(
                                "no function named ",
                                name,
                                " is defined here."),
                            Assembler.Highlight(expression)));
                    return(Array.Empty <object>());
                }
                else
                {
                    if (moduleInstancesByName.TryGetValue(moduleId, out ModuleInstance inst))
                    {
                        if (TryInvokeNamedFunction(inst, name, args, expression, out IReadOnlyList <object> results, reportExceptions))
                        {
                            return(results);
                        }
                        else
                        {
                            Log.Log(
                                new LogEntry(
                                    Severity.Error,
                                    "undefined function",
                                    Quotation.QuoteEvenInBold(
                                        "no function named ",
                                        name,
                                        " is defined in module ",
                                        moduleId,
                                        "."),
                                    Assembler.Highlight(expression)));
                            return(Array.Empty <object>());
                        }
                    }
                    else
                    {
                        Log.Log(
                            new LogEntry(
                                Severity.Error,
                                "undefined module",
                                Quotation.QuoteEvenInBold(
                                    "no module named ",
                                    moduleId,
                                    " is defined here."),
                                Assembler.Highlight(expression)));
                        return(Array.Empty <object>());
                    }
                }
            }
            else if (expression.IsCallTo("get"))
            {
                var tail     = expression.Tail;
                var moduleId = Assembler.AssembleLabelOrNull(ref tail);
                var name     = Assembler.AssembleString(tail[0], Log);
                if (moduleId == null)
                {
                    foreach (var inst in moduleInstances)
                    {
                        if (inst.ExportedGlobals.TryGetValue(name, out Variable def))
                        {
                            return(new[] { def.Get <object>() });
                        }
                    }

                    Log.Log(
                        new LogEntry(
                            Severity.Error,
                            "undefined global",
                            Quotation.QuoteEvenInBold(
                                "no global named ",
                                name,
                                " is defined here."),
                            Assembler.Highlight(expression)));
                    return(Array.Empty <object>());
                }
                else
                {
                    if (moduleInstancesByName.TryGetValue(moduleId, out ModuleInstance inst))
                    {
                        if (inst.ExportedGlobals.TryGetValue(name, out Variable def))
                        {
                            return(new[] { def.Get <object>() });
                        }
                        else
                        {
                            Log.Log(
                                new LogEntry(
                                    Severity.Error,
                                    "undefined global",
                                    Quotation.QuoteEvenInBold(
                                        "no global named ",
                                        name,
                                        " is defined in module ",
                                        moduleId,
                                        "."),
                                    Assembler.Highlight(expression)));
                            return(Array.Empty <object>());
                        }
                    }
                    else
                    {
                        Log.Log(
                            new LogEntry(
                                Severity.Error,
                                "undefined module",
                                Quotation.QuoteEvenInBold(
                                    "no module named ",
                                    moduleId,
                                    " is defined here."),
                                Assembler.Highlight(expression)));
                        return(Array.Empty <object>());
                    }
                }
            }
            else
            {
                Log.Log(
                    new LogEntry(
                        Severity.Error,
                        "unknown action",
                        Quotation.QuoteEvenInBold(
                            "expression ",
                            expression.Head.Span.Text,
                            " was not recognized as a known script action."),
                        Assembler.Highlight(expression)));
                return(Array.Empty <object>());
            }
        }
Пример #16
0
        public static int Main(string[] args)
        {
            // Acquire a log.
            var rawLog = TerminalLog.Acquire();

            log = new TransformLog(
                rawLog,
                new Func <LogEntry, LogEntry>[]
            {
                MakeDiagnostic
            });

            // Parse command-line options.
            var parser = new GnuOptionSetParser(
                Options.All, Options.Input);

            var recLog        = new RecordingLog(log);
            var parsedOptions = parser.Parse(args, recLog);

            if (recLog.Contains(Severity.Error))
            {
                // Stop the program if the command-line arguments
                // are half baked.
                return(1);
            }

            if (parsedOptions.GetValue <bool>(Options.Help))
            {
                // Wrap the help message into a log entry and send it to the log.
                TerminalLog.AcquireStandardOutput().Log(
                    new LogEntry(
                        Severity.Info,
                        new HelpMessage(
                            "ilopt is a command-line tool that optimizes CIL assemblies.",
                            "ilopt path [options...]",
                            Options.All)));
                return(0);
            }

            var inputPath = parsedOptions.GetValue <string>(Options.Input);

            if (string.IsNullOrEmpty(inputPath))
            {
                log.Log(
                    new LogEntry(
                        Severity.Error,
                        "nothing to optimize",
                        "no input file"));
                return(1);
            }

            var outputPath = parsedOptions.GetValue <string>(Options.Output);

            if (string.IsNullOrEmpty(outputPath))
            {
                outputPath = Path.GetFileNameWithoutExtension(inputPath) + ".opt" + Path.GetExtension(inputPath);
            }

            var printIr = parsedOptions.GetValue <bool>(Options.PrintIr);

            // Read the assembly from disk.
            Mono.Cecil.AssemblyDefinition cecilAsm;
            try
            {
                cecilAsm = Mono.Cecil.AssemblyDefinition.ReadAssembly(
                    inputPath,
                    new Mono.Cecil.ReaderParameters
                {
                    ReadWrite = false
                });
            }
            catch (Exception)
            {
                log.Log(
                    new LogEntry(
                        Severity.Error,
                        "unreadable assembly",
                        Quotation.QuoteEvenInBold(
                            "cannot read assembly at ",
                            inputPath,
                            ".")));
                return(1);
            }

            try
            {
                // Make all non-public types, methods and fields in the assembly
                // internal if the user requests it. This will work to
                // our advantage.
                if (parsedOptions.GetValue <bool>(Options.Internalize))
                {
                    MakeInternal(cecilAsm);
                }

                // Wrap the CIL assembly in a Flame assembly.
                var flameAsm = ClrAssembly.Wrap(cecilAsm);

                // Optimize the assembly.
                OptimizeAssemblyAsync(
                    flameAsm,
                    printIr,
                    parsedOptions.GetValue <bool>(Options.Parallel)).Wait();

                // Write the optimized assembly to disk.
                cecilAsm.Write(outputPath);
            }
            finally
            {
                // Be sure to dispose the assembly after we've used it.
                cecilAsm.Dispose();
            }

            return(0);
        }
Пример #17
0
        public static int Main(string[] args)
        {
            // Acquire a log.
            var rawLog = TerminalLog.Acquire();
            var log    = new TransformLog(
                rawLog,
                new Func <LogEntry, LogEntry>[]
            {
                MakeDiagnostic
            });

            // Parse command-line options.
            var parser = new GnuOptionSetParser(
                Options.All, Options.Input);

            var recLog        = new RecordingLog(log);
            var parsedOptions = parser.Parse(args, recLog);

            if (recLog.Contains(Severity.Error))
            {
                // Stop the program if the command-line arguments
                // are half baked.
                return(1);
            }

            if (parsedOptions.GetValue <bool>(Options.Help))
            {
                // Wrap the help message into a log entry and send it to the log.
                rawLog.Log(
                    new LogEntry(
                        Severity.Info,
                        new HelpMessage(
                            "fbfc is a compiler that turns Brainfuck code into CIL assemblies.",
                            "fbfc path [options...]",
                            Options.All)));
                return(0);
            }

            var inputPath = parsedOptions.GetValue <string>(Options.Input);

            if (string.IsNullOrEmpty(inputPath))
            {
                log.Log(
                    new LogEntry(
                        Severity.Error,
                        "nothing to compile",
                        "no input file"));
                return(1);
            }

            var outputPath = parsedOptions.GetValue <string>(Options.Output);

            if (string.IsNullOrEmpty(outputPath))
            {
                outputPath = Path.GetFileNameWithoutExtension(inputPath) + ".exe";
            }

            // Read the Brainfuck source code from disk.
            SourceDocument source;

            try
            {
                source = new StringDocument(inputPath, File.ReadAllText(inputPath));
            }
            catch (Exception)
            {
                log.Log(
                    new LogEntry(
                        Severity.Error,
                        "invalid source path",
                        Quotation.QuoteEvenInBold(
                            "cannot read Brainfuck source code at ",
                            inputPath,
                            ".")));
                return(1);
            }

            var asmName  = Path.GetFileNameWithoutExtension(outputPath);
            var cecilAsm = Mono.Cecil.AssemblyDefinition.CreateAssembly(
                new Mono.Cecil.AssemblyNameDefinition(asmName, new Version(1, 0, 0, 0)),
                asmName,
                Mono.Cecil.ModuleKind.Console);

            var flameAsm = ClrAssembly.Wrap(cecilAsm);

            var typeEnv  = flameAsm.Resolver.TypeEnvironment;
            var compiler = new Compiler(
                flameAsm,
                Dependencies.Resolve(
                    typeEnv,
                    new ReadOnlyTypeResolver(typeEnv.Object.Parent.Assembly),
                    log),
                log,
                parsedOptions);

            compiler.Compile(source);

            cecilAsm.Write(outputPath);

            return(0);
        }
Пример #18
0
        public static int Main(string[] args)
        {
            // Acquire a log for printing output.
            var rawLog = new RecordingLog(TerminalLog.Acquire());

            // Create a derived log for printing diagnostics.
            var log = CreateDiagnosticLog(rawLog);

            // Parse command-line arguments.
            var optParser = new GnuOptionSetParser(Options.All, Options.Url);

            // Actually parse the options.
            var parsedOptions = optParser.Parse(args, log);

            if (rawLog.Contains(Severity.Error))
            {
                // Ouch. Command-line arguments were bad. Stop testing now.
                return(1);
            }

            if (parsedOptions.ContainsOption(Options.Color))
            {
                if (parsedOptions.GetValue <bool>(Options.Color))
                {
                    rawLog = new RecordingLog(
                        TerminalLog.AcquireStandardError(
                            new AnsiStyleManager(Console.Error)));
                }
                else
                {
                    rawLog = new RecordingLog(
                        TerminalLog.AcquireStandardError(
                            NoStyleManager.Instance));
                }
                log = CreateDiagnosticLog(rawLog);
            }

            if (parsedOptions.GetValue <bool>(Options.Help))
            {
                // Print a cute little help message (to stdout instead of stderr).
                var helpLog = TerminalLog.AcquireStandardOutput();
                helpLog.Log(
                    new Pixie.LogEntry(
                        Severity.Message,
                        new HelpMessage(
                            "Runs UnSHACLed's functional tests.",
                            "selenium-tests [url-or-options...]",
                            Options.All)));
                return(0);
            }

            string testUrl = parsedOptions.GetValue <string>(Options.Url);
            bool   noUrl   = string.IsNullOrWhiteSpace(testUrl);

            if ((noUrl && !parsedOptions.ContainsOption(Options.BuildApplication)) ||
                parsedOptions.GetValue <bool>(Options.BuildApplication))
            {
                // Build the application if there's no URL and `--no-build-app`
                // was not specified or if `--build-app` was specified.
                log.Log(
                    new Pixie.LogEntry(
                        Severity.Info,
                        "status",
                        "building UnSHACLed..."));
                BuildUnSHACLed();
                log.Log(
                    new Pixie.LogEntry(
                        Severity.Info,
                        "status",
                        "UnSHACLed built successfully!"));
            }

            Process serverProcess = null;

            if (noUrl)
            {
                // If nobody bothered to specify a URL, then we'll just have to
                // host it ourselves.
                serverProcess = HostUnSHACLed(8080, log);
                if (serverProcess == null)
                {
                    return(1);
                }
                testUrl = "http://localhost:8080/index.html";
            }

            var browserNames = parsedOptions.ContainsOption(Options.Browsers)
                ? parsedOptions.GetValue <IReadOnlyList <string> >(Options.Browsers)
                : new[] { "firefox" };

            var browsersToUse = ParseBrowserNames(browserNames, log);

            if (rawLog.Contains(Severity.Error))
            {
                // Couldn't parse the command-line args. Better quit now.
                return(1);
            }

            if (parsedOptions.GetValue <bool>(Options.PrintApplicationUrl))
            {
                log.Log(
                    new Pixie.LogEntry(
                        Severity.Message,
                        "application url",
                        Quotation.QuoteEvenInBold(
                            "the absolute app url is ",
                            testUrl,
                            ".")));
            }

            try
            {
                Run(testUrl, browsersToUse, log, rawLog);
            }
            finally
            {
                if (serverProcess != null)
                {
                    serverProcess.Kill();
                    serverProcess.Dispose();
                }
            }

            // If things went swimmingly, then return a zero exit code.
            // Otherwise, let the world know that something is wrong.
            return(rawLog.Contains(Severity.Error) ? 1 : 0);
        }
Пример #19
0
        private BlockFlow DecodeBlockFlow(
            LNode node,
            FlowGraphBuilder graph,
            Dictionary <Symbol, BasicBlockBuilder> blocks,
            Dictionary <Symbol, ValueTag> valueTags)
        {
            if (node.Calls(CodeSymbols.Goto))
            {
                Branch target;
                if (FeedbackHelpers.AssertArgCount(node, 1, Log) &&
                    AssertDecodeBranch(node.Args[0], graph, blocks, valueTags, out target))
                {
                    return(new JumpFlow(target));
                }
                else
                {
                    return(UnreachableFlow.Instance);
                }
            }
            else if (node.Calls(CodeSymbols.Switch))
            {
                // Decode the value being switched on as well as the default branch.
                Instruction switchVal;
                Branch      defaultTarget;
                if (FeedbackHelpers.AssertArgCount(node, 3, Log) &&
                    AssertDecodeInstruction(node.Args[0], valueTags, out switchVal) &&
                    AssertDecodeBranch(node.Args[1], graph, blocks, valueTags, out defaultTarget))
                {
                    // Decode the switch cases.
                    var switchCases = ImmutableList.CreateBuilder <SwitchCase>();
                    foreach (var caseNode in node.Args[2].Args)
                    {
                        if (!FeedbackHelpers.AssertArgCount(caseNode, 2, Log) ||
                            !FeedbackHelpers.AssertIsCall(caseNode.Args[0], Log))
                        {
                            continue;
                        }

                        var constants = ImmutableHashSet.CreateRange <Constant>(
                            caseNode.Args[0].Args
                            .Select(DecodeConstant)
                            .Where(x => x != null));

                        Branch caseTarget;
                        if (AssertDecodeBranch(caseNode.Args[1], graph, blocks, valueTags, out caseTarget))
                        {
                            switchCases.Add(new SwitchCase(constants, caseTarget));
                        }
                    }
                    return(new SwitchFlow(switchVal, switchCases.ToImmutable(), defaultTarget));
                }
                else
                {
                    return(UnreachableFlow.Instance);
                }
            }
            else if (node.Calls(CodeSymbols.Return))
            {
                Instruction retValue;
                if (FeedbackHelpers.AssertArgCount(node, 1, Log) &&
                    AssertDecodeInstruction(node.Args[0], valueTags, out retValue))
                {
                    return(new ReturnFlow(retValue));
                }
                else
                {
                    return(UnreachableFlow.Instance);
                }
            }
            else if (node.Calls(CodeSymbols.Try))
            {
                Instruction tryValue;
                Branch      successBranch;
                Branch      exceptionBranch;
                if (FeedbackHelpers.AssertArgCount(node, 3, Log) &&
                    AssertDecodeInstruction(node.Args[0], valueTags, out tryValue) &&
                    AssertDecodeBranch(node.Args[1], graph, blocks, valueTags, out successBranch) &&
                    AssertDecodeBranch(node.Args[2], graph, blocks, valueTags, out exceptionBranch))
                {
                    return(new TryFlow(tryValue, successBranch, exceptionBranch));
                }
                else
                {
                    return(UnreachableFlow.Instance);
                }
            }
            else if (node.IsIdNamed(EncoderState.unreachableFlowSymbol))
            {
                return(UnreachableFlow.Instance);
            }
            else
            {
                FeedbackHelpers.LogSyntaxError(
                    Log,
                    node,
                    Quotation.QuoteEvenInBold(
                        "unknown type of flow; expected one of ",
                        CodeSymbols.Goto.Name, ", ",
                        CodeSymbols.Switch.Name, ", ",
                        CodeSymbols.Try.Name, ", ",
                        CodeSymbols.Return.Name, " or ",
                        EncoderState.unreachableFlowSymbol.Name, "."));
                return(UnreachableFlow.Instance);
            }
        }
Пример #20
0
        /// <inheritdoc/>
        public override ITypeMember Decode(LNode data, DecoderState state)
        {
            if (data.Calls(accessorSymbol))
            {
                if (!FeedbackHelpers.AssertArgCount(data, 2, state.Log) ||
                    !FeedbackHelpers.AssertIsId(data.Args[1], state.Log))
                {
                    return(null);
                }

                var property = state.DecodeProperty(data.Args[0]);
                if (property == null)
                {
                    return(null);
                }
                else
                {
                    var kindName = data.Args[1].Name.Name;
                    var accessor = property.Accessors.FirstOrDefault(
                        acc => accessorKindEncodings[acc.Kind] == kindName);

                    if (accessor == null)
                    {
                        FeedbackHelpers.LogSyntaxError(
                            state.Log,
                            data.Args[1],
                            Quotation.QuoteEvenInBold(
                                "property ",
                                FeedbackHelpers.Print(data.Args[0]),
                                " does not define a ",
                                kindName,
                                " accessor."));
                    }
                    return(accessor);
                }
            }
            else if (data.Calls(CodeSymbols.Dot))
            {
                // Simple dot indicates a field.
                IType      parentType;
                SimpleName name;
                if (!AssertDecodeTypeAndName(data, state, out parentType, out name))
                {
                    return(null);
                }

                var candidates = state.TypeMemberIndex
                                 .GetAll(parentType, name)
                                 .OfType <IField>()
                                 .ToArray();

                return(CheckSingleCandidate(
                           candidates,
                           data.Args[0],
                           data.Args[1],
                           "field",
                           state));
            }
            else if (data.CallsMin(CodeSymbols.IndexBracks, 1))
            {
                IType      parentType;
                SimpleName name;
                if (!AssertDecodeTypeAndName(data.Args[0], state, out parentType, out name))
                {
                    return(null);
                }

                var indexTypes = data.Args
                                 .Slice(1)
                                 .EagerSelect(state.DecodeType);

                var candidates = state.TypeMemberIndex
                                 .GetAll(parentType, name)
                                 .OfType <IProperty>()
                                 .Where(prop =>
                                        prop.IndexerParameters
                                        .Select(p => p.Type)
                                        .SequenceEqual(indexTypes))
                                 .ToArray();

                return(CheckSingleCandidate(
                           candidates,
                           data.Args[0].Args[0],
                           data,
                           "property",
                           state));
            }
            else if (data.Calls(CodeSymbols.Lambda))
            {
                IType      parentType;
                SimpleName name;
                if (!FeedbackHelpers.AssertArgCount(data, 2, state.Log) ||
                    !FeedbackHelpers.AssertIsCall(data.Args[0], state.Log) ||
                    !AssertDecodeTypeAndName(data.Args[0].Target, state, out parentType, out name))
                {
                    return(null);
                }

                // TODO: implement generic parameter decoding, use generic
                // parameters in resolution process.

                var paramTypes = data.Args[0].Args
                                 .EagerSelect(state.DecodeType);

                var retType = state.DecodeType(data.Args[1]);

                var candidates = state.TypeMemberIndex
                                 .GetAll(parentType, name)
                                 .OfType <IMethod>()
                                 .Where(method =>
                                        method.Parameters
                                        .Select(p => p.Type)
                                        .SequenceEqual(paramTypes) &&
                                        object.Equals(
                                            method.ReturnParameter.Type,
                                            retType))
                                 .ToArray();

                return(CheckSingleCandidate(
                           candidates,
                           data.Args[0].Target.Args[0],
                           data,
                           "method",
                           state));
            }
            else if (data.Calls(CodeSymbols.Of))
            {
                if (!FeedbackHelpers.AssertMinArgCount(data, 1, state.Log))
                {
                    return(null);
                }

                var func = state.DecodeMethod(data.Args[0]);
                var args = data.Args.Slice(1).EagerSelect(state.DecodeType);

                if (func.GenericParameters.Count == args.Count)
                {
                    return(func.MakeGenericMethod(args));
                }
                else
                {
                    state.Log.LogSyntaxError(
                        data,
                        Quotation.QuoteEvenInBold(
                            "generic arity mismatch; expected ",
                            func.GenericParameters.Count.ToString(),
                            " parameters but got ",
                            args.Count.ToString(),
                            "."));
                    return(null);
                }
            }
            else
            {
                state.Log.LogSyntaxError(
                    data,
                    Quotation.QuoteEvenInBold(
                        "cannot interpret ",
                        FeedbackHelpers.Print(data),
                        " as a type member; expected a call to one of ",
                        accessorSymbol.Name, ", ",
                        CodeSymbols.Dot.Name, ", ",
                        CodeSymbols.IndexBracks.Name, ", ",
                        CodeSymbols.Of.Name, " or ",
                        CodeSymbols.Lambda.Name));
                return(null);
            }
        }
Пример #21
0
        public RepoModule()
            : base("repo")
        {
            RegisterContentTrackerGet <dynamic>(
                "/file/{owner}/{repoName}/{token}/{filePath}",
                async(args, user, client) =>
            {
                string repoOwner = args.owner;
                string repoName  = args.repoName;
                string filePath  = args.filePath;

                try
                {
                    return(await client.GetFileContents(
                               repoOwner, repoName, filePath));
                }
                catch (ContentTrackerException)
                {
                    Program.GlobalLog.Log(
                        new LogEntry(
                            Severity.Warning,
                            "malformed request",
                            Quotation.QuoteEvenInBold(
                                "request ",
                                "GET " + Request.Url.ToString(),
                                " tried to read an entity that is not a file.")));
                    return(HttpStatusCode.BadRequest);
                }
            });

            RegisterContentTrackerPut <dynamic>(
                "/file/{owner}/{repoName}/{token}/{filePath}",
                async(args, user, client) =>
            {
                string repoOwner = args.owner;
                string repoName  = args.repoName;
                string filePath  = args.filePath;
                lock (lockDictionary)
                {
                    var lockOwner = GetLockOwner(repoOwner, repoName, filePath);
                    if (lockOwner != user)
                    {
                        Program.GlobalLog.Log(
                            new LogEntry(
                                Severity.Warning,
                                "malformed request",
                                Quotation.QuoteEvenInBold(
                                    "request ",
                                    "PUT " + Request.Url.ToString(),
                                    " tried to update file ",
                                    CreateFileKey(repoOwner, repoName, filePath),
                                    " but didn't hold a lock.")));
                        return(HttpStatusCode.BadRequest);
                    }
                }

                string newFileContents = Request.Body.AsString();

                try
                {
                    bool createdNewFile = await client.SetFileContents(
                        repoOwner,
                        repoName,
                        filePath,
                        newFileContents);

                    UpdateFileChangedTimestamp(repoOwner, repoName, filePath);
                    return(createdNewFile
                        ? HttpStatusCode.Created
                        : HttpStatusCode.OK);
                }
                catch (ContentTrackerException)
                {
                    Program.GlobalLog.Log(
                        new LogEntry(
                            Severity.Warning,
                            "malformed request",
                            Quotation.QuoteEvenInBold(
                                "request ",
                                "PUT " + Request.Url.ToString(),
                                " tried to update an entity that is a file.")));
                    return(HttpStatusCode.BadRequest);
                }
            });

            RegisterContentTrackerGet <dynamic>(
                "/poll-file/{owner}/{repoName}/{token}/{filePath}",
                async(args, user, client) =>
            {
                string repoOwner = args.owner;
                string repoName  = args.repoName;
                string filePath  = args.filePath;

                string timestampStr = Request.Body.AsString();
                var prevTimestamp   = string.IsNullOrWhiteSpace(timestampStr)
                    ? DateTime.MinValue
                    : DateTime.Parse(timestampStr);

                DateTime changeTimestamp;
                bool isModified = HasFileChanged(
                    repoOwner,
                    repoName,
                    filePath,
                    prevTimestamp,
                    out changeTimestamp);

                var response           = new Dictionary <string, object>();
                response["isModified"] = isModified;
                response["lastChange"] = changeTimestamp;
                if (isModified)
                {
                    try
                    {
                        response["contents"] = await client.GetFileContents(
                            repoOwner, repoName, filePath);
                        return(response);
                    }
                    catch (ContentTrackerException)
                    {
                        return(HttpStatusCode.BadRequest);
                    }
                }
                else
                {
                    return(response);
                }
            });

            RegisterContentTrackerGet <dynamic>(
                "/file-names/{owner}/{repoName}/{token}",
                async(args, user, client) =>
            {
                string repoOwner = args.owner;
                string repoName  = args.repoName;

                return(await client.GetFileNames(repoOwner, repoName));
            });

            RegisterContentTrackerPost(
                "/create-repo/{repoName}/{token}",
                (args, user, client) =>
            {
                string repoName = args.repoName;
                return(client.CreateRepository(repoName));
            });

            RegisterUserGet <bool>(
                "/has-lock/{owner}/{repoName}/{token}/{filePath}",
                (args, user) =>
            {
                string repoOwner = args.owner;
                string repoName  = args.repoName;
                string filePath  = args.filePath;

                lock (lockDictionary)
                {
                    var lockOwner = GetLockOwner(repoOwner, repoName, filePath);
                    return(Task.FromResult(
                               lockOwner != null && lockOwner.Token == user.Token));
                }
            });

            RegisterUserPost <bool>(
                "/request-lock/{owner}/{repoName}/{token}/{filePath}",
                (args, user) =>
            {
                string repoOwner = args.owner;
                string repoName  = args.repoName;
                string filePath  = args.filePath;

                lock (lockDictionary)
                {
                    var lockOwner = GetLockOwner(repoOwner, repoName, filePath);
                    if (lockOwner == null || !lockOwner.IsActive)
                    {
                        var key = CreateFileKey(repoOwner, repoName, filePath);
                        Program.GlobalLog.Log(
                            new LogEntry(
                                Severity.Info,
                                "log acquisition",
                                Quotation.QuoteEvenInBold(
                                    "user ",
                                    user.Token,
                                    " acquired a lock on file ",
                                    key,
                                    ".")));
                        lockDictionary[key] = user;
                        return(Task.FromResult(true));
                    }
                    else if (lockOwner.Token == user.Token)
                    {
                        return(Task.FromResult(true));
                    }
                    else
                    {
                        return(Task.FromResult(false));
                    }
                }
            });

            RegisterUserPost <HttpStatusCode>(
                "/relinquish-lock/{owner}/{repoName}/{token}/{filePath}",
                (args, user) =>
            {
                string repoOwner = args.owner;
                string repoName  = args.repoName;
                string filePath  = args.filePath;

                lock (lockDictionary)
                {
                    var lockOwner = GetLockOwner(repoOwner, repoName, filePath);
                    if (lockOwner == null || lockOwner.Token == user.Token)
                    {
                        var key = CreateFileKey(repoOwner, repoName, filePath);
                        lockDictionary.Remove(key);
                        Program.GlobalLog.Log(
                            new LogEntry(
                                Severity.Info,
                                "log relinquished",
                                Quotation.QuoteEvenInBold(
                                    "user ",
                                    user.Token,
                                    " relinquished a lock on file ",
                                    key,
                                    ".")));
                        return(Task.FromResult(HttpStatusCode.OK));
                    }
                    else
                    {
                        return(Task.FromResult(HttpStatusCode.BadRequest));
                    }
                }
            });
        }
Пример #22
0
        /// <summary>
        /// Runs a single expression in the script.
        /// </summary>
        /// <param name="expression">The expression to run.</param>
        public TestStatistics Run(SExpression expression)
        {
            if (expression.IsCallTo("module"))
            {
                var module   = Assembler.AssembleModule(expression, out string moduleId);
                var instance = Wasm.Interpret.ModuleInstance.Instantiate(
                    module,
                    importer,
                    policy: ExecutionPolicy.Create(maxMemorySize: 0x1000),
                    compiler: Compiler);

                moduleInstances.Add(instance);
                if (moduleId != null)
                {
                    moduleInstancesByName[moduleId] = instance;
                }
                if (module.StartFunctionIndex.HasValue)
                {
                    instance.Functions[(int)module.StartFunctionIndex.Value].Invoke(Array.Empty <object>());
                }
                return(TestStatistics.Empty);
            }
            else if (expression.IsCallTo("register"))
            {
                var tail = expression.Tail;
                var name = Assembler.AssembleString(tail[0], Log);
                tail = tail.Skip(1).ToArray();
                var moduleId = Assembler.AssembleLabelOrNull(ref tail);
                if (moduleId == null)
                {
                    importer.RegisterImporter(name, new ModuleExportsImporter(moduleInstances[moduleInstances.Count - 1]));
                }
                else
                {
                    importer.RegisterImporter(name, new ModuleExportsImporter(moduleInstancesByName[moduleId]));
                }
                return(TestStatistics.Empty);
            }
            else if (expression.IsCallTo("invoke") || expression.IsCallTo("get"))
            {
                RunAction(expression);
                return(TestStatistics.SingleSuccess);
            }
            else if (expression.IsCallTo("assert_return"))
            {
                var results  = RunAction(expression.Tail[0]);
                var expected = expression.Tail
                               .Skip(1)
                               .Zip(results, (expr, val) => EvaluateConstExpr(expr, val.GetType()))
                               .ToArray();

                if (expected.Length != results.Count)
                {
                    Log.Log(
                        new LogEntry(
                            Severity.Error,
                            "assertion failed",
                            "action produced result ",
                            string.Join(", ", results),
                            "; expected ",
                            string.Join(", ", expected),
                            ".",
                            Assembler.Highlight(expression)));
                    return(TestStatistics.SingleFailure);
                }

                bool failures = false;
                for (int i = 0; i < expected.Length; i++)
                {
                    if (!object.Equals(results[i], expected[i]))
                    {
                        if (AlmostEquals(results[i], expected[i]))
                        {
                            Log.Log(
                                new LogEntry(
                                    Severity.Warning,
                                    "rounding error",
                                    "action produced result ",
                                    results[i].ToString(),
                                    "; expected ",
                                    expected[i].ToString(),
                                    ".",
                                    Assembler.Highlight(expression)));
                        }
                        else
                        {
                            Log.Log(
                                new LogEntry(
                                    Severity.Error,
                                    "assertion failed",
                                    "action produced result ",
                                    results[i].ToString(),
                                    "; expected ",
                                    expected[i].ToString(),
                                    ".",
                                    Assembler.Highlight(expression)));
                            failures = true;
                        }
                    }
                }
                return(failures ? TestStatistics.SingleFailure : TestStatistics.SingleSuccess);
            }
            else if (expression.IsCallTo("assert_trap") || expression.IsCallTo("assert_exhaustion"))
            {
                var       expected  = Assembler.AssembleString(expression.Tail[1], Log);
                bool      caught    = false;
                Exception exception = null;
                try
                {
                    if (expression.Tail[0].IsCallTo("module"))
                    {
                        Run(expression.Tail[0]);
                    }
                    else
                    {
                        RunAction(expression.Tail[0], false);
                    }
                }
                catch (TrapException ex)
                {
                    caught    = ex.SpecMessage == expected;
                    exception = ex;
                }
                catch (PixieException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    caught    = false;
                    exception = ex;
                }

                if (caught)
                {
                    return(TestStatistics.SingleSuccess);
                }
                else
                {
                    if (exception == null)
                    {
                        Log.Log(
                            new LogEntry(
                                Severity.Error,
                                "assertion failed",
                                "action should have trapped, but didn't.",
                                Assembler.Highlight(expression)));
                    }
                    else
                    {
                        Log.Log(
                            new LogEntry(
                                Severity.Error,
                                "assertion failed",
                                "action trapped as expected, but with an unexpected exception. ",
                                exception.ToString(),
                                Assembler.Highlight(expression)));
                    }
                    return(TestStatistics.SingleFailure);
                }
            }
            else if (expression.IsCallTo("assert_return_canonical_nan"))
            {
                var  results = RunAction(expression.Tail[0]);
                bool isCanonicalNaN;
                if (results.Count != 1)
                {
                    Log.Log(
                        new LogEntry(
                            Severity.Error,
                            "assertion failed",
                            "action produced ",
                            results.Count.ToString(),
                            " results (",
                            string.Join(", ", results),
                            "); expected a single canonical NaN.",
                            Assembler.Highlight(expression)));
                    return(TestStatistics.SingleFailure);
                }
                else if (results[0] is double)
                {
                    var val = Interpret.ValueHelpers.ReinterpretAsInt64((double)results[0]);
                    isCanonicalNaN = val == Interpret.ValueHelpers.ReinterpretAsInt64((double)FloatLiteral.NaN(false)) ||
                                     val == Interpret.ValueHelpers.ReinterpretAsInt64((double)FloatLiteral.NaN(true));
                }
                else if (results[0] is float)
                {
                    var val = Interpret.ValueHelpers.ReinterpretAsInt32((float)results[0]);
                    isCanonicalNaN = val == Interpret.ValueHelpers.ReinterpretAsInt32((float)FloatLiteral.NaN(false)) ||
                                     val == Interpret.ValueHelpers.ReinterpretAsInt32((float)FloatLiteral.NaN(true));
                }
                else
                {
                    isCanonicalNaN = false;
                }
                if (isCanonicalNaN)
                {
                    return(TestStatistics.SingleSuccess);
                }
                else
                {
                    Log.Log(
                        new LogEntry(
                            Severity.Error,
                            "assertion failed",
                            "action produced ",
                            results[0].ToString(),
                            "; expected a single canonical NaN.",
                            Assembler.Highlight(expression)));
                    return(TestStatistics.SingleFailure);
                }
            }
            else if (expression.IsCallTo("assert_return_arithmetic_nan"))
            {
                var  results = RunAction(expression.Tail[0]);
                bool isNaN;
                if (results.Count != 1)
                {
                    Log.Log(
                        new LogEntry(
                            Severity.Error,
                            "assertion failed",
                            "action produced ",
                            results.Count.ToString(),
                            " results (",
                            string.Join(", ", results),
                            "); expected a single NaN.",
                            Assembler.Highlight(expression)));
                    return(TestStatistics.SingleFailure);
                }
                else if (results[0] is double)
                {
                    isNaN = double.IsNaN((double)results[0]);
                }
                else if (results[0] is float)
                {
                    isNaN = float.IsNaN((float)results[0]);
                }
                else
                {
                    isNaN = false;
                }
                if (isNaN)
                {
                    return(TestStatistics.SingleSuccess);
                }
                else
                {
                    Log.Log(
                        new LogEntry(
                            Severity.Error,
                            "assertion failed",
                            "action produced ",
                            results[0].ToString(),
                            "; expected a single NaN.",
                            Assembler.Highlight(expression)));
                    return(TestStatistics.SingleFailure);
                }
            }
            else
            {
                Log.Log(
                    new LogEntry(
                        Severity.Warning,
                        "unknown script command",
                        Quotation.QuoteEvenInBold(
                            "expression ",
                            expression.Head.Span.Text,
                            " was not recognized as a known script command."),
                        Assembler.Highlight(expression)));
                return(TestStatistics.SingleUnknown);
            }
        }