138 lines
4.9 KiB
C#
138 lines
4.9 KiB
C#
using Languages.SPython.Frontend.Converters;
|
||||
using PascalABCCompiler.SyntaxTree;
|
||||
|
||||
namespace Languages.Pascal.Frontend.Converters
|
||||
{
|
||||
public class UnsupportedConstructsVisitor : BaseEnterExitVisitor
|
||||
{
|
||||
private int blockLevel = 0;
|
||||
// function returns a value
|
||||
private bool isInFunction = false;
|
||||
// procedure doesn't return value
|
||||
private bool isInProcedure = false;
|
||||
|
||||
public UnsupportedConstructsVisitor() { }
|
||||
|
||||
public override void Enter(syntax_tree_node st)
|
||||
{
|
||||
if (st is statement_list)
|
||||
{
|
||||
++blockLevel;
|
||||
}
|
||||
if (st is procedure_definition pd)
|
||||
{
|
||||
if (pd.proc_header is function_header)
|
||||
isInFunction = true;
|
||||
else
|
||||
isInProcedure = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Exit(syntax_tree_node st)
|
||||
{
|
||||
if (st is statement_list)
|
||||
{
|
||||
--blockLevel;
|
||||
}
|
||||
if (st is procedure_definition)
|
||||
{
|
||||
isInProcedure = isInFunction = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void visit(return_statement _return_statement)
|
||||
{
|
||||
// 'return' или 'return expr' вне функции
|
||||
if (!isInFunction && !isInProcedure)
|
||||
{
|
||||
throw new SPythonSyntaxVisitorError("RETURN_NOT_IN_FUNCTION",
|
||||
_return_statement.source_context);
|
||||
}
|
||||
// 'return' внутри функции, которая должна возвращать значение
|
||||
if (isInFunction && _return_statement.expr == null)
|
||||
{
|
||||
throw new SPythonSyntaxVisitorError("RETURN_NOT_RETURN_VALUE",
|
||||
_return_statement.source_context);
|
||||
}
|
||||
// 'return expr' внутри функции, которая не возвращает значение
|
||||
if (isInProcedure && _return_statement.expr != null)
|
||||
{
|
||||
throw new SPythonSyntaxVisitorError("RETURN_HAS_RETURN_VALUE",
|
||||
_return_statement.expr.source_context);
|
||||
}
|
||||
|
||||
base.visit(_return_statement);
|
||||
}
|
||||
|
||||
public override void visit(global_statement _global_statement)
|
||||
{
|
||||
// конструкция 'global ...' используется вне функции
|
||||
if (!isInProcedure && !isInFunction)
|
||||
{
|
||||
throw new SPythonSyntaxVisitorError("GLOBAL_NOT_IN_FUNCTION",
|
||||
_global_statement.source_context);
|
||||
}
|
||||
// конструкция 'global ...' используется
|
||||
// не на самом внешнем блоке внутри функции
|
||||
if (blockLevel != 2)
|
||||
{
|
||||
throw new SPythonSyntaxVisitorError("GLOBAL_IN_NOT_OUTERMOST_BLOCK",
|
||||
_global_statement.source_context);
|
||||
}
|
||||
|
||||
base.visit(_global_statement);
|
||||
}
|
||||
|
||||
public override void visit(import_statement _import_statement)
|
||||
{
|
||||
// конструкция 'import ...'
|
||||
// используется не на глобальном уровне
|
||||
if (blockLevel > 1)
|
||||
{
|
||||
throw new SPythonSyntaxVisitorError("LOCAL_IMPORT_USE",
|
||||
_import_statement.source_context);
|
||||
}
|
||||
|
||||
base.visit(_import_statement);
|
||||
}
|
||||
|
||||
public override void visit(from_import_statement _from_import_statement)
|
||||
{
|
||||
// конструкция 'from ... import ...'
|
||||
// используется не на глобальном уровне
|
||||
if (blockLevel > 1)
|
||||
{
|
||||
throw new SPythonSyntaxVisitorError("LOCAL_FROM_IMPORT_USE",
|
||||
_from_import_statement.source_context);
|
||||
}
|
||||
|
||||
base.visit(_from_import_statement);
|
||||
}
|
||||
|
||||
public override void visit(procedure_definition _procedure_definition)
|
||||
{
|
||||
// объявление функции не на глобальном уровне
|
||||
if (blockLevel > 1)
|
||||
{
|
||||
throw new SPythonSyntaxVisitorError("LOCAL_FUNCTION_DECLARATION",
|
||||
_procedure_definition.source_context);
|
||||
}
|
||||
|
||||
base.visit(_procedure_definition);
|
||||
}
|
||||
|
||||
public override void visit(assign_tuple _assign_tuple)
|
||||
{
|
||||
// выявление ошибок типа
|
||||
// a, b = 1, 2, 3
|
||||
if (_assign_tuple.expr is tuple_node right_part
|
||||
&& _assign_tuple.vars.Count < right_part.el.Count
|
||||
)
|
||||
{
|
||||
throw new SPythonSyntaxVisitorError("LEFT_SIZE_TUPLE_ASSIGNMENT_LESS_THAN_RIGHT",
|
||||
_assign_tuple.source_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|