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