private KecaknoahScriptMethodInfo PrecompileFunction(KecaknoahFunctionAstNode ast) { var al = ast.Parameters; var result = new KecaknoahScriptMethodInfo(ast.Name, ast.Parameters.Count, ast.AllowsVariableArguments); result.Codes = new KecaknoahIL(); var b = PrecompileBlock(ast.Children, "").ToList(); foreach (var i in b.Where(p => p.Type == KecaknoahILCodeType.Jump || p.Type == KecaknoahILCodeType.FalseJump || p.Type == KecaknoahILCodeType.TrueJump)) { i.IntegerValue = b.FindIndex(p => p.Type == KecaknoahILCodeType.Label && p.StringValue == i.StringValue); } foreach (var i in b.Where(p => p.Type == KecaknoahILCodeType.Label)) i.Type = KecaknoahILCodeType.Nop; if (b.Any(p => (p.Type == KecaknoahILCodeType.Jump || p.Type == KecaknoahILCodeType.FalseJump || p.Type == KecaknoahILCodeType.TrueJump) && p.IntegerValue == -1)) { throw new InvalidOperationException("対応していないラベルがあります"); } result.Codes.PushCodes(b); foreach (var i in result.Codes.Codes) { if (i.Type == KecaknoahILCodeType.LoadObject && al.Contains(i.StringValue)) { i.Type = KecaknoahILCodeType.PushArgument; i.IntegerValue = al.IndexOf(i.StringValue); } } return result; }
private KecaknoahScriptMethodInfo PrecompileFunction(KecaknoahFunctionAstNode ast) { var al = ast.Parameters; var result = new KecaknoahScriptMethodInfo(ast.Name, ast.Parameters.Count, ast.AllowsVariableArguments); result.Codes = new KecaknoahIL(); var b = PrecompileBlock(ast.Children, "").ToList(); foreach (var i in b.Where(p => p.Type == KecaknoahILCodeType.Jump || p.Type == KecaknoahILCodeType.FalseJump || p.Type == KecaknoahILCodeType.TrueJump)) { i.IntegerValue = b.FindIndex(p => p.Type == KecaknoahILCodeType.Label && p.StringValue == i.StringValue); } foreach (var i in b.Where(p => p.Type == KecaknoahILCodeType.Label)) { i.Type = KecaknoahILCodeType.Nop; } if (b.Any(p => (p.Type == KecaknoahILCodeType.Jump || p.Type == KecaknoahILCodeType.FalseJump || p.Type == KecaknoahILCodeType.TrueJump) && p.IntegerValue == -1)) { throw new InvalidOperationException("対応していないラベルがあります"); } result.Codes.PushCodes(b); foreach (var i in result.Codes.Codes) { if (i.Type == KecaknoahILCodeType.LoadObject && al.Contains(i.StringValue)) { i.Type = KecaknoahILCodeType.PushArgument; i.IntegerValue = al.IndexOf(i.StringValue); } } return(result); }
static IList<string> AssembleFunction(KecaknoahScriptMethodInfo info) { var result = new List<string>(); result.Add($".function {info.Name}"); foreach (var i in info.Codes.Codes) { result.Add(" " + i.ToString()); } return result; }
/// <summary> /// メソッドを追加します。 /// </summary> /// <param name="method">追加するメソッド</param> internal void AddClassMethod(KecaknoahScriptMethodInfo method) { classMethods.Add(method); }
/// <summary> /// メソッドを追加します。 /// </summary> /// <param name="method">追加するメソッド</param> internal void AddInstanceMethod(KecaknoahScriptMethodInfo method) { methods.Add(method); }
private IList <KecaknoahILCode> PrecompileExpression(KecaknoahAstNode node) { var result = new List <KecaknoahILCode>(); if (node.Type != KecaknoahAstNodeType.Expression) { throw new ArgumentException("ASTが式でない件について"); } var en = node as KecaknoahExpressionAstNode; if (en is KecaknoahBinaryExpressionAstNode) { var exp = en as KecaknoahBinaryExpressionAstNode; result.AddRange(PrecompileBinaryExpression(exp)); } else if (en is KecaknoahFactorExpressionAstNode) { var exp = en as KecaknoahFactorExpressionAstNode; switch (exp.FactorType) { case KecaknoahFactorType.IntegerValue: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushInteger, IntegerValue = exp.IntegerValue }); break; case KecaknoahFactorType.SingleValue: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushDouble, FloatValue = exp.SingleValue }); break; case KecaknoahFactorType.DoubleValue: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushDouble, FloatValue = exp.DoubleValue }); break; case KecaknoahFactorType.StringValue: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushString, StringValue = exp.StringValue }); break; case KecaknoahFactorType.BooleanValue: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushBoolean, BooleanValue = exp.BooleanValue }); break; case KecaknoahFactorType.Nil: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushNil }); break; case KecaknoahFactorType.Identifer: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = exp.StringValue }); break; case KecaknoahFactorType.ParenExpression: result.AddRange(PrecompileExpression(exp.ExpressionNode)); break; case KecaknoahFactorType.CoroutineResume: if (exp.BooleanValue) { // state = coresume(cor, val) result.AddRange(PrecompileExpression(exp.ExpressionNode)); } result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.ResumeCoroutine, StringValue = exp.StringValue, BooleanValue = exp.BooleanValue }); break; case KecaknoahFactorType.Array: foreach (var i in exp.ElementNodes) { result.AddRange(PrecompileExpression(i)); } result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.MakeArray, IntegerValue = exp.ElementNodes.Count }); break; case KecaknoahFactorType.Lambda: var lma = exp.ElementNodes.Select(p => ((KecaknoahFactorExpressionAstNode)p).StringValue).ToList(); var name = $"Lambda-{Guid.NewGuid().ToString().Substring(0, 17)}"; var func = new KecaknoahScriptMethodInfo(name); var eil = PrecompileExpression(exp.ExpressionNode); eil.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Return }); foreach (var i in eil.Where(p => p.Type == KecaknoahILCodeType.LoadObject && lma.Contains(p.StringValue))) { i.Type = KecaknoahILCodeType.PushArgument; i.IntegerValue = lma.IndexOf(i.StringValue); } func.Codes = new KecaknoahIL(); func.Codes.PushCodes(eil); if (cuc.Count == 0) { current.methods.Add(func); } else { cuc.Peek().AddInstanceMethod(func); } result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = name }); break; } } else if (en is KecaknoahArgumentCallExpressionAstNode) { var exp = en as KecaknoahArgumentCallExpressionAstNode; if (exp.Target is KecaknoahFactorExpressionAstNode && (exp.Target as KecaknoahFactorExpressionAstNode).FactorType == KecaknoahFactorType.VariableArguments) { //vargs foreach (var arg in exp.Arguments) { result.AddRange(PrecompileExpression(arg)); } result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadVarg, IntegerValue = exp.Arguments.Count }); } else { if (exp.ExpressionType == KecaknoahOperatorType.IndexerAccess) { result.AddRange(PrecompileIndexerCall(exp)); } else { result.AddRange(PrecompileFunctionCall(exp)); } } } else if (en is KecaknoahMemberAccessExpressionAstNode) { var exp = en as KecaknoahMemberAccessExpressionAstNode; result.AddRange(PrecompileExpression(exp.Target)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadMember, StringValue = exp.MemberName }); } else if (en is KecaknoahPrimaryExpressionAstNode) { var exp = en as KecaknoahPrimaryExpressionAstNode; //後置 switch (exp.ExpressionType) { case KecaknoahOperatorType.Increment: result.AddRange(PrecompileSuffixIncrement(exp)); break; case KecaknoahOperatorType.Decrement: result.AddRange(PrecompileSuffixDecrement(exp)); break; default: throw new NotImplementedException("多分実装してない1次式なんだと思う"); } result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Pop }); } else if (en is KecaknoahUnaryExpressionAstNode) { var exp = en as KecaknoahUnaryExpressionAstNode; switch (exp.ExpressionType) { case KecaknoahOperatorType.Minus: result.AddRange(PrecompileExpression(exp.Target)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Negative }); break; case KecaknoahOperatorType.Not: result.AddRange(PrecompileExpression(exp.Target)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Not }); break; case KecaknoahOperatorType.Increment: result.AddRange(PrecompilePrefixIncrement(exp)); break; case KecaknoahOperatorType.Decrement: result.AddRange(PrecompilePrefixDecrement(exp)); break; } } else { throw new InvalidOperationException("ごめん何言ってるかさっぱりわかんない"); } return(result); }
private static KecaknoahScriptMethodInfo ReadMethod(BinaryReader reader) { string name = null; var length = 0; var vargs = false; while (true) { switch ((MethodElementType)reader.ReadByte()) { case MethodElementType.Name: name = reader.ReadString(); break; case MethodElementType.ArgumentLength: length = reader.ReadInt32(); break; case MethodElementType.VariableArgument: vargs = true; break; case MethodElementType.StartCode: var method = new KecaknoahScriptMethodInfo(name, length, vargs); var il = new KecaknoahIL(); method.Codes = il; var count = reader.ReadInt32(); for (var i = 0; i < count; i++) { switch (reader.ReadByte()) { case 0: il.PushCode(KecaknoahILCodeType.Nop); break; case 1: il.PushCode(KecaknoahILCodeType.PushInteger, reader.ReadInt64()); break; case 2: il.PushCode(KecaknoahILCodeType.PushString, reader.ReadString()); break; case 3: il.PushCode(KecaknoahILCodeType.PushSingle, reader.ReadSingle()); break; case 4: il.PushCode(KecaknoahILCodeType.PushDouble, reader.ReadDouble()); break; case 5: il.PushCode(KecaknoahILCodeType.PushBoolean, false); break; case 6: il.PushCode(KecaknoahILCodeType.PushBoolean, true); break; case 7: il.PushCode(KecaknoahILCodeType.PushNil); break; case 8: il.PushCode(KecaknoahILCodeType.Pop); break; case 9: il.PushCode(KecaknoahILCodeType.Plus); break; case 10: il.PushCode(KecaknoahILCodeType.Minus); break; case 11: il.PushCode(KecaknoahILCodeType.Multiply); break; case 12: il.PushCode(KecaknoahILCodeType.Divide); break; case 13: il.PushCode(KecaknoahILCodeType.Modular); break; case 14: il.PushCode(KecaknoahILCodeType.And); break; case 15: il.PushCode(KecaknoahILCodeType.Or); break; case 16: il.PushCode(KecaknoahILCodeType.Xor); break; case 17: il.PushCode(KecaknoahILCodeType.Not); break; case 18: il.PushCode(KecaknoahILCodeType.Negative); break; case 19: il.PushCode(KecaknoahILCodeType.AndAlso); break; case 20: il.PushCode(KecaknoahILCodeType.OrElse); break; case 21: il.PushCode(KecaknoahILCodeType.LeftBitShift); break; case 22: il.PushCode(KecaknoahILCodeType.RightBitShift); break; case 23: il.PushCode(KecaknoahILCodeType.Equal); break; case 24: il.PushCode(KecaknoahILCodeType.NotEqual); break; case 25: il.PushCode(KecaknoahILCodeType.Greater); break; case 26: il.PushCode(KecaknoahILCodeType.Lesser); break; case 27: il.PushCode(KecaknoahILCodeType.GreaterEqual); break; case 28: il.PushCode(KecaknoahILCodeType.LesserEqual); break; case 29: il.PushCode(KecaknoahILCodeType.Assign); break; case 30: il.PushCode(KecaknoahILCodeType.Jump, reader.ReadInt32()); break; case 31: il.PushCode(KecaknoahILCodeType.TrueJump, reader.ReadInt32()); break; case 32: il.PushCode(KecaknoahILCodeType.FalseJump, reader.ReadInt32()); break; case 33: il.PushCode(KecaknoahILCodeType.Return); break; case 34: il.PushCode(KecaknoahILCodeType.Yield); break; case 35: il.PushCode(KecaknoahILCodeType.Call, reader.ReadInt32()); break; case 36: il.PushCode(KecaknoahILCodeType.IndexerCall, reader.ReadInt32()); break; case 37: il.PushCode(KecaknoahILCodeType.PushArgument, reader.ReadInt32()); break; case 38: il.PushCode(KecaknoahILCodeType.LoadObject, reader.ReadString()); break; case 39: il.PushCode(KecaknoahILCodeType.LoadMember, reader.ReadString()); break; case 40: il.PushCode(KecaknoahILCodeType.AsValue); break; case 41: il.PushCode(KecaknoahILCodeType.LoadVarg, reader.ReadInt32()); break; case 42: var code = new KecaknoahILCode() { Type = KecaknoahILCodeType.StartCoroutine }; code.StringValue = reader.ReadString(); code.IntegerValue = reader.ReadInt32(); il.PushCode(code); break; case 43: il.PushCode(new KecaknoahILCode() { Type = KecaknoahILCodeType.ResumeCoroutine, StringValue = reader.ReadString(), BooleanValue = false }); break; case 44: il.PushCode(new KecaknoahILCode() { Type = KecaknoahILCodeType.ResumeCoroutine, StringValue = reader.ReadString(), BooleanValue = true }); break; case 45: il.PushCode(KecaknoahILCodeType.MakeArray, reader.ReadInt32()); break; case 46: il.PushCode(KecaknoahILCodeType.PlusAssign); break; case 47: il.PushCode(KecaknoahILCodeType.MinusAssign); break; case 48: il.PushCode(KecaknoahILCodeType.MultiplyAssign); break; case 49: il.PushCode(KecaknoahILCodeType.DivideAssign); break; case 50: il.PushCode(KecaknoahILCodeType.AndAssign); break; case 51: il.PushCode(KecaknoahILCodeType.OrAssign); break; case 52: il.PushCode(KecaknoahILCodeType.XorAssign); break; case 53: il.PushCode(KecaknoahILCodeType.ModularAssign); break; case 54: il.PushCode(KecaknoahILCodeType.LeftBitShiftAssign); break; case 55: il.PushCode(KecaknoahILCodeType.RightBitShiftAssign); break; case 56: il.PushCode(KecaknoahILCodeType.NilAssign); break; default: throw new InvalidDataException("危険オペコードにはダマされない!!近づかない!!"); } } return method; default: throw new InvalidDataException("無効なメソッド"); } } }
private static void WriteMethod(KecaknoahScriptMethodInfo method, BinaryWriter writer) { writer.Write((byte)MethodElementType.Name); writer.Write(method.Name); writer.Write((byte)MethodElementType.ArgumentLength); writer.Write(method.ArgumentLength); if (method.VariableArgument) writer.Write((byte)MethodElementType.VariableArgument); writer.Write((byte)MethodElementType.StartCode); var codes = method.Codes.Codes; writer.Write(codes.Count); foreach (var x in codes) { switch (x.Type) { case KecaknoahILCodeType.Nop: writer.Write((byte)0); break; case KecaknoahILCodeType.Label: goto case KecaknoahILCodeType.Nop; case KecaknoahILCodeType.PushInteger: writer.Write((byte)1); writer.Write(x.IntegerValue); break; case KecaknoahILCodeType.PushString: writer.Write((byte)2); writer.Write(x.StringValue); break; case KecaknoahILCodeType.PushSingle: writer.Write((byte)3); writer.Write((float)x.FloatValue); break; case KecaknoahILCodeType.PushDouble: writer.Write((byte)4); writer.Write(x.FloatValue); break; case KecaknoahILCodeType.PushBoolean: writer.Write(x.BooleanValue ? (byte)6 : (byte)5); break; case KecaknoahILCodeType.PushNil: writer.Write((byte)7); break; case KecaknoahILCodeType.Pop: writer.Write((byte)8); break; case KecaknoahILCodeType.Plus: writer.Write((byte)9); break; case KecaknoahILCodeType.Minus: writer.Write((byte)10); break; case KecaknoahILCodeType.Multiply: writer.Write((byte)11); break; case KecaknoahILCodeType.Divide: writer.Write((byte)12); break; case KecaknoahILCodeType.Modular: writer.Write((byte)13); break; case KecaknoahILCodeType.And: writer.Write((byte)14); break; case KecaknoahILCodeType.Or: writer.Write((byte)15); break; case KecaknoahILCodeType.Xor: writer.Write((byte)16); break; case KecaknoahILCodeType.Not: writer.Write((byte)17); break; case KecaknoahILCodeType.Negative: writer.Write((byte)18); break; case KecaknoahILCodeType.AndAlso: writer.Write((byte)19); break; case KecaknoahILCodeType.OrElse: writer.Write((byte)20); break; case KecaknoahILCodeType.LeftBitShift: writer.Write((byte)21); break; case KecaknoahILCodeType.RightBitShift: writer.Write((byte)22); break; case KecaknoahILCodeType.Equal: writer.Write((byte)23); break; case KecaknoahILCodeType.NotEqual: writer.Write((byte)24); break; case KecaknoahILCodeType.Greater: writer.Write((byte)25); break; case KecaknoahILCodeType.Lesser: writer.Write((byte)26); break; case KecaknoahILCodeType.GreaterEqual: writer.Write((byte)27); break; case KecaknoahILCodeType.LesserEqual: writer.Write((byte)28); break; case KecaknoahILCodeType.Assign: writer.Write((byte)29); break; case KecaknoahILCodeType.Jump: writer.Write((byte)30); writer.Write((int)x.IntegerValue); break; case KecaknoahILCodeType.TrueJump: writer.Write((byte)31); writer.Write((int)x.IntegerValue); break; case KecaknoahILCodeType.FalseJump: writer.Write((byte)32); writer.Write((int)x.IntegerValue); break; case KecaknoahILCodeType.Return: writer.Write((byte)33); break; case KecaknoahILCodeType.Yield: writer.Write((byte)34); break; case KecaknoahILCodeType.Call: writer.Write((byte)35); writer.Write((int)x.IntegerValue); break; case KecaknoahILCodeType.IndexerCall: writer.Write((byte)36); writer.Write((int)x.IntegerValue); break; case KecaknoahILCodeType.PushArgument: writer.Write((byte)37); writer.Write((int)x.IntegerValue); break; case KecaknoahILCodeType.LoadObject: writer.Write((byte)38); writer.Write(x.StringValue); break; case KecaknoahILCodeType.LoadMember: writer.Write((byte)39); writer.Write(x.StringValue); break; case KecaknoahILCodeType.AsValue: writer.Write((byte)40); break; case KecaknoahILCodeType.LoadVarg: writer.Write((byte)41); writer.Write((int)x.IntegerValue); break; case KecaknoahILCodeType.StartCoroutine: writer.Write((byte)42); writer.Write(x.StringValue); writer.Write((int)x.IntegerValue); break; case KecaknoahILCodeType.ResumeCoroutine: writer.Write(x.BooleanValue ? (byte)44 : (byte)43); writer.Write(x.StringValue); break; case KecaknoahILCodeType.MakeArray: writer.Write((byte)45); writer.Write((int)x.IntegerValue); break; case KecaknoahILCodeType.PlusAssign: writer.Write((byte)46); break; case KecaknoahILCodeType.MinusAssign: writer.Write((byte)47); break; case KecaknoahILCodeType.MultiplyAssign: writer.Write((byte)48); break; case KecaknoahILCodeType.DivideAssign: writer.Write((byte)49); break; case KecaknoahILCodeType.AndAssign: writer.Write((byte)50); break; case KecaknoahILCodeType.OrAssign: writer.Write((byte)51); break; case KecaknoahILCodeType.XorAssign: writer.Write((byte)52); break; case KecaknoahILCodeType.ModularAssign: writer.Write((byte)53); break; case KecaknoahILCodeType.LeftBitShiftAssign: writer.Write((byte)54); break; case KecaknoahILCodeType.RightBitShiftAssign: writer.Write((byte)55); break; case KecaknoahILCodeType.NilAssign: writer.Write((byte)56); break; default: throw new InvalidDataException("In Kecaknoah, please"); } } }
private IList<KecaknoahILCode> PrecompileExpression(KecaknoahAstNode node) { var result = new List<KecaknoahILCode>(); if (node.Type != KecaknoahAstNodeType.Expression) throw new ArgumentException("ASTが式でない件について"); var en = node as KecaknoahExpressionAstNode; if (en is KecaknoahBinaryExpressionAstNode) { var exp = en as KecaknoahBinaryExpressionAstNode; result.AddRange(PrecompileBinaryExpression(exp)); } else if (en is KecaknoahFactorExpressionAstNode) { var exp = en as KecaknoahFactorExpressionAstNode; switch (exp.FactorType) { case KecaknoahFactorType.IntegerValue: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushInteger, IntegerValue = exp.IntegerValue }); break; case KecaknoahFactorType.SingleValue: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushDouble, FloatValue = exp.SingleValue }); break; case KecaknoahFactorType.DoubleValue: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushDouble, FloatValue = exp.DoubleValue }); break; case KecaknoahFactorType.StringValue: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushString, StringValue = exp.StringValue }); break; case KecaknoahFactorType.BooleanValue: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushBoolean, BooleanValue = exp.BooleanValue }); break; case KecaknoahFactorType.Nil: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushNil }); break; case KecaknoahFactorType.Identifer: result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = exp.StringValue }); break; case KecaknoahFactorType.ParenExpression: result.AddRange(PrecompileExpression(exp.ExpressionNode)); break; case KecaknoahFactorType.CoroutineResume: if (exp.BooleanValue) { // state = coresume(cor, val) result.AddRange(PrecompileExpression(exp.ExpressionNode)); } result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.ResumeCoroutine, StringValue = exp.StringValue, BooleanValue = exp.BooleanValue }); break; case KecaknoahFactorType.Array: foreach (var i in exp.ElementNodes) result.AddRange(PrecompileExpression(i)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.MakeArray, IntegerValue = exp.ElementNodes.Count }); break; case KecaknoahFactorType.Lambda: var lma = exp.ElementNodes.Select(p => ((KecaknoahFactorExpressionAstNode)p).StringValue).ToList(); var name = $"Lambda-{Guid.NewGuid().ToString().Substring(0, 17)}"; var func = new KecaknoahScriptMethodInfo(name); var eil = PrecompileExpression(exp.ExpressionNode); eil.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Return }); foreach (var i in eil.Where(p => p.Type == KecaknoahILCodeType.LoadObject && lma.Contains(p.StringValue))) { i.Type = KecaknoahILCodeType.PushArgument; i.IntegerValue = lma.IndexOf(i.StringValue); } func.Codes = new KecaknoahIL(); func.Codes.PushCodes(eil); if (cuc.Count == 0) { current.methods.Add(func); } else { cuc.Peek().AddInstanceMethod(func); } result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = name }); break; } } else if (en is KecaknoahArgumentCallExpressionAstNode) { var exp = en as KecaknoahArgumentCallExpressionAstNode; if (exp.Target is KecaknoahFactorExpressionAstNode && (exp.Target as KecaknoahFactorExpressionAstNode).FactorType == KecaknoahFactorType.VariableArguments) { //vargs foreach (var arg in exp.Arguments) result.AddRange(PrecompileExpression(arg)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadVarg, IntegerValue = exp.Arguments.Count }); } else { if (exp.ExpressionType == KecaknoahOperatorType.IndexerAccess) { result.AddRange(PrecompileIndexerCall(exp)); } else { result.AddRange(PrecompileFunctionCall(exp)); } } } else if (en is KecaknoahMemberAccessExpressionAstNode) { var exp = en as KecaknoahMemberAccessExpressionAstNode; result.AddRange(PrecompileExpression(exp.Target)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadMember, StringValue = exp.MemberName }); } else if (en is KecaknoahPrimaryExpressionAstNode) { var exp = en as KecaknoahPrimaryExpressionAstNode; //後置 switch (exp.ExpressionType) { case KecaknoahOperatorType.Increment: result.AddRange(PrecompileSuffixIncrement(exp)); break; case KecaknoahOperatorType.Decrement: result.AddRange(PrecompileSuffixDecrement(exp)); break; default: throw new NotImplementedException("多分実装してない1次式なんだと思う"); } result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Pop }); } else if (en is KecaknoahUnaryExpressionAstNode) { var exp = en as KecaknoahUnaryExpressionAstNode; switch (exp.ExpressionType) { case KecaknoahOperatorType.Minus: result.AddRange(PrecompileExpression(exp.Target)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Negative }); break; case KecaknoahOperatorType.Not: result.AddRange(PrecompileExpression(exp.Target)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Not }); break; case KecaknoahOperatorType.Increment: result.AddRange(PrecompilePrefixIncrement(exp)); break; case KecaknoahOperatorType.Decrement: result.AddRange(PrecompilePrefixDecrement(exp)); break; } } else { throw new InvalidOperationException("ごめん何言ってるかさっぱりわかんない"); } return result; }
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; }
private IList<KecaknoahILCode> PrecompileClassLambda(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); } } } var ln = $"Lambda-{Guid.NewGuid().ToString().Substring(0, 17)}"; ; var mi = new KecaknoahScriptMethodInfo(ln, lma.Count, false); var lc = new KecaknoahIL(); lc.PushCodes(il); mi.Codes = lc; var result = new List<KecaknoahILCode>(); current.methods.Add(mi); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = ln }); return result; }