/// <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; 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.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> /// Обрабатывает случай, когда левая часть присваивания 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(compiler_string_consts.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(compiler_string_consts.assign_name, to, clip_expr, get_location(_assign)); return_value(en); return(true); } } return(false); }
/// <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> /// Обрабатывает случай, когда левая часть присваивания имеет тип 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); }
/// <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>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; 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); 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> /// Автовыведение типов в 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> /// Преобразует в семантическое представление поля to и from, проводя семантические проверки. /// </summary> private void AssignCheckAndConvert(assign _assign, out addressed_expression to, out expression_node from) { 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); //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 = convert_strong(_assign.from); 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() && !SemanticRules.AllowChangeLoopVariable) { var_definition_node toAsVariable = GetLocalVariableFromAdressExpressionIfPossible(to); if (toAsVariable != null && context.is_loop_variable(toAsVariable)) { 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"); } } }