/// <summary> /// 指定した<see cref="KecaknoahIL"/>を式として実行し、<see cref="KecaknoahStackFrame"/>を返します。 /// </summary> /// <param name="il"></param> /// <returns>結果</returns> public KecaknoahStackFrame ExecuteWithStackFrame(KecaknoahIL il) { var sf = new KecaknoahStackFrame(this, il); sf.Execute(); return(sf); }
/// <summary> /// 式からなる<see cref="KecaknoahAst"/>をプリコンパイルします。 /// </summary> /// <param name="ast">対象の<see cref="KecaknoahAst"/></param> /// <returns>プリコンパイル結果</returns> public KecaknoahIL PrecompileExpression(KecaknoahAst ast) { var result = new KecaknoahIL(); result.PushCodes(PrecompileExpression(ast.RootNode)); return(result); }
/// <summary> /// 指定されたILを式として実行し、結果を返します。 /// </summary> /// <param name="il">実行する<see cref="KecaknoahIL"/></param> /// <returns>結果</returns> public KecaknoahObject ExecuteExpressionIL(KecaknoahIL il) { var s = new KecaknoahStackFrame(this, il); s.Execute(); return(s.ReturningObject); }
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> /// 指定した<see cref="KecaknoahIL"/>を式として実行します。 /// </summary> /// <param name="il"></param> /// <returns>結果</returns> public KecaknoahObject Execute(KecaknoahIL il) { var sf = new KecaknoahStackFrame(this, il); sf.Execute(); return(sf.ReturningObject); }
/// <summary> /// 新しいインスタンスを初期化します。 /// </summary> /// <param name="ctx">実行している<see cref="KecaknoahContext"/></param> /// <param name="il">実行する<see cref="KecaknoahIL"/></param> public KecaknoahStackFrame(KecaknoahContext ctx, KecaknoahIL il) { Codes = il.Codes; ProgramCounter = 0; RunningContext = ctx; }
internal IReadOnlyList <KecaknoahILCode> PrecompileBlock(IReadOnlyList <KecaknoahAstNode> ast, string loopId) { var result = new KecaknoahIL(); List <string> locals = new List <string>(); foreach (var i in ast) { if (i is KecaknoahExpressionAstNode) { if (i is KecaknoahFactorExpressionAstNode) { var exp = i as KecaknoahFactorExpressionAstNode; if (exp.FactorType != KecaknoahFactorType.CoroutineResume) { throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); } } else if (i is KecaknoahArgumentCallExpressionAstNode) { var exp = i as KecaknoahArgumentCallExpressionAstNode; if (exp.ExpressionType != KecaknoahOperatorType.FunctionCall) { throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); } result.PushCodes(PrecompileFunctionCall(exp)); result.PushCode(KecaknoahILCodeType.Pop); } else if (i is KecaknoahBinaryExpressionAstNode) { var exp = i as KecaknoahBinaryExpressionAstNode; switch (exp.ExpressionType) { case KecaknoahOperatorType.Assign: case KecaknoahOperatorType.PlusAssign: case KecaknoahOperatorType.MinusAssign: case KecaknoahOperatorType.MultiplyAssign: case KecaknoahOperatorType.DivideAssign: case KecaknoahOperatorType.AndAssign: case KecaknoahOperatorType.OrAssign: case KecaknoahOperatorType.XorAssign: case KecaknoahOperatorType.ModularAssign: case KecaknoahOperatorType.LeftBitShiftAssign: case KecaknoahOperatorType.RightBitShiftAssign: case KecaknoahOperatorType.NilAssign: result.PushCodes(PrecompileBinaryExpression(exp)); result.PushCode(KecaknoahILCodeType.Pop); break; default: throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); } } else if (i is KecaknoahPrimaryExpressionAstNode) { var exp = i as KecaknoahPrimaryExpressionAstNode; switch (exp.ExpressionType) { case KecaknoahOperatorType.Increment: result.PushCodes(PrecompileSuffixIncrement(exp)); result.PushCode(KecaknoahILCodeType.Pop); break; case KecaknoahOperatorType.Decrement: result.PushCodes(PrecompileSuffixDecrement(exp)); result.PushCode(KecaknoahILCodeType.Pop); break; default: throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); } } else if (i is KecaknoahUnaryExpressionAstNode) { var exp = i as KecaknoahUnaryExpressionAstNode; switch (exp.ExpressionType) { case KecaknoahOperatorType.Increment: result.PushCodes(PrecompilePrefixIncrement(exp)); result.PushCode(KecaknoahILCodeType.Pop); break; case KecaknoahOperatorType.Decrement: result.PushCodes(PrecompilePrefixDecrement(exp)); result.PushCode(KecaknoahILCodeType.Pop); break; default: throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); } } else { throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); } } else if (i is KecaknoahLocalAstNode) { var lc = i as KecaknoahLocalAstNode; locals.Add(lc.Name); if (lc.InitialExpression != null) { result.PushCode(KecaknoahILCodeType.LoadObject, lc.Name); result.PushCodes(PrecompileExpression(lc.InitialExpression)); result.PushCode(KecaknoahILCodeType.Assign); } } else if (i is KecaknoahReturnAstNode) { var rc = i as KecaknoahReturnAstNode; if (rc.Value != null) { result.PushCodes(PrecompileExpression(rc.Value)); } else { result.PushCode(KecaknoahILCodeType.PushNil); } result.PushCode(rc.Type == KecaknoahAstNodeType.ReturnStatement ? KecaknoahILCodeType.Return : KecaknoahILCodeType.Yield); } else if (i is KecaknoahCoroutineDeclareAstNode) { var cd = i as KecaknoahCoroutineDeclareAstNode; result.PushCodes(PrecompileExpression(cd.InitialExpression)); foreach (var pe in cd.ParameterExpressions) { result.PushCodes(PrecompileExpression(pe)); } result.PushCode(new KecaknoahILCode { Type = KecaknoahILCodeType.StartCoroutine, StringValue = cd.Name, IntegerValue = cd.ParameterExpressions.Count }); } else if (i is KecaknoahContinueAstNode) { var ca = i as KecaknoahContinueAstNode; var ln = ca.Label != "" ? ca.Label : loopId; result.PushCode(KecaknoahILCodeType.Jump, $"{ln}-" + (i.Type == KecaknoahAstNodeType.ContinueStatement ? "Continue" : "End")); } else if (i is KecaknoahIfAstNode) { result.PushCodes(PrecompileIf(i as KecaknoahIfAstNode, loopId)); } else if (i is KecaknoahForAstNode) { result.PushCodes(PrecompileFor(i as KecaknoahForAstNode)); } else if (i is KecaknoahForeachAstNode) { result.PushCodes(PrecompileForeach(i as KecaknoahForeachAstNode)); } else if (i is KecaknoahLoopAstNode) { result.PushCodes(PrecompileWhile(i as KecaknoahLoopAstNode)); } } return(result.Codes); }
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("無効なメソッド"); } } }
internal IReadOnlyList<KecaknoahILCode> PrecompileBlock(IReadOnlyList<KecaknoahAstNode> ast, string loopId) { var result = new KecaknoahIL(); List<string> locals = new List<string>(); foreach (var i in ast) { if (i is KecaknoahExpressionAstNode) { if (i is KecaknoahFactorExpressionAstNode) { var exp = i as KecaknoahFactorExpressionAstNode; if (exp.FactorType != KecaknoahFactorType.CoroutineResume) throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); } else if (i is KecaknoahArgumentCallExpressionAstNode) { var exp = i as KecaknoahArgumentCallExpressionAstNode; if (exp.ExpressionType != KecaknoahOperatorType.FunctionCall) throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); result.PushCodes(PrecompileFunctionCall(exp)); result.PushCode(KecaknoahILCodeType.Pop); } else if (i is KecaknoahBinaryExpressionAstNode) { var exp = i as KecaknoahBinaryExpressionAstNode; switch (exp.ExpressionType) { case KecaknoahOperatorType.Assign: case KecaknoahOperatorType.PlusAssign: case KecaknoahOperatorType.MinusAssign: case KecaknoahOperatorType.MultiplyAssign: case KecaknoahOperatorType.DivideAssign: case KecaknoahOperatorType.AndAssign: case KecaknoahOperatorType.OrAssign: case KecaknoahOperatorType.XorAssign: case KecaknoahOperatorType.ModularAssign: case KecaknoahOperatorType.LeftBitShiftAssign: case KecaknoahOperatorType.RightBitShiftAssign: case KecaknoahOperatorType.NilAssign: result.PushCodes(PrecompileBinaryExpression(exp)); result.PushCode(KecaknoahILCodeType.Pop); break; default: throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); } } else if (i is KecaknoahPrimaryExpressionAstNode) { var exp = i as KecaknoahPrimaryExpressionAstNode; switch (exp.ExpressionType) { case KecaknoahOperatorType.Increment: result.PushCodes(PrecompileSuffixIncrement(exp)); result.PushCode(KecaknoahILCodeType.Pop); break; case KecaknoahOperatorType.Decrement: result.PushCodes(PrecompileSuffixDecrement(exp)); result.PushCode(KecaknoahILCodeType.Pop); break; default: throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); } } else if (i is KecaknoahUnaryExpressionAstNode) { var exp = i as KecaknoahUnaryExpressionAstNode; switch (exp.ExpressionType) { case KecaknoahOperatorType.Increment: result.PushCodes(PrecompilePrefixIncrement(exp)); result.PushCode(KecaknoahILCodeType.Pop); break; case KecaknoahOperatorType.Decrement: result.PushCodes(PrecompilePrefixDecrement(exp)); result.PushCode(KecaknoahILCodeType.Pop); break; default: throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); } } else { throw new InvalidOperationException("ステートメントにできる式はcoresume・代入・呼び出し・インクリメント・デクリメントのみです"); } } else if (i is KecaknoahLocalAstNode) { var lc = i as KecaknoahLocalAstNode; locals.Add(lc.Name); if (lc.InitialExpression != null) { result.PushCode(KecaknoahILCodeType.LoadObject, lc.Name); result.PushCodes(PrecompileExpression(lc.InitialExpression)); result.PushCode(KecaknoahILCodeType.Assign); } } else if (i is KecaknoahReturnAstNode) { var rc = i as KecaknoahReturnAstNode; if (rc.Value != null) { result.PushCodes(PrecompileExpression(rc.Value)); } else { result.PushCode(KecaknoahILCodeType.PushNil); } result.PushCode(rc.Type == KecaknoahAstNodeType.ReturnStatement ? KecaknoahILCodeType.Return : KecaknoahILCodeType.Yield); } else if (i is KecaknoahCoroutineDeclareAstNode) { var cd = i as KecaknoahCoroutineDeclareAstNode; result.PushCodes(PrecompileExpression(cd.InitialExpression)); foreach (var pe in cd.ParameterExpressions) result.PushCodes(PrecompileExpression(pe)); result.PushCode(new KecaknoahILCode { Type = KecaknoahILCodeType.StartCoroutine, StringValue = cd.Name, IntegerValue = cd.ParameterExpressions.Count }); } else if (i is KecaknoahContinueAstNode) { var ca = i as KecaknoahContinueAstNode; result.PushCode(KecaknoahILCodeType.Jump, $"{loopId}-" + (i.Type == KecaknoahAstNodeType.ContinueStatement ? "Continue" : "End")); } else if (i is KecaknoahIfAstNode) { result.PushCodes(PrecompileIf(i as KecaknoahIfAstNode, loopId)); } else if (i is KecaknoahForAstNode) { result.PushCodes(PrecompileFor(i as KecaknoahForAstNode)); } else if (i is KecaknoahForeachAstNode) { result.PushCodes(PrecompileForeach(i as KecaknoahForeachAstNode)); } else if (i is KecaknoahLoopAstNode) { result.PushCodes(PrecompileWhile(i as KecaknoahLoopAstNode)); } } return result.Codes; }
/// <summary> /// 式からなる<see cref="KecaknoahAst"/>をプリコンパイルします。 /// </summary> /// <param name="ast">対象の<see cref="KecaknoahAst"/></param> /// <returns>プリコンパイル結果</returns> public KecaknoahIL PrecompileExpression(KecaknoahAst ast) { var result = new KecaknoahIL(); result.PushCodes(PrecompileExpression(ast.RootNode)); return result; }
/// <summary> /// フィールドを追加します。 /// </summary> /// <param name="local">追加するメソッド</param> /// <param name="exp">初期化式を定義する<see cref="KecaknoahIL"/></param> internal void AddLocal(string local, KecaknoahIL exp) { LocalInfos.Add(new KecaknoahScriptLocalInfo { Name = local, InitializeIL = exp }); localnames.Add(local); }
/// <summary> /// 指定した<see cref="KecaknoahIL"/>を式として実行し、<see cref="KecaknoahStackFrame"/>を返します。 /// </summary> /// <param name="il"></param> /// <returns>結果</returns> public KecaknoahStackFrame ExecuteWithStackFrame(KecaknoahIL il) { var sf = new KecaknoahStackFrame(this, il); sf.Execute(); return sf; }
/// <summary> /// 指定した<see cref="KecaknoahIL"/>を式として実行します。 /// </summary> /// <param name="il"></param> /// <returns>結果</returns> public KecaknoahObject Execute(KecaknoahIL il) { var sf = new KecaknoahStackFrame(this, il); sf.Execute(); return sf.ReturningObject; }
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; }