pascalabcnet/AdditionalLanguages/SPython/SyntaxTreeConverters/SPythonStandardTreeConverter/UnsupportedConstructsVisitor.cs
Александр Земляк 17f6a9b956
Spython test suite (#3362)
* Reorganize files in TestSuite dir for multiple languages

* Add SPython samples to TestSuite

* Update TestRunner to support multiple languages

* Delete dll files accidentally pushed

* Update .gitignore

* Revert "Delete dll files accidentally pushed"

This reverts commit 62bcba2b821d58ae51ec98e9dadcf621bb0fc003.

* Update testing dir path in Testing.cs

* Improve TestRunner output

* Add random module and it's usage sample

* Reorganize gitignore files

* Move pascal tests back to TestSuite and create new TestSuiteLanguagePlugins folder for SPython

* Revert "Update testing dir path in Testing.cs"

This reverts commit 7d94eafb25292421bce8315520b4f6a0de001bbd.

* Revert crlf changes in pascal tests

* Test changes of _RebuildReleaseAndRunTestsForGitHubActions.bat

* Revert "Test changes of _RebuildReleaseAndRunTestsForGitHubActions.bat"

This reverts commit 234ceae3e3a339fbc68a6170e2bd201dab14d67d.

* Test changes in StorageLocationPicker

* Another test changes in StorageLocationPicker.cs

* Rename LanguagePlugins folder to AdditionalLanguages

* Decouple TestRunner from language names and parameters

* Revert calling TestRunner without parameters in .bat files

* Fix formatter tests nogui exception handling

* Small refactoring in Testing.cs and TestRunner fix of working directory
2025-12-21 21:11:52 +03:00

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);
}
}
}
}