2017-02-19 16:29:24 +03:00
|
|
|
|
// Copyright (c) Ivan Bondarev, Stanislav Mihalkovich (for details please see \doc\copyright.txt)
|
|
|
|
|
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
|
|
|
|
using System;
|
2016-07-18 13:07:08 +03:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
|
|
using PascalABCCompiler;
|
|
|
|
|
|
using PascalABCCompiler.SyntaxTree;
|
|
|
|
|
|
|
|
|
|
|
|
using PascalABCCompiler.Errors;
|
|
|
|
|
|
|
|
|
|
|
|
namespace SyntaxVisitors
|
|
|
|
|
|
{
|
|
|
|
|
|
public class MarkMethodHasYieldAndCheckSomeErrorsVisitor : WalkingVisitorNew
|
|
|
|
|
|
{
|
|
|
|
|
|
private bool HasYields = false;
|
|
|
|
|
|
private procedure_definition CurrentMethod = null;
|
|
|
|
|
|
|
|
|
|
|
|
private Stack<procedure_definition> MethodsStack = new Stack<procedure_definition>();
|
|
|
|
|
|
|
2017-01-30 10:19:35 +03:00
|
|
|
|
public static MarkMethodHasYieldAndCheckSomeErrorsVisitor New
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return new MarkMethodHasYieldAndCheckSomeErrorsVisitor(); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-07-18 13:07:08 +03:00
|
|
|
|
public override void visit(function_lambda_definition ld)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ld.DescendantNodes().OfType<yield_node>().Count() > 0)
|
|
|
|
|
|
{
|
2016-07-18 15:58:32 +03:00
|
|
|
|
throw new SyntaxVisitorError("LAMBDA_EXPRESSIONS_CANNOT_CONTAIN_YIELD", ld.source_context);
|
2016-07-18 13:07:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//base.visit(ld); // SSM 15/07/16 - незачем обходить внутренности лямбды - мы и так ищем внутри них yield - этого в этом визиторе достаточно
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(with_statement ws)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ws.DescendantNodes().OfType<yield_node>().Count() > 0)
|
|
|
|
|
|
{
|
2016-07-18 15:58:32 +03:00
|
|
|
|
throw new SyntaxVisitorError("YIELDS_INSIDE_WITH_ARE_ILLEGAL", ws.source_context);
|
2016-07-18 13:07:08 +03:00
|
|
|
|
}
|
2019-02-13 21:02:35 +03:00
|
|
|
|
if (ws.DescendantNodes().OfType<yield_sequence_node>().Count() > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new SyntaxVisitorError("YIELDSEQUENCES_INSIDE_WITH_ARE_ILLEGAL", ws.source_context);
|
|
|
|
|
|
}
|
2016-07-18 13:07:08 +03:00
|
|
|
|
base.visit(ws);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-09-12 07:11:26 +03:00
|
|
|
|
ident IdResult = null;
|
2016-07-18 13:07:08 +03:00
|
|
|
|
public override void visit(procedure_definition pd)
|
|
|
|
|
|
{
|
|
|
|
|
|
//this.CurrentMethod = pd;
|
|
|
|
|
|
|
|
|
|
|
|
MethodsStack.Push(pd);
|
|
|
|
|
|
|
|
|
|
|
|
HasYields = false;
|
|
|
|
|
|
|
|
|
|
|
|
base.visit(pd);
|
|
|
|
|
|
pd.has_yield = HasYields;
|
|
|
|
|
|
|
|
|
|
|
|
if (pd.has_yield) // SSM bug fix #219
|
|
|
|
|
|
{
|
|
|
|
|
|
var ee = pd.proc_body as block;
|
|
|
|
|
|
if (ee != null)
|
|
|
|
|
|
{
|
2016-07-18 15:58:32 +03:00
|
|
|
|
var FirstTypeDeclaration = ee.defs.DescendantNodes().OfType<type_declarations>();
|
|
|
|
|
|
if (FirstTypeDeclaration.Count() > 0)
|
2016-07-18 13:07:08 +03:00
|
|
|
|
{
|
2016-07-18 15:58:32 +03:00
|
|
|
|
throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_LOCAL_TYPE_DEFINITIONS", FirstTypeDeclaration.First().source_context);
|
2016-07-18 13:07:08 +03:00
|
|
|
|
}
|
2018-11-05 14:57:36 +03:00
|
|
|
|
var FirstInheritedIdent = ee.DescendantNodes().OfType<inherited_ident>(); // SSM bug fix #1440
|
|
|
|
|
|
if (FirstInheritedIdent.Count() > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_INHERITED_CALLS", FirstInheritedIdent.First().source_context);
|
|
|
|
|
|
}
|
2016-07-18 13:07:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-09-12 07:11:26 +03:00
|
|
|
|
/*if (pd.has_yield)
|
|
|
|
|
|
{
|
|
|
|
|
|
var dn = pd.DescendantNodes().OfType<ident>().Where(id => id.name.ToLower() == "result").FirstOrDefault();
|
|
|
|
|
|
if (dn != null)
|
|
|
|
|
|
throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_RESULT", dn);
|
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
|
|
if (pd.has_yield)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (IdResult != null)
|
|
|
|
|
|
throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_RESULT", IdResult);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-07-18 13:07:08 +03:00
|
|
|
|
var innerPds = pd.DescendantNodes().OfType<procedure_definition>();
|
|
|
|
|
|
|
|
|
|
|
|
if (pd.has_yield && innerPds.Count() > 0
|
|
|
|
|
|
|| innerPds.Where(npd => npd.has_yield).Count() > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Есть yield и вложенные - плохо
|
|
|
|
|
|
// Или нет yield но есть вложенные с yield
|
2016-07-18 15:58:32 +03:00
|
|
|
|
throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_NESTED_SUBROUTINES", pd.source_context);
|
2016-07-18 13:07:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (pd.has_yield && pd.DescendantNodes().OfType<try_stmt>().Count() > 0)
|
|
|
|
|
|
{
|
2016-07-18 15:58:32 +03:00
|
|
|
|
throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_TRY_EXCEPT_FINALLY", pd.source_context);
|
2016-07-18 13:07:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (pd.has_yield && pd.DescendantNodes().OfType<lock_stmt>().Count() > 0)
|
|
|
|
|
|
{
|
2016-07-18 15:58:32 +03:00
|
|
|
|
throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_LOCK", pd.source_context);
|
2016-07-18 13:07:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HasYields = false;
|
2018-09-12 07:11:26 +03:00
|
|
|
|
IdResult = null;
|
2016-07-18 13:07:08 +03:00
|
|
|
|
|
|
|
|
|
|
MethodsStack.Pop();
|
|
|
|
|
|
|
|
|
|
|
|
//this.CurrentMethod = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(ident id)
|
|
|
|
|
|
{
|
2018-09-12 07:11:26 +03:00
|
|
|
|
if (MethodsStack.Count > 0 && id.name.ToLower() == "result")
|
|
|
|
|
|
{
|
|
|
|
|
|
IdResult = id;
|
|
|
|
|
|
//throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_RESULT", id.source_context);
|
|
|
|
|
|
}
|
2016-07-18 13:07:08 +03:00
|
|
|
|
//if (CurrentMethod == null || !HasYields)
|
|
|
|
|
|
if (MethodsStack.Count == 0 || !HasYields)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(dot_node dn)
|
|
|
|
|
|
{
|
|
|
|
|
|
ProcessNode(dn.left);
|
|
|
|
|
|
if (dn.right.GetType() != typeof(ident))
|
|
|
|
|
|
ProcessNode(dn.right);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-07-19 21:16:08 +03:00
|
|
|
|
public void visit_yield_helper(syntax_tree_node yn)
|
2016-07-18 13:07:08 +03:00
|
|
|
|
{
|
2016-07-22 13:00:58 +03:00
|
|
|
|
procedure_definition pd = null;
|
|
|
|
|
|
if (MethodsStack.Count > 0)
|
|
|
|
|
|
pd = MethodsStack.Peek();
|
2016-07-18 13:07:08 +03:00
|
|
|
|
|
|
|
|
|
|
if (pd == null)
|
2016-07-18 15:58:32 +03:00
|
|
|
|
throw new SyntaxVisitorError("ONLY_FUNCTIONS_CAN_CONTAIN_YIELDS", yn.source_context);
|
2016-07-18 13:07:08 +03:00
|
|
|
|
|
|
|
|
|
|
var fh = (pd.proc_header as function_header);
|
|
|
|
|
|
if (fh == null)
|
2016-07-18 15:58:32 +03:00
|
|
|
|
throw new SyntaxVisitorError("ONLY_FUNCTIONS_CAN_CONTAIN_YIELDS", pd.proc_header.source_context);
|
2019-02-14 00:10:32 +03:00
|
|
|
|
|
|
|
|
|
|
var ttr = fh.return_type as template_type_reference;
|
2019-02-14 00:22:58 +03:00
|
|
|
|
if (ttr != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ttr.name.names.Count == 1 && ttr.name.names[0].name.ToLower() == "ienumerable" && ttr.params_list.Count == 1)
|
|
|
|
|
|
fh.return_type = new sequence_type(ttr.params_list.params_list[0]);
|
|
|
|
|
|
else if (ttr.name.names.Count == 4 && ttr.name.names[0].name.ToLower() == "system" && ttr.name.names[1].name.ToLower() == "collections" && ttr.name.names[2].name.ToLower() == "generic" && ttr.name.names[3].name.ToLower() == "ienumerable" && ttr.params_list.Count == 1)
|
|
|
|
|
|
fh.return_type = new sequence_type(ttr.params_list.params_list[0]);
|
|
|
|
|
|
}
|
2016-07-18 13:07:08 +03:00
|
|
|
|
var seqt = fh.return_type as sequence_type;
|
|
|
|
|
|
if (seqt == null)
|
|
|
|
|
|
throw new SyntaxVisitorError("YIELD_FUNC_MUST_RETURN_SEQUENCE", fh.source_context);
|
2018-12-30 18:10:07 +03:00
|
|
|
|
if (seqt.elements_type is procedure_header || seqt.elements_type is function_header)
|
|
|
|
|
|
throw new SyntaxVisitorError("YIELD_FUNC_CANNOT_RETURN_SEQUENCE_OF_ANONYMOUS_DELEGATES", fh.source_context);
|
2016-07-18 13:07:08 +03:00
|
|
|
|
var pars = fh.parameters;
|
|
|
|
|
|
if (pars != null)
|
|
|
|
|
|
foreach (var ps in pars.params_list)
|
|
|
|
|
|
{
|
2019-02-17 16:19:07 +03:00
|
|
|
|
if (ps.param_kind != parametr_kind.none && ps.param_kind != parametr_kind.params_parametr)
|
2016-07-18 15:58:32 +03:00
|
|
|
|
throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_VAR_CONST_PARAMS_MODIFIERS", pars.source_context);
|
2019-02-17 16:19:07 +03:00
|
|
|
|
/*if (ps.inital_value != null)
|
|
|
|
|
|
throw new SyntaxVisitorError("FUNCTIONS_WITH_YIELDS_CANNOT_CONTAIN_DEFAULT_PARAMETERS", pars.source_context);*/
|
2016-07-18 13:07:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HasYields = true;
|
2016-07-19 21:16:08 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-07-18 13:07:08 +03:00
|
|
|
|
|
2016-07-19 21:16:08 +03:00
|
|
|
|
public override void visit(yield_node yn)
|
|
|
|
|
|
{
|
|
|
|
|
|
visit_yield_helper(yn);
|
|
|
|
|
|
base.visit(yn);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(yield_sequence_node yn)
|
|
|
|
|
|
{
|
|
|
|
|
|
visit_yield_helper(yn);
|
2016-07-18 13:07:08 +03:00
|
|
|
|
base.visit(yn);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|