pascalabcnet/Yield/SyntaxVisitors/YieldVisitors/MarkMethodHasYieldVisitor.cs
miks1965 e7b65c421b bug fix #219
Несколько новых перегрузок методов расширений для массивов
2016-07-17 20:09:53 +03:00

142 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
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>();
public override void visit(function_lambda_definition ld)
{
if (ld.DescendantNodes().OfType<yield_node>().Count() > 0)
{
throw new SyntaxError("Лямбда-выражения не могут содержать yield", "", ld.source_context, ld);
}
//base.visit(ld); // SSM 15/07/16 - незачем обходить внутренности лямбды - мы и так ищем внутри них yield - этого в этом визиторе достаточно
}
public override void visit(with_statement ws)
{
if (ws.DescendantNodes().OfType<yield_node>().Count() > 0)
{
throw new SyntaxError("Yield запрещен внутри with", "", ws.source_context, ws);
}
base.visit(ws);
}
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)
{
var FirstTypeDeclaration = ee.defs.DescendantNodes().OfType<type_declarations>().First();
if (FirstTypeDeclaration != null)
{
throw new SyntaxError("Функции с yield не могут содержать локальные определения типов", "", FirstTypeDeclaration.source_context, FirstTypeDeclaration);
}
}
}
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
throw new SyntaxError("Функции с yield не могут содержать вложенных подпрограмм result", "", pd.source_context, pd);
}
if (pd.has_yield && pd.DescendantNodes().OfType<try_stmt>().Count() > 0)
{
throw new SyntaxError("Функции с yield не могут содержать блоков try..except..finally", "", pd.source_context, pd);
}
if (pd.has_yield && pd.DescendantNodes().OfType<lock_stmt>().Count() > 0)
{
throw new SyntaxError("Функции с yield не могут содержать lock", "", pd.source_context, pd);
}
HasYields = false;
MethodsStack.Pop();
//this.CurrentMethod = null;
}
public override void visit(ident id)
{
//if (CurrentMethod == null || !HasYields)
if (MethodsStack.Count == 0 || !HasYields)
{
return;
}
if (id.name.ToLower() == "result")
{
throw new SyntaxError("Функции с yield не могут использовать result", "", id.source_context, id);
}
}
public override void visit(dot_node dn)
{
ProcessNode(dn.left);
if (dn.right.GetType() != typeof(ident))
ProcessNode(dn.right);
}
public override void visit(yield_node yn)
{
//var pd = CurrentMethod;
var pd = MethodsStack.Peek();
if (pd == null)
throw new SyntaxError("Только функции могут содержать yield", "", yn.source_context, yn);
var fh = (pd.proc_header as function_header);
if (fh == null)
throw new SyntaxError("Только функции могут содержать yield", "", pd.proc_header.source_context, pd.proc_header);
var seqt = fh.return_type as sequence_type;
if (seqt == null)
throw new SyntaxError("Функции с yield должны возвращать последовательность", "", fh.source_context, fh);
var pars = fh.parameters;
if (pars != null)
foreach (var ps in pars.params_list)
{
if (ps.param_kind != parametr_kind.none)
throw new SyntaxError("В параметрах функции с yield не должно быть модификаторов 'var', 'const' или 'params'", "", pars.source_context, pars);
if (ps.inital_value != null)
throw new SyntaxError("Параметры функции с yield не должны иметь начальных значений", "", pars.source_context, pars);
}
HasYields = true;
base.visit(yn);
}
}
}