private IList <ICompileError> DiagnoseSourceFile(SourceFile sourceFile) { // NOTE: For now we just parse and check syntax var result = new List <ICompileError>(); // Create a dependency system var system = new DependencySystem("../stdlib"); var symTab = system.SymbolTable; // Register for errors system.CompileError += (s, err) => result.Add(err); // From now on we do semantic checking // If at any phase we encounter errors, simply terminate // Parse the ast var ast = system.ParseAst(sourceFile); if (result.Count > 0) { return(result); } // Do symbol resolution SymbolResolution.Resolve(symTab, ast); if (result.Count > 0) { return(result); } // Finally type-check system.TypeCheck(ast); return(result); }
private LocationOrLocationLinks FindDefinition(SourceFile sourceFile, Text.Position position) { // TODO: A bit redundant to parse again, we need to store ASTs too // We could do that in the dependency system or something // Also we are instantiating multiple dependency systems // Create a dependency system var system = new DependencySystem("../stdlib"); var symTab = system.SymbolTable; var ast = system.ParseAst(sourceFile); SymbolResolution.Resolve(symTab, ast); var node = FindByPosition.Find(ast, position); // NOTE: We wouldn't need the check here, but ReferredSymbol throws... // We should avoid that if (node is Expression.Identifier ident) { var symbol = symTab.ReferredSymbol(ident); if (symbol.Definition != null && symbol.Definition.ParseTreeNode != null) { var treeNode = symbol.Definition.ParseTreeNode; return(new LocationOrLocationLinks( new LocationOrLocationLink(Translator.TranslateLocation(treeNode.Span)))); } } return(new LocationOrLocationLinks()); }
public override Value Execute(VirtualMachine vm, IEnumerable <Value> args) { var fileName = GetFileName(vm, args); // TODO: Skip if already imported? // This could be part of the system so it could just return the proper scope to wrap // Or the intrinsic itself could cache already loaded in values // Load in file // TODO: syntax status? var ast = System.LoadAst(fileName); // We need to create a struct type that contains the constants in the file // First we define the new scope System.SymbolTable.PushScope(Semantic.ScopeKind.Struct); var structScope = System.SymbolTable.CurrentScope; // Define things // TODO: compile status? SymbolResolution.Resolve(System.SymbolTable, ast); // Pop scope System.SymbolTable.PopScope(); // Create the new type var moduleType = new Type.Struct( structScope, new Syntax.Token(new Text.Span(), Syntax.TokenType.KwStruct, "struct"), new Dictionary <string, Type.Struct.Field>()); // Wrap it, return it return(new Value.User(moduleType)); }
/// <summary> /// Adds a TargetInstruction attribute to each intrinsic callable that doesn't have one, /// unless the automatically determined target instruction name conflicts with another target instruction name. /// The automatically determined name of the target instruction is the lower case version of the unqualified callable name. /// Type constructors and generic callables are left unchanged. /// </summary> /// <returns>Returns true if all missing attributes have been successfully added and false if some attributes could not be added.</returns> /// <exception cref="InvalidOperationException">All intrinsic callables need to have exactly one body specialization.</exception> public static bool TryAddMissingTargetInstructionAttributes(QsCompilation compilation, out QsCompilation transformed) { var success = true; List <string> instructionNames = new List <string>(); // populate the intruction names with all manually specified ones first foreach (var callable in compilation.Namespaces.Callables()) { var manuallySpecified = SymbolResolution.TryGetTargetInstructionName(callable.Attributes); if (manuallySpecified.IsValue) { instructionNames.Add(manuallySpecified.Item); } } QsCallable AddAttribute(QsCallable callable) { if (callable.Specializations.Length != 1) { throw new InvalidOperationException("intrinsic callable needs to have exactly one body specialization"); } var instructionName = callable.FullName.Name.ToLowerInvariant(); if (instructionNames.Contains(instructionName)) { success = false; return(callable); } return(callable.AddAttribute( AttributeUtils.BuildAttribute( BuiltIn.TargetInstruction.FullName, AttributeUtils.StringArgument(instructionName)))); } QsNamespace AddAttributes(QsNamespace ns) { var elements = ns.Elements.Select(element => element is QsNamespaceElement.QsCallable callable && callable.Item.IsIntrinsic && callable.Item.Signature.TypeParameters.Length == 0 && !NameDecorator.IsAutoGeneratedName(callable.Item.FullName) && !callable.Item.Kind.IsTypeConstructor && !callable.Item.Attributes.Any(BuiltIn.DefinesTargetInstruction) ? QsNamespaceElement.NewQsCallable(AddAttribute(callable.Item)) : element); return(new QsNamespace(ns.Name, elements.ToImmutableArray(), ns.Documentation)); } var namespaces = compilation.Namespaces.Select(AddAttributes).ToImmutableArray(); transformed = new QsCompilation(namespaces, compilation.EntryPoints); return(success); }
// TODO: Hack public void ResetSymbolTable() { SymbolTable = new SymbolTable(this); SymbolTable.DefineBuiltinPrimitives(); // Load prelude { // TODO: Syntax status? var preludeAst = LoadAst("prelude.yk"); // TODO: compile status? SymbolResolution.Resolve(SymbolTable, preludeAst); } SymbolTable.DefineBuiltinIntrinsics(); }
private Expression MakePathExpression(params string[] pieces) { Debug.Assert(pieces.Length > 0); Expression result = new Expression.Identifier(null, pieces[0]); foreach (var piece in pieces.Skip(1)) { result = new Expression.DotPath(null, result, piece); } // TODO: compile status? SymbolResolution.Resolve(SymbolTable, result); return(result); }
/// <summary> /// Constructs a documented item. /// </summary> /// <param name="nsName">The name of the namespace that defines this item</param> /// <param name="itemName">The name of the item itself</param> /// <param name="kind">The item's kind: operation, function, or UDT</param> /// <param name="documentation">The source documentation for the item</param> internal DocItem(string nsName, string itemName, string kind, ImmutableArray <string> documentation, IEnumerable <QsDeclarationAttribute> attributes) { namespaceName = nsName; name = itemName; uid = (namespaceName + "." + name).ToLowerInvariant(); itemType = kind; var res = SymbolResolution.TryFindRedirect(attributes); deprecated = res.IsValue; replacement = res.ValueOr(""); comments = new DocComment(documentation, name, deprecated, replacement); }
public Declaration.File Elim(Declaration.File file) { var collector = new CollectDependencies(System); collector.Collect(file); dependencyMap = collector.DependencyMap; var result = (Declaration.File)Transform(file); System.ResetSymbolTable(); // TODO: note below // NOTE: Do we need to care about compile status here? SymbolResolution.Resolve(System.SymbolTable, result); //Console.WriteLine(result.Dump()); return(result); }
public DependencySystem(string standardLibraryPath) { StandardLibraryPath = standardLibraryPath; SymbolTable = new SymbolTable(this); TypeTranslator = new TypeTranslator(this); codegen = new Codegen(this); typeEval = new TypeEval(this); typeCheck = new TypeCheck(this); SymbolTable.DefineBuiltinPrimitives(); // Load prelude { // TODO: syntax status? var preludeAst = LoadAst("prelude.yk"); // TODO: compile status? SymbolResolution.Resolve(SymbolTable, preludeAst); } SymbolTable.DefineBuiltinIntrinsics(); CompileError += OnCompileError; }
/// <summary> /// Returns a sequence of suggestions on how deprecated syntax can be updated based on the generated diagnostics, /// and given the file for which those diagnostics were generated. /// Returns an empty enumerable if any of the given arguments is null. /// </summary> internal static IEnumerable <(string, WorkspaceEdit)> SuggestionsForDeprecatedSyntax (this FileContentManager file, IEnumerable <Diagnostic> diagnostics) { if (file == null || diagnostics == null) { return(Enumerable.Empty <(string, WorkspaceEdit)>()); } var deprecatedUnitTypes = diagnostics.Where(DiagnosticTools.WarningType(WarningCode.DeprecatedUnitType)); var deprecatedNOToperators = diagnostics.Where(DiagnosticTools.WarningType(WarningCode.DeprecatedNOToperator)); var deprecatedANDoperators = diagnostics.Where(DiagnosticTools.WarningType(WarningCode.DeprecatedANDoperator)); var deprecatedORoperators = diagnostics.Where(DiagnosticTools.WarningType(WarningCode.DeprecatedORoperator)); var deprecatedOpCharacteristics = diagnostics.Where(DiagnosticTools.WarningType(WarningCode.DeprecatedOpCharacteristics)); (string, WorkspaceEdit) ReplaceWith(string text, LSP.Range range) { bool NeedsWs(Char ch) => Char.IsLetterOrDigit(ch) || ch == '_'; if (range?.Start != null && range.End != null) { var beforeEdit = file.GetLine(range.Start.Line).Text.Substring(0, range.Start.Character); var afterEdit = file.GetLine(range.End.Line).Text.Substring(range.End.Character); if (beforeEdit.Any() && NeedsWs(beforeEdit.Last())) { text = $" {text}"; } if (afterEdit.Any() && NeedsWs(afterEdit.First())) { text = $"{text} "; } } var edit = new TextEdit { Range = range?.Copy(), NewText = text }; return($"Replace with \"{text.Trim()}\".", file.GetWorkspaceEdit(edit)); } // update deprecated keywords and operators var suggestionsForUnitType = deprecatedUnitTypes.Select(d => ReplaceWith(Keywords.qsUnit.id, d.Range)); var suggestionsForNOT = deprecatedNOToperators.Select(d => ReplaceWith(Keywords.qsNOTop.op, d.Range)); var suggestionsForAND = deprecatedANDoperators.Select(d => ReplaceWith(Keywords.qsANDop.op, d.Range)); var suggestionsForOR = deprecatedORoperators.Select(d => ReplaceWith(Keywords.qsORop.op, d.Range)); // update deprecated operation characteristics syntax var typeToQs = new ExpressionTypeToQs(new ExpressionToQs()); string CharacteristicsAnnotation(Characteristics c) { typeToQs.onCharacteristicsExpression(SymbolResolution.ResolveCharacteristics(c)); return($"{Keywords.qsCharacteristics.id} {typeToQs.Output}"); } var suggestionsForOpCharacteristics = deprecatedOpCharacteristics.SelectMany(d => { // TODO: TryGetQsSymbolInfo currently only returns information about the inner most leafs rather than all types etc. // Once it returns indeed all types in the fragment, the following code block should be replaced by the commented out code below. var fragment = file.TryGetFragmentAt(d.Range.Start, out var _); IEnumerable <Characteristics> GetCharacteristics(QsTuple <Tuple <QsSymbol, QsType> > argTuple) => SyntaxGenerator.ExtractItems(argTuple).SelectMany(item => item.Item2.ExtractCharacteristics()).Distinct(); var characteristicsInFragment = fragment?.Kind is QsFragmentKind.FunctionDeclaration function ? GetCharacteristics(function.Item2.Argument) : fragment?.Kind is QsFragmentKind.OperationDeclaration operation ? GetCharacteristics(operation.Item2.Argument) : fragment?.Kind is QsFragmentKind.TypeDefinition type ? GetCharacteristics(type.Item2) : Enumerable.Empty <Characteristics>(); //var symbolInfo = file.TryGetQsSymbolInfo(d.Range.Start, false, out var fragment); //var characteristicsInFragment = (symbolInfo?.UsedTypes ?? Enumerable.Empty<QsType>()) // .SelectMany(t => t.ExtractCharacteristics()).Distinct(); var fragmentStart = fragment?.GetRange()?.Start; return(characteristicsInFragment .Where(c => c.Range.IsValue && DiagnosticTools.GetAbsoluteRange(fragmentStart, c.Range.Item).Overlaps(d.Range)) .Select(c => ReplaceWith(CharacteristicsAnnotation(c), d.Range))); }); return(suggestionsForOpCharacteristics.ToArray() .Concat(suggestionsForUnitType) .Concat(suggestionsForNOT) .Concat(suggestionsForAND) .Concat(suggestionsForOR)); }