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(); }
/// <summary> /// Gets the next element that has not been resolved /// </summary> /// <param name="compileUnits">The compile units to search</param> /// <returns>A <see cref="CodeObject"/> representing the next code object that needs to be patched</returns> public static CodeObject GetNextUnresolvedElement(IEnumerable <CodeCompileUnit> compileUnits) { CodeObject result = null; foreach (var cu in compileUnits) { CodeDomVisitor.Visit(cu, (ctx) => { var co = ctx.Target as CodeObject; if (null != co) { if (co.UserData.Contains("slang:unresolved")) { result = co; ctx.Cancel = true; } } }); if (null != result) { return(result); } } return(null); }
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 RunTemplate() { // compute the primes. algorithm borrowed // from SLax at https://stackoverflow.com/questions/1510124/program-to-find-prime-numbers var primesMax = 100; var primesArr = Enumerable.Range(0, (int)Math.Floor(2.52 * Math.Sqrt(primesMax) / Math.Log(primesMax))).Aggregate( Enumerable.Range(2, primesMax - 1).ToList(), (result, index) => { var bp = result[index]; var sqr = bp * bp; result.RemoveAll(i => i >= sqr && i % bp == 0); return(result); } ).ToArray(); // read the template into the compile unit CodeCompileUnit ccu; using (var stm = File.OpenRead(@"..\..\Template.cs")) ccu = SlangParser.ReadCompileUnitFrom(stm); // patch it either before or after modifying it SlangPatcher.Patch(ccu); // find the target namespace and change it var ns = ccu.TryGetNamespace("T_NAMESPACE"); ns.Name = "TestNS"; // find the target class var type = ns.TryGetType("T_TYPE"); // change the name type.Name = "TestPrimes"; // get the Primes field: var primes = type.TryGetMember("Primes") as CodeMemberField; // change the init expression to the primes array primes.InitExpression = CU.Literal(primesArr); // fixup any references to T_NAMESPACE or T_TYPE CodeDomVisitor.Visit(ccu, (ctx) => { var ctr = ctx.Target as CodeTypeReference; if (null != ctr) { ctr.BaseType = ctr.BaseType.Replace("T_NAMESPACE", ns.Name).Replace("T_TYPE", type.Name); } }); // already patched prior // SlangPatcher.Patch(ccu); // now write the result out Console.WriteLine(CU.ToString(ccu)); }
private static void _FillTypeMap(CodeNamespace codeNamespace, Dictionary <string, CodeTypeDeclaration> typeMap) { CodeDomVisitor.Visit(codeNamespace, (ctx) => { var td = ctx.Target as CodeTypeDeclaration; if (null != td) { foreach (CodeAttributeDeclaration decl in td.CustomAttributes) { if (0 == string.Compare("System.Xml.Serialization.XmlTypeAttribute", decl.AttributeType.BaseType, StringComparison.InvariantCulture)) { typeMap.Add(td.Name, td); break; } } } }, CodeDomVisitTargets.Types); }
static bool _HasUnresolved(CodeObject target) { if (target.UserData.Contains("slang:unresolved")) { return(true); } var result = false; CodeDomVisitor.Visit(target, (ctx) => { var co = ctx.Target as CodeObject; if (null != co && co.UserData.Contains("slang:unresolved")) { result = true; ctx.Cancel = true; } }); return(result); }
private static void _FillPropFldMaps(CodeTypeDeclaration td, HashSet <string> propElem, HashSet <string> propAttr, Dictionary <string, string> fldMap) { CodeDomVisitor.Visit(td, (ctx) => { var prop = ctx.Target as CodeMemberProperty; if (null != prop) { foreach (CodeAttributeDeclaration decl in prop.CustomAttributes) { var isAttr = 0 == string.Compare("System.Xml.Serialization.XmlAttributeAttribute", decl.AttributeType.BaseType, StringComparison.InvariantCulture); var isElem = !isAttr && 0 == string.Compare("System.Xml.Serialization.XmlElementAttribute", decl.AttributeType.BaseType, StringComparison.InvariantCulture); if (isAttr || isElem) { if (0 < prop.GetStatements.Count) { var mr = prop.GetStatements[0] as CodeMethodReturnStatement; if (null != mr) { var fr = mr.Expression as CodeFieldReferenceExpression; if (null != fr) { fldMap.Add(fr.FieldName, prop.Name); if (isElem) { propElem.Add(prop.Name); } if (isAttr) { propAttr.Add(prop.Name); } } } } break; } } } }, CodeDomVisitTargets.Types | CodeDomVisitTargets.Members); }
/// <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(); 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 CodeVariableReferenceExpression, ctx, resolver); _Patch(ctx.Target as CodeDelegateInvokeExpression, ctx, resolver); _Patch(ctx.Target as CodeObjectCreateExpression, 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 CodeTypeReference, ctx, resolver); } }); } resolver.Refresh(); } }
static void Demo3(CodeCompileUnit ccu) { /// now let's take our code and modify it CodeDomVisitor.Visit(ccu, (ctx) => { // we're looking for a method invocation var mi = ctx.Target as CodeMethodInvokeExpression; if (null != mi) { // ... calling WriteLine if ("WriteLine" == mi.Method?.MethodName) { // replace the passed in expression with "Hello world!" mi.Parameters.Clear(); mi.Parameters.Add(new CodePrimitiveExpression("Hello world!")); // done after the first WriteLine so we cancel ctx.Cancel = true; } } }); Console.WriteLine(CodeDomUtility.ToString(ccu)); Console.WriteLine("Press any key..."); Console.ReadKey(); Console.Clear(); }
public static int Run(string[] args, TextReader stdin, TextWriter stdout, TextWriter stderr) { // our return code var result = 0; // app parameters string inputfile = null; string outputfile = null; string codeclass = null; string codelanguage = null; string codenamespace = null; string externaltoken = null; string nfagraph = null; string dfagraph = null; bool ignorecase = false; bool noshared = false; bool ifstale = false; // our working variables TextReader input = null; TextWriter output = null; try { if (0 == args.Length) { _PrintUsage(stderr); result = -1; } else if (args[0].StartsWith("/")) { throw new ArgumentException("Missing input file."); } else { // process the command line args inputfile = args[0]; for (var i = 1; i < args.Length; ++i) { switch (args[i].ToLowerInvariant()) { case "/output": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance outputfile = args[i]; break; case "/class": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance codeclass = args[i]; break; case "/language": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance codelanguage = args[i]; break; case "/namespace": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance codenamespace = args[i]; break; case "/external": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance externaltoken = args[i]; break; case "/nfagraph": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance nfagraph = args[i]; break; case "/dfagraph": if (args.Length - 1 == i) // check if we're at the end { throw new ArgumentException(string.Format("The parameter \"{0}\" is missing an argument", args[i].Substring(1))); } ++i; // advance dfagraph = args[i]; break; case "/ignorecase": ignorecase = true; break; case "/noshared": noshared = true; break; case "/ifstale": ifstale = true; break; default: throw new ArgumentException(string.Format("Unknown switch {0}", args[i])); } } // now build it if (string.IsNullOrEmpty(codeclass)) { // default we want it to be named after the code file // otherwise we'll use inputfile if (null != outputfile) { codeclass = Path.GetFileNameWithoutExtension(outputfile); } else { codeclass = Path.GetFileNameWithoutExtension(inputfile); } } if (string.IsNullOrEmpty(codelanguage)) { if (!string.IsNullOrEmpty(outputfile)) { codelanguage = Path.GetExtension(outputfile); if (codelanguage.StartsWith(".")) { codelanguage = codelanguage.Substring(1); } } if (string.IsNullOrEmpty(codelanguage)) { codelanguage = "cs"; } } var stale = true; if (ifstale && null != outputfile) { stale = _IsStale(inputfile, outputfile); if (!stale) { stale = _IsStale(CodeBase, outputfile); } } if (!stale) { stderr.WriteLine("{0} skipped building {1} because it was not stale.", Name, outputfile); } else { if (null != outputfile) { stderr.Write("{0} is building file: {1}", Name, outputfile); } else { stderr.Write("{0} is building tokenizer.", Name); } input = new StreamReader(inputfile); var rules = new List <LexRule>(); string line; while (null != (line = input.ReadLine())) { var lc = LexContext.Create(line); lc.TrySkipCCommentsAndWhiteSpace(); if (-1 != lc.Current) { rules.Add(LexRule.Parse(lc)); } } input.Close(); input = null; LexRule.FillRuleIds(rules); var ccu = new CodeCompileUnit(); var cns = new CodeNamespace(); if (!string.IsNullOrEmpty(codenamespace)) { cns.Name = codenamespace; } ccu.Namespaces.Add(cns); var fa = _BuildLexer(rules, ignorecase, inputfile); var symbolTable = _BuildSymbolTable(rules); var symids = new int[symbolTable.Length]; for (var i = 0; i < symbolTable.Length; ++i) { symids[i] = i; } var blockEnds = _BuildBlockEnds(rules); var nodeFlags = _BuildNodeFlags(rules); if (null != nfagraph) { fa.RenderToFile(nfagraph); } fa = fa.ToDfa(); DfaEntry[] dfaTable = null; dfaTable = _ToDfaStateTable(fa, symids); if (!noshared) { if (string.IsNullOrEmpty(externaltoken)) { // import our Export/Token.cs into the library _ImportCompileUnit(Deslanged.Token, cns); } // import our Export/TableTokenizer.cs into the library _ImportCompileUnit(Deslanged.TableTokenizer, cns); } if (!string.IsNullOrEmpty(externaltoken)) { cns.Imports.Add(new CodeNamespaceImport(externaltoken)); } var origName = "Rolex."; CodeTypeDeclaration td = null; if (null == td) { td = Deslanged.TableTokenizerTemplate.Namespaces[1].Types[0]; origName += td.Name; td.Name = codeclass; CodeGenerator.GenerateSymbolConstants(td, symbolTable); } CodeDomVisitor.Visit(td, (ctx) => { var tr = ctx.Target as CodeTypeReference; if (null != tr) { if (0 == string.Compare(origName, tr.BaseType, StringComparison.InvariantCulture)) { tr.BaseType = codeclass; } } }); CodeMemberField f = null; f = CodeDomUtility.GetByName("DfaTable", td.Members) as CodeMemberField; f.InitExpression = CodeGenerator.GenerateDfaTableInitializer(dfaTable); f = CodeDomUtility.GetByName("NodeFlags", td.Members) as CodeMemberField; f.InitExpression = CodeDomUtility.Literal(nodeFlags); f = CodeDomUtility.GetByName("BlockEnds", td.Members) as CodeMemberField; f.InitExpression = CodeDomUtility.Literal(blockEnds); cns.Types.Add(td); var hasColNS = false; foreach (CodeNamespaceImport nsi in cns.Imports) { if (0 == string.Compare(nsi.Namespace, "System.Collections.Generic", StringComparison.InvariantCulture)) { hasColNS = true; break; } } if (!hasColNS) { cns.Imports.Add(new CodeNamespaceImport("System.Collections.Generic")); } stderr.WriteLine(); var prov = CodeDomProvider.CreateProvider(codelanguage); var opts = new CodeGeneratorOptions(); opts.BlankLinesBetweenMembers = false; opts.VerbatimOrder = true; if (null == outputfile) { output = stdout; } else { // open the file and truncate it if necessary var stm = File.Open(outputfile, FileMode.Create); stm.SetLength(0); output = new StreamWriter(stm); } prov.GenerateCodeFromCompileUnit(ccu, output, opts); } } } // we don't like to catch in debug mode #if !DEBUG catch (Exception ex) { result = _ReportError(ex, stderr); } #endif finally { // close the input file if necessary if (null != input) { input.Close(); } // close the output file if necessary if (null != outputfile && null != output) { output.Close(); } } return(result); }
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 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)); }