static void _Patch(CodeMemberProperty prop, CodeDomVisitContext ctx, CodeDomResolver resolver) { if (null != prop) { // TODO: make sure the member is actually public if (null == prop.PrivateImplementationType) { var scope = resolver.GetScope(prop); var td = scope.DeclaringType; var binder = new CodeDomBinder(scope); for (int ic = td.BaseTypes.Count, i = 0; i < ic; ++i) { var ctr = td.BaseTypes[i]; var t = resolver.TryResolveType(ctr, scope); if (null != t) { var ma = binder.GetPropertyGroup(t, prop.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); if (0 < ma.Length) { var p = binder.SelectProperty(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, ma, null, _GetParameterTypes(prop.Parameters), null); if (null != p) { prop.ImplementationTypes.Add(ctr); } } } } } prop.UserData.Remove("slang:unresolved"); } }
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 _Patch(CodeDelegateInvokeExpression di, CodeDomVisitContext ctx, CodeDomResolver resolver) { if (null != di) { // these can be method invokes depending. if (null != di.TargetObject) { // probably already fixed in an earlier visit var mr = di.TargetObject as CodeMethodReferenceExpression; if (null != mr) { var mi = new CodeMethodInvokeExpression(mr); mi.Parameters.AddRange(di.Parameters); CodeDomVisitor.ReplaceTarget(ctx, mi); //args.Cancel = true; } else { var cco = di.TargetObject as CodeObject; if (null == cco) { System.Diagnostics.Debugger.Break(); } } } else { // we really are at a loss here as the only way this would be valid is // through a self call on a delegate object itself, like this(); throw new InvalidProgramException(_AppendLineInfo("Untargeted delegate invoke produced by slang parser", di)); } //return; } }
static void _Patch(CodeAssignStatement ast, CodeDomVisitContext ctx, CodeDomResolver res) { if (null != ast) { var eventRef = ast.Left as CodeEventReferenceExpression; if (null != eventRef) { var bo = ast.Right as CodeBinaryOperatorExpression; if (null != bo) { var trg = bo.Right; if (CodeBinaryOperatorType.Add == bo.Operator) { CodeDomVisitor.ReplaceTarget(ctx, new CodeAttachEventStatement(eventRef, trg)); } else if (CodeBinaryOperatorType.Subtract == bo.Operator) { CodeDomVisitor.ReplaceTarget(ctx, new CodeRemoveEventStatement(eventRef, trg)); } } } else if (!ast.Left.UserData.Contains("slang:unresolved")) { ast.UserData.Remove("slang:unresolved"); } } }
public static CodeCompileUnit Demo1() { // evaluates a simple expression var res = new CodeDomResolver(); Console.WriteLine(res.Evaluate(SlangParser.ParseExpression("5*4-7"))); // takes this file and get a codedom from it var ccu = SlangParser.ReadCompileUnitFrom("..\\..\\Demo1.cs"); ccu.ReferencedAssemblies.Add("CodeDomGoKit.dll"); ccu.ReferencedAssemblies.Add(typeof(CodeObject).Assembly.GetName().ToString()); // now patch the parsed codedom so it's correct // NOTE: slang can't actually bind to this because it is a paramarray method // but we don't care here because it's not necessary. Slang only binds to what // it needs to and we never need the return type anyway (which is void) SlangPatcher.Patch(ccu); // now write it out in VB Console.WriteLine(CodeDomUtility.ToString(ccu, "vb")); // return the code we generated so we can use it for other demos // yay recycling Console.WriteLine("Press any key..."); Console.ReadKey(); Console.Clear(); return(ccu); }
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 bool _IsDelegate(CodeExpression target, CodeDomResolver res) { var v = target as CodeVariableReferenceExpression; if (null != v && v.UserData.Contains("slang:unresolved")) { var scope = res.GetScope(target); if (scope.MemberNames.Contains(v.VariableName)) { return(true); } } return(false); }
static void _Patch(CodeObjectCreateExpression oc, CodeDomVisitContext ctx, CodeDomResolver res) { if (null != oc) // we have to check to see if this is a delegate creation expression { oc.UserData.Remove("slang:unresolved"); if (1 == oc.Parameters.Count) { if (_IsDelegate(oc.Parameters[0], res)) { var del = _GetDelegateFromFields(oc, oc.Parameters[0], res); CodeDomVisitor.ReplaceTarget(ctx, del); } } } }
static void _Patch(CodeTypeReferenceExpression tr, CodeDomVisitContext ctx, CodeDomResolver res) { if (null != tr) { if (res.IsValidType(tr.Type)) { tr.Type.UserData.Remove("slang:unresolved"); tr.UserData.Remove("slang:unresolved"); } else { // TODO: Check for nested type. throw new ArgumentException(_AppendLineInfo(string.Format("Unable to resolve type {0}", tr.Type.BaseType), tr.Type), "compileUnits"); } } }
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 _Patch(CodeIndexerExpression indexer, CodeDomVisitContext ctx, CodeDomResolver resolver) { if (null != indexer) { if (indexer.TargetObject.UserData.Contains("slang:unresolved")) { return; } var ctr = resolver.GetTypeOfExpression(indexer.TargetObject); if (null != ctr.ArrayElementType && 0 < ctr.ArrayRank) { var ai = new CodeArrayIndexerExpression(indexer.TargetObject); ai.Indices.AddRange(indexer.Indices); CodeDomVisitor.ReplaceTarget(ctx, ai); //return; } indexer.UserData.Remove("slang:unresolved"); } }
static void _Patch(CodeVariableDeclarationStatement vd, CodeDomVisitContext ctx, CodeDomResolver resolver) { if (null != vd) { if (CodeDomResolver.IsNullOrVoidType(vd.Type) || (0 == vd.Type.ArrayRank && 0 == vd.Type.TypeArguments.Count && 0 == string.Compare("var", vd.Type.BaseType, StringComparison.InvariantCulture))) { if (null == vd.InitExpression) { throw new ArgumentException(_AppendLineInfo("The code contains an incomplete variable declaration", vd), "resolver"); } if (!_HasUnresolved(vd.InitExpression)) { var t = resolver.GetTypeOfExpression(vd.InitExpression, resolver.GetScope(vd.InitExpression)); vd.Type = t; if (!CodeDomResolver.IsNullOrVoidType(t)) { vd.UserData.Remove("slang:unresolved"); } } } } }
static void _Patch(CodeTypeReference tr, CodeDomVisitContext ctx, CodeDomResolver res) { if (null != tr) { if (res.IsValidType(tr, res.GetScope(tr))) { tr.UserData.Remove("slang:unresolved"); return; } // see if this is an attribute type var n = tr.BaseType; tr.BaseType += "Attribute"; if (res.IsValidType(tr, res.GetScope(tr))) { tr.UserData.Remove("slang:unresolved"); return; } tr.BaseType = n; // restore it // this is probably a nested type but with . instead of + // so now we need to crack it apart and hunt it down throw new NotImplementedException(); } }
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)); }
static void _Patch(CodeBinaryOperatorExpression op, CodeDomVisitContext ctx, CodeDomResolver resolver) { if (null != op) { //var rf = op.Left as CodeFieldReferenceExpression; //if (null != rf && rf.FieldName == "Reduce") // System.Diagnostics.Debugger.Break(); var scope = resolver.GetScope(op); if (CodeBinaryOperatorType.IdentityEquality == op.Operator) { if (_HasUnresolved(op.Left)) { return; } //var vop = op.Right as CodeVariableReferenceExpression; //if (null != vop && vop.VariableName == "n") // System.Diagnostics.Debugger.Break(); var tr1 = resolver.GetTypeOfExpression(op.Left); if (resolver.IsValueType(tr1)) { if (_HasUnresolved(op.Right)) { return; } var tr2 = resolver.GetTypeOfExpression(op.Right); if (resolver.IsValueType(tr2)) { var op2 = new CodeBinaryOperatorExpression(op.Left, CodeBinaryOperatorType.ValueEquality, op.Right); CodeDomVisitor.ReplaceTarget(ctx, op2); return; } } op.UserData.Remove("slang:unresolved"); } else if (CodeBinaryOperatorType.IdentityInequality == op.Operator) { if (_HasUnresolved(op.Left)) { return; } var tr1 = resolver.GetTypeOfExpression(op.Left); if (resolver.IsValueType(tr1)) { if (_HasUnresolved(op.Right)) { return; } var tr2 = resolver.GetTypeOfExpression(op.Right); if (resolver.IsValueType(tr2)) { // we have to hack the codedom because there is no value inequality op.Operator = CodeBinaryOperatorType.ValueEquality; var newOp = new CodeBinaryOperatorExpression(new CodePrimitiveExpression(false), CodeBinaryOperatorType.ValueEquality, op); CodeDomVisitor.ReplaceTarget(ctx, newOp); } } op.UserData.Remove("slang:unresolved"); } } }
static void Demo6() { // load the xsd XmlSchema xsd = null; using (FileStream stream = new FileStream("..\\..\\Test.xsd", FileMode.Open, FileAccess.Read)) { xsd = XmlSchema.Read(stream, null); } XmlSchemas xsds = new XmlSchemas(); xsds.Add(xsd); xsds.Compile(null, true); XmlSchemaImporter xsdImporter = new XmlSchemaImporter(xsds); // create the codedom CodeNamespace ns = new CodeNamespace(); CodeCompileUnit ccu = new CodeCompileUnit(); ccu.ReferencedAssemblies.Add(typeof(XmlTypeAttribute).Assembly.GetName().ToString()); ccu.Namespaces.Add(ns); XmlCodeExporter codeExporter = new XmlCodeExporter(ns, ccu); var maps = new List <XmlTypeMapping>(); foreach (XmlSchemaType schemaType in xsd.SchemaTypes.Values) { maps.Add(xsdImporter.ImportSchemaType(schemaType.QualifiedName)); } foreach (XmlSchemaElement schemaElement in xsd.Elements.Values) { maps.Add(xsdImporter.ImportTypeMapping(schemaElement.QualifiedName)); } foreach (XmlTypeMapping map in maps) { codeExporter.ExportTypeMapping(map); } var typeMap = new Dictionary <string, CodeTypeDeclaration>(StringComparer.InvariantCulture); _FillTypeMap(ns, typeMap); foreach (var kvp in typeMap) { var td = kvp.Value; var propElem = new HashSet <string>(StringComparer.InvariantCulture); var propAttr = new HashSet <string>(StringComparer.InvariantCulture); var fldMap = new Dictionary <string, string>(); _FillPropFldMaps(td, propElem, propAttr, fldMap); // fix up our xml type attribute foreach (CodeAttributeDeclaration d in td.CustomAttributes) { if (0 == string.Compare(d.AttributeType.BaseType, "System.Xml.Serialization.XmlAttributeAttribute", StringComparison.InvariantCulture)) { d.Arguments.Insert(0, new CodeAttributeArgument("TypeName", new CodePrimitiveExpression(td.Name))); break; } } // correct the type name td.Name = _ToNetCase(td.Name); CodeDomVisitor.Visit(td, (ctx) => { var fldRef = ctx.Target as CodeFieldReferenceExpression; if (null != fldRef && fldMap.ContainsKey(fldRef.FieldName)) { fldRef.FieldName = _ToPrivFldName(fldRef.FieldName); return; } var fld = ctx.Target as CodeMemberField; if (null != fld && fldMap.ContainsKey(fld.Name)) { fld.Name = _ToPrivFldName(fld.Name); var ctr = fld.Type; if (0 < ctr.ArrayRank) { ctr = ctr.ArrayElementType; } if (!CodeDomResolver.IsPrimitiveType(ctr)) { ctr.BaseType = _ToNetCase(ctr.BaseType); } } var prop = ctx.Target as CodeMemberProperty; if (null != prop && (propElem.Contains(prop.Name) || propAttr.Contains(prop.Name))) { var n = prop.Name; var ctr = prop.Type; if (0 < ctr.ArrayRank) { ctr = ctr.ArrayElementType; } if (!CodeDomResolver.IsPrimitiveType(ctr)) { ctr.BaseType = _ToNetCase(ctr.BaseType); } prop.Name = _ToNetCase(n); if (propElem.Contains(n)) { foreach (CodeAttributeDeclaration a in prop.CustomAttributes) { if (0 == string.Compare("System.Xml.Serialization.XmlElementAttribute", a.AttributeType.BaseType, StringComparison.InvariantCulture)) { a.Arguments.Insert(0, new CodeAttributeArgument("ElementName", new CodePrimitiveExpression(n))); break; } } } else { foreach (CodeAttributeDeclaration a in prop.CustomAttributes) { if (0 == string.Compare("System.Xml.Serialization.XmlAttributeAttribute", a.AttributeType.BaseType, StringComparison.InvariantCulture)) { a.Arguments.Insert(0, new CodeAttributeArgument("AttributeName", new CodePrimitiveExpression(n))); break; } } } } }); } // Check for invalid characters in identifiers CodeGenerator.ValidateIdentifiers(ns); // output the C# code Console.WriteLine(CodeDomUtility.ToString(ccu)); }
static CodeDelegateCreateExpression _GetDelegateFromFields(CodeObjectCreateExpression oc, CodeExpression target, CodeDomResolver res) { var v = target as CodeVariableReferenceExpression; if (null != v) { var scope = res.GetScope(v); if (scope.MemberNames.Contains(v.VariableName)) { return(new CodeDelegateCreateExpression(oc.CreateType, new CodeThisReferenceExpression(), v.VariableName)); } } throw new NotImplementedException(); }
static void _Patch(CodeFieldReferenceExpression fr, CodeDomVisitContext ctx, CodeDomResolver resolver) { if (null != fr) { // this probably means part of our field has been resolved, or at the very least // it does not come from a rooted var ref. if (!fr.TargetObject.UserData.Contains("slang:unresolved")) { var scope = resolver.GetScope(fr); var binder = new CodeDomBinder(scope); var t = resolver.GetTypeOfExpression(fr.TargetObject, scope); if (null != t && CodeDomResolver.IsNullOrVoidType(t) && fr.TargetObject is CodeVariableReferenceExpression) { return; // can't patch this field yet - it's part of a var reference that hasn't been filled in } var isStatic = false; var tre = fr.TargetObject as CodeTypeReferenceExpression; if (null != tre) { isStatic = true; } var tt = resolver.TryResolveType(isStatic ? tre.Type : t, scope, true); if (null == tt) { throw new InvalidOperationException(_AppendLineInfo(string.Format("The type {0} could not be resolved", t.BaseType), t)); } var td = tt as CodeTypeDeclaration; // TODO: This code could be a lot faster if we added some functionality to the binder // we're just checking to see if the method, property or field exists var m = binder.GetField(tt, fr.FieldName, _BindFlags); if (null != m) { fr.UserData.Remove("slang:unresolved"); return; } m = binder.GetEvent(tt, fr.FieldName, _BindFlags); if (null != m) { var er = new CodeEventReferenceExpression(fr.TargetObject, fr.FieldName); CodeDomVisitor.ReplaceTarget(ctx, er); return; } var ml = binder.GetMethodGroup(tt, fr.FieldName, _BindFlags); if (0 < ml.Length) { var mr = new CodeMethodReferenceExpression(fr.TargetObject, fr.FieldName); CodeDomVisitor.ReplaceTarget(ctx, mr); return; } ml = binder.GetPropertyGroup(tt, fr.FieldName, _BindFlags); if (0 < ml.Length) { var pr = new CodePropertyReferenceExpression(fr.TargetObject, fr.FieldName); CodeDomVisitor.ReplaceTarget(ctx, pr); return; } throw new InvalidProgramException(_AppendLineInfo(string.Format("Cannot deterimine the target reference {0}", fr.FieldName), fr)); } // TODO: This used to be first but I moved it here. // This shouldn't be done first because it's resolving types before fields and // that is a no no. I still need to make sure it doesn't break things var path = _GetUnresRootPathOfExpression(fr); if (null != path) { // now we have something to work with. var scope = resolver.GetScope(fr); var sa = path.Split('.'); if (1 == sa.Length) { System.Diagnostics.Debugger.Break(); throw new NotImplementedException(); } else { object t = null; string tn = null; CodeExpression tf = fr; CodeExpression ptf = null; CodeTypeReference ctr = null; for (var i = sa.Length - 1; i >= 1; --i) { tn = string.Join(".", sa, 0, i); ptf = tf; tf = _GetTargetOfExpression(tf); ctr = new CodeTypeReference(tn); t = resolver.TryResolveType(ctr, scope); if (null != t) { break; } } if (null != t) { var tt = t as Type; if (null != tt) { ctr = new CodeTypeReference(tt); } else { ctr = resolver.GetQualifiedType(ctr, scope); } // we found a type reference _SetTargetOfExpression(ptf, new CodeTypeReferenceExpression(ctr)); return; //args.Cancel = true; } } } } }
static void _Patch(CodeVariableReferenceExpression vr, CodeDomVisitContext ctx, CodeDomResolver resolver) { if (null != vr) { var scope = resolver.GetScope(vr); if (0 == string.Compare("value", vr.VariableName, StringComparison.InvariantCulture)) { // this could be a property set value reference var p = scope.Member as CodeMemberProperty; if (null != p) { var found = false; for (int ic = p.SetStatements.Count, i = 0; i < ic; ++i) { found = false; CodeDomVisitor.Visit(p.SetStatements[i], (ctx2) => { if (ctx2.Target == vr) { found = true; ctx2.Cancel = true; } }); if (found) { break; } } if (found) { CodeDomVisitor.ReplaceTarget(ctx, new CodePropertySetValueReferenceExpression()); return; } } } CodeTypeReference ctr; if (scope.VariableTypes.TryGetValue(vr.VariableName, out ctr)) { if (!CodeDomResolver.IsNullOrVoidType(ctr)) { vr.UserData.Remove("slang:unresolved"); return; } } // we need to replace it. if (scope.ArgumentTypes.ContainsKey(vr.VariableName)) { var a = new CodeArgumentReferenceExpression(vr.VariableName); CodeDomVisitor.ReplaceTarget(ctx, a); return; //args.Cancel = true; } else if (scope.FieldNames.Contains(vr.VariableName)) { CodeTypeReference tref; // find out where it belongs. if (scope.ThisTargets.Contains(vr.VariableName)) { var f = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), vr.VariableName); CodeDomVisitor.ReplaceTarget(ctx, f); //return; } else if (scope.TypeTargets.TryGetValue(vr.VariableName, out tref)) { var f = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(tref), vr.VariableName); CodeDomVisitor.ReplaceTarget(ctx, f); //return; } return; } else if (scope.MethodNames.Contains(vr.VariableName)) { CodeTypeReference tref; // find out where it belongs. if (scope.ThisTargets.Contains(vr.VariableName)) { var m = new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), vr.VariableName); CodeDomVisitor.ReplaceTarget(ctx, m); return; //args.Cancel = true; } if (scope.TypeTargets.TryGetValue(vr.VariableName, out tref)) { var m = new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(tref), vr.VariableName); CodeDomVisitor.ReplaceTarget(ctx, m); return; //args.Cancel = true; } } else if (scope.PropertyNames.Contains(vr.VariableName)) { CodeTypeReference tref; // find out where it belongs. if (scope.ThisTargets.Contains(vr.VariableName)) { var p = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), vr.VariableName); CodeDomVisitor.ReplaceTarget(ctx, p); return; //args.Cancel = true; } else if (scope.TypeTargets.TryGetValue(vr.VariableName, out tref)) { var p = new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(tref), vr.VariableName); CodeDomVisitor.ReplaceTarget(ctx, p); return; //args.Cancel = true; } } else if (scope.EventNames.Contains(vr.VariableName)) { CodeTypeReference tref; // find out where it belongs. if (scope.ThisTargets.Contains(vr.VariableName)) { var e = new CodeEventReferenceExpression(new CodeThisReferenceExpression(), vr.VariableName); CodeDomVisitor.ReplaceTarget(ctx, e); return; //args.Cancel = true; } else if (scope.TypeTargets.TryGetValue(vr.VariableName, out tref)) { var e = new CodeEventReferenceExpression(new CodeTypeReferenceExpression(tref), vr.VariableName); CodeDomVisitor.ReplaceTarget(ctx, e); return; //args.Cancel = true; } } return; } return; }
static void _Patch(CodeMemberMethod meth, CodeDomVisitContext ctx, CodeDomResolver resolver) { if (null != meth) { // TODO: make sure the member is actually public if (null == meth.PrivateImplementationType) { var scope = resolver.GetScope(meth); var td = scope.DeclaringType; var binder = new CodeDomBinder(scope); for (int ic = td.BaseTypes.Count, i = 0; i < ic; ++i) { var ctr = td.BaseTypes[i]; var t = resolver.TryResolveType(ctr, scope); if (null != t) { var ma = binder.GetMethodGroup(t, meth.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); if (0 < ma.Length) { var isIface = false; var ttd = t as CodeTypeDeclaration; if (null != ttd) { isIface = ttd.IsInterface; } else { var rrt = t as Type; isIface = rrt.IsInterface; } if (isIface) { var m = binder.SelectMethod(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, ma, _GetParameterTypes(meth.Parameters), null); if (null != m) { meth.ImplementationTypes.Add(ctr); } } } } } } meth.UserData.Remove("slang:unresolved"); if ("Main" == meth.Name && (meth.Attributes & MemberAttributes.ScopeMask) == MemberAttributes.Static) { if (0 == meth.Parameters.Count && null == meth.ReturnType || "System.Void" == meth.ReturnType.BaseType) { var epm = new CodeEntryPointMethod(); epm.Attributes = meth.Attributes; epm.LinePragma = meth.LinePragma; epm.StartDirectives.AddRange(meth.StartDirectives); epm.EndDirectives.AddRange(meth.EndDirectives); epm.Comments.AddRange(meth.Comments); epm.CustomAttributes.AddRange(meth.CustomAttributes); epm.ReturnTypeCustomAttributes.AddRange(meth.ReturnTypeCustomAttributes); epm.TypeParameters.AddRange(meth.TypeParameters); epm.PrivateImplementationType = meth.PrivateImplementationType; epm.ImplementationTypes.AddRange(meth.ImplementationTypes); epm.Name = meth.Name; epm.Statements.AddRange(meth.Statements); CodeDomVisitor.ReplaceTarget(ctx, epm); } } //return; } }
/// <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; } } }