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; }
/// <summary> /// メソッドのノードを追加します。 /// </summary> /// <param name="node">メソッドノード</param> protected internal void AddFunctionNode(KecaknoahFunctionAstNode node) { funcs.Add(node); AddNode(node); }
private static void ParseFunctionArgumentsList(Queue<KecaknoahToken> tokens, KecaknoahFunctionAstNode result) { var nt = tokens.Peek(); switch (nt.Type) { case KecaknoahTokenType.NewLine: case KecaknoahTokenType.Semicolon: break; case KecaknoahTokenType.ParenStart: tokens.Dequeue(); while (true) { nt = tokens.Dequeue(); switch (nt.Type) { case KecaknoahTokenType.Identifer: result.Parameters.Add(nt.TokenString); tokens.CheckSkipToken(KecaknoahTokenType.Comma); break; case KecaknoahTokenType.VariableArguments: result.AllowsVariableArguments = true; if (!tokens.CheckToken(KecaknoahTokenType.ParenEnd)) throw new KecaknoahParseException(nt.CreateErrorAt("可変長引数は最後に配置してください")); break; case KecaknoahTokenType.ParenEnd: goto EndArgsList; default: throw new KecaknoahParseException(nt.CreateErrorAt("仮引数リストに識別子・可変長引数以外を指定しないでください。")); } } EndArgsList:; break; } }
private KecaknoahFunctionAstNode ParseFunction(Queue<KecaknoahToken> tokens, bool top) { var result = new KecaknoahFunctionAstNode(); if (tokens.CheckSkipToken(KecaknoahTokenType.StaticKeyword)) { if (top) { throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("トップレベルのメソッドにstaticは指定できません。")); } else { result.StaticMethod = true; } } var nt = tokens.Dequeue(); if (nt.Type != KecaknoahTokenType.Identifer) throw new KecaknoahParseException(nt.CreateErrorAt("メソッド名にはキーワードではない識別子を指定してください。")); result.Name = nt.TokenString; ParseFunctionArgumentsList(tokens, result); if (!tokens.SkipLogicalLineBreak()) throw new KecaknoahParseException(nt.CreateErrorAt("func宣言の後ろに改行が必要です。")); foreach (var n in ParseBlock(tokens)) result.AddNode(n); if (!tokens.CheckSkipToken(KecaknoahTokenType.EndFuncKeyword)) throw new KecaknoahParseException(nt.CreateErrorAt("endfuncがありません。")); return result; }