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 IList<KecaknoahILCode> PrecompileForeach(KecaknoahForeachAstNode fn) { if (fn.IsCoroutineSource) { return PrecompileCoroutineForeach(fn); } else { return PrecompileNormalForeach(fn); } }
private IList<KecaknoahILCode> PrecompileNormalForeach(KecaknoahForeachAstNode fn) { var id = Guid.NewGuid().ToString().Substring(0, 8); var result = new List<KecaknoahILCode>(); var cntn = $"{id}-Counter"; result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = cntn }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushInteger, IntegerValue = 0 }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Assign }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Pop }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Label, StringValue = $"{id}-Next" }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = cntn }); result.AddRange(PrecompileExpression(fn.Source)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadMember, StringValue = "length" }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Lesser }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.FalseJump, StringValue = $"{id}-End" }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = fn.ElementVariableName }); result.AddRange(PrecompileExpression(fn.Source)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = cntn }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.IndexerCall, IntegerValue = 1 }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Assign }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Pop }); result.AddRange(PrecompileBlock(fn.Children, id)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Label, StringValue = $"{id}-Continue" }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = cntn }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PushInteger, IntegerValue = 1 }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.PlusAssign }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Pop }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Jump, StringValue = $"{id}-Next" }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Label, StringValue = $"{id}-End" }); return result; }
private IList<KecaknoahILCode> PrecompileCoroutineForeach(KecaknoahForeachAstNode fn) { var id = Guid.NewGuid().ToString().Substring(0, 8); var result = new List<KecaknoahILCode>(); result.AddRange(PrecompileExpression(fn.Source)); foreach (var pe in fn.CoroutineArguments) result.AddRange(PrecompileExpression(pe)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.StartCoroutine, StringValue = $"{id}-Coroutine", IntegerValue = fn.CoroutineArguments.Count }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Label, StringValue = $"{id}" }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.LoadObject, StringValue = fn.ElementVariableName }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.ResumeCoroutine, StringValue = $"{id}-Coroutine", BooleanValue = true }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.FalseJump, StringValue = $"{id}-End" }); result.AddRange(PrecompileBlock(fn.Children, id)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Jump, StringValue = $"{id}" }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Label, StringValue = $"{id}-End" }); return result; }