private static void WriteClass(KecaknoahScriptClassInfo klass, BinaryWriter writer) { writer.Write((byte)ClassElementType.Name); writer.Write(klass.Name); writer.Write((byte)ClassElementType.StartBlocks); writer.Write(klass.inners.Count + klass.methods.Count + klass.classMethods.Count + klass.Locals.Count); foreach (var x in klass.inners) { writer.Write((byte)ClassBlockType.InnerClass); WriteClass(x, writer); } foreach (var x in klass.methods) { writer.Write((byte)ClassBlockType.InstanceMethod); WriteMethod(x, writer); } foreach (var x in klass.classMethods) { writer.Write((byte)ClassBlockType.ClassMethod); WriteMethod(x, writer); } foreach (var x in klass.Locals) { writer.Write((byte)ClassBlockType.Local); writer.Write(x); } }
static IList<string> AssembleClass(KecaknoahScriptClassInfo info) { var result = new List<string>(); result.Add($".class {info.Name}"); foreach (var i in info.Locals) { result.Add(" .local" + i); } result.Add(" "); foreach (var i in info.InstanceMethods) { result.AddRange(AssembleFunction(i as KecaknoahScriptMethodInfo).Select(p => " " + p)); result.Add(" "); } foreach (var i in info.ClassMethods) { result.AddRange(AssembleFunction(i as KecaknoahScriptMethodInfo).Select(p => " " + p)); result.Add(" "); } foreach (var i in info.InnerClasses) { result.AddRange(AssembleClass(i as KecaknoahScriptClassInfo).Select(p => " " + p)); result.Add(" "); } return result; }
private KecaknoahScriptClassInfo PrecompileClass(KecaknoahClassAstNode ast) { //TODO: local初期値式対応 var result = new KecaknoahScriptClassInfo(ast.Name); cuc.Push(result); foreach (var i in ast.Functions) { if (i.StaticMethod) { result.AddClassMethod(PrecompileFunction(i)); } else { result.AddInstanceMethod(PrecompileFunction(i)); } } foreach (var i in ast.Locals) { if (i.InitialExpression != null) { var il = new KecaknoahIL(); il.PushCodes(PrecompileExpression(i.InitialExpression)); result.AddLocal(i.Name, il); } else { result.AddLocal(i.Name, null); } } cuc.Pop(); return result; }
/// <summary> /// インナークラスを追加します。 /// </summary> /// <param name="klass">追加するクラス</param> internal void AddInnerClass(KecaknoahScriptClassInfo klass) { if (inners.Any(p => p.Name == klass.Name)) { throw new ArgumentException("同じ名前のインナークラスがすでに存在します。"); } inners.Add(klass); }
private KecaknoahScriptClassInfo PrecompileClass(KecaknoahClassAstNode ast) { //TODO: local初期値式対応 var result = new KecaknoahScriptClassInfo(ast.Name); cuc.Push(result); foreach (var i in ast.Functions) { if (i.StaticMethod) { result.AddClassMethod(PrecompileFunction(i)); } else { result.AddInstanceMethod(PrecompileFunction(i)); } } foreach (var i in ast.Locals) { result.AddLocal(i.Name); } cuc.Pop(); return(result); }
private static KecaknoahScriptClassInfo ReadClass(BinaryReader reader) { string name = null; while (true) { switch ((ClassElementType)reader.ReadByte()) { case ClassElementType.Name: name = reader.ReadString(); break; case ClassElementType.StartBlocks: var klass = new KecaknoahScriptClassInfo(name); var count = reader.ReadInt32(); for (var i = 0; i < count; i++) { switch ((ClassBlockType)reader.ReadByte()) { case ClassBlockType.InnerClass: klass.AddInnerClass(ReadClass(reader)); break; case ClassBlockType.InstanceMethod: klass.AddInstanceMethod(ReadMethod(reader)); break; case ClassBlockType.ClassMethod: klass.AddInstanceMethod(ReadMethod(reader)); break; case ClassBlockType.Local: klass.AddLocal(reader.ReadString(), null); break; default: throw new InvalidDataException("やめて"); } } return klass; default: throw new InvalidDataException("無効なクラス"); } } }
/// <summary> /// インナークラスを追加します。 /// </summary> /// <param name="klass">追加するクラス</param> internal void AddInnerClass(KecaknoahScriptClassInfo klass) { if (inners.Any(p => p.Name == klass.Name)) throw new ArgumentException("同じ名前のインナークラスがすでに存在します。"); inners.Add(klass); }
private IList<KecaknoahILCode> PrecompileLexicalLambda(IList<KecaknoahILCode> il, List<string> lma) { var caps = new List<string>(); for (int i = 0; i < il.Count; i++) { var c = il[i]; if (c.Type == KecaknoahILCodeType.LoadObject) { var name = c.StringValue; if (lma.Contains(name)) { c.Type = KecaknoahILCodeType.PushArgument; c.IntegerValue = lma.IndexOf(name); } else { //キャプチャ対象 c.Type = KecaknoahILCodeType.LoadMember; if (caps.Contains(name)) { c.StringValue = $"cap_{caps.IndexOf(name)}"; } else { c.StringValue = $"cap_{caps.Count}"; caps.Add(name); } il.Insert(i, new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = "self" }); } } } var ln = $"Lambda-{Guid.NewGuid().ToString().Substring(0, 17)}"; var cl = new KecaknoahScriptClassInfo(ln); var ctor = new KecaknoahIL(); for (int i = 0; i < caps.Count; i++) { cl.AddLocal($"cap_{i}", null); ctor.PushCode(KecaknoahILCodeType.LoadObject, "self"); ctor.PushCode(KecaknoahILCodeType.LoadMember, $"cap_{i}"); ctor.PushCode(KecaknoahILCodeType.PushArgument, i); ctor.PushCode(KecaknoahILCodeType.Assign); } var ci = new KecaknoahScriptMethodInfo("new", caps.Count, false); ci.Codes = ctor; cl.AddClassMethod(ci); var fi = new KecaknoahScriptMethodInfo("body", lma.Count, false); fi.Codes = new KecaknoahIL(); fi.Codes.PushCodes(il); cl.AddInstanceMethod(fi); current.classes.Add(cl); var result = new List<KecaknoahILCode>(); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = ln }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadMember, StringValue = "new" }); foreach (var i in caps) result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = i }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Call, IntegerValue = caps.Count }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadMember, StringValue = "body" }); return result; }