/// <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); } }; }
/// <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); } }
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))); }
/// <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.")); }
/// <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(), ".")); }
/// <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(), ").")); }
/// <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."))); } }
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; } }
/// <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()); }
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]); } }
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); }
/// <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)); }
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>()); } }
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); }
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); }
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); }
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); } }
/// <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); } }
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)); } } }); }
/// <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); } }