private KecaknoahLoopAstNode ParseWhile(Queue<KecaknoahToken> tokens, bool single) { var result = new KecaknoahLoopAstNode(); var t = tokens.Peek(); if (t.Type == KecaknoahTokenType.Identifer) { tokens.Dequeue(); result.Name = t.TokenString; } else { result.Name = Guid.NewGuid().ToString().Substring(0, 8); } if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenStart)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("whileの条件式はカッコでくくってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 result.Condition = ParseExpression(tokens); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("whileの条件式はカッコでくくってください。")); if (single || !tokens.SkipLogicalLineBreak()) { if (tokens.SkipLogicalLineBreak()) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("単行while文のみ記述できます。")); foreach (var i in ParseSingleLineStatement(tokens)) result.AddNode(i); } else { foreach (var i in ParseBlock(tokens)) result.AddNode(i); if (!tokens.CheckSkipToken(KecaknoahTokenType.NextKeyword)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("nextで終わっていません。")); } return result; }
private KecaknoahLoopAstNode ParseForeach(Queue<KecaknoahToken> tokens, bool single) { var result = new KecaknoahForeachAstNode(); var t = tokens.Peek(); if (t.Type == KecaknoahTokenType.Identifer) { tokens.Dequeue(); result.Name = t.TokenString; } else { result.Name = Guid.NewGuid().ToString().Substring(0, 8); } if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenStart)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("whileの条件式はカッコでくくってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 var nt = tokens.Dequeue(); if (nt.Type != KecaknoahTokenType.Identifer) throw new KecaknoahParseException(nt.CreateErrorAt("foreachのループ変数には識別子を指定してください。")); result.ElementVariableName = nt.TokenString; tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 nt = tokens.Dequeue(); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 if (nt.Type == KecaknoahTokenType.InKeyword) { result.Source = ParseExpression(tokens); } else if (nt.Type == KecaknoahTokenType.OfKeyword) { result.IsCoroutineSource = true; result.Source = ParseExpression(tokens); if (tokens.CheckSkipToken(KecaknoahTokenType.Colon)) { if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenStart)) throw new KecaknoahParseException(nt.CreateErrorAt("コルーチンの引数リストが不正です。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 while (true) { result.CoroutineArguments.Add(ParseExpression(tokens)); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 if (tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) break; if (!tokens.CheckSkipToken(KecaknoahTokenType.Comma)) throw new KecaknoahParseException(nt.CreateErrorAt("コルーチンの引数リストが閉じていません。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 } } } else { throw new KecaknoahParseException(nt.CreateErrorAt("foreachにはinかofを指定してください。")); } tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("foreachの条件式はカッコでくくってください。")); if (single || !tokens.SkipLogicalLineBreak()) { if (tokens.SkipLogicalLineBreak()) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("単行foreach文のみ記述できます。")); foreach (var i in ParseSingleLineStatement(tokens)) result.AddNode(i); } else { foreach (var i in ParseBlock(tokens)) result.AddNode(i); if (!tokens.CheckSkipToken(KecaknoahTokenType.NextKeyword)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("nextで終わっていません。")); } return result; }
private KecaknoahIfAstNode ParseCase(Queue<KecaknoahToken> tokens) { var result = new KecaknoahIfAstNode(); var ifb = new KecaknoahIfBlockAstNode(); ifb.Condition = new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.BooleanValue, BooleanValue = false }; result.IfBlock = ifb; if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenStart)) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("case文の判定式はカッコでくくってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 var target = ParseExpression(tokens); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("case文の判定式はカッコでくくってください。")); if (!tokens.SkipLogicalLineBreak()) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("case文の判定式の後は改行してください。")); var wls = new List<KecaknoahExpressionAstNode>(); var df = false; while (true) { var nt = tokens.Peek(); if (nt.Type == KecaknoahTokenType.EndCaseKeyword) { tokens.Dequeue(); break; } else if (nt.Type == KecaknoahTokenType.WhenKeyword) { tokens.Dequeue(); var t2 = ParseExpression(tokens); if (!tokens.CheckSkipToken(KecaknoahTokenType.Colon)) throw new KecaknoahParseException(nt.CreateErrorAt("whenの式の後ろはコロンを付けてください。")); wls.Add(t2); tokens.SkipLogicalLineBreak(); continue; } else if (nt.Type == KecaknoahTokenType.DefaultKeyword) { tokens.Dequeue(); if (!tokens.CheckSkipToken(KecaknoahTokenType.Colon)) throw new KecaknoahParseException(nt.CreateErrorAt("defaultの後ろはコロンを付けてください。")); df = true; continue; } else { var bl = ParseBlock(tokens); if (wls.Count == 0) { if (!df) throw new KecaknoahParseException(nt.CreateErrorAt("case文内でブロックが浮いています。")); var en = new KecaknoahIfBlockAstNode(); foreach (var j in bl) en.AddNode(j); result.ElseBlock = en; df = false; } else { var tn = new KecaknoahBinaryExpressionAstNode(); tn.ExpressionType = KecaknoahOperatorType.OrElse; tn.FirstNode = new KecaknoahBinaryExpressionAstNode { ExpressionType = KecaknoahOperatorType.Equal, FirstNode = target, SecondNode = wls[0] }; var eln = new KecaknoahIfBlockAstNode(); foreach (var i in wls.Skip(1)) { var nc = new KecaknoahBinaryExpressionAstNode { ExpressionType = KecaknoahOperatorType.Equal, FirstNode = target, SecondNode = i }; tn.SecondNode = nc; var ntn = new KecaknoahBinaryExpressionAstNode(); ntn.FirstNode = tn; ntn.ExpressionType = KecaknoahOperatorType.OrElse; tn = ntn; } eln.Condition = tn.FirstNode; foreach (var j in bl) eln.AddNode(j); result.ElifBlocks.Add(eln); if (df) { result.ElseBlock = eln; df = false; } wls.Clear(); } } } return result; }
private KecaknoahForAstNode ParseFor(Queue<KecaknoahToken> tokens, bool single) { var result = new KecaknoahForAstNode(); var t = tokens.Peek(); if (t.Type == KecaknoahTokenType.Identifer) { tokens.Dequeue(); result.Name = t.TokenString; } else { result.Name = Guid.NewGuid().ToString().Substring(0, 8); } if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenStart)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("forの各式は全体をカッコでくくってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 while (true) { var exp = ParseExpression(tokens); result.InitializeExpressions.Add(exp); if (tokens.CheckSkipToken(KecaknoahTokenType.Semicolon)) break; if (!tokens.CheckSkipToken(KecaknoahTokenType.Comma)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("初期化式はコンマで区切ってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 } tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 result.Condition = ParseExpression(tokens); if (!tokens.CheckSkipToken(KecaknoahTokenType.Semicolon)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("セミコロンで区切ってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 while (true) { var exp = ParseExpression(tokens); result.CounterExpressions.Add(exp); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 if (tokens.CheckToken(KecaknoahTokenType.ParenEnd)) break; if (!tokens.CheckSkipToken(KecaknoahTokenType.Comma)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("初期化式はコンマで区切ってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 } if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("forの各式は全体をカッコでくくってください。")); if (single || !tokens.SkipLogicalLineBreak()) { if (tokens.SkipLogicalLineBreak()) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("単行for文のみ記述できます。")); foreach (var i in ParseSingleLineStatement(tokens)) result.AddNode(i); } else { foreach (var i in ParseBlock(tokens)) result.AddNode(i); if (!tokens.CheckSkipToken(KecaknoahTokenType.NextKeyword)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("nextで終わっていません。")); } return result; }
private KecaknoahReturnAstNode ParseReturn(Queue<KecaknoahToken> tokens) { var result = new KecaknoahReturnAstNode(); var nt = tokens.Dequeue(); result.Type = nt.Type == KecaknoahTokenType.ReturnKeyword ? KecaknoahAstNodeType.ReturnStatement : KecaknoahAstNodeType.YieldStatement; if (!tokens.SkipLogicalLineBreak()) result.Value = ParseExpression(tokens); return result; }
private KecaknoahIfAstNode ParseIf(Queue<KecaknoahToken> tokens, bool single) { var result = new KecaknoahIfAstNode(); if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenStart)) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("if文の条件式はカッコでくくってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 var cnd = ParseExpression(tokens); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 var ifb = new KecaknoahIfBlockAstNode(); ifb.Condition = cnd; if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("if文の条件式が閉じていません。")); if (!tokens.CheckSkipToken(KecaknoahTokenType.ThenKeyword)) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("thenキーワードをおいてください。")); if (!single && tokens.SkipLogicalLineBreak()) { //ブロックif var b = ParseBlock(tokens); foreach (var i in b) ifb.AddNode(i); result.IfBlock = ifb; while (true) { var nt = tokens.Dequeue(); if (nt.Type == KecaknoahTokenType.EndifKeyword) { break; } else if (nt.Type == KecaknoahTokenType.ElifKeyword) { if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenStart)) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("elif文の条件式はカッコでくくってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 cnd = ParseExpression(tokens); var elb = new KecaknoahIfBlockAstNode(); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 elb.Condition = cnd; if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("elif文の条件式が閉じていません。")); if (!tokens.CheckSkipToken(KecaknoahTokenType.ThenKeyword)) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("thenキーワードをおいてください。")); tokens.SkipLogicalLineBreak(); b = ParseBlock(tokens); foreach (var i in b) elb.AddNode(i); result.ElifBlocks.Add(elb); } else if (nt.Type == KecaknoahTokenType.ElseKeyword) { tokens.SkipLogicalLineBreak(); var esb = new KecaknoahIfBlockAstNode(); b = ParseBlock(tokens); foreach (var i in b) esb.AddNode(i); result.ElseBlock = esb; } else { throw new KecaknoahParseException(nt.CreateErrorAt("不正なif文です。")); } } } else { //単行if ifb.AddNode(ParseSingleLineStatement(tokens)); result.IfBlock = ifb; if (tokens.CheckSkipToken(KecaknoahTokenType.ElseKeyword)) { var esb = new KecaknoahIfBlockAstNode(); esb.AddNode(ParseSingleLineStatement(tokens)); result.ElseBlock = esb; } } return result; }
private IList<KecaknoahLocalAstNode> ParseLocal(Queue<KecaknoahToken> tokens) { var result = new List<KecaknoahLocalAstNode>(); while (true) { var nt = tokens.Dequeue(); if (nt.Type != KecaknoahTokenType.Identifer) throw new KecaknoahParseException(nt.CreateErrorAt("識別子を指定してください。")); var lan = new KecaknoahLocalAstNode(); lan.Name = nt.TokenString; result.Add(lan); if (tokens.SkipLogicalLineBreak()) return result; nt = tokens.Dequeue(); switch (nt.Type) { case KecaknoahTokenType.Assign: lan.InitialExpression = ParseExpression(tokens); if (tokens.SkipLogicalLineBreak()) return result; if (!tokens.CheckSkipToken(KecaknoahTokenType.Comma)) throw new KecaknoahParseException(nt.CreateErrorAt("無効なlocal宣言です。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 break; case KecaknoahTokenType.Comma: tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 continue; default: throw new KecaknoahParseException(nt.CreateErrorAt("無効なlocal宣言です。")); } } }
private KecaknoahAstNode ParseFirstLevel(Queue<KecaknoahToken> tokens) { var result = new KecaknoahAstNode(); tokens.SkipLogicalLineBreak(); try { while (tokens.Count != 0) { var t = tokens.Dequeue(); switch (t.Type) { case KecaknoahTokenType.UseKeyword: t = tokens.Dequeue(); if (t.Type != KecaknoahTokenType.StringLiteral) throw new KecaknoahParseException(t.CreateErrorAt("use文には文字列を指定してください。")); result.AddNode(new KecaknoahUseAstNode { Target = t.TokenString }); break; case KecaknoahTokenType.ClassKeyword: result.AddNode(ParseClass(tokens)); break; case KecaknoahTokenType.FuncKeyword: result.AddNode(ParseFunction(tokens, true)); break; default: throw new KecaknoahParseException(t.CreateErrorAt("トップレベルにはクラスとメソッド、use文以外は定義できません。")); } tokens.SkipLogicalLineBreak(); } } catch (KecaknoahParseException) { throw; } return result; }
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; }
private IList<KecaknoahAstNode> ParseBlock(Queue<KecaknoahToken> tokens) { var result = new List<KecaknoahAstNode>(); while (true) { tokens.SkipLogicalLineBreak(); //式かもしれないのでPeek var nt = tokens.Peek(); switch (nt.Type) { case KecaknoahTokenType.IfKeyword: tokens.Dequeue(); result.Add(ParseIf(tokens, false)); break; case KecaknoahTokenType.CaseKeyword: tokens.Dequeue(); result.Add(ParseCase(tokens)); break; case KecaknoahTokenType.ForKeyword: tokens.Dequeue(); result.Add(ParseFor(tokens, false)); break; case KecaknoahTokenType.WhileKeyword: tokens.Dequeue(); result.Add(ParseWhile(tokens, false)); break; case KecaknoahTokenType.ForeachKeyword: tokens.Dequeue(); result.Add(ParseForeach(tokens, false)); break; case KecaknoahTokenType.DoKeyword: break; case KecaknoahTokenType.ElifKeyword: case KecaknoahTokenType.ElseKeyword: case KecaknoahTokenType.EndifKeyword: case KecaknoahTokenType.WhenKeyword: case KecaknoahTokenType.DefaultKeyword: case KecaknoahTokenType.EndCaseKeyword: case KecaknoahTokenType.EndFuncKeyword: case KecaknoahTokenType.NextKeyword: //呼ばれ元で終了判定するから飛ばさないでね goto EndBlock; default: result.AddRange(ParseSingleLineStatement(tokens)); break; } } EndBlock: return result; }
private KecaknoahClassAstNode ParseClass(Queue<KecaknoahToken> tokens) { var result = new KecaknoahClassAstNode(); var nt = tokens.Dequeue(); if (nt.Type != KecaknoahTokenType.Identifer) throw new KecaknoahParseException(nt.CreateErrorAt("クラス名にはキーワードではない識別子を指定してください。")); result.Name = nt.TokenString; if (!tokens.SkipLogicalLineBreak()) throw new KecaknoahParseException(nt.CreateErrorAt("class宣言の後ろに改行が必要です。")); while (true) { tokens.SkipLogicalLineBreak(); var t = tokens.Dequeue(); if (t.Type == KecaknoahTokenType.EndclassKeyword) break; switch (t.Type) { case KecaknoahTokenType.FuncKeyword: result.AddFunctionNode(ParseFunction(tokens, false)); break; case KecaknoahTokenType.LocalKeyword: result.AddLocalNode(ParseLocal(tokens)); break; default: throw new KecaknoahParseException(nt.CreateErrorAt("クラス内にはメソッドかlocal宣言のみ記述出来ます。")); } } return result; }
private KecaknoahAstNode ParseFirstLevel(Queue<KecaknoahToken> tokens) { var result = new KecaknoahAstNode(); tokens.SkipLogicalLineBreak(); try { while (tokens.Count != 0) { var t = tokens.Dequeue(); switch (t.Type) { case KecaknoahTokenType.ClassKeyword: result.AddNode(ParseClass(tokens)); break; case KecaknoahTokenType.FuncKeyword: result.AddNode(ParseFunction(tokens, true)); break; default: throw new KecaknoahParseException(t.CreateErrorAt("トップレベルにはクラスとメソッド以外は定義できません。")); } tokens.SkipLogicalLineBreak(); } } catch (KecaknoahParseException) { throw; } return result; }
private KecaknoahFactorExpressionAstNode ParseFactorExpression(Queue<KecaknoahToken> tokens) { var t = tokens.Dequeue(); string lv = ""; switch (t.Type) { case KecaknoahTokenType.CoresumeKeyword: if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenStart)) throw new KecaknoahParseException(t.CreateErrorAt("coresumeが不正です。")); t = tokens.Dequeue(); if (t.Type != KecaknoahTokenType.Identifer) throw new KecaknoahParseException(t.CreateErrorAt("coresumeが不正です。")); var result = new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.CoroutineResume, StringValue = t.TokenString }; if (tokens.CheckSkipToken(KecaknoahTokenType.Comma)) { //代入とステート返却 result.ExpressionNode = ParseExpression(tokens); result.BooleanValue = true; } if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) throw new KecaknoahParseException(t.CreateErrorAt("coresumeが不正です。")); return result; case KecaknoahTokenType.And: var lambda = new KecaknoahFactorExpressionAstNode(); lambda.FactorType = KecaknoahFactorType.Lambda; if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenStart)) throw new KecaknoahParseException(t.CreateErrorAt("ラムダ式の&には引数リストを続けてください。")); if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) while (true) { lambda.ElementNodes.Add(new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.Identifer, StringValue = tokens.Dequeue().TokenString }); if (tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) break; if (!tokens.CheckSkipToken(KecaknoahTokenType.Comma)) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("ラムダ引数がカッコで閉じていなません。")); } if (!tokens.CheckSkipToken(KecaknoahTokenType.Lambda)) throw new KecaknoahParseException(t.CreateErrorAt("ラムダ式の引数リストに=>で式を続けてください。")); lambda.ExpressionNode = ParseExpression(tokens); return lambda; case KecaknoahTokenType.ParenStart: tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 var exp = ParseExpression(tokens); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("カッコは閉じてください。")); return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.ParenExpression, ExpressionNode = exp }; case KecaknoahTokenType.BracketStart: var are = new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.Array }; tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 while (true) { are.ElementNodes.Add(ParseExpression(tokens)); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 if (tokens.CheckSkipToken(KecaknoahTokenType.BracketEnd)) break; if (!tokens.CheckSkipToken(KecaknoahTokenType.Comma)) throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("配列がカッコで閉じていなません。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 } return are; case KecaknoahTokenType.TrueKeyword: case KecaknoahTokenType.FalseKeyword: return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.BooleanValue, BooleanValue = Convert.ToBoolean(t.TokenString) }; case KecaknoahTokenType.NilKeyword: return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.Nil }; case KecaknoahTokenType.VargsKeyword: return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.VariableArguments }; case KecaknoahTokenType.Identifer: return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.Identifer, StringValue = t.TokenString }; case KecaknoahTokenType.StringLiteral: return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.StringValue, StringValue = t.TokenString }; case KecaknoahTokenType.BinaryNumberLiteral: lv = t.TokenString.Substring(2); if (lv.Length > 64) lv = lv.Substring(lv.Length - 64); return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.IntegerValue, IntegerValue = unchecked(Convert.ToInt64(lv, 2)) }; case KecaknoahTokenType.OctadecimalNumberLiteral: lv = t.TokenString.Substring(2); if (lv.Length > 64) lv = lv.Substring(lv.Length - 21); return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.IntegerValue, IntegerValue = unchecked(Convert.ToInt64(lv, 8)) }; case KecaknoahTokenType.HexadecimalNumberLiteral: lv = t.TokenString.Substring(2); if (lv.Length > 64) lv = lv.Substring(lv.Length - 16); return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.IntegerValue, IntegerValue = unchecked(Convert.ToInt64(lv, 16)) }; case KecaknoahTokenType.HexatridecimalNumberLiteral: return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.IntegerValue, IntegerValue = unchecked(Base36.Decode(t.TokenString.Substring(2))) }; case KecaknoahTokenType.DecimalNumberLiteral: if (t.TokenString.IndexOf('.') >= 0) { lv = t.TokenString.Substring(0, t.TokenString.Length - 1); var v = 0.0; var r = double.TryParse(lv, out v); return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.DoubleValue, DoubleValue = r ? v : double.MaxValue }; } else { var v = 0L; var r = long.TryParse(t.TokenString, out v); return new KecaknoahFactorExpressionAstNode { FactorType = KecaknoahFactorType.IntegerValue, IntegerValue = r ? v : long.MaxValue }; } default: throw new KecaknoahParseException(t.CreateErrorAt("意味不明なfactorが検出されました。")); } }
private KecaknoahExpressionAstNode ParseBinaryExpression(Queue<KecaknoahToken> tokens, int priority) { if (priority > OperatorMaxPriority) return ParseUnaryExpression(tokens); var left = ParseBinaryExpression(tokens, priority + 1); var result = new KecaknoahBinaryExpressionAstNode(); result.FirstNode = left; while (true) { if (tokens.Count == 0) break; if (tokens.CheckToken( KecaknoahTokenType.ParenEnd, KecaknoahTokenType.Comma, KecaknoahTokenType.BracketEnd, KecaknoahTokenType.ThenKeyword, KecaknoahTokenType.ElseKeyword, KecaknoahTokenType.Semicolon, KecaknoahTokenType.NewLine, KecaknoahTokenType.Colon)) { //tokens.Dequeue(); break; } var nt = tokens.Peek(); if (OperatorPriorities[nt.Type] != priority) break; tokens.Dequeue(); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 var right = ParseBinaryExpression(tokens, priority + 1); result.SecondNode = right; result.ExpressionType = OperatorsTokenTable[nt.Type]; var newres = new KecaknoahBinaryExpressionAstNode(); newres.FirstNode = result; result = newres; } if (priority == 1) { var pn = result.FirstNode as KecaknoahBinaryExpressionAstNode; if (pn == null) return result.FirstNode; while (pn.FirstNode is KecaknoahBinaryExpressionAstNode) { switch (pn.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: break; default: return pn; } var kb = pn.FirstNode as KecaknoahBinaryExpressionAstNode; var nn = new KecaknoahBinaryExpressionAstNode(); nn.ExpressionType = pn.ExpressionType; nn.SecondNode = pn.SecondNode; nn.FirstNode = kb.SecondNode; pn.FirstNode = kb.FirstNode; pn.SecondNode = nn; } return pn; } return result.FirstNode; }
private IList<KecaknoahCoroutineDeclareAstNode> ParseCoroutineDeclare(Queue<KecaknoahToken> tokens) { var result = new List<KecaknoahCoroutineDeclareAstNode>(); while (true) { var nt = tokens.Dequeue(); if (nt.Type != KecaknoahTokenType.Identifer) throw new KecaknoahParseException(nt.CreateErrorAt("識別子を指定してください。")); var lan = new KecaknoahCoroutineDeclareAstNode(); lan.Name = nt.TokenString; nt = tokens.Dequeue(); if (nt.Type != KecaknoahTokenType.Assign) throw new KecaknoahParseException(nt.CreateErrorAt("coroutine宣言は必ず代入してください。")); lan.InitialExpression = ParseExpression(tokens); if (tokens.CheckSkipToken(KecaknoahTokenType.Colon)) { //引数 if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenStart)) throw new KecaknoahParseException(nt.CreateErrorAt("coroutine宣言の引数リストが不正です。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 while (true) { lan.ParameterExpressions.Add(ParseExpression(tokens)); if (tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) break; if (!tokens.CheckSkipToken(KecaknoahTokenType.Comma)) throw new KecaknoahParseException(nt.CreateErrorAt("coroutine宣言の引数リストが閉じていません。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 } } result.Add(lan); if (!tokens.CheckSkipToken(KecaknoahTokenType.Comma)) break; } return result; }
/// <summary> /// インデクサの引数リスト処理 /// </summary> /// <param name="tokens"></param> /// <param name="parent"></param> /// <returns></returns> private KecaknoahArgumentCallExpressionAstNode ParsePrimaryIndexerAccessExpression(Queue<KecaknoahToken> tokens, KecaknoahPrimaryExpressionAstNode parent) { var r = new KecaknoahArgumentCallExpressionAstNode(); r.Target = parent; r.ExpressionType = KecaknoahOperatorType.IndexerAccess; tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 if (tokens.CheckSkipToken(KecaknoahTokenType.BracketEnd)) return r; while (true) { r.Arguments.Add(ParseExpression(tokens)); if (tokens.CheckSkipToken(KecaknoahTokenType.Comma)) continue; tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 if (tokens.CheckSkipToken(KecaknoahTokenType.BracketEnd)) break; throw new KecaknoahParseException(tokens.Peek().CreateErrorAt("メソッド呼び出しの引数リストが無効です。")); } return r; }
private KecaknoahTryAstNode ParseTry(Queue<KecaknoahToken> tokens) { var result = new KecaknoahTryAstNode(); tokens.SkipLogicalLineBreak(); result.AddNode(ParseBlock(tokens)); while (true) { var nt = tokens.Dequeue(); switch (nt.Type) { case KecaknoahTokenType.CatchKeyword: nt = tokens.Dequeue(); if (nt.Type != KecaknoahTokenType.Identifer) throw new KecaknoahParseException(nt.CreateErrorAt("catchブロックに変数名を指定してください。")); result.CatcherVariableName = nt.TokenString; tokens.SkipLogicalLineBreak(); result.CatcherBlock.Clear(); result.CatcherBlock = ParseBlock(tokens); break; case KecaknoahTokenType.FinallyKeyword: nt = tokens.Dequeue(); tokens.SkipLogicalLineBreak(); result.FinallyBlock.Clear(); result.FinallyBlock = ParseBlock(tokens); break; case KecaknoahTokenType.EndTryKeyword: goto EndTry; default: throw new KecaknoahParseException(nt.CreateErrorAt("不正なtry文です。")); } } EndTry: return result; }