private IReadOnlyList <KernelCommand> SplitSubmission( KernelCommand originalCommand, string code, CreateChildCommand createCommand) { var commands = new List <KernelCommand>(); var nugetRestoreOnKernels = new HashSet <string>(); var hoistedCommandsIndex = 0; var tree = Parse(code, originalCommand.TargetKernelName); var nodes = tree.GetRoot().ChildNodes.ToArray(); var targetKernelName = originalCommand.TargetKernelName ?? KernelLanguage; var lastKernelUri = originalCommand.KernelUri; KernelNameDirectiveNode lastKernelNameNode = null; foreach (var node in nodes) { switch (node) { case DirectiveNode directiveNode: var parseResult = directiveNode.GetDirectiveParseResult(); if (parseResult.Errors.Any()) { if (directiveNode.IsUnknownActionDirective()) { commands.Add(createCommand(directiveNode, originalCommand, lastKernelNameNode)); } else { commands.Clear(); commands.Add( new AnonymousKernelCommand((kernelCommand, context) => { var message = string.Join(Environment.NewLine, parseResult.Errors .Select(e => e.ToString())); context.Fail(message: message); return(Task.CompletedTask); }, parent: originalCommand)); } break; } var directiveCommand = new DirectiveCommand( parseResult, originalCommand, directiveNode) { TargetKernelName = targetKernelName }; if (directiveNode is KernelNameDirectiveNode kernelNameNode) { targetKernelName = kernelNameNode.KernelName; lastKernelNameNode = kernelNameNode; } if (parseResult.CommandResult.Command.Name == "#r") { var value = parseResult.ValueForArgument <PackageReferenceOrFileInfo>("package"); if (value.Value is FileInfo) { AddHoistedCommand(createCommand(directiveNode, originalCommand, lastKernelNameNode)); } else { directiveCommand.KernelUri = lastKernelUri; directiveCommand.TargetKernelName = targetKernelName; AddHoistedCommand(directiveCommand); nugetRestoreOnKernels.Add(targetKernelName); } } else if (parseResult.CommandResult.Command.Name == "#i") { directiveCommand.KernelUri = lastKernelUri; directiveCommand.TargetKernelName = targetKernelName; AddHoistedCommand(directiveCommand); } else { commands.Add(directiveCommand); if (directiveNode is KernelNameDirectiveNode) { hoistedCommandsIndex = commands.Count; } } break; case LanguageNode languageNode: commands.Add(createCommand(languageNode, originalCommand, lastKernelNameNode)); break; default: throw new ArgumentOutOfRangeException(nameof(node)); } } foreach (var kernelName in nugetRestoreOnKernels) { var kernel = _kernel.FindKernel(kernelName); if (kernel?.SubmissionParser.GetDirectiveParser() is { } parser) { var restore = new DirectiveCommand( parser.Parse("#!nuget-restore"), originalCommand) { KernelUri = kernel.Uri, TargetKernelName = kernelName }; AddHoistedCommand(restore); } } if (NoSplitWasNeeded(out var originalSubmission)) { return(originalSubmission); } foreach (var command in commands) { command.Parent = originalCommand; } return(commands); void AddHoistedCommand(KernelCommand command) { commands.Insert(hoistedCommandsIndex++, command); } bool NoSplitWasNeeded(out IReadOnlyList <KernelCommand> splitSubmission) { if (commands.Count == 0) { splitSubmission = new[] { originalCommand }; return(true); } if (commands.Count == 1) { if (commands[0] is SubmitCode sc) { if (code.Equals(sc.Code, StringComparison.Ordinal)) { splitSubmission = new[] { originalCommand }; return(true); } } } splitSubmission = null; return(false); } }
private void ParseSubmission(PolyglotSubmissionNode rootNode) { var currentLanguage = DefaultLanguage; for (var i = 0; i < _tokens !.Count; i++) { var currentToken = _tokens[i]; switch (currentToken) { case DirectiveToken directiveToken: DirectiveNode directiveNode; if (IsChooseKernelDirective(directiveToken)) { directiveNode = new KernelNameDirectiveNode(directiveToken, _sourceText, rootNode.SyntaxTree); currentLanguage = directiveToken.DirectiveName; } else { directiveNode = new ActionDirectiveNode( directiveToken, _sourceText, currentLanguage, rootNode.SyntaxTree); } if (_tokens.Count > i + 1 && _tokens[i + 1] is TriviaToken triviaNode) { i += 1; directiveNode.Add(triviaNode); } if (_tokens.Count > i + 1 && _tokens[i + 1] is DirectiveArgsToken directiveArgs) { i += 1; directiveNode.Add(directiveArgs); } var directiveName = directiveNode.ChildNodesAndTokens.First().Text; if (IsDefinedInRootKernel(directiveName)) { directiveNode.DirectiveParser = _rootKernelDirectiveParser; } else if (_subkernelDirectiveParsersByLanguageName != null && _subkernelDirectiveParsersByLanguageName.TryGetValue(currentLanguage, out var getParser)) { directiveNode.DirectiveParser = getParser(); } else { directiveNode.DirectiveParser = _rootKernelDirectiveParser; } if (directiveToken.Text == "#r") { var parseResult = directiveNode.GetDirectiveParseResult(); if (parseResult.Errors.Count == 0) { var value = parseResult.CommandResult.GetArgumentValueOrDefault <PackageReferenceOrFileInfo>("package"); if (value?.Value is FileInfo) { // #r <file> is treated as a LanguageNode to be handled by the compiler AppendAsLanguageNode(directiveNode); break; } } } rootNode.Add(directiveNode); break; case LanguageToken languageToken: AppendAsLanguageNode(languageToken); break; case TriviaToken trivia: rootNode.Add(trivia); break; default: throw new ArgumentOutOfRangeException(nameof(currentToken)); } } void AppendAsLanguageNode(SyntaxNodeOrToken nodeOrToken) { if (rootNode.ChildNodes.LastOrDefault() is LanguageNode previousLanguageNode && previousLanguageNode.Language == currentLanguage) { previousLanguageNode.Add(nodeOrToken); }