pascalabcnet/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Assign.cs
AlexanderZemlyak 342375501b
New languages engine (#3120)
* Implement first version of languages interfaces and classes

ParsersController заменен на LanguageProvider.

* Update ParserTools.csproj

* Update RemoteCompiler.cs

* Update TestRunner

* Rename LanguageIntegrator project to Languages

* Update TestRunner

* Rename Parsers folder

* Rename PascalABCParser.dll to PascalABCLanguage.dll

* Reorganise LanguageIntegrator and rename DocTagsParser

* Update Release Generators

* Update language loading messages

* Update linux version

* Move BaseParser fields to ILanguage interface

* Revert "Update Release Generators"

This reverts commit 26a991c71b81e643d9fbd9a815ddca222768dda9.

* Revert "Rename PascalABCParser.dll to PascalABCLanguage.dll"

* Clean the mess in parser folders

* Organize namespaces properly

* Revert "Rename LanguageIntegrator project to Languages"

* Add new enclosing folders for standard languages

* Organize namespaces of LanguageIntegrator properly

* Rename StandardLanguages to Languages

* Comment the rest of Visual basic source code

* Update OutputPath in pascal parser project

* Move BaseParser methods to IParser

* Restore Pascal parser project initial structure

* Add PascalLanguage project

* Move SyntaxTreeConverters project to Languages\Pascal folder

* Rename SemanticRules in parser project

* Rename Errors1 to Errors in parser project

* Delete LambdaConverter dll from installer

* Update language integrator to load *Language.dll files

* Move lambda converter project to pascal lanuage dir

* Revert "Delete LambdaConverter dll from installer"

This reverts commit dd56f559ebe4f8c4c5c33752d44e6953001b96a5.

* Switch off VBNETParser building

* Delete syntax tree converters controller

* Delete lambda converter dll from repository

* Reorganize syntax tree to semantic tree conversion stage

* Add BaseLanguage class to make language initialization more neat

* Delete syntax tree post processors entity from ILanguage and refactor ABCStatistics calls

* Add new IDocParser interface for documentation comments parser

* Clean up folders

* Add helper data structures to reduce parameters amount in CompileInterface and CompileImplementation

* Add documentation to language classes

* Move Union struct in global namespace and project (ParserTools)

* Add more comments and a safe select language method

* Rename SemanticRules class

* Fix directives format null bug

* Add System.Linq ref to LanguageIntegrator

* Delete SyntaxToSemanticTreeConverter interface

* Add BaseSyntaxTreeConverter

* Call safe select language method in intellisence

* Delete source files providers from parsers

* Rename GetSyntaxTree method

* Change Prebuild tree to be virtual - not abstract

* Refresh documentation a bit

* Add temporary language check for ABCHealth button

* Add parser reference to parser tools

* Move current compilation unit assigning higher to avoid bug with unit check

* Delete null DirectiveInfo's and refactor directives' code

* Add a few more comments
2024-05-25 12:26:32 +03:00

549 lines
29 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 PascalABCCompiler.SemanticTree;
using PascalABCCompiler.SyntaxTree;
using PascalABCCompiler.SystemLibrary;
using PascalABCCompiler.TreeRealization;
using SymTable = SymbolTable;
namespace PascalABCCompiler.TreeConverter
{
public partial class syntax_tree_visitor
{
public bool internal_is_assign;
public override void visit(assign _assign)
{
var loc = get_location(_assign);
addressed_expression to;
expression_node from;
// SSM - идея для особого присваивания, по которому находится тип в SymTable
/*var sc = context.CurrentScope;
var ttt = sc.Find("a");
(ttt[0].sym_info as namespace_variable).type = convert_strong(_assign.from).type;*/
AssignCheckAndConvert(_assign, out to, out from);
InferLambdaResultTypeFromAssignment(_assign, from, to);
if (ProcessAssignToPropertyIfPossible(_assign, to, loc, from))
return;
if (ProcessAssignmentToEventIfPossible(_assign, to, from, loc))
return;
if (ProcessAssignmentToShortStringIfPossible(_assign, to, from, loc))
return;
assign_is_converting = true;
if (to.type.type_special_kind == type_special_kind.set_type && from.type.type_special_kind == type_special_kind.set_type && // SSM 12/07/19 fix #1795
convertion_data_and_alghoritms.is_value_int_type(to.type.element_type) &&
convertion_data_and_alghoritms.is_value_real_type(from.type.element_type))
AddError(new CanNotConvertTypes(from, from.type, to.type, from.location));
statement_node en = find_operator(_assign.operator_type, to, from, get_location(_assign));
assign_is_converting = false;
return_value(en);
}
/// <summary>
/// Выводит тип результата лямбды по первому присваиванию переменной Result.
/// </summary>
private void InferLambdaResultTypeFromAssignment(assign _assign, expression_node from, addressed_expression to)
{
if (stflambda.Count > 0) // мы находимся внутри лямбды - возможно, вложенной
{
var fld = stflambda.Peek();
if (_assign.to is ident && (_assign.to as ident).name.ToLower() == "result" && fld.RealSemTypeOfResExpr == null)
// если это - первое присваивание Result
{
fld.RealSemTypeOfResExpr = from.type;
fld.RealSemTypeOfResult = to.type;
}
}
}
/// <summary>
/// Обрабатывает случай, когда левая часть присваивания short string.
/// </summary>
/// <returns>True - обработка прошла, иначе False.</returns>
private bool ProcessAssignmentToShortStringIfPossible(assign _assign, addressed_expression to, expression_node from, location loc)
{
if (_assign.operator_type == Operators.Assignment)
{
if (to is simple_array_indexing &&
(to as simple_array_indexing).simple_arr_expr.type.type_special_kind == type_special_kind.short_string)
{
expression_node expr = (to as simple_array_indexing).simple_arr_expr;
expression_node ind_expr = (to as simple_array_indexing).ind_expr;
from = convertion_data_and_alghoritms.convert_type(from, SystemLibrary.SystemLibrary.char_type);
ind_expr = convertion_data_and_alghoritms.create_simple_function_call(
SystemLibInitializer.SetCharInShortStringProcedure.sym_info as function_node,
loc,
expr,
ind_expr,
new int_const_node((expr.type as short_string_type_node).Length, null), from);
return_value(find_operator(StringConstants.assign_name, expr, ind_expr, get_location(_assign)));
return true;
}
if (to.type.type_special_kind == type_special_kind.short_string)
{
if (from.type is null_type_node)
AddError(get_location(_assign), "NIL_WITH_VALUE_TYPES_NOT_ALLOWED");
expression_node clip_expr = convertion_data_and_alghoritms.create_simple_function_call(
SystemLibInitializer.ClipShortStringProcedure.sym_info as function_node,
loc,
convertion_data_and_alghoritms.convert_type(from, SystemLibrary.SystemLibrary.string_type),
new int_const_node((to.type as short_string_type_node).Length,
null));
statement_node en = find_operator(StringConstants.assign_name, to, clip_expr, get_location(_assign));
return_value(en);
return true;
}
}
return false;
}
/// <summary>
/// Преобразует в семантическое представление поля to и from, проводя семантические проверки.
/// </summary>
private void AssignCheckAndConvert(assign _assign, out addressed_expression to, out expression_node from)
{
// SSM 29/03/24
var fromAsLambda0 = _assign.from as function_lambda_definition;
expression_node from0 = null;
if (fromAsLambda0 == null)
{
// Перенёс вычисление from в начало - чтобы потом сделать узел, задающий тип при первом присваивании
from0 = convert_strong(_assign.from);
if (_assign.first_assignment_defines_type) // всегда в этом случае должно быть присваивание := а не += и т.д.
{
var sc = context.CurrentScope;
var ttt = sc.Find((_assign.to as ident).name); // всегда в этом случае должно быть простое имя
(ttt[0].sym_info as var_definition_node).type = from0.type;
}
}
internal_is_assign = true;
to = convert_address_strong(_assign.to);
internal_is_assign = false;
if (to == null)
AddError(get_location(_assign.to), "CAN_NOT_ASSIGN_TO_LEFT_PART");
//(ssyy) Вставляю проверки прямо сюда, т.к. запарился вылавливать другие случаи.
bool flag;
general_node_type node_type;
if (convertion_data_and_alghoritms.check_for_constant_or_readonly(to, out flag, out node_type))
{
if (flag)
AddError(to.location, "CAN_NOT_ASSIGN_TO_CONSTANT_OBJECT");
else
AddError(new CanNotAssignToReadOnlyElement(to.location, node_type));
}
// SSM исправление Саушкина 10.03.16
var fromAsLambda = _assign.from as function_lambda_definition;
if (fromAsLambda != null)
{
#region Вывод параметров лямбда-выражения
LambdaHelper.InferTypesFromVarStmt(to.type, fromAsLambda, this, _assign.operator_type); //lroman//
#endregion
var lambdaVisitMode = fromAsLambda.lambda_visit_mode;
fromAsLambda.lambda_visit_mode = LambdaVisitMode.VisitForAdvancedMethodCallProcessing;
from = convert_strong(_assign.from);
fromAsLambda.lambda_visit_mode = lambdaVisitMode;
}
else
{
from = from0;
ProcessAssigntToAutoType(to, ref from);
}
// end
//SSM 4.04.16
if (to.type is undefined_type)
to.type = from.type;
location loc = get_location(_assign);
if (to is class_field_reference)
{
var classFieldRef = to as class_field_reference;
if (classFieldRef.obj.type.type_special_kind == type_special_kind.record &&
classFieldRef.obj is base_function_call)
{
//исключим ситуацию обращения к массиву
if (!(classFieldRef.obj is common_method_call &&
(classFieldRef.obj as common_method_call).obj.type.type_special_kind ==
type_special_kind.array_wrapper))
AddError(loc, "LEFT_SIDE_CANNOT_BE_ASSIGNED_TO");
}
//else check_field_reference_for_assign(to as class_field_reference,loc);
}
if (context.is_in_cycle() && !SemanticRulesConstants.AllowChangeLoopVariable)
{
var_definition_node toAsVariable = GetLocalVariableFromAdressExpressionIfPossible(to);
if (toAsVariable != null && context.is_loop_variable(toAsVariable) && _assign.source_context != null) // последнее - обрезает проверку для сгенерированного i += 1 в foreach ... index i
AddError(to.location, "CANNOT_ASSIGN_TO_LOOP_VARIABLE");
}
{
var classFieldRef = (to as simple_array_indexing)?.simple_arr_expr as class_field_reference;
if (classFieldRef?.obj is constant_node)
AddError(loc, "LEFT_SIDE_CANNOT_BE_ASSIGNED_TO");
}
}
/// <summary>
/// Автовыведение типов в yield'ax.
/// </summary>
private void ProcessAssigntToAutoType(addressed_expression to, ref expression_node from)
{
var sequence = to.type as compiled_generic_instance_type_node;
// SSM 26.06.16 - правка в связи с автовыведением типов в yieldах
if (to.type is auto_type)
{
try_convert_typed_expression_to_function_call(ref from);
if (to is class_field_reference)
{
var cfr = to as class_field_reference;
if (from is typed_expression) // SSM 22.12.18 syntax_tree_visitor.cs 16066 - взял оттуда
{
base_function_call bfc = ((from as typed_expression).type as delegated_methods).proper_methods[0];
/*if (bfc.function.is_generic_function && _var_def_statement.vars_type == null)
{
AddError(inital_value.location, "CAN_NOT_DEDUCE_TYPE_{0}", null);
}
foreach (parameter p in bfc.simple_function_node.parameters)
{
if (p.type.is_generic_parameter)
AddError(inital_value.location, "USE_ANONYMOUS_FUNCTION_TYPE_WITH_GENERICS");
} */
common_type_node del =
convertion_data_and_alghoritms.type_constructor.create_delegate(context.get_delegate_type_name(), bfc.simple_function_node.return_value_type, bfc.simple_function_node.parameters, context.converted_namespace, null);
context.converted_namespace.types.AddElement(del); //- сомневаюсь - контекст уже поменялся!
//tn = del;
from = convertion_data_and_alghoritms.explicit_convert_type(from, del);
from.type = del;
}
cfr.field.type = from.type;
cfr.type = from.type; // Это неверно работает когда yieldится процедура #1439
// SSM 1.11.18 попытка правки возвращения процедуры в yield
//if (from.type.semantic_node_type == semantic_node_type.delegated_method)
//cfr.type.semantic_node_type = semantic_node_type.delegated_method;
cfr.field.inital_value = context.GetInitalValueForVariable(cfr.field, cfr.field.inital_value);
}
else if (to is local_block_variable_reference)
{
var lvr = to as local_block_variable_reference;
lvr.var.type = from.type;
lvr.type = from.type;
lvr.var.inital_value = context.GetInitalValueForVariable(lvr.var, lvr.var.inital_value);
}
else AddError(to.location, "Не могу вывести тип при наличии yield: " + to.type.full_name);
//to.type = from.type; // и без всякого real_type!
}
else if (sequence?.instance_params[0] is ienumerable_auto_type)
{
type_node elem_type = null;
try_convert_typed_expression_to_function_call(ref from);
bool bb; // здесь bb не нужно. Оно нужно в foreach
var b = FindIEnumerableElementType(from.type, ref elem_type, out bb);
if (!b)
AddError(from.location, "CAN_NOT_EXECUTE_FOREACH_BY_EXPR_OF_TYPE_{0}", from.type.full_name);
var IEnumType = new template_type_reference(new named_type_reference("System.Collections.Generic.IEnumerable"),
new template_param_list(new semantic_type_node(elem_type)));
if (to is class_field_reference)
{
var cfr = to as class_field_reference;
cfr.field.type = convert_strong(IEnumType);
cfr.type = cfr.field.type;
}
else if (to is local_block_variable_reference)
{
var lvr = to as local_block_variable_reference;
lvr.var.type = convert_strong(IEnumType); // замена типа у описания переменной
lvr.type = lvr.var.type; // замена типа у переменной
}
}
}
/// <summary>
/// Обрабатывает случай, когда левая часть присваивания свойство.
/// </summary>
/// <returns>True - обработка прошла, иначе False.</returns>
private bool ProcessAssignToPropertyIfPossible(assign _assign, addressed_expression to, location loc,
expression_node from)
{
//проверка на обращение к полю записи возвращенной из функции с целью присваивания
//нужно чтобы пользователь не мог менять временный обьект
if (to.semantic_node_type == semantic_node_type.static_property_reference ||
to.semantic_node_type == semantic_node_type.non_static_property_reference)
{
property_node pn;
if (to.semantic_node_type == semantic_node_type.static_property_reference)
pn = (to as static_property_reference).property;
else
pn = (to as non_static_property_reference).property;
var ot = MapCompositeAssignmentOperatorToSameBinaryOperator(_assign);
var oper_ass_in_prop = ot != Operators.Undefined;
if (_assign.operator_type == Operators.Assignment || oper_ass_in_prop)
{
if (oper_ass_in_prop)
{
if (pn.get_function == null)
AddError(loc, "THIS_PROPERTY_{0}_CAN_NOT_BE_READED", pn.name);
base_function_call prop_expr;
if (to.semantic_node_type == semantic_node_type.non_static_property_reference)
{
prop_expr = create_not_static_method_call(pn.get_function,
(to as non_static_property_reference).expression, loc, false);
prop_expr.parameters.AddRange((to as non_static_property_reference).fact_parametres);
}
else
{
prop_expr = create_static_method_call(pn.get_function, loc, pn.comprehensive_type, false);
prop_expr.parameters.AddRange((to as static_property_reference).fact_parametres);
}
from = find_operator(ot, prop_expr, from, loc);
}
if (to.semantic_node_type == semantic_node_type.static_property_reference)
{
static_property_reference spr = (static_property_reference) to;
if (spr.property.set_function == null)
{
AddError(loc, "THIS_PROPERTY_{0}_CAN_NOT_BE_WRITED", spr.property.name);
}
check_property_params(spr, loc);
function_node set_func = spr.property.set_function;
if (from.type is delegated_methods && !spr.property.property_type.IsDelegate)
from = convert_if_typed_expression_to_function_call(from, true);
from = convertion_data_and_alghoritms.convert_type(from, spr.property.property_type);
spr.fact_parametres.AddElement(from);
base_function_call bfc = create_static_method_call(set_func, loc,
spr.property.comprehensive_type,
true);
bfc.parameters.AddRange(spr.fact_parametres);
return_value((statement_node) bfc);
}
else if (to.semantic_node_type == semantic_node_type.non_static_property_reference)
{
non_static_property_reference nspr = (non_static_property_reference) to;
check_property_params(nspr, loc);
if (from.type is delegated_methods && !nspr.property.property_type.IsDelegate)
from = convert_if_typed_expression_to_function_call(from, true);
from = convertion_data_and_alghoritms.convert_type(from, nspr.property.property_type);
nspr.fact_parametres.AddElement(from);
//Обработка s[i]:='c'
if (SystemUnitAssigned)
if (nspr.property.comprehensive_type == SystemLibrary.SystemLibrary.string_type)
{
if (nspr.property == SystemLibrary.SystemLibrary.string_type.default_property_node)
{
if (SystemLibInitializer.StringDefaultPropertySetProcedure != null)
{
expressions_list exl = new expressions_list();
exl.AddElement(nspr.expression);
exl.AddElement(nspr.fact_parametres[0]);
exl.AddElement(from);
function_node fn = convertion_data_and_alghoritms.select_function(exl,
SystemLibInitializer.StringDefaultPropertySetProcedure
.SymbolInfo, loc);
expression_node ret =
convertion_data_and_alghoritms.create_simple_function_call(fn, loc,
exl.ToArray());
return_value((statement_node) ret);
return true;
}
}
}
if (nspr.property.set_function == null)
{
AddError(loc, "THIS_PROPERTY_{0}_CAN_NOT_BE_WRITED", nspr.property.name);
}
function_node set_func = nspr.property.set_function;
base_function_call bfc = create_not_static_method_call(set_func, nspr.expression, loc,
true);
bfc.parameters.AddRange(nspr.fact_parametres);
return_value((statement_node) bfc);
}
return true;
}
}
return false;
}
/// <summary>
/// Если addressedExpression это ссылка на переменную, то возвращает узел этой переменной.
/// Например, для namespace_variable_reference вернёт (addressedExpression as namespace_variable_reference).var
/// </summary>
/// <returns>Возвращает узел этой переменной, иначе null</returns>
private static var_definition_node GetLocalVariableFromAdressExpressionIfPossible(addressed_expression addressedExpression)
{
switch (addressedExpression.semantic_node_type)
{
case semantic_node_type.namespace_variable_reference:
return (addressedExpression as namespace_variable_reference).var;
case semantic_node_type.local_variable_reference:
return (addressedExpression as local_variable_reference).var;
case semantic_node_type.local_block_variable_reference:
return (addressedExpression as local_block_variable_reference).var;
default:
return null;
}
}
/// <summary>
/// Сопоставляет составному присваиванию его аналог.
/// Оператору '+=' возвращает '+', для '-=' возвращает '-', и т.д.
/// </summary>
/// <returns>Возвращает оператор. Если было передано не присваивание возвращает Operators.Undefined</returns>
private static Operators MapCompositeAssignmentOperatorToSameBinaryOperator(assign _assign)
{
switch (_assign.operator_type)
{
case Operators.AssignmentAddition:
return Operators.Plus;
case Operators.AssignmentBitwiseAND:
return Operators.BitwiseAND;
case Operators.AssignmentBitwiseLeftShift:
return Operators.BitwiseLeftShift;
case Operators.AssignmentBitwiseOR:
return Operators.BitwiseOR;
case Operators.AssignmentBitwiseRightShift:
return Operators.BitwiseRightShift;
case Operators.AssignmentBitwiseXOR:
return Operators.BitwiseXOR;
case Operators.AssignmentDivision:
return Operators.Division;
case Operators.AssignmentModulus:
return Operators.ModulusRemainder;
case Operators.AssignmentMultiplication:
return Operators.Multiplication;
case Operators.AssignmentSubtraction:
return Operators.Minus;
default:
return Operators.Undefined;
}
}
/// <summary>
/// Обрабатывает случай, когда левая часть присваивания имеет тип event.
/// </summary>
/// <returns>True - обработка прошла, иначе False.</returns>
private bool ProcessAssignmentToEventIfPossible(assign _assign, addressed_expression to, expression_node from,
location loc)
{
if ((to.semantic_node_type == semantic_node_type.static_event_reference)
|| (to.semantic_node_type == semantic_node_type.nonstatic_event_reference))
{
statement_node event_assign = null;
static_event_reference ser = (static_event_reference) to;
expression_node right_del = convertion_data_and_alghoritms.convert_type(from, ser.en.delegate_type);
switch (_assign.operator_type)
{
case Operators.AssignmentAddition:
{
if (to.semantic_node_type == semantic_node_type.static_event_reference)
{
event_assign = convertion_data_and_alghoritms.create_simple_function_call(
ser.en.add_method, loc, right_del);
}
else
{
if (ser.en.semantic_node_type == semantic_node_type.compiled_event)
{
nonstatic_event_reference nser = (nonstatic_event_reference) ser;
compiled_function_node cfn = (compiled_function_node) ser.en.add_method;
compiled_function_call tmp_event_assign = new compiled_function_call(cfn, nser.obj, loc);
tmp_event_assign.parameters.AddElement(right_del);
event_assign = tmp_event_assign;
}
else if (ser.en.semantic_node_type == semantic_node_type.common_event)
{
nonstatic_event_reference nser = (nonstatic_event_reference) ser;
common_method_node cfn = (common_method_node) ser.en.add_method;
common_method_call tmp_event_assign = new common_method_call(cfn, nser.obj, loc);
tmp_event_assign.parameters.AddElement(right_del);
event_assign = tmp_event_assign;
}
}
break;
}
case Operators.AssignmentSubtraction:
{
if (to.semantic_node_type == semantic_node_type.static_event_reference)
{
event_assign = convertion_data_and_alghoritms.create_simple_function_call(
ser.en.remove_method, loc, right_del);
}
else
{
if (ser.en.semantic_node_type == semantic_node_type.compiled_event)
{
nonstatic_event_reference nser = (nonstatic_event_reference) ser;
compiled_function_node cfn = (compiled_function_node) ser.en.remove_method;
compiled_function_call tmp_event_assign = new compiled_function_call(cfn, nser.obj, loc);
tmp_event_assign.parameters.AddElement(right_del);
event_assign = tmp_event_assign;
}
else if (ser.en.semantic_node_type == semantic_node_type.common_event)
{
nonstatic_event_reference nser = (nonstatic_event_reference) ser;
common_method_node cfn = (common_method_node) ser.en.remove_method;
common_method_call tmp_event_assign = new common_method_call(cfn, nser.obj, loc);
tmp_event_assign.parameters.AddElement(right_del);
event_assign = tmp_event_assign;
}
}
break;
}
default:
{
AddError(loc, "ASSIGN_TO_EVENT");
//throw new CanNotApplyThisOperationToEvent
break;
}
}
return_value(event_assign);
return true;
}
return false;
}
}
}