using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace UdonSharp.Compiler { public class InternalMethodHandler { enum InternalFunc { None, // Static functions MajorVersion, MinorVersion, PatchVersion, Build, VersionStr, TypeIDGeneric, TypeNameGeneric, ScriptVersion, ScriptCompileDate, ScriptCompilerName, // Instance functions TypeIDInstance, TypeNameInstance, } const int UDON_SHARP_MAJOR_VERSION = 0; const int UDON_SHARP_MINOR_VERSION = 8; const int UDON_SHARP_PATCH_VERSION = 3; const int UDON_SHARP_BUILD = 29; static readonly string UDON_SHARP_VERSION_STR = $"v{UDON_SHARP_MAJOR_VERSION}.{UDON_SHARP_MINOR_VERSION}.{UDON_SHARP_PATCH_VERSION}+{UDON_SHARP_BUILD}"; ASTVisitorContext visitorContext; ExpressionCaptureScope captureScope; InternalFunc captureFunc = InternalFunc.None; System.Type genericType = null; public InternalMethodHandler(ASTVisitorContext visitorContextIn, ExpressionCaptureScope captureScopeIn) { visitorContext = visitorContextIn; captureScope = captureScopeIn; } public bool ResolveAccessToken(string accessToken) { if (captureScope.captureArchetype == ExpressionCaptureArchetype.Type) { return false; #if false if (captureScope.captureType != typeof(UdonSharpUtility)) return false; switch (accessToken) { case nameof(UdonSharpUtility.GetCompilerMajorVersion): captureFunc = InternalFunc.MajorVersion; break; case nameof(UdonSharpUtility.GetCompilerMinorVersion): captureFunc = InternalFunc.MinorVersion; break; case nameof(UdonSharpUtility.GetCompilerPatchVersion): captureFunc = InternalFunc.PatchVersion; break; case nameof(UdonSharpUtility.GetCompilerBuild): captureFunc = InternalFunc.Build; break; case nameof(UdonSharpUtility.GetCompilerVersionString): captureFunc = InternalFunc.VersionStr; break; case nameof(UdonSharpUtility.GetTypeID): captureFunc = InternalFunc.TypeIDGeneric; break; case nameof(UdonSharpUtility.GetUdonScriptVersion): captureFunc = InternalFunc.ScriptVersion; break; case nameof(UdonSharpUtility.GetLastCompileDate): captureFunc = InternalFunc.ScriptCompileDate; break; case nameof(UdonSharpUtility.GetCompilerName): captureFunc = InternalFunc.ScriptCompilerName; break; default: captureFunc = InternalFunc.None; return false; } return captureFunc != InternalFunc.None; #endif } else if (captureScope.captureArchetype == ExpressionCaptureArchetype.Unknown || captureScope.captureArchetype == ExpressionCaptureArchetype.This || captureScope.captureArchetype == ExpressionCaptureArchetype.LocalSymbol || captureScope.captureArchetype == ExpressionCaptureArchetype.Property || captureScope.captureArchetype == ExpressionCaptureArchetype.Field || captureScope.captureArchetype == ExpressionCaptureArchetype.ExternUserField || captureScope.captureArchetype == ExpressionCaptureArchetype.ArrayIndexer) { captureFunc = InternalFunc.None; switch (accessToken) { case nameof(UdonSharpBehaviour.GetUdonTypeID): captureFunc = InternalFunc.TypeIDInstance; break; case nameof(UdonSharpBehaviour.GetUdonTypeName): captureFunc = InternalFunc.TypeNameInstance; break; } if (captureFunc == InternalFunc.None) return false; return true; } return false; } public void HandleGenericAccess(List genericTypeArgs) { if (captureFunc == InternalFunc.TypeIDInstance) { captureFunc = InternalFunc.TypeIDGeneric; } else if (captureFunc == InternalFunc.TypeNameInstance) { captureFunc = InternalFunc.TypeNameGeneric; } else { throw new System.ArgumentException($"Cannot call generic internal function {captureFunc}"); } genericType = genericTypeArgs.First(); } public SymbolDefinition Invoke(SymbolDefinition[] invokeParams) { SymbolDefinition methodResult = null; System.Type resultSymbolType = null; string lookupSymbolName = null; switch (captureFunc) { case InternalFunc.TypeIDInstance: case InternalFunc.TypeIDGeneric: resultSymbolType = typeof(long); lookupSymbolName = "udonTypeID"; break; case InternalFunc.TypeNameInstance: case InternalFunc.TypeNameGeneric: resultSymbolType = typeof(string); lookupSymbolName = "udonTypeName"; break; default: throw new System.ArgumentException("Invalid internal method invocation"); } methodResult = visitorContext.topTable.CreateUnnamedSymbol(resultSymbolType, SymbolDeclTypeFlags.Internal); if (captureFunc == InternalFunc.TypeIDInstance || captureFunc == InternalFunc.TypeNameInstance) { SymbolDefinition invokeSymbol = captureScope.accessSymbol; using (ExpressionCaptureScope resultSetterScope = new ExpressionCaptureScope(visitorContext, null)) { resultSetterScope.SetToLocalSymbol(methodResult); using (ExpressionCaptureScope getInvokeScope = new ExpressionCaptureScope(visitorContext, null)) { getInvokeScope.SetToLocalSymbol(invokeSymbol); getInvokeScope.ResolveAccessToken(nameof(VRC.Udon.UdonBehaviour.GetProgramVariable)); string symbolName = visitorContext.topTable.GetReflectionSymbol(lookupSymbolName, resultSymbolType).symbolUniqueName; SymbolDefinition invokeResult = getInvokeScope.Invoke(new SymbolDefinition[] { visitorContext.topTable.CreateConstSymbol(typeof(string), symbolName) }); JumpLabel exitBranchJump = visitorContext.labelTable.GetNewJumpLabel("exitUdonTypeIdLoc"); JumpLabel falseBranchLoc = visitorContext.labelTable.GetNewJumpLabel("falseUdonTypeIdLoc"); SymbolDefinition nullCheckSymbol = null; using (ExpressionCaptureScope nullCheckCondition = new ExpressionCaptureScope(visitorContext, null)) { nullCheckCondition.SetToMethods(UdonSharpUtils.GetOperators(typeof(object), BuiltinOperatorType.Inequality)); nullCheckSymbol = nullCheckCondition.Invoke(new SymbolDefinition[] { invokeResult, visitorContext.topTable.CreateConstSymbol(typeof(object), null) }); } visitorContext.uasmBuilder.AddJumpIfFalse(falseBranchLoc, nullCheckSymbol); resultSetterScope.ExecuteSet(captureScope.CastSymbolToType(invokeResult, resultSymbolType, true)); visitorContext.uasmBuilder.AddJump(exitBranchJump); // If the value is null visitorContext.uasmBuilder.AddJumpLabel(falseBranchLoc); if (captureFunc == InternalFunc.TypeIDInstance) resultSetterScope.ExecuteSet(visitorContext.topTable.CreateConstSymbol(typeof(long), 0L)); else resultSetterScope.ExecuteSet(visitorContext.topTable.CreateConstSymbol(typeof(string), "UnknownType")); visitorContext.uasmBuilder.AddJumpLabel(exitBranchJump); } } } else { object resultSymbolValue = null; if (captureFunc == InternalFunc.TypeIDGeneric) resultSymbolValue = Internal.UdonSharpInternalUtility.GetTypeID(genericType); else if (captureFunc == InternalFunc.TypeNameGeneric) resultSymbolValue = Internal.UdonSharpInternalUtility.GetTypeName(genericType); methodResult = visitorContext.topTable.CreateConstSymbol(resultSymbolType, resultSymbolValue); } using (ExpressionCaptureScope propagateScope = new ExpressionCaptureScope(visitorContext, visitorContext.topCaptureScope)) { propagateScope.SetToLocalSymbol(methodResult); } return methodResult; } } }