pascalabcnet/TreeConverter/TreeConversion/semantic_checks_for_sugar.cs
2025-05-24 21:36:36 +03:00

461 lines
21 KiB
C#
Raw Permalink 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 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 = IsTupleType(t);
var IsKeyValuePair = !IsTuple && IsKeyValuePairType(t);
var IsSequence = !IsTuple && IsSequenceType(t);
if (!IsTuple && !IsKeyValuePair && !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_ASSIGNMENT");
}
if (IsKeyValuePair)
{
var n = vars.variables.Count();
if (n > 2)
AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_KEYVALUEPAIR_ASSIGNMENT");
}
}
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)
{
bool bb;
type_node elem_type = null;
var b = FindIEnumerableElementType(expr.type, ref elem_type, out bb);
if (!b)
AddError(expr.location, "TUPLE_OR_SEQUENCE_EXPECTED");
return;
}
var IsTuple = IsTupleType(t);
var IsKeyValuePair = !IsTuple && IsKeyValuePairType(t);
var IsSequence = !IsTuple && !IsKeyValuePair && IsSequenceType(t);
if (!IsTuple && !IsKeyValuePair && !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_ASSIGNMENT");
}
if (IsKeyValuePair)
{
var n = vars.idents.Count();
if (n > 2)
AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_KEYVALUEPAIR_ASSIGNMENT");
}
}
void CheckOrdinaryType(expression ex)
{
var expr = convert_strong(ex);
internal_interface ii = expr.type.get_internal_interface(internal_interface_kind.ordinal_interface);
if (ii == null)
{
AddError(new OrdinalTypeExpected(get_location(ex)));
}
}
void CheckOrdinaryType(expression_node expr)
{
internal_interface ii = expr.type.get_internal_interface(internal_interface_kind.ordinal_interface);
if (ii == null)
{
AddError(new OrdinalTypeExpected(expr.location));
}
}
void CheckInteger(expression ex)
{
if (ex == null)
return;
var semex = convert_strong(ex);
var b = convertion_data_and_alghoritms.can_convert_type(semex, SystemLibrary.SystemLibrary.integer_type);
if (!b)
AddError(get_location(ex), "INTEGER_VALUE_EXPECTED");
}
void CheckIntegerOrIndex(expression ex)
{
var semex = convert_strong(ex);
var b = convertion_data_and_alghoritms.can_convert_type(semex, SystemLibrary.SystemLibrary.integer_type);
var toIsIndex = (semex is common_constructor_call toCall) &&
toCall.common_type.comprehensive_namespace.namespace_full_name.Equals(StringConstants.pascalSystemUnitName) &&
toCall.common_type.PrintableName.Equals("SystemIndex");
var toIsIndex1 = (semex is compiled_constructor_call toCall1) &&
toCall1.compiled_type.compiled_type.FullName.Equals("PABCSystem.SystemIndex");
if (!b && !toIsIndex && !toIsIndex1)
{
AddError(get_location(ex), "INTEGER_VALUE_EXPECTED");
}
}
void semantic_check_method_call_as_slice_expr(SyntaxTree.method_call mc)
// нельзя проверять сахарный узел, т.к.могут быть вложенные сахарные expression!!
{
var v = (mc.dereferencing_value as dot_node).left;
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<T> или 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 from = mc.parameters.expressions[1];
var to = mc.parameters.expressions[2];
expression step = mc.parameters.expressions.Count > 3 ? mc.parameters.expressions[3] : null;
CheckIntegerOrIndex(from);
CheckIntegerOrIndex(to);
CheckInteger(step);
}
void semantic_check_method_call_as_slice_expr_multi(SyntaxTree.method_call mc)
{
var v = (mc.dereferencing_value as dot_node).left;
var semvar = convert_strong(v);
if (semvar is typed_expression)
semvar = convert_typed_expression_to_function_call(semvar as typed_expression);
if (semvar.type.type_special_kind != SemanticTree.type_special_kind.array_kind)
AddError(semvar.location, "SLICES_MULTI_DIMENSIONAL_ARRAY_EXPECTED");
// Теперь с размерностями разберёмся
int rank = 0;
if (semvar.type is compiled_type_node)
rank = (semvar.type as compiled_type_node).rank;
else if (semvar.type is common_type_node)
rank = (semvar.type as common_type_node).rank;
if (rank != mc.parameters.Count)
AddError(semvar.location, "NUMBER_OF_SLICES_IN_MULTIDIMENSIONAL_ARRAY_SHOULD_BE_EQUAL_TO_ARRAY_RANK");
foreach (var param in mc.parameters.expressions)
{
var p = param as method_call; // Tuple.Create
if (p == null)
AddError(semvar.location, "_Compiler_error_param_must_be_Tuple");
var from = p.parameters.expressions[0];
var to = p.parameters.expressions[1];
var step = p.parameters.expressions[2];
CheckIntegerOrIndex(from);
CheckIntegerOrIndex(to);
CheckInteger(step);
}
}
/*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 != null && t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) && !av.type.is_generic_parameter && !av.type.IsDelegate)
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<T> или 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(StringConstants.pascalSystemUnitName) &&
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(StringConstants.pascalSystemUnitName) &&
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");
}
}
}