Skip to content

Commit

Permalink
Add string indexer because Udon still hasn't added it
Browse files Browse the repository at this point in the history
- Gets a substring at the character index, converts it to a char[], and gets the first character from the character array
MerlinVR committed Nov 27, 2020
1 parent d42fcfb commit 6bf65ca
Showing 2 changed files with 34 additions and 4 deletions.
34 changes: 30 additions & 4 deletions Assets/UdonSharp/Editor/UdonSharpExpressionCapture.cs
Original file line number Diff line number Diff line change
@@ -489,21 +489,47 @@ public SymbolDefinition ExecuteGet()
string getIndexerUdonName;
if (arraySymbol.symbolCsType == typeof(string))
{
getIndexerUdonName = visitorContext.resolverContext.GetUdonMethodName(arraySymbol.symbolCsType.GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(e => e.Name == "get_Chars").First());
// udon-workaround: This is where support for Udon's string indexer would go, IF IT HAD ONE
//getIndexerUdonName = visitorContext.resolverContext.GetUdonMethodName(arraySymbol.symbolCsType.GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(e => e.Name == "get_Chars").First());

elementType = typeof(char);

SymbolDefinition substringStrSymbol;
using (ExpressionCaptureScope substringScope = new ExpressionCaptureScope(visitorContext, null))
{
substringScope.SetToLocalSymbol(arraySymbol);
substringScope.ResolveAccessToken(nameof(string.Substring));

substringStrSymbol = substringScope.Invoke(new SymbolDefinition[] { arrayIndexerIndexValue.symbol, visitorContext.topTable.CreateConstSymbol(typeof(int), 1) });
}

SymbolDefinition subStrCharArrSymbol;

using (ExpressionCaptureScope charArrScope = new ExpressionCaptureScope(visitorContext, null))
{
charArrScope.SetToLocalSymbol(substringStrSymbol);
charArrScope.ResolveAccessToken(nameof(string.ToCharArray));

subStrCharArrSymbol = charArrScope.Invoke(new SymbolDefinition[] { });
}

getIndexerUdonName = visitorContext.resolverContext.GetUdonMethodName(typeof(char[]).GetMethods(BindingFlags.Public | BindingFlags.Instance).First(e => e.Name == "Get"));
visitorContext.uasmBuilder.AddPush(subStrCharArrSymbol);
visitorContext.uasmBuilder.AddPush(visitorContext.topTable.CreateConstSymbol(typeof(int), 0)); // 0 index
}
else
{
getIndexerUdonName = visitorContext.resolverContext.GetUdonMethodName(arraySymbol.symbolCsType.GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(e => e.Name == "Get").First());
elementType = arraySymbol.userCsType.GetElementType();

visitorContext.uasmBuilder.AddPush(arraySymbol);
visitorContext.uasmBuilder.AddPush(arrayIndexerIndexValue.symbol);
}

arrayBacktraceValue = accessValue;

outSymbol = AllocateOutputSymbol(elementType);

visitorContext.uasmBuilder.AddPush(arraySymbol);
visitorContext.uasmBuilder.AddPush(arrayIndexerIndexValue.symbol);
visitorContext.uasmBuilder.AddPush(outSymbol);
visitorContext.uasmBuilder.AddExternCall(getIndexerUdonName);
}
@@ -2175,7 +2201,7 @@ public void HandleArrayIndexerAccess(SymbolDefinition.COWValue indexerValue, Sym

System.Type returnType = GetReturnType(true);

if (!returnType.IsArray/* && returnType != typeof(string)*/) // Uncomment the check for string when VRC has added the actual indexer function to Udon.
if (!returnType.IsArray && returnType != typeof(string)) // We have hacky handling for strings now
throw new System.Exception("Can only run array indexers on array types");

SymbolDefinition cowIndexerSymbol = indexerValue.symbol;
4 changes: 4 additions & 0 deletions Assets/UdonSharp/Tests/TestScripts/Core/MethodCallsTest.cs
Original file line number Diff line number Diff line change
@@ -56,6 +56,10 @@ public void ExecuteTests()
selfUdon.enabled = false;
tester.TestAssertion("UdonBehaviour ref enabled", selfUdon.enabled == false);
selfUdon.enabled = true;

string testStr2 = "hello";

tester.TestAssertion("String indexer", testStr2[0] == 'h' && testStr2[1] == 'e' && testStr2[2] == 'l');
}

//public void test(int a, bool b, float c = 5f, params float[] d)

0 comments on commit 6bf65ca

Please sign in to comment.