singrdk/base/Windows/csic/mkvisitor.cs

216 lines
7.3 KiB
C#
Raw Normal View History

2008-11-17 18:29:00 -05:00
using System;
using System.Collections;
using System.IO;
using System.Diagnostics;
using System.Reflection;
using SysType = System.Type;
public class visitor {
static string classname = "CLASSNAME";
static string args = "ARGTYPE ARG", argnames = "";
static string returntype = "void";
static string modifiers = "";
static bool rewrite = false;
readonly static string progname = Environment.GetCommandLineArgs()[0];
public static void Main(string[] argv) {
int nusage = 0;
TextWriter w = Console.Out;
for (int i = 0; i < argv.Length; i++)
if (argv[i] == "-?") {
Usage();
return;
} else if (argv[i] == "-rewrite") {
rewrite = true;
returntype = "AST";
args = "";
classname = "rewrite";
} else if (argv[i] == "-class" && i+1 < argv.Length)
classname = argv[++i];
else if (argv[i] == "-args" && i+1 < argv.Length)
args = argv[++i];
else if (argv[i] == "-return" && i+1 < argv.Length)
returntype = argv[++i];
else if (argv[i] == "-out" && i+1 < argv.Length) {
if (w != Console.Out)
w.Close();
try {
w = new StreamWriter(argv[++i]);
} catch (Exception e) {
Console.Error.WriteLine("{0}: can't write \"{1}\": {2}", progname, argv[i], e.Message);
w = Console.Out;
}
} else if (argv[i] == "-public" || argv[i] == "-virtual"
|| argv[i] == "-private" || argv[i] == "-static"
|| argv[i] == "-sealed" || argv[i] == "-internal"
|| argv[i] == "-override" || argv[i] == "-abstract"
|| argv[i] == "-protected"|| argv[i] == "-sealed"
|| argv[i] == "-new")
modifiers += argv[i].Substring(1) + " ";
else {
Console.Error.WriteLine("{0}: unrecognized option \"{1}\"", progname, argv[i]);
if (nusage++ == 0)
Usage();
}
if (args != "") {
string[] parms = args.Split(',');
foreach (string arg in parms)
argnames += ", " + arg.Trim().Split(' ')[1];
args = ", " + args;
}
Generate(w);
if (w != Console.Out)
w.Close();
}
static void Usage() {
Console.Error.WriteLine("Usage: {0} [ option ]...\nOptions:", progname);
foreach (string opt in new string[] {"-?", "-rewrite", "-class classname", "-args argument",
"-return typename", "-out filename", "-public", "-virtual", "-private", "-static", "-sealed", "-internal",
"-override", "-abstract", "-protected", "-sealed", "-new"})
Console.Error.WriteLine("\t{0}", opt);
}
static Assembly baseAssembly = Assembly.Load("base");
static SysType[] GetTypes() {
return baseAssembly.GetExportedTypes();
}
static SysType GetType(string name) {
return baseAssembly.GetType(name);
}
class compare : IComparer {
int IComparer.Compare(object x, object y) {
SysType u = (SysType)x, v = (SysType)y;
return u.Name.CompareTo(v.Name);
}
}
static void Generate(TextWriter w) {
w.WriteLine(!rewrite ?
@"using System;
using System.IO;
public class {0} {{
protected TextWriter w;
public {0}(TextWriter w) {{
this.w = w;
}}" : @"using System;
public class {0} {{
virtual public AST match(AST ast) {{
return ast;
}}", classname, args);
ArrayList q = new ArrayList();
foreach (SysType t in GetTypes())
if (InheritsFrom(t, "AST"))
q.Add(t);
q.Sort(new compare());
foreach (SysType t in q)
ProcessType(t, w);
GenerateVisit(GetTypes(), w);
w.WriteLine("}");
}
static void GenerateVisit(SysType[] types, TextWriter w) {
w.WriteLine("\tvirtual public {1} visit(AST ast{0}) {{", args, returntype);
int n = 0;
foreach (SysType t in types)
if (t.BaseType != null && t.BaseType.Name == "AST") {
if (returntype == "void")
w.WriteLine("\t\t{2}if (ast is {0}) {0}(({0})ast{1});", t.Name, argnames, n > 0 ? "else " : " ");
else
w.WriteLine("\t\tif (ast is {0}) return {0}(({0})ast{1});", t.Name, argnames);
n++;
}
w.WriteLine("\t\t{0}throw new ArgumentException();", n > 0 ? "else " : "");
w.WriteLine("\t}");
}
static bool IsAnnotated(FieldInfo f) {
Attribute[] attrs = Attribute.GetCustomAttributes(f, true);
return attrs.Length > 1 || attrs.Length == 1 && !MayBeNull(f);
}
static bool InheritsFrom(SysType t, string name) {
while ((t = t.BaseType) != null)
if (t.Name == name)
return true;
return false;
}
static void ProcessType(SysType t, TextWriter w) {
if (t.IsAbstract && InheritsFrom(t, "AST"))
ProcessAbstractType(t, w);
else if (InheritsFrom(t, "AST"))
ProcessConcreteType(t, w);
}
static void ProcessAbstractType(SysType t, TextWriter w) {
w.WriteLine("\t{3}{2} {0}({0} ast{1}) {{", t.Name, args, returntype, modifiers);
int n = 0;
foreach (SysType u in GetTypes())
if (u.BaseType == t) {
w.Write("\t\t{1}if (ast is {0}) ", u.Name, n > 0 ? "else " : " ");
if (returntype != "void")
w.Write("return ");
w.WriteLine("{0}(({0})ast{1});", u.Name, argnames);
n++;
}
w.WriteLine("\t\t{0}throw new ArgumentException();", n > 0 ? "else " : "");
w.WriteLine("\t}");
}
static void ProcessConcreteType(SysType t, TextWriter w) {
w.WriteLine("\t{3}{2} {0}({0} ast{1}) {{", t.Name, args, returntype, modifiers);
foreach (FieldInfo f in t.GetFields())
if (f.Name != "parent")
ProcessField(f, w);
if (rewrite)
w.WriteLine("\t\treturn match(ast);");
else if (returntype != "void")
w.WriteLine("\t\treturn null;");
w.WriteLine("\t}");
}
static bool MayBeNull(FieldInfo f) {
return Attribute.GetCustomAttribute(f, baseAssembly.GetType("MayBeNullAttribute")) != null;
}
static void ProcessField(FieldInfo f, TextWriter w) {
SysType t = f.FieldType;
if (t.Name.EndsWith("List") && InheritsFrom(t, "CollectionBase")) {
string elemname = t.Name.Substring(0, t.Name.Length - 4);
SysType u = GetType(elemname);
if (u != null && InheritsFrom(u, "AST") && !IsAnnotated(f)) {
string indent = "\t\t";
if (MayBeNull(f)) {
w.WriteLine("\t\tif (ast.{0} != null)", f.Name);
indent += "\t";
}
if (!rewrite) {
w.WriteLine("{2}foreach ({0} x in ast.{1})", elemname, f.Name, indent);
w.WriteLine("{2}\t{0}(x{1});", elemname, argnames, indent);
} else {
w.WriteLine("{1}for (int i = 0; i < ast.{0}.Count; i++)", f.Name, indent);
w.WriteLine("{3}\tast.{1}[i] = ({0}){0}(ast.{1}[i]{2});", elemname, f.Name, argnames, indent);
}
} else if (!rewrite)
CommentField(f, w);
} else if (InheritsFrom(t, "AST") && !IsAnnotated(f)) {
if (MayBeNull(f)) {
w.WriteLine("\t\tif (ast.{0} != null)", f.Name);
w.Write("\t");
}
if (!rewrite)
w.WriteLine("\t\t{0}(ast.{1}{2});", t.Name, f.Name, argnames);
else
w.WriteLine("\t\tast.{1} = ({0}){0}(ast.{1}{2});", t.Name, f.Name, argnames);
} else if (!rewrite)
CommentField(f, w);
}
static void CommentField(FieldInfo f, TextWriter w) {
w.Write("\t\t//");
Attribute[] attrs = Attribute.GetCustomAttributes(f);
if (attrs.Length > 0) {
w.Write(" [");
for (int i = 0; i < attrs.Length; i++) {
if (i > 0)
w.Write(",");
string name = attrs[i].GetType().Name;
if (name.EndsWith("Attribute"))
name = name.Substring(0, name.Length-9);
w.Write("{0}", name);
}
w.Write("]");
}
w.WriteLine(" {0} ast.{1}", f.FieldType.Name, f.Name);
}
}