public override void VisitInstanceFunctionCallSyntax(InstanceFunctionCallSyntax syntax) { FunctionFlags currentFlags = allowedFlags; this.Visit(syntax.BaseExpression); this.Visit(syntax.Dot); this.Visit(syntax.Name); this.Visit(syntax.OpenParen); allowedFlags = allowedFlags.HasDecoratorFlag() ? FunctionFlags.Default : allowedFlags; this.VisitNodes(syntax.Arguments); this.Visit(syntax.CloseParen); allowedFlags = currentFlags; if (!syntax.Name.IsValid) { // the parser produced an instance function calls with an invalid name // all instance function calls must be bound to a symbol, so let's // bind to a symbol without any errors (there's already a parse error) this.bindings.Add(syntax, new ErrorSymbol()); return; } if (bindings.TryGetValue(syntax.BaseExpression, out var baseSymbol) && baseSymbol is NamespaceSymbol namespaceSymbol) { var functionSymbol = allowedFlags.HasDecoratorFlag() // Decorator functions are only valid when HasDecoratorFlag() is true which means // the instance function call is the top level expression of a DecoratorSyntax node. ? namespaceSymbol.Type.MethodResolver.TryGetSymbol(syntax.Name) ?? namespaceSymbol.Type.DecoratorResolver.TryGetSymbol(syntax.Name) : namespaceSymbol.Type.MethodResolver.TryGetSymbol(syntax.Name); var foundSymbol = SymbolValidator.ResolveNamespaceQualifiedFunction(allowedFlags, functionSymbol, syntax.Name, namespaceSymbol); this.bindings.Add(syntax, foundSymbol); } }
private Symbol LookupGlobalSymbolByName(IdentifierSyntax identifierSyntax, bool isFunctionCall) { // attempt to find name in the built in namespaces. imported namespaces will be present in the declarations list as they create declared symbols. if (this.namespaceResolver.BuiltIns.TryGetValue(identifierSyntax.IdentifierName) is { } namespaceSymbol) { // namespace symbol found return(namespaceSymbol); } // declarations must not have a namespace value, namespaces are used to fully qualify a function access. // There might be instances where a variable declaration for example uses the same name as one of the imported // functions, in this case to differentiate a variable declaration vs a function access we check the namespace value, // the former case must have an empty namespace value whereas the latter will have a namespace value. if (this.declarations.TryGetValue(identifierSyntax.IdentifierName, out var globalSymbol)) { // we found the symbol in the global namespace return(globalSymbol); } // attempt to find function in all imported namespaces var foundSymbols = namespaceResolver.ResolveUnqualifiedFunction(identifierSyntax, includeDecorators: allowedFlags.HasAnyDecoratorFlag()); if (foundSymbols.Count() > 1) { // ambiguous symbol return(new ErrorSymbol(DiagnosticBuilder.ForPosition(identifierSyntax).AmbiguousSymbolReference(identifierSyntax.IdentifierName, namespaceResolver.GetNamespaceNames().ToImmutableSortedSet(StringComparer.Ordinal)))); } var foundSymbol = foundSymbols.FirstOrDefault(); return(isFunctionCall ? SymbolValidator.ResolveUnqualifiedFunction(allowedFlags, foundSymbol, identifierSyntax, namespaceResolver) : SymbolValidator.ResolveUnqualifiedSymbol(foundSymbol, identifierSyntax, namespaceResolver, declarations.Keys)); }
private Symbol LookupSymbolByName(IdentifierSyntax identifierSyntax, bool isFunctionCall) { // attempt to find name in the imported namespaces if (this.namespaces.TryGetValue(identifierSyntax.IdentifierName, out var namespaceSymbol)) { // namespace symbol found return(namespaceSymbol); } // declarations must not have a namespace value, namespaces are used to fully qualify a function access. // There might be instances where a variable declaration for example uses the same name as one of the imported // functions, in this case to differentiate a variable declaration vs a function access we check the namespace value, // the former case must have an empty namespace value whereas the latter will have a namespace value. if (this.declarations.TryGetValue(identifierSyntax.IdentifierName, out var localSymbol)) { // we found the symbol in the local namespace return(localSymbol); } // attempt to find function in all imported namespaces var foundSymbols = this.namespaces .Select(kvp => allowedFlags.HasDecoratorFlag() ? kvp.Value.Type.MethodResolver.TryGetSymbol(identifierSyntax) ?? kvp.Value.Type.DecoratorResolver.TryGetSymbol(identifierSyntax) : kvp.Value.Type.MethodResolver.TryGetSymbol(identifierSyntax)) .Where(symbol => symbol != null) .ToList(); if (foundSymbols.Count > 1) { // ambiguous symbol return(new ErrorSymbol(DiagnosticBuilder.ForPosition(identifierSyntax).AmbiguousSymbolReference(identifierSyntax.IdentifierName, this.namespaces.Keys))); } var foundSymbol = foundSymbols.FirstOrDefault(); return(isFunctionCall ? SymbolValidator.ResolveUnqualifiedFunction(allowedFlags, foundSymbol, identifierSyntax, namespaces.Values) : SymbolValidator.ResolveUnqualifiedSymbol(foundSymbol, identifierSyntax, namespaces.Values, declarations.Keys)); }
public override void VisitInstanceFunctionCallSyntax(InstanceFunctionCallSyntax syntax) { base.VisitInstanceFunctionCallSyntax(syntax); if (!syntax.Name.IsValid) { // the parser produced an instance function calls with an invalid name // all instance function calls must be bound to a symbol, so let's // bind to a symbol without any errors (there's already a parse error) this.bindings.Add(syntax, new ErrorSymbol()); return; } if (bindings.TryGetValue(syntax.BaseExpression, out var baseSymbol) && baseSymbol is NamespaceSymbol namespaceSymbol) { var functionSymbol = namespaceSymbol.Type.MethodResolver.TryGetSymbol(syntax.Name); var foundSymbol = SymbolValidator.ResolveNamespaceQualifiedFunction(allowedFlags, functionSymbol, syntax.Name, namespaceSymbol); this.bindings.Add(syntax, foundSymbol); } }