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 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 IList<KecaknoahILCode> PrecompileIf(KecaknoahIfAstNode ifn, string loopId) { //まあまずかぶらないでしょう var id = Guid.NewGuid().ToString().Substring(0, 8); var result = new List<KecaknoahILCode>(); result.AddRange(PrecompileExpression(ifn.IfBlock.Condition)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.FalseJump, StringValue = $"{id}-IfEnd" }); result.AddRange(PrecompileBlock(ifn.IfBlock.Children, loopId)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Jump, StringValue = $"{id}-End" }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Label, StringValue = $"{id}-IfEnd" }); var c = 0; foreach (var i in ifn.ElifBlocks) { result.AddRange(PrecompileExpression(i.Condition)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.FalseJump, StringValue = $"{id}-Elif{c}End" }); result.AddRange(PrecompileBlock(i.Children, loopId)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Jump, StringValue = $"{id}-End" }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Label, StringValue = $"{id}-Elif{c}End" }); c++; } if (ifn.ElseBlock != null) { result.AddRange(PrecompileBlock(ifn.ElseBlock.Children, loopId)); } result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Label, StringValue = $"{id}-End" }); return result; }