using System; using System.Collections.Generic; using System.Linq; using System.Text; using PascalABCCompiler.SyntaxTree; using PascalABCCompiler.TreeRealization; namespace PascalABCCompiler.TreeConverter { public partial class syntax_tree_visitor { public void semantic_check_assign_tuple(addressed_value_list vars, expression ex) { // Почти полностью идентичный код в двух проверках var expr = convert_strong(ex); expr = convert_if_typed_expression_to_function_call(expr); var t = ConvertSemanticTypeNodeToNETType(expr.type); if (t == null) AddError(expr.location, "TUPLE_OR_SEQUENCE_EXPECTED"); var IsTuple = false; var IsSequence = false; if (t.FullName.StartsWith("System.Tuple")) IsTuple = true; if (!IsTuple) { if (t.Name.Equals("IEnumerable`1") || t.GetInterface("IEnumerable`1") != null) IsSequence = true; } if (!IsTuple && !IsSequence) { AddError(expr.location, "TUPLE_OR_SEQUENCE_EXPECTED"); } if (IsTuple) { var n = vars.variables.Count(); if (n > t.GetGenericArguments().Count()) AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMRNT"); } } public void semantic_check_assign_var_tuple(ident_list vars, expression ex) { // Почти полностью идентичный код в двух проверках var expr = convert_strong(ex); expr = convert_if_typed_expression_to_function_call(expr); var t = ConvertSemanticTypeNodeToNETType(expr.type); if (t == null) AddError(expr.location, "TUPLE_OR_SEQUENCE_EXPECTED"); var IsTuple = false; var IsSequence = false; if (t.FullName.StartsWith("System.Tuple")) IsTuple = true; if (!IsTuple) { if (t.Name.Equals("IEnumerable`1") || t.GetInterface("IEnumerable`1") != null) IsSequence = true; } if (!IsTuple && !IsSequence) { AddError(expr.location, "TUPLE_OR_SEQUENCE_EXPECTED"); } if (IsTuple) { var n = vars.idents.Count(); if (n > t.GetGenericArguments().Count()) AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMRNT"); } } void semantic_check_method_call_as_slice_expr(SyntaxTree.method_call mc) // нельзя проверять сахарный узел, т.к.могут быть вложенные сахарные expression!! { var v = (mc.dereferencing_value as dot_node).left; var from = mc.parameters.expressions[1] as expression; var to = mc.parameters.expressions[2] as expression; expression step = mc.parameters.expressions.Count > 3 ? mc.parameters.expressions[3] : null; var semvar = convert_strong(v); if (semvar is typed_expression) semvar = convert_typed_expression_to_function_call(semvar as typed_expression); var IsSlicedType = 0; // проверим, является ли semvar.type динамическим массивом, списком List или строкой if (semvar.type.type_special_kind == SemanticTree.type_special_kind.array_kind) IsSlicedType = 1; if (IsSlicedType == 0) { var t = ConvertSemanticTypeNodeToNETType(semvar.type); // не работает для array of T // semvar.type должен быть array of T, List или string if (t == null) IsSlicedType = 0; // можно ничего не присваивать :) // else if (t.IsArray) // IsSlicedType = 1; else if (t == typeof(System.String)) IsSlicedType = 2; else if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List<>)) IsSlicedType = 3; } if (IsSlicedType == 0) AddError(get_location(v), "BAD_SLICE_OBJECT"); var semfrom = convert_strong(from); var b = convertion_data_and_alghoritms.can_convert_type(semfrom, SystemLibrary.SystemLibrary.integer_type); var fromIsIndex = (semfrom is common_constructor_call fromCall) && fromCall.common_type.comprehensive_namespace.namespace_full_name.Equals("PABCSystem") && fromCall.common_type.PrintableName.Equals("SystemIndex"); if (!b && !fromIsIndex) AddError(get_location(from), "INTEGER_VALUE_EXPECTED"); // semantic tree - type special kind // staticSystemLib посмотреть. // SystemIndex - переименовать. var semto = convert_strong(to); b = convertion_data_and_alghoritms.can_convert_type(semto, SystemLibrary.SystemLibrary.integer_type); var toIsIndex = (semto is common_constructor_call toCall) && toCall.common_type.comprehensive_namespace.namespace_full_name.Equals("PABCSystem") && toCall.common_type.PrintableName.Equals("SystemIndex"); if (!b && !toIsIndex) AddError(get_location(to), "INTEGER_VALUE_EXPECTED"); if (step != null) { var semstep = convert_strong(step); b = convertion_data_and_alghoritms.can_convert_type(semstep, SystemLibrary.SystemLibrary.integer_type); if (!b) AddError(get_location(step), "INTEGER_VALUE_EXPECTED"); } } /*void semantic_check_tuple(SyntaxTree.tuple_node tup) { //if (tup.el.expressions.Count > 7) // AddError(get_location(tup),"TUPLE_ELEMENTS_COUNT_MUST_BE_LESSEQUAL_7"); }*/ public void semantic_check_dot_question(SyntaxTree.question_colon_expression qce) { var av = convert_strong((qce.condition as bin_expr).left); Type t = null; if (av.type is compiled_generic_instance_type_node ctn2) t = ctn2.compiled_original_generic.compiled_type; else if (av.type is compiled_type_node ctn1) t = ctn1.compiled_type; if (av.type.type_special_kind == SemanticTree.type_special_kind.array_kind) return; if (!av.type.is_class && !av.type.IsInterface && !(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))) AddError(av.location, "OPERATOR_DQ_MUST_BE_USED_WITH_A_REFERENCE_TYPE_VALUETYPE"); } public void semantic_check_loop_stmt(SyntaxTree.expression ex) { var sem_ex = convert_strong(ex); var b = convertion_data_and_alghoritms.can_convert_type(sem_ex, SystemLibrary.SystemLibrary.integer_type); if (!b) AddError(sem_ex.location, "INTEGER_VALUE_EXPECTED"); } public void semantic_check_slice_assignment_types(SyntaxTree.expression expr1, SyntaxTree.expression expr2, method_call mc) { var slice = expr1 as slice_expr; var leftValue = convert_strong(slice.v); var leftType = leftValue.type; var rightValue = convert_strong(expr2); var rightType = rightValue.type; var v = slice.v; var from = mc.parameters.expressions[2] as expression; var to = mc.parameters.expressions[3] as expression; expression step = mc.parameters.expressions.Count > 4 ? mc.parameters.expressions[4] : null; var semvar = convert_strong(v); if (semvar is typed_expression) semvar = convert_typed_expression_to_function_call(semvar as typed_expression); var IsSlicedType = 0; // проверим, является ли semvar.type динамическим массивом, списком List или строкой if (semvar.type.type_special_kind == SemanticTree.type_special_kind.array_kind) IsSlicedType = 1; if (IsSlicedType == 0) { var t = ConvertSemanticTypeNodeToNETType(semvar.type); // не работает для array of T // semvar.type должен быть array of T, List или string if (t == null) IsSlicedType = 0; // можно ничего не присваивать :) // else if (t.IsArray) // IsSlicedType = 1; else if (t == typeof(System.String)) IsSlicedType = 2; else if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List<>)) IsSlicedType = 3; } if (IsSlicedType == 0) AddError(get_location(v), "BAD_SLICE_OBJECT"); var semfrom = convert_strong(from); var fromIsIndex = (semfrom is common_constructor_call fromCall) && fromCall.common_type.comprehensive_namespace.namespace_full_name.Equals("PABCSystem") && fromCall.common_type.PrintableName.Equals("SystemIndex"); var b = convertion_data_and_alghoritms.can_convert_type(semfrom, SystemLibrary.SystemLibrary.integer_type); if (!b && !fromIsIndex) AddError(get_location(from), "INTEGER_VALUE_EXPECTED"); var semto = convert_strong(to); var toIsIndex = (semto is common_constructor_call toCall) && toCall.common_type.comprehensive_namespace.namespace_full_name.Equals("PABCSystem") && toCall.common_type.PrintableName.Equals("SystemIndex"); b = convertion_data_and_alghoritms.can_convert_type(semto, SystemLibrary.SystemLibrary.integer_type); if (!b && !toIsIndex) AddError(get_location(to), "INTEGER_VALUE_EXPECTED"); if (step != null) { var semstep = convert_strong(step); b = convertion_data_and_alghoritms.can_convert_type(semstep, SystemLibrary.SystemLibrary.integer_type); if (!b) AddError(get_location(step), "INTEGER_VALUE_EXPECTED"); } if (!AreTheSameType(leftType, rightType)) { AddError(get_location(expr2), "EXPRESSION_OF_TYPE_{0}_CANNOT_BE_ASSIGNED_TO_SLICE_OF_TYPE_{1}", rightType.PrintableName, leftType.PrintableName); } } /*void common_diap_check(expression from, expression to) { }*/ void semantic_check_method_call_as_diapason_expr(SyntaxTree.method_call mc) { var from = mc.parameters.expressions[0]; var to = mc.parameters.expressions[1]; var semfrom = convert_strong(from); var b = convertion_data_and_alghoritms.can_convert_type(semfrom, SystemLibrary.SystemLibrary.integer_type); var b1 = false; var br = false; if (!b) b1 = convertion_data_and_alghoritms.can_convert_type(semfrom, SystemLibrary.SystemLibrary.char_type); if (!b1) br = convertion_data_and_alghoritms.can_convert_type(semfrom, SystemLibrary.SystemLibrary.double_type); if (!b && !b1 && !br) AddError(get_location(from), "INTEGER_OR_REAL_OR_CHAR_VALUE_EXPECTED"); var semto = convert_strong(to); var c = convertion_data_and_alghoritms.can_convert_type(semto, SystemLibrary.SystemLibrary.integer_type); var c1 = false; var cr = false; if (!c) c1 = convertion_data_and_alghoritms.can_convert_type(semto, SystemLibrary.SystemLibrary.char_type); if (!c1) cr = convertion_data_and_alghoritms.can_convert_type(semto, SystemLibrary.SystemLibrary.double_type); if (!c && !c1 && !cr) AddError(get_location(to), "INTEGER_OR_REAL_OR_CHAR_VALUE_EXPECTED"); //if (b != c || c1 != b1 || cr != br) if (b && c || c1 && b1 || cr && br) return; if (b && cr || c && br) return; AddError(get_location(to), "INCOMPATIBLE_DIAPASON_BOUNDS_TYPES"); } void semantic_check_method_call_as_inrange_expr(SyntaxTree.method_call mc) { var v = mc.parameters.expressions[0]; var from = mc.parameters.expressions[1]; var to = mc.parameters.expressions[2]; var semv = convert_strong(v); var a = convertion_data_and_alghoritms.can_convert_type(semv, SystemLibrary.SystemLibrary.integer_type); var a1 = false; var ar = false; if (!a) a1 = convertion_data_and_alghoritms.can_convert_type(semv, SystemLibrary.SystemLibrary.char_type); if (!a1) ar = convertion_data_and_alghoritms.can_convert_type(semv, SystemLibrary.SystemLibrary.double_type); if (!a && !a1 && !ar) AddError(get_location(v), "INTEGER_OR_REAL_OR_CHAR_VALUE_EXPECTED"); var semfrom = convert_strong(from); var b = convertion_data_and_alghoritms.can_convert_type(semfrom, SystemLibrary.SystemLibrary.integer_type); var b1 = false; var br = false; if (!b) b1 = convertion_data_and_alghoritms.can_convert_type(semfrom, SystemLibrary.SystemLibrary.char_type); if (!b1) br = convertion_data_and_alghoritms.can_convert_type(semfrom, SystemLibrary.SystemLibrary.double_type); if (!b && !b1 && !br) AddError(get_location(from), "INTEGER_OR_REAL_OR_CHAR_VALUE_EXPECTED"); var semto = convert_strong(to); var c = convertion_data_and_alghoritms.can_convert_type(semto, SystemLibrary.SystemLibrary.integer_type); var c1 = false; var cr = false; if (!c) c1 = convertion_data_and_alghoritms.can_convert_type(semto, SystemLibrary.SystemLibrary.char_type); if (!c1) cr = convertion_data_and_alghoritms.can_convert_type(semto, SystemLibrary.SystemLibrary.double_type); if (!c && !c1 && !cr) AddError(get_location(to), "INTEGER_OR_REAL_OR_CHAR_VALUE_EXPECTED"); var incompbound = true; if (b && c || c1 && b1 || cr && br) incompbound = false; if (b && cr || c && br) incompbound = false; if (incompbound) AddError(get_location(to), "INCOMPATIBLE_DIAPASON_BOUNDS_TYPES"); if (a && b1 || ar && b1 || a1 && b || a1 && c) AddError(get_location(v), "INCOMPATIBLE_TYPES_OF_ELEMENT_AND_DIAPASON"); } void semantic_check_for_new_range(SyntaxTree.diapason_expr_new diap, type_definition td, ident id) { var from = diap.left; var to = diap.right; var semfrom = convert_strong(from); var b = convertion_data_and_alghoritms.can_convert_type(semfrom, SystemLibrary.SystemLibrary.integer_type); var b1 = false; if (!b) b1 = convertion_data_and_alghoritms.can_convert_type(semfrom, SystemLibrary.SystemLibrary.char_type); if (!b && !b1) AddError(get_location(from), "INTEGER_OR_CHAR_VALUE_EXPECTED"); var semto = convert_strong(to); var c = convertion_data_and_alghoritms.can_convert_type(semto, SystemLibrary.SystemLibrary.integer_type); var c1 = false; if (!c) c1 = convertion_data_and_alghoritms.can_convert_type(semto, SystemLibrary.SystemLibrary.char_type); if (!c && !c1) AddError(get_location(to), "INTEGER_OR_CHAR_VALUE_EXPECTED"); if (b != c || c1 != b1) AddError(get_location(to), "INCOMPATIBLE_DIAPASON_BOUNDS_TYPES"); if (td != null && !(td is no_type_foreach)) { // то мы определили тип явно в заголовке var semtype = convert_strong(td); var d = convertion_data_and_alghoritms.can_convert_type(semtype, SystemLibrary.SystemLibrary.integer_type); var d1 = false; if (!d) d1 = convertion_data_and_alghoritms.can_convert_type(semtype, SystemLibrary.SystemLibrary.char_type); if (!d && !d1) AddError(get_location(td), "INTEGER_OR_CHAR_VALUE_EXPECTED"); if (b != d || b1 != d1) AddError(get_location(id), "INCOMPATIBLE_TYPES_OF_ELEMENT_AND_DIAPASON"); } else if (td == null) { var semid = convert_strong(id); var e = convertion_data_and_alghoritms.can_convert_type(semid, SystemLibrary.SystemLibrary.integer_type); var e1 = false; if (!e) e1 = convertion_data_and_alghoritms.can_convert_type(semid, SystemLibrary.SystemLibrary.char_type); if (!e && !e1) AddError(get_location(id), "INTEGER_OR_CHAR_VALUE_EXPECTED"); if (b != e || b1 != e1) AddError(get_location(id), "INCOMPATIBLE_TYPES_OF_ELEMENT_AND_DIAPASON"); } } void semantic_check_for_indices(SyntaxTree.expression expr) { // Надо проверить, что expr - это одноразмерный массив или список. Эта проверка была в visit(foreach) var semexpr = convert_strong(expr); var Is1DArr = Is1DArray(semexpr); var il = IsIList(semexpr); // Тут может быть другая ситуация - Indices может быть членом semexpr - и тогда нельзя преобразовывать if (!Is1DArr && !il) AddError(get_location(expr), "ONE_DIM_ARRAY_OR_LIST_EXPECTED"); } } }