216 lines
7.3 KiB
C#
216 lines
7.3 KiB
C#
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);
|
|
}
|
|
} |