Skip to content

Commit

Permalink
add indexability in expressions (#3682)
Browse files Browse the repository at this point in the history
allows us to change lines like this 

```c#
new IndexerExpression(output, i).Assign(Literal('-')).Terminate()
```

into lines like this

```c#
output[i].Assign(Literal('-')).Terminate()
```
  • Loading branch information
m-nash authored Jun 27, 2024
1 parent 8f837b1 commit 7e68cdc
Show file tree
Hide file tree
Showing 15 changed files with 67 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.ClientModel.Snippets;
using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Providers;
using Microsoft.Generator.CSharp.Snippets;

namespace Microsoft.Generator.CSharp.ClientModel
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
using Microsoft.Generator.CSharp.Providers;
using Microsoft.Generator.CSharp.Snippets;
using Microsoft.Generator.CSharp.Statements;
using Microsoft.Generator.CSharp.TypedSnippets;
using static Microsoft.Generator.CSharp.Snippets.Snippet;
using static Microsoft.Generator.CSharp.ClientModel.Snippets.TypeFormattersSnippet;
using static Microsoft.Generator.CSharp.ClientModel.Snippets.ModelSerializationExtensionsSnippet;
Expand Down Expand Up @@ -270,7 +269,7 @@ private MethodProvider BuildGetCharMethodProvider()
{
Throw(New.NotSupportedException(new FormattableStringExpression("Cannot convert \\\"{0}\\\" to a char", [text])))
},
Return(text.Index(0))
Return(text[0])
},
Throw(New.NotSupportedException(new FormattableStringExpression("Cannot convert {0} to a char", [element.ValueKind])))
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,23 +165,24 @@ private MethodProvider BuildToBase64UrlStringMethodProvider()
Declare("numWholeOrPartialInputBlocks", new IntSnippet(new BinaryOperatorExpression("/", new KeywordExpression("checked", new BinaryOperatorExpression("+", valueLength, Int(2))), Int(3))), out var numWholeOrPartialInputBlocks),
Declare("size", new IntSnippet(new KeywordExpression("checked", new BinaryOperatorExpression("*", numWholeOrPartialInputBlocks, Int(4)))), out var size),
};
var output = new VariableExpression(typeof(char[]), "output");
var outputVar = new VariableExpression(typeof(char[]), "output");
var output = new IndexableExpression(outputVar);
body.Add(new MethodBodyStatement[]
{
Declare(output, New.Array(typeof(char), size)),
Declare(outputVar, New.Array(typeof(char), size)),
EmptyLineStatement,
Declare("numBase64Chars", new IntSnippet(new InvokeStaticMethodExpression(typeof(Convert), nameof(Convert.ToBase64CharArray), [value, Int(0), valueLength, output, Int(0)])), out var numBase64Chars),
EmptyLineStatement,
Declare("i", Int(0), out var i),
new ForStatement(null, LessThan(i, numBase64Chars), new UnaryOperatorExpression("++", i, true))
{
Declare("ch", new CharSnippet(new IndexerExpression(output, i)), out var ch),
Declare("ch", new CharSnippet(output[i]), out var ch),
new IfElseStatement(new IfStatement(Equal(ch, Literal('+')))
{
new IndexerExpression(output, i).Assign(Literal('-')).Terminate()
output[i].Assign(Literal('-')).Terminate()
}, new IfElseStatement(new IfStatement(Equal(ch, Literal('/')))
{
new IndexerExpression(output, i).Assign(Literal('_')).Terminate()
output[i].Assign(Literal('_')).Terminate()
}, new IfStatement(Equal(ch, Literal('=')))
{
Break
Expand Down Expand Up @@ -215,27 +216,28 @@ private MethodProvider BuildFromBase64UrlString()
SwitchCaseExpression.Default(ThrowExpression(New.InvalidOperationException(Literal("Malformed input"))))
})), out var paddingCharsToAdd)
};
var output = new VariableExpression(typeof(char[]), "output");
var outputVar = new VariableExpression(typeof(char[]), "output");
var output = new IndexableExpression(outputVar);
var outputLength = output.Property("Length");
body.Add(new MethodBodyStatement[]
{
Declare(output, New.Array(typeof(char), new BinaryOperatorExpression("+", value.Length, paddingCharsToAdd))),
Declare(outputVar, New.Array(typeof(char), new BinaryOperatorExpression("+", value.Length, paddingCharsToAdd))),
Declare("i", Int(0), out var i),
new ForStatement(null, LessThan(i, value.Length), new UnaryOperatorExpression("++", i, true))
{
Declare("ch", value.Index(i), out var ch),
Declare("ch", value[i], out var ch),
new IfElseStatement(new IfStatement(Equal(ch, Literal('-')))
{
new IndexerExpression(output, i).Assign(Literal('+')).Terminate()
output[i].Assign(Literal('+')).Terminate()
}, new IfElseStatement(new IfStatement(Equal(ch, Literal('_')))
{
new IndexerExpression(output, i).Assign(Literal('/')).Terminate()
}, new IndexerExpression(output, i).Assign(ch).Terminate()))
output[i].Assign(Literal('/')).Terminate()
}, output[i].Assign(ch).Terminate()))
},
EmptyLineStatement,
new ForStatement(null, LessThan(i, outputLength), new UnaryOperatorExpression("++", i, true))
{
new IndexerExpression(output, i).Assign(Literal('=')).Terminate()
output[i].Assign(Literal('=')).Terminate()
},
EmptyLineStatement,
Return(new InvokeStaticMethodExpression(typeof(Convert), nameof(Convert.FromBase64CharArray), new[] { output, Int(0), outputLength }))
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Generator.CSharp.Expressions;

namespace Microsoft.Generator.CSharp.Snippets
{
public record IndexableExpression(ValueExpression Inner) : ValueExpression
{
public IndexableExpression(CSharpType type, string name) : this(new VariableExpression(type, name))
{
}

public ValueExpression this[ValueExpression index] => new IndexerExpression(this, index);

internal override void Write(CodeWriter writer)
{
Inner.Write(writer);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ private class ChangeTrackingDictionaryTemplate<TKey, TValue> { }
private readonly DictionarySnippet _innerDictionary;
private readonly MethodSignature _ensureDictionarySignature;

private InvokeInstanceMethodExpression EnsureDictionary { get; init; }
private IndexableExpression EnsureDictionary { get; init; }
private BoolSnippet IsUndefined { get; } = new BoolSnippet(new MemberExpression(This, "IsUndefined"));

public ChangeTrackingDictionaryProvider()
Expand All @@ -43,7 +43,7 @@ public ChangeTrackingDictionaryProvider()
_innerDictionaryField = new FieldProvider(FieldModifiers.Private, new CSharpType(typeof(IDictionary<,>), _tKey, _tValue), "_innerDictionary");
_innerDictionary = new DictionarySnippet(_tKey, _tValue, new VariableExpression(_IDictionary, _innerDictionaryField.Declaration));
_ensureDictionarySignature = new MethodSignature("EnsureDictionary", null, MethodSignatureModifiers.Public, _IDictionary, null, Array.Empty<ParameterProvider>());
EnsureDictionary = This.Invoke(_ensureDictionarySignature);
EnsureDictionary = new(This.Invoke(_ensureDictionarySignature));
}

protected override TypeSignatureModifiers GetDeclarationModifiers()
Expand Down Expand Up @@ -160,11 +160,11 @@ private PropertyProvider BuildIndexer()
{
Throw(New.Instance(typeof(KeyNotFoundException), Nameof(_indexParam)))
},
Return(new ArrayElementExpression(EnsureDictionary, _indexParam)),
Return(EnsureDictionary[_indexParam]),
},
new MethodBodyStatement[]
{
new ArrayElementExpression(EnsureDictionary, _indexParam).Assign(new KeywordExpression("value", null)).Terminate()
EnsureDictionary[_indexParam].Assign(Value).Terminate()
}));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ private class ChangeTrackingListTemplate<T> { }
private readonly CSharpType _iReadOnlyListOfT;

private BoolSnippet IsUndefined { get; } = new BoolSnippet(new MemberExpression(This, "IsUndefined"));
private InvokeInstanceMethodExpression EnsureList { get; init; }
private IndexableExpression EnsureList { get; init; }

public ChangeTrackingListProvider()
{
Expand All @@ -42,7 +42,7 @@ public ChangeTrackingListProvider()
_innerList = new VariableExpression(_iListOfT, _innerListField.Declaration);
_tArray = typeof(ChangeTrackingListTemplate<>).GetGenericArguments()[0].MakeArrayType();
_tParam = new ParameterProvider("item", $"The item.", _t);
EnsureList = This.Invoke(_ensureListSignature);
EnsureList = new(This.Invoke(_ensureListSignature));
}

protected override TypeSignatureModifiers GetDeclarationModifiers()
Expand Down Expand Up @@ -136,15 +136,15 @@ private PropertyProvider BuildIndexer()
{
Throw(New.Instance(typeof(ArgumentOutOfRangeException), Nameof(_indexParam)))
},
Return(new ArrayElementExpression(EnsureList, _indexParam)),
Return(EnsureList[_indexParam]),
},
new MethodBodyStatement[]
{
new IfStatement(IsUndefined)
{
Throw(New.Instance(typeof(ArgumentOutOfRangeException), Nameof(_indexParam)))
},
new ArrayElementExpression(EnsureList, _indexParam).Assign(new KeywordExpression("value", null)).Terminate()
EnsureList[_indexParam].Assign(Value).Terminate()
}));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ public static ValueExpression ArgumentException(ValueExpression parameter, Value
public static ValueExpression JsonException(ValueExpression message)
=> Instance(typeof(JsonException), message);

public static EnumerableSnippet Array(CSharpType? elementType) => new(elementType ?? typeof(object), new NewArrayExpression(elementType));
public static EnumerableSnippet Array(CSharpType? elementType, params ValueExpression[] items) => new(elementType ?? typeof(object), new NewArrayExpression(elementType, new ArrayInitializerExpression(items)));
public static EnumerableSnippet Array(CSharpType? elementType, bool isInline, params ValueExpression[] items) => new(elementType ?? typeof(object), new NewArrayExpression(elementType, new ArrayInitializerExpression(items, isInline)));
public static EnumerableSnippet Array(CSharpType? elementType, ValueExpression size) => new(elementType ?? typeof(object), new NewArrayExpression(elementType, Size: size));
public static IndexableExpression Array(CSharpType? elementType) => new(new NewArrayExpression(elementType));
public static IndexableExpression Array(CSharpType? elementType, params ValueExpression[] items) => new(new NewArrayExpression(elementType, new ArrayInitializerExpression(items)));
public static IndexableExpression Array(CSharpType? elementType, bool isInline, params ValueExpression[] items) => new(new NewArrayExpression(elementType, new ArrayInitializerExpression(items, isInline)));
public static IndexableExpression Array(CSharpType? elementType, ValueExpression size) => new(new NewArrayExpression(elementType, Size: size));

public static DictionarySnippet Dictionary(CSharpType keyType, CSharpType valueType)
=> new(keyType, valueType, new NewInstanceExpression(new CSharpType(typeof(Dictionary<,>), keyType, valueType), []));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ internal override void Write(CodeWriter writer)

public static ValueExpression DefaultOf(CSharpType type) => type is { IsValueType: true, IsNullable: false } ? Default.CastTo(type) : Null.CastTo(type);

public static ValueExpression Value { get; } = new KeywordExpression("value", null);
public static ValueExpression Default { get; } = new KeywordExpression("default", null);
public static ValueExpression Null { get; } = new KeywordExpression("null", null);
public static ValueExpression This { get; } = new KeywordExpression("this", null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ public MethodBodyStatement Add(ValueExpression key, ValueExpression value)

public MethodBodyStatement Add(KeyValuePairSnippet pair)
=> Untyped.Invoke(nameof(Dictionary<object, object>.Add), pair).Terminate();

public ValueExpression this[ValueExpression key] => new IndexerExpression(Untyped, key);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public sealed record ListSnippet(CSharpType ItemType, ValueExpression Untyped) :
{
public MethodBodyStatement Add(ValueExpression item) => Untyped.Invoke(nameof(List<object>.Add), item).Terminate();

public ValueExpression ToArray() => Untyped.Invoke(nameof(List<object>.ToArray));
public IndexableExpression ToArray() => new(Untyped.Invoke(nameof(List<object>.ToArray)));

public ValueExpression this[ValueExpression index] => new IndexerExpression(Untyped, index);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// Licensed under the MIT License.

using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Snippets;

namespace Microsoft.Generator.CSharp.TypedSnippets
namespace Microsoft.Generator.CSharp.Snippets
{
public sealed record ObjectSnippet(ValueExpression Untyped) : TypedSnippet<object>(Untyped)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ namespace Microsoft.Generator.CSharp.Snippets
{
public sealed record StringSnippet(ValueExpression Untyped) : TypedSnippet<string>(Untyped)
{
public CharSnippet Index(ValueExpression index) => new(new IndexerExpression(this, index));
public CharSnippet Index(int index) => Index(Snippet.Literal(index));
public ValueExpression Length => Property(nameof(string.Length));

public static BoolSnippet Equals(StringSnippet left, StringSnippet right, StringComparison comparisonType)
Expand All @@ -29,5 +27,9 @@ public StringSnippet Substring(ValueExpression startIndex)
=> new(new InvokeInstanceMethodExpression(this, nameof(string.Substring), new[] { startIndex }, null, false));
public ValueExpression ToCharArray()
=> new InvokeInstanceMethodExpression(this, nameof(string.ToCharArray), Array.Empty<ValueExpression>(), null, false);

public CharSnippet this[ValueExpression index] => new(new IndexerExpression(this, index));

public CharSnippet this[int index] => this[Snippet.Literal(index)];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Collections.Generic;
using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Providers;
using Microsoft.Generator.CSharp.Snippets;

namespace Microsoft.Generator.CSharp.Tests
{
Expand Down
Loading

0 comments on commit 7e68cdc

Please sign in to comment.