Home > Uncategorized > Adventures in Roslyn: Using pointer syntax as a shorthand for IEnumerable

Adventures in Roslyn: Using pointer syntax as a shorthand for IEnumerable

Another quickie extension to C#. In the current language, a type declaration T! is shorthand for Nullable.

But equally important in modern C# programs are sequences of values, so a similar shorthand for IEnumerable would be ideal. The asterisk symbol is underused (you can suffix a type with asterisk to make a pointer, but only in unsafe contexts), and this was the choice made by the intriguing research language Cω that influenced LINQ, so let’s copy that:

    int* numbers = new[] { 1, 6, 55, 4, 11 };

    foreach (var n in numbers)
        Console.WriteLine(n);

In Binder_Symbols.cs we find:

    case SyntaxKind.PointerType:
        {
            var node = (PointerTypeSyntax)syntax;            
            ReportUnsafeIfNotAllowed(node, diagnostics);

            var elementType = BindType(node.ElementType, diagnostics, basesBeingResolved);
            if (elementType.IsManagedType)
            {
                // "Cannot take the address of, get the size of, or declare a pointer to a managed type ('{0}')"
                Error(diagnostics, ErrorCode.ERR_ManagedAddr, node, elementType);
            }

            return new PointerTypeSymbol(elementType);
        }

The call ReportUnsafeIfNotAllowed is what checks for the unsafe context. So I commented that out and added my own check for not-unsafe, before doing something very similar to what happens for T? -> Nullable elsewhere in the same file:

    case SyntaxKind.PointerType:
        {
            var node = (PointerTypeSyntax)syntax;

            //ReportUnsafeIfNotAllowed(node, diagnostics);
            if (this.IsIndirectlyInIterator || !this.InUnsafeRegion)
            {
                NamedTypeSymbol enumerableT = GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T, diagnostics, syntax);
                TypeSymbol typeArgument = BindType(node.ElementType, diagnostics, basesBeingResolved);
                NamedTypeSymbol constructedType = enumerableT.Construct(typeArgument);
                if (ShouldCheckConstraints)
                {
                    constructedType.CheckConstraints(this.Compilation, this.Conversions, syntax.Location, diagnostics);
                }
                return constructedType;
            }

            var elementType = BindType(node.ElementType, diagnostics, basesBeingResolved);
            if (elementType.IsManagedType)
            {
                // "Cannot take the address of, get the size of, or declare a pointer to a managed type ('{0}')"
                Error(diagnostics, ErrorCode.ERR_ManagedAddr, node, elementType);
            }

            return new PointerTypeSymbol(elementType);
        }

And we’re done! We can now say things like:

static int *Squares(int *nums)
{
    return nums.Select(n => n * n);
}

Roslyn may not be very pretty – it’s a hand-crafted top-down system, so it looks nothing like the “text book” functional parsers. But it’s a real product as opposed to a clean example, so that’s hardly surprising. Regardless, it is proving easy (even fun) to hack.

Advertisements
Categories: Uncategorized Tags:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: