public override void Visit(BreakExpressionNode node) { var kw = node.BreakKeywordToken; if (!kw.IsMissing) { var func = _scope.Function !; if (func.GetLoop() is PrimaryExpressionNode loop) { var block = loop switch { ForExpressionNode f => f.Body, WhileExpressionNode w => w.Body, _ => throw DebugAssert.Unreachable(), }; node.SetAnnotation("Target", loop); node.SetAnnotation("Uses", func.GetUses(func.GetDepth(block))); } else { Error(node, SyntaxDiagnosticKind.InvalidLoopTarget, kw.Location, "No enclosing 'while' or 'for' expression for this 'break' expression"); } } base.Visit(node); }
static FlareTestEnvironment() { var os = "unix"; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { os = "windows"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { os = "darwin"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD)) { os = "freebsd"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { os = "linux"; } var(arch, bits) = RuntimeInformation.ProcessArchitecture switch { Architecture.X86 => ("x86", "32"), Architecture.X64 => ("x86", "64"), Architecture.Arm => ("arm", "32"), Architecture.Arm64 => ("arm", "64"), _ => throw DebugAssert.Unreachable(), }; Symbols = ImmutableHashSet.Create(os, $"{os}-{arch}", $"{os}-{bits}", $"{os}-{arch}-{bits}", arch, $"{arch}-{bits}", bits); }
public override IEnumerable <(SyntaxNode, SyntaxDiagnostic)> Run(NamedDeclarationNode node) { if (node.VisibilityKeywordToken?.Kind != SyntaxTokenKind.PubKeyword) { yield break; } var type = node switch { ConstantDeclarationNode _ => "constant", FunctionDeclarationNode _ => "function", ExternalDeclarationNode _ => "function", _ => throw DebugAssert.Unreachable(), }; var ident = node.NameToken; if (ident.IsMissing) { yield break; } var diag = CheckDocAttribute(node.Attributes, ident.Location, $"Public {type} {ident} is undocumented"); if (diag != null) { yield return(node, diag); } }
/// <summary> /// Consumes a symbol from oldSymbols, and puts it into destination and/or tails of oldSymbols. Handles overlapping with newSymbols. /// The head of a symbol is the part from start of the *old* symbol till the start of the *new* one. /// The tail of the symbol is the part from the end of the *new* symbol till the end of the *old*. /// This function copies over the head to the destination and adds a tail to the tail set (of course /// when it makes sense). /// </summary> /// <param name="newSymbols">Provider of new symbols.</param> /// <param name="destination">Destination container.</param> /// <param name="oldSymbols">OldSymbolsProvider, symbols provider.</param> /// <param name="createdSymbols">Container with the symbols that got created during merging.</param> /// <param name="deletedSymbols">Container with the symbols that got got replaced/deleted during merging.</param> private void AddSymbolWithHashing(OldSymbolProvider oldSymbols, ISymbolProvider newSymbols, ICollection <Symbol> destination, ICollection <Symbol> createdSymbols, ICollection <Symbol> deletedSymbols) { var consumedSymbolType = oldSymbols.CurrentType; var symbolToAdd = oldSymbols.Consume(); //If there is no symbol to potentially overlap just copy the orignal one if (newSymbols.Empty) { destination.Add(symbolToAdd); return; } if (consumedSymbolType == OldSymbolProvider.SymbolType.Original) { deletedSymbols.Add(symbolToAdd); } //If the symbol to add starts before the new one, add its head to the destination. if (symbolToAdd.Start < newSymbols.Current.Start) { Symbol symbolHead; symbolToAdd.TryGetRightTrimmed(newSymbols.Current.Start, out symbolHead); //If there are symbols on the tail list, check if the trimming would produce the same interval. //If so, we skip the current addition. We do so, because in such case we want to preserve the top (most inner-one) former symbol. //We need, however, to process the possible remainder, a new tail might be generated. Symbol trimmedTail; if (!oldSymbols.HasNextTail || !oldSymbols.NextTail.TryGetRightTrimmed(newSymbols.Current.Start, out trimmedTail) || comparer.Compare(symbolHead, trimmedTail) != 0) { destination.Add(symbolHead); createdSymbols.Add(symbolHead); } } if (newSymbols.Current.Length == 0 && symbolToAdd.Start == newSymbols.Current.Start) { destination.Add(symbolToAdd); return; } //if there is something behind it add it to the new symbols list if (symbolToAdd.End > newSymbols.Current.End) { Symbol symbolTail; symbolToAdd.TryGetLeftTrimmed(newSymbols.Current.End, out symbolTail); oldSymbols.AddTail(symbolTail); #if DEBUG DebugAssert.AssertFalse( newSymbols.Current.Overlaps(symbolTail), "New symbol overlaps with created tail! Old and new symbols should not overlap." ); #endif return; } //There is one another case. Where the overlapping candidate completely overshadows the symbol. //Don't do anything, the overshadowed symbol got deleted anyways and no new symbol gets created. }
public override void ToString(IndentedTextWriter writer) { writer.Write(Value switch { null => "nil", bool b => b ? "true" : "false", string a => $":{a}", BigInteger i => i.ToString(), double d => d.ToString(), ReadOnlyMemory <byte> s => $"\"{Encoding.UTF8.GetString(s.Span)}\"", _ => throw DebugAssert.Unreachable(), });
public override TreeReference Visit(LogicalExpressionNode node, TreeReference state) { var loc = node.OperatorToken.Location; var left = Visit(node.LeftOperand); var right = Visit(node.RightOperand); return(node.OperatorToken.Kind switch { SyntaxTokenKind.AndKeyword => new TreeLogicalAndNode(_context, loc, left, right), SyntaxTokenKind.OrKeyword => new TreeLogicalOrNode(_context, loc, left, right), _ => throw DebugAssert.Unreachable(), });
public override string ToString() { var value = Value switch { null => "nil", bool b => b ? "true" : "false", string a => $":{a}", BigInteger i => i.ToString(), double d => d.ToString(), ReadOnlyMemory <byte> s => $"\"{Encoding.UTF8.GetString(s.Span)}\"", _ => throw DebugAssert.Unreachable(), }; return($"{Name} = {value}"); }
public override void ToString(IndentedTextWriter writer) { writer.Write("("); Left.ToString(writer); writer.Write(" {0} ", Operator switch { TreeRelationalOperator.Equal => "==", TreeRelationalOperator.NotEqual => "!=", TreeRelationalOperator.LessThan => "<", TreeRelationalOperator.LessThanOrEqual => "<=", TreeRelationalOperator.GreaterThan => ">", TreeRelationalOperator.GreaterThanOrEqual => ">=", _ => throw DebugAssert.Unreachable(), });
Project(string path) { ProjectDirectory = new DirectoryInfo(Path.GetDirectoryName(path) !); DependencyDirectory = new DirectoryInfo(Path.Combine(ProjectDirectory.FullName, "dep")); SourceDirectory = new DirectoryInfo(Path.Combine(ProjectDirectory.FullName, "src")); BuildDirectory = new DirectoryInfo(Path.Combine(ProjectDirectory.FullName, "bin")); // TODO: make this parsing more robust in general, and add error reporting. var table = Toml.ReadFile(path); var project = (TomlTable)table.Get("project"); Type = (ProjectType)Enum.Parse(typeof(ProjectType), project.Get <string>("type"), true); Name = project.Get <string>("name"); MainModule = new FileInfo(Path.Combine(SourceDirectory.FullName, Path.ChangeExtension(Name, StandardModuleLoader.ModuleFileNameExtension) !)); ExecutableFileName = table.TryGetValue("executable")?.Get <string>(); Version = SemanticVersion.Parse(project.Get <string>("version")); License = project.TryGetValue("license")?.Get <string>(); Description = project.TryGetValue("description")?.Get <string>(); ProjectUri = project.TryGetValue("url") is TomlObject o1 ? new Uri(o1.Get <string>()) : null; DocumentationUri = project.TryGetValue("url-doc") is TomlObject o2 ? new Uri(o2.Get <string>()) : null; SourceUri = project.TryGetValue("url-src") is TomlObject o3 ? new Uri(o3.Get <string>()) : null; var cfg = new SyntaxLintConfiguration(); if (table.TryGetValue("lints") is TomlTable lints) { foreach (var kvp in lints) { cfg = cfg.Set(kvp.Key, kvp.Value.Get <string>().ToLowerInvariant() switch { LanguageLinter.NoneSeverityName => (SyntaxDiagnosticSeverity?)null, LanguageLinter.SuggestionSeverityName => SyntaxDiagnosticSeverity.Suggestion, LanguageLinter.WarninngSeverityName => SyntaxDiagnosticSeverity.Warning, LanguageLinter.ErrorSeverityName => SyntaxDiagnosticSeverity.Error, _ => throw DebugAssert.Unreachable(), });
internal Module(ModuleLoader loader, ModulePath path, ProgramNode node) : base(node.Attributes) { Loader = loader; Path = path; var decls = ImmutableArray <Declaration> .Empty; foreach (var decl in node.Declarations) { if (decl is UseDeclarationNode) { continue; } decls = decls.Add(decl switch { ConstantDeclarationNode c => (Declaration) new Constant(this, c), FunctionDeclarationNode f => new Function(this, f), ExternalDeclarationNode e => new External(this, e), TestDeclarationNode t => new Test(this, t), _ => throw DebugAssert.Unreachable(), });
public FlareTestResult Run() { var syms = FlareTestEnvironment.Symbols; foreach (var filter in Filters) { var ok = filter.Kind switch { FlareTestFilterKind.IfSet => syms.Contains(filter.Value), FlareTestFilterKind.IfUnset => !syms.Contains(filter.Value), _ => throw DebugAssert.Unreachable(), }; if (!ok) { return(new FlareTestResult()); } } var vars = new Dictionary <string, string>(); foreach (var elem in Environment.GetEnvironmentVariables()) { var(key, value) = (DictionaryEntry)elem !; vars.Add((string)key, (string)value !); } // Note that we might need to overwrite existing variables here. foreach (var(key, value) in Variables) { vars[key] = value; } var stdout = new StringBuilder(); var stderr = new StringBuilder();
(SourceLocation, SyntaxTokenKind) LexOperator(SourceLocation location) { var c1 = ((Rune)MoveNext() !).Value; var r2 = PeekNext(); var c2 = r2?.Value; // Handle most of the special operators first, where the runes can't possibly be // part of a longer custom operator. if (c1 == '!') { if (c2 == '=') { ConsumeNext(); } else { Error(SyntaxDiagnosticKind.IncompleteOperator, _location, $"Expected '=', but found {(r2 != null ? $"'{r2}'" : "end of input")}"); } return(location, SyntaxTokenKind.ExclamationEquals); } if (c1 == '<' && c2 == '=') { ConsumeNext(); return(location, SyntaxTokenKind.OpenAngleEquals); } if (c1 == '=') { if (c2 == '=') { ConsumeNext(); return(location, SyntaxTokenKind.EqualsEquals); } else if (c2 == '>') { ConsumeNext(); return(location, SyntaxTokenKind.EqualsCloseAngle); } return(location, SyntaxTokenKind.Equals); } if (c1 == '>' && c2 == '=') { ConsumeNext(); return(location, SyntaxTokenKind.OpenAngleEquals); } var parts = 1; // Lex the full operator. while (PeekNext() is Rune cur) { switch (cur.Value) { case '%': case '&': case '*': case '+': case '-': case '/': case '<': case '>': case '^': case '|': case '~': ConsumeNext(); parts++; continue; default: break; } break; } // Handle remaining special operators. switch (parts) { case 1: if (c1 == '<') { return(location, SyntaxTokenKind.OpenAngle); } if (c1 == '>') { return(location, SyntaxTokenKind.CloseAngle); } break; case 2: if (c1 == '-' && c2 == '>') { return(location, SyntaxTokenKind.MinusCloseAngle); } if (c1 == '<' && c2 == '-') { return(location, SyntaxTokenKind.OpenAngleMinus); } break; } SyntaxTokenKind kind; // At this point, it's definitely a custom operator, so determine the category. switch (c1) { case '%': case '*': case '/': kind = SyntaxTokenKind.MultiplicativeOperator; break; case '+': case '-': case '~': kind = SyntaxTokenKind.AdditiveOperator; break; case '<': case '>': kind = SyntaxTokenKind.ShiftOperator; break; case '&': case '^': case '|': kind = SyntaxTokenKind.BitwiseOperator; break; default: throw DebugAssert.Unreachable(); } return(location, kind); }
static BigInteger CreateInteger(string value) { var radix = 10; if (value.StartsWith("0B") || value.StartsWith("0b")) { radix = 2; } else if (value.StartsWith("0O") || value.StartsWith("0o")) { radix = 8; } else if (value.StartsWith("0X") || value.StartsWith("0x")) { radix = 16; } var str = value.AsSpan(); // Strip base prefix. if (radix != 10) { str = str.Slice(2); } // Avoid BigInteger allocations/calculations for some very common cases. if (str.Trim('0').IsEmpty) { return(BigInteger.Zero); } if (str.TrimStart('0').SequenceEqual("1")) { return(BigInteger.One); } var result = BigInteger.Zero; foreach (var c in str) { int digit; if (c - '0' <= 9) { digit = c - '0'; } else if (c - 'A' <= 'Z' - 'A') { digit = c - 'A' + 10; } else if (c - 'a' <= 'z' - 'a') { digit = c - 'a' + 10; } else { throw DebugAssert.Unreachable(); } result = result * radix + digit; } return(result); }
protected override TreePattern DefaultVisit(SyntaxNode node, TreePattern state) { throw DebugAssert.Unreachable(); }