static void Demo4(CodeCompileUnit ccu) { // create one of these lil guys var res = new CodeDomResolver(); // add our code to it res.CompileUnits.Add(ccu); // give it a chance to build its information over our code res.Refresh(); CodeDomVisitor.Visit(ccu, (ctx) => { // for every expression... var expr = ctx.Target as CodeExpression; if (null != expr) { // except method reference expressions... var mri = expr as CodeMethodReferenceExpression; if (null != mri) { return; } // get the expression type var type = res.TryGetTypeOfExpression(expr); // write it along with the expression itself Console.WriteLine( "Expression type {0}: {1} is {2}", expr.GetType().Name, CodeDomUtility.ToString(expr), null != type?CodeDomUtility.ToString(type):"unresolvable"); } }); Console.WriteLine("Press any key..."); Console.ReadKey(); Console.Clear(); }
static void RunResolver() { byte[] data; using (var stream = File.OpenRead(@"myfile.bin")) { data = new byte[(int)stream.Length]; stream.Read(data, 0, data.Length); } // create a resolver var res = new CodeDomResolver(); // read the resolver sample into the compile unit CodeCompileUnit ccu; using (var stm = File.OpenRead(@"..\..\Resolver.cs")) ccu = SlangParser.ReadCompileUnitFrom(stm); // remember to patch it! SlangPatcher.Patch(ccu); Console.Error.WriteLine(CU.ToString(ccu)); // add the compile unit to the resolver res.CompileUnits.Add(ccu); // prepare the resolver // any time you add compile units you'll need // to call Refresh() res.Refresh(); // go through all expressions in the // graph and try to get their type CodeDomVisitor.Visit(ccu, (ctx) => { var expr = ctx.Target as CodeExpression; if (null != expr) { // we want everything except CodeTypeReferenceExpression var ctre = expr as CodeTypeReferenceExpression; if (null == ctre) { // get the scope of the expression var scope = res.GetScope(expr); CodeTypeReference ctr = res.TryGetTypeOfExpression(expr, scope); if (null != ctr) { Console.WriteLine(CU.ToString(expr) + " is type: " + CU.ToString(ctr)); Console.WriteLine("Scope Dump:"); Console.WriteLine(scope.ToString()); } } } }); }
static void Demo5(CodeCompileUnit ccu) { // once again, we need one of these var res = new CodeDomResolver(); res.CompileUnits.Add(ccu); res.Refresh(); // we happen to know Program is the 1st type in the 2nd namespace* var prg = ccu.Namespaces[1].Types[0]; // we need the scope where we're at var scope = res.GetScope(prg); // because our binder attaches to it var binder = new CodeDomBinder(scope); // now get all the methods with the specified name and flags var members = binder.GetMethodGroup(prg, "TestOverload", BindingFlags.Public | BindingFlags.Static); Console.WriteLine("There are {0} TestOverload method overloads.", members.Length); // try selecting one that takes a single string parameter var argTypes1 = new CodeTypeReference[] { new CodeTypeReference(typeof(string)) }; var m = binder.SelectMethod(BindingFlags.Public | BindingFlags.Static, members, argTypes1, null); if (null != m) { Console.WriteLine("Select TestOverload(string) returned:"); _DumpMethod(m); } else { Console.WriteLine("Unable to bind to method"); } // try selecting one that takes a single it parameter var argTypes2 = new CodeTypeReference[] { new CodeTypeReference(typeof(int)) }; m = binder.SelectMethod(BindingFlags.Public | BindingFlags.Static, members, argTypes2, null); if (null != m) { Console.WriteLine("Select TestOverload(int) returned:"); _DumpMethod(m); } else { Console.WriteLine("Unable to bind to method"); } Console.WriteLine("Press any key..."); Console.ReadKey(); Console.Clear(); }
static void RunBinding() { // we'll need the resolver in a bit var res = new CodeDomResolver(); // read the binding sample into the compile unit CodeCompileUnit ccu; using (var stm = File.OpenRead(@"..\..\Binding.cs")) ccu = SlangParser.ReadCompileUnitFrom(stm); // add the compile unit to the resolver res.CompileUnits.Add(ccu); // prepare the resolver res.Refresh(); // get the first class available var tdecl = ccu.Namespaces[1].Types[0]; // capture the scope at the typedecl level var scope = res.GetScope(tdecl); // create a new binder with that scope var binder = new CodeDomBinder(scope); // get the method group for Test(...) var methodGroup = binder.GetMethodGroup(tdecl, "Test", BindingFlags.Public | BindingFlags.Instance); // select the method that can take a string value var m = binder.SelectMethod(BindingFlags.Public, methodGroup, new CodeTypeReference[] { new CodeTypeReference(typeof(string)) }, null); Console.WriteLine(CU.ToString((CodeMemberMethod)m)); // select the method that can take a short value // (closest match accepts int) m = binder.SelectMethod(BindingFlags.Public, methodGroup, new CodeTypeReference[] { new CodeTypeReference(typeof(short)) }, null); Console.WriteLine(CU.ToString((CodeMemberMethod)m)); }
/// <summary> /// Patches the CodeDOM tree received from the <see cref="SlangParser"/> into something more usable, by resolving type information and replacing various elements in the CodeDOM graph /// </summary> /// <param name="compileUnits">The <see cref="CodeCompileUnit"/> objects to patch</param> public static void Patch(IEnumerable <CodeCompileUnit> compileUnits) { var resolver = new CodeDomResolver(); foreach (var ccu in compileUnits) { resolver.CompileUnits.Add(ccu); } resolver.Refresh(); restart: var working = -1; var oworking = 0; while (0 != working && oworking != working) { oworking = working; working = 0; for (int ic = resolver.CompileUnits.Count, i = 0; i < ic; ++i) { CodeDomVisitor.Visit(resolver.CompileUnits[i], (ctx) => { var co = ctx.Target as CodeObject; if (null != co && co.UserData.Contains("slang:unresolved")) { ++working; _Patch(ctx.Target as CodeFieldReferenceExpression, ctx, resolver); _Patch(ctx.Target as CodeVariableDeclarationStatement, ctx, resolver); _Patch(ctx.Target as CodeAssignStatement, ctx, resolver); _Patch(ctx.Target as CodeVariableReferenceExpression, ctx, resolver); _Patch(ctx.Target as CodeDelegateInvokeExpression, ctx, resolver); _Patch(ctx.Target as CodeObjectCreateExpression, ctx, resolver); _Patch(ctx.Target as CodeBinaryOperatorExpression, ctx, resolver); _Patch(ctx.Target as CodeIndexerExpression, ctx, resolver); _Patch(ctx.Target as CodeMemberMethod, ctx, resolver); _Patch(ctx.Target as CodeMemberProperty, ctx, resolver); _Patch(ctx.Target as CodeTypeReferenceExpression, ctx, resolver); _Patch(ctx.Target as CodeTypeReference, ctx, resolver); } }); } resolver.Refresh(); } oworking = working; working = 0; if (0 < oworking) { // one last time for (int ic = resolver.CompileUnits.Count, i = 0; i < ic; ++i) { CodeDomVisitor.Visit(resolver.CompileUnits[i], (ctx) => { var co = ctx.Target as CodeObject; if (null != co && co.UserData.Contains("slang:unresolved")) { ++working; _Patch(ctx.Target as CodeFieldReferenceExpression, ctx, resolver); _Patch(ctx.Target as CodeVariableDeclarationStatement, ctx, resolver); _Patch(ctx.Target as CodeAssignStatement, ctx, resolver); _Patch(ctx.Target as CodeVariableReferenceExpression, ctx, resolver); _Patch(ctx.Target as CodeDelegateInvokeExpression, ctx, resolver); _Patch(ctx.Target as CodeObjectCreateExpression, ctx, resolver); _Patch(ctx.Target as CodeBinaryOperatorExpression, ctx, resolver); _Patch(ctx.Target as CodeIndexerExpression, ctx, resolver); _Patch(ctx.Target as CodeMemberMethod, ctx, resolver); _Patch(ctx.Target as CodeMemberProperty, ctx, resolver); _Patch(ctx.Target as CodeTypeReferenceExpression, ctx, resolver); _Patch(ctx.Target as CodeTypeReference, ctx, resolver); } }); } if (oworking != working) { goto restart; } } }