-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(binder): add new simplified binder
- Loading branch information
Showing
12 changed files
with
640 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using System.Text; | ||
using Panther.CodeAnalysis.Syntax; | ||
using Panther.CodeAnalysis.Text; | ||
|
||
namespace Panther.CodeAnalysis.Binder; | ||
|
||
public class Binder : SyntaxVisitor | ||
{ | ||
private readonly DiagnosticBag _diagnostics; | ||
private Symbol _symbolTable; | ||
|
||
private Binder(Symbol symbolTable, DiagnosticBag diagnostics) | ||
{ | ||
_diagnostics = diagnostics; | ||
_symbolTable = symbolTable; | ||
} | ||
|
||
public static (ImmutableArray<Diagnostic> diagnostics, Symbol symbolTable) Bind( | ||
ImmutableArray<SyntaxTree> syntaxTrees | ||
) => Bind(Symbol.NewRoot(), syntaxTrees); | ||
|
||
public static (ImmutableArray<Diagnostic> diagnostics, Symbol symbolTable) Bind( | ||
Symbol symbolTable, | ||
ImmutableArray<SyntaxTree> syntaxTrees | ||
) | ||
{ | ||
var diagnostics = new DiagnosticBag(); | ||
|
||
foreach (var tree in syntaxTrees) | ||
{ | ||
var binder = new Binder(symbolTable, diagnostics); | ||
binder.Visit(tree.Root); | ||
} | ||
|
||
return (diagnostics.ToImmutableArray(), symbolTable); | ||
} | ||
|
||
protected override void DefaultVisit(SyntaxNode node) | ||
{ | ||
foreach ( | ||
var child in node.GetChildren().Where(child => child.Kind > SyntaxKind.ExpressionMarker) | ||
) | ||
Visit(child); | ||
} | ||
|
||
private void VisitContainer(SyntaxNode node, SymbolFlags symbolFlags, SyntaxToken identifier) | ||
{ | ||
VisitContainer(node, symbolFlags, identifier.Text, identifier.Location); | ||
} | ||
|
||
private void VisitContainer( | ||
SyntaxNode node, | ||
SymbolFlags symbolFlags, | ||
string name, | ||
TextLocation location | ||
) | ||
{ | ||
var (scope, existing) = _symbolTable.DeclareSymbol(name, symbolFlags, location); | ||
if (existing) | ||
{ | ||
_diagnostics.ReportDuplicateSymbol(name, scope.Location, location); | ||
} | ||
|
||
var current = _symbolTable; | ||
|
||
_symbolTable = scope; | ||
|
||
this.DefaultVisit(node); | ||
|
||
_symbolTable = current; | ||
} | ||
|
||
private void DeclareSymbol(SyntaxToken identifier, SymbolFlags symbolFlags) | ||
{ | ||
var name = identifier.Text; | ||
var location = identifier.Location; | ||
var existing = _symbolTable.Lookup(name); | ||
if (existing is not null) | ||
{ | ||
_diagnostics.ReportDuplicateSymbol(name, existing.Location, location); | ||
} | ||
|
||
_symbolTable.DeclareSymbol(name, symbolFlags, location); | ||
} | ||
|
||
public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) | ||
{ | ||
VisitContainer(node, SymbolFlags.Namespace, node.Name.ToText(), node.Name.Location); | ||
} | ||
|
||
public override void VisitClassDeclaration(ClassDeclarationSyntax node) | ||
{ | ||
VisitContainer(node, SymbolFlags.Class, node.Identifier); | ||
} | ||
|
||
public override void VisitObjectDeclaration(ObjectDeclarationSyntax node) | ||
{ | ||
VisitContainer(node, SymbolFlags.Object, node.Identifier); | ||
} | ||
|
||
public override void VisitFunctionDeclaration(FunctionDeclarationSyntax node) | ||
{ | ||
VisitContainer(node, SymbolFlags.Method, node.Identifier); | ||
} | ||
|
||
public override void VisitParameter(ParameterSyntax node) | ||
{ | ||
var flags = _symbolTable.Flags.HasFlag(SymbolFlags.Class) | ||
? SymbolFlags.Field | ||
: SymbolFlags.Parameter; | ||
|
||
DeclareSymbol(node.Identifier, flags); | ||
} | ||
|
||
public override void VisitVariableDeclarationStatement(VariableDeclarationStatementSyntax node) | ||
{ | ||
var flags = | ||
_symbolTable.Flags.HasFlag(SymbolFlags.Class) | ||
|| _symbolTable.Flags.HasFlag(SymbolFlags.Object) | ||
? SymbolFlags.Field | ||
: SymbolFlags.Local; | ||
|
||
// TODO: need a way to deal with block scope for variables (or maybe we just don't have block scope for now) | ||
DeclareSymbol(node.IdentifierToken, flags); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using Panther.CodeAnalysis.Text; | ||
|
||
namespace Panther.CodeAnalysis.Binder; | ||
|
||
public class Symbol(string name, SymbolFlags flags, TextLocation location, Symbol? parent) | ||
: IEnumerable<Symbol> | ||
{ | ||
private Dictionary<string, Symbol>? _symbols; | ||
private List<Symbol>? _symbolList; | ||
|
||
public static Symbol NewRoot() => new("", SymbolFlags.None, TextLocation.None, null); | ||
|
||
public string Name => name; | ||
public SymbolFlags Flags => flags; | ||
public TextLocation Location => location; | ||
public Symbol? Parent => parent; | ||
|
||
public string FullName | ||
{ | ||
get | ||
{ | ||
var parentName = Parent?.FullName; | ||
return string.IsNullOrEmpty(parentName) ? Name : $"{parentName}.{Name}"; | ||
} | ||
} | ||
|
||
|
||
public (Symbol, bool existing) DeclareClass(string name, TextLocation location) => | ||
DeclareSymbol(name, SymbolFlags.Class, location); | ||
|
||
public (Symbol, bool existing) DeclareField(string name, TextLocation location) => | ||
DeclareSymbol(name, SymbolFlags.Field, location); | ||
|
||
public (Symbol, bool existing) DeclareMethod(string name, TextLocation location) => | ||
DeclareSymbol(name, SymbolFlags.Method, location); | ||
|
||
public (Symbol, bool existing) DeclareSymbol(string name, SymbolFlags flags, TextLocation location) | ||
{ | ||
_symbols ??= new(); | ||
_symbolList ??= new(); | ||
var symbol = new Symbol(name, flags, location, this); | ||
var existing = !_symbols.TryAdd(name, symbol); | ||
|
||
if(!existing) _symbolList.Add(symbol); | ||
|
||
return (existing ? _symbols[name] : symbol, existing); | ||
} | ||
|
||
public Symbol? Lookup(string name, bool includeParents = true) => | ||
_symbols?.GetValueOrDefault(name) ?? this.Parent?.Lookup(name, includeParents); | ||
|
||
public IEnumerator<Symbol> GetEnumerator() | ||
{ | ||
if(_symbolList == null) | ||
yield break; | ||
|
||
foreach (var symbol in _symbolList) | ||
yield return symbol; | ||
} | ||
|
||
IEnumerator IEnumerable.GetEnumerator() | ||
{ | ||
return GetEnumerator(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System; | ||
|
||
namespace Panther.CodeAnalysis.Binder; | ||
|
||
[Flags] | ||
public enum SymbolFlags | ||
{ | ||
None = 0, | ||
|
||
// Symbol type | ||
Namespace = 1, | ||
Object = 1 << 1, | ||
Class = 1 << 2, | ||
Method = 1 << 3, | ||
Field = 1 << 4, | ||
Property = 1 << 5, | ||
Parameter = 1 << 6, | ||
Local = 1 << 7, | ||
|
||
// Symbol Access | ||
Private = None, // may not use this but should eventually be the default access level | ||
Protected = 1 << 8, | ||
Public = 1 << 9, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.