This commit is contained in:
Mikhalkovich Stanislav 2024-08-18 16:05:42 +03:00
commit db4b53be20
22 changed files with 694 additions and 244 deletions

View file

@ -1,11 +1,12 @@
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
//ѕри внесении изменений в структуру PCU файла версию увеличить на 1
// при внесении изменений в структуру PCU файла версию увеличить на 1
namespace PascalABCCompiler.PCU
{
public static class PCUFileFormatVersion
{
public static System.Int16 Version = 120;
public static System.Int16 Version = 121;
}
}

View file

@ -3238,7 +3238,12 @@ namespace PascalABCCompiler.PCU
var_definition_node vdn = GetLocalOrNamespaceVariableByOffset(br.ReadInt32());
expression_node expr = CreateExpression();
statement_node body = CreateStatement();
return new foreach_node(vdn, expr, body, null);
type_node elementType = null;
if (CanReadObject())
elementType = GetTypeReference();
bool isGeneric = br.ReadBoolean();
return new foreach_node(vdn, expr, body, elementType, isGeneric, null);
}
private statement_node CreateLock()

View file

@ -3558,6 +3558,9 @@ namespace PascalABCCompiler.PCU
bw.Write(GetMemberOffset(fn.ident));
VisitExpression(fn.in_what);
VisitStatement(fn.what_do);
if (CanWriteObject(fn.element_type))
WriteTypeReference(fn.element_type);
bw.Write(fn.is_generic);
}
private void VisitLock(lock_statement node)

View file

@ -866,58 +866,6 @@ namespace PascalABCCompiler.NETGenerator {
return null;
}
public MethodInfo GetEnumeratorMethod(Type t, out Type[] generic_args)
{
generic_args = null;
Type generic_def = null;
if (t.IsGenericType && !t.IsGenericTypeDefinition)
generic_def = t.GetGenericTypeDefinition();
else
generic_def = t;
if (generic_def.IsArray && generic_def.GetElementType().IsGenericParameter)
{
return TypeFactory.IEnumerableGenericType.GetMethod("GetEnumerator");
}
if (generic_def.IsArray)
{
if (IsConstructedGenericType(generic_def.GetElementType()))
return TypeBuilder.GetMethod(TypeFactory.IEnumerableGenericType.MakeGenericType(generic_def.GetElementType()), TypeFactory.IEnumerableGenericType.GetMethod("GetEnumerator"));
else
return TypeFactory.IEnumerableGenericType.MakeGenericType(generic_def.GetElementType()).GetMethod("GetEnumerator");
}
else if (generic_def.IsGenericParameter)
{
return TypeFactory.IEnumerableType.GetMethod("GetEnumerator", Type.EmptyTypes);
}
foreach (Type interf in generic_def.GetInterfaces())
{
if (interf.IsGenericType && interf.GetGenericTypeDefinition() == TypeFactory.IEnumerableGenericType)
{
MethodInfo mi = interf.GetGenericTypeDefinition().GetMethod("GetEnumerator");
if (generic_def != t)
{
if (t.GetGenericArguments().Length != interf.GetGenericTypeDefinition().GetGenericArguments().Length)
return null;
Type gt = interf.GetGenericTypeDefinition().MakeGenericType(t.GetGenericArguments());
if (IsConstructedGenericType(gt))
return TypeBuilder.GetMethod(gt, mi);
else
return interf.GetGenericTypeDefinition().MakeGenericType(t.GetGenericArguments()).GetMethod("GetEnumerator");
}
else if (IsConstructedGenericType(interf))
{
//return TypeBuilder.GetMethod(TypeFactory.IEnumerableGenericType.MakeGenericType(interf.GetGenericArguments()), TypeFactory.IEnumerableGenericType.GetMethod("GetEnumerator"));
//return TypeFactory.IEnumerableType.GetMethod("GetEnumerator", Type.EmptyTypes);
generic_args = interf.GetGenericArguments();
return TypeBuilder.GetMethod(interf, mi);
}
else
return interf.GetMethod("GetEnumerator");
}
}
return TypeFactory.IEnumerableType.GetMethod("GetEnumerator", Type.EmptyTypes);
}
public void SetAsProcessing(ICommonTypeNode type)
{
processing_types[type] = true;

View file

@ -1755,7 +1755,18 @@ namespace PascalABCCompiler.NETGenerator
private void AddTypeWithoutConvert(ICommonTypeNode t)
{
if (helper.GetTypeReference(t) != null) return;
TypeBuilder tb = mb.DefineType(BuildTypeName(t.name), ConvertAttributes(t), t.is_value_type?TypeFactory.ValueType:null, new Type[0]);
TypeBuilder tb = null;
try
{
tb = mb.DefineType(BuildTypeName(t.name), ConvertAttributes(t), t.is_value_type ? TypeFactory.ValueType : null, new Type[0]);
}
catch (ArgumentException ex)
{
if (ex.Message.IndexOf("fullname") != -1)
throw new PascalABCCompiler.Errors.CommonCompilerError(ex.Message.Replace("System.ArgumentException: ", ""), t.Location.document.file_name, t.Location.begin_line_num, t.Location.begin_column_num);
throw ex;
}
helper.AddType(t, tb);
//(ssyy) обрабатываем generics
if (t.is_generic_type_definition)
@ -8268,7 +8279,7 @@ namespace PascalABCCompiler.NETGenerator
private bool EmitBox(IExpressionNode from, Type LocalType)
{
if ((from.type.is_value_type || from.type.is_generic_parameter) && !(from is SemanticTree.INullConstantNode) && (LocalType == TypeFactory.ObjectType || TypeIsInterface(LocalType)))
if ((from.type.is_value_type || from.type.is_generic_parameter) && !(from is SemanticTree.INullConstantNode) && (LocalType == TypeFactory.ObjectType || TypeIsInterface(LocalType) || LocalType == TypeFactory.EnumType))
{
il.Emit(OpCodes.Box, helper.GetTypeReference(from.type).tp);//упаковка
return true;
@ -9850,6 +9861,10 @@ namespace PascalABCCompiler.NETGenerator
case basic_function_type.ior: il.Emit(OpCodes.Or); break;
case basic_function_type.ixor: il.Emit(OpCodes.Xor); break;
case basic_function_type.enumsand: il.Emit(OpCodes.And); break;
case basic_function_type.enumsor: il.Emit(OpCodes.Or); break;
case basic_function_type.enumsxor: il.Emit(OpCodes.Xor); break;
case basic_function_type.land: il.Emit(OpCodes.And); break;
case basic_function_type.lor: il.Emit(OpCodes.Or); break;
case basic_function_type.lxor: il.Emit(OpCodes.Xor); break;
@ -11601,40 +11616,46 @@ namespace PascalABCCompiler.NETGenerator
public override void visit(IForeachNode value)
{
VarInfo vi = helper.GetVariable(value.VarIdent);
//Type interf = helper.GetTypeReference(value.InWhatExpr.type).tp;
Type var_tp = helper.GetTypeReference(value.VarIdent.type).tp;
//(ssyy) 12.04.2008 Поиск IEnumerable не нужен! Это дело семантики!
Type in_what_type = helper.GetTypeReference(value.InWhatExpr.type).tp;
Type return_type = null;
bool is_generic = false;
Type[] generic_args = null;
MethodInfo enumer_mi = null; //typeof(System.Collections.IEnumerable).GetMethod("GetEnumerator", Type.EmptyTypes);
if (/*var_tp.IsValueType &&*/ !var_tp.IsGenericParameter && !(in_what_type.IsArray && in_what_type.GetArrayRank() > 1))
Type return_type;
MethodInfo enumer_mi;
Type elementType = helper.GetTypeReference(value.ElementType).tp;
bool is_generic = value.IsGeneric;
if (is_generic)
{
enumer_mi = helper.GetEnumeratorMethod(in_what_type, out generic_args);
if (enumer_mi == null)
// если элемент перечисления объявлен в коде
// или типоаргумент элемента перечисления объявлен в коде
// например IEnumerable<MyType>, array of MyType
if (helper.IsConstructedGenericType(elementType))
{
enumer_mi = typeof(System.Collections.IEnumerable).GetMethod("GetEnumerator", Type.EmptyTypes);
return_type = enumer_mi.ReturnType;
enumer_mi = TypeBuilder.GetMethod(
TypeFactory.IEnumerableGenericType.MakeGenericType(elementType),
TypeFactory.IEnumerableGenericType.GetMethod("GetEnumerator")
);
// IEnumerator<elementType>
return_type = enumer_mi.ReturnType
.GetGenericTypeDefinition()
.MakeGenericType(elementType);
}
// для полностью скомпилированных типов TypeBuilder не требуется
// IEnumerable<integer>, array of string
else
{
is_generic = enumer_mi.ReturnType.IsGenericType;
enumer_mi = TypeFactory.IEnumerableGenericType.MakeGenericType(elementType).GetMethod("GetEnumerator");
return_type = enumer_mi.ReturnType;
if (in_what_type.IsGenericType && return_type.IsGenericType && !return_type.IsGenericTypeDefinition)
return_type = return_type.GetGenericTypeDefinition().MakeGenericType(in_what_type.GetGenericArguments());
else if (in_what_type.IsArray && return_type.IsGenericType && !return_type.IsGenericTypeDefinition)
return_type = return_type.GetGenericTypeDefinition().MakeGenericType(in_what_type.GetElementType());
else if (generic_args != null)
return_type = return_type.GetGenericTypeDefinition().MakeGenericType(generic_args);
}
}
else
{
enumer_mi = typeof(System.Collections.IEnumerable).GetMethod("GetEnumerator", Type.EmptyTypes);
enumer_mi = TypeFactory.IEnumerableType.GetMethod("GetEnumerator");
return_type = enumer_mi.ReturnType;
}
LocalBuilder lb = il.DeclareLocal(return_type);
if (save_debug_info) lb.SetLocalSymInfo("$enumer$" + uid++);

View file

@ -64,7 +64,7 @@ namespace PascalABCCompiler.SemanticTree
//write,writei,writed,writec,writeb,read,readi,readd,readc,readb,expd,absd,absi //temporary functions (Нужны только на начальном этапе отладки. Потом обязательно удалить.)
objtoobj, boolinc, booldec, boolsinc, boolsdec, booltoi, enumgr, enumgreq, enumsm, enumsmeq,
booltob, booltosb, booltos, booltous, booltoui, booltol, booltoul,
ltop, ptol
ltop, ptol, enumsand, enumsor, enumsxor
};
public enum runtime_statement_type { invoke_delegate, ctor_delegate, begin_invoke_delegate, end_invoke_delegate };
@ -2350,6 +2350,16 @@ namespace PascalABCCompiler.SemanticTree
{
get;
}
ITypeNode ElementType
{
get;
}
bool IsGeneric
{
get;
}
}
public interface ILockStatement : IStatementNode, ILocated

12
TestSuite/enum10.pas Normal file
View file

@ -0,0 +1,12 @@
type
Days = (mon,Tue,Wed,Thi,Fri,Sat,Sun);
procedure MyPrint(obj: object);
begin
assert(obj.ToString() = 'Fri');
end;
begin
var en: System.Enum;
en := fri;
MyPrint(en);
end.

19
TestSuite/enum9.pas Normal file
View file

@ -0,0 +1,19 @@
type
Days = (
None = 0, // 0
Monday = 1, // 1
Tuesday = 2, // 2
Wednesday = 4, // 4
Thursday = 8, // 8
Friday = 16, // 16
Saturday = 32, // 32
Sunday = 64, // 64
Weekend = Saturday or Sunday
);
begin
var d : Days := Saturday;
var meetingDays := Days.Monday or Days.Friday;
assert((d and Days.Weekend) = Saturday);
assert((meetingDays and Days.Friday) = Days.Friday);
end.

View file

@ -0,0 +1,20 @@
//!Невозможно выполнить оператор foreach или yield sequence по выражению типа c1
uses System.Collections, System.Collections.Generic;
type
c1 = class (IEnumerable<integer>, IEnumerable<string>)
public
function IEnumerable<string>.GetEnumerator: IEnumerator<string>;
begin end;
function IEnumerable<integer>.GetEnumerator: IEnumerator<integer>;
begin end;
function IEnumerable.GetEnumerator: IEnumerator;
begin end;
end;
begin
foreach var item in new c1 do ;
end.

View file

@ -0,0 +1,6 @@
type
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = class end;
begin
System.Reflection.Assembly.GetEntryAssembly.GetTypes.Single(t->t.Name.StartsWith('a'*50)).FullName.Println.Length.Print;
end.

View file

@ -0,0 +1,48 @@
{$reference 'foreach_resolver_lib.dll'}
type
c0 = class
procedure pr:= exit;
end;
begin
var v1:= new c1<integer, c0>;
v1._element:= new c0;
foreach var item in v1 do
item.pr;
Assert(check);
check:= false;
var v2:= new c2;
v2._element:= 'myStr';
foreach var item in v2 do
item.Replace('my', 'your');
Assert(check);
check:= false;
var v3:= new c3;
v3._element:= 'myStr';
foreach var item in v3 do
print(item);
Assert(check);
check:= false;
var v4:= new c4;
v4._element:= 'myStr';
foreach var item in v4 do
item.Replace('my', 'your');
Assert(check);
check:= false;
var v5:= new c5;
v5._element:= 4;
foreach var item in v5 do
Assert(item = 4);
Assert(check);
end.

View file

@ -0,0 +1,67 @@
uses System.Collections, System.Collections.Generic;
type
c1 = class (IEnumerable<integer>)
public
function IEnumerable<integer>.GetEnumerator: IEnumerator<integer>;
begin
Assert(false);
end;
function GetEnumerator: IEnumerator;
begin
result:= Seq&<object>().GetEnumerator;
end;
end;
c2<T1, T2> = class (IEnumerable<T2>)
public
function GetEnumerator: IEnumerator<T2>;
begin
result:= Seq&<T2>().GetEnumerator;
end;
function IEnumerable.GetEnumerator: IEnumerator;
begin
Assert(false);
end;
end;
c3 = class (IEnumerable<integer>, IEnumerable<string>)
public
function GetEnumerator: IEnumerator<string>;
begin
result:= Seq&<string>().GetEnumerator;
end;
function IEnumerable<integer>.GetEnumerator: IEnumerator<integer>;
begin
Assert(false);
end;
function IEnumerable.GetEnumerator: IEnumerator;
begin
Assert(false);
end;
end;
c4 = class (c2<integer, int64>)
end;
begin
var v1:= new c1;
foreach var item in v1 do ;
var v2:= new c2<byte, string>;
foreach var item in v2 do ;
var v3:= new c3;
foreach var item in v3 do ;
var v4:= new c4;
foreach var item in v4 do ;
end.

Binary file not shown.

View file

@ -0,0 +1,58 @@
library foreach_resolver_lib;
uses System.Collections, System.Collections.Generic;
var check:= false;
type
c1<T1, T2> = class (IEnumerable<T1>, IEnumerable<T2>)
public
_element: T2;
function GetEnumerator: IEnumerator<T2>;
begin
check:= true;
result:= lst( _element ).GetEnumerator;
end;
function IEnumerable<T1>.GetEnumerator: IEnumerator<T1>;
begin end;
function IEnumerable.GetEnumerator: IEnumerator;
begin end;
end;
c2 = class (IEnumerable<integer>, IEnumerable<string>)
public
_element: string;
function GetEnumerator: IEnumerator<string>;
begin
check:= true;
result:= lst(_element).GetEnumerator;
end;
function IEnumerable<integer>.GetEnumerator: IEnumerator<integer>;
begin end;
function IEnumerable.GetEnumerator: IEnumerator;
begin end;
end;
c3 = class (IEnumerable<string>)
public
_element: object;
function IEnumerable<string>.GetEnumerator: IEnumerator<string>;
begin end;
function GetEnumerator: IEnumerator;
begin
check:= true;
result:= |_element|.GetEnumerator;
end;
end;
c4 = class (c2) end;
c5 = class (c1<string, integer>) end;
end.

6
TestSuite/nullable18.pas Normal file
View file

@ -0,0 +1,6 @@
begin
var a := |default(integer?),nil,1|;
assert(a[1] = nil);
assert(a[0] = nil);
assert(a[2] = 1);
end.

View file

@ -641,8 +641,8 @@ namespace TreeConverter.LambdaExpressions.Closure
type_node elemType = null;
if (inWhat.type == null)
inWhat = tmp;
bool bb; // здесь bb не нужно. Оно нужно в foreach
_visitor.FindIEnumerableElementType(/*_foreach_stmt, */inWhat.type, ref elemType, out bb);
bool sys_coll_ienum;
_visitor.FindIEnumerableElementType(/*_foreach_stmt, */inWhat.type, ref elemType, out sys_coll_ienum);
if (_foreach_stmt.type_name == null)
{
@ -676,7 +676,7 @@ namespace TreeConverter.LambdaExpressions.Closure
if (!(vdn.type is compiled_generic_instance_type_node))
_visitor.convertion_data_and_alghoritms.check_convert_type_with_inheritance(vdn.type, elemType, _visitor.get_location(_foreach_stmt.identifier));
var fn = new foreach_node(vdn, inWhat, null, _visitor.get_location(_foreach_stmt));
var fn = new foreach_node(vdn, inWhat, null, elemType, !sys_coll_ienum, _visitor.get_location(_foreach_stmt));
_visitor.context.enter_in_cycle(fn);
_visitor.context.loop_var_stack.Push(vdn);

View file

@ -2683,12 +2683,18 @@ namespace PascalABCCompiler.SystemLibrary
int_const_node left = parameters[0] as int_const_node;
if (left == null)
{
return null;
if (parameters[0] is enum_const_node ecn)
left = new int_const_node(ecn.constant_value, ecn.location);
else
return null;
}
int_const_node right = parameters[1] as int_const_node;
if (right == null)
{
return null;
if (parameters[1] is enum_const_node ecn)
right = new int_const_node(ecn.constant_value, ecn.location);
else
return null;
}
return (make_int_const(((left.constant_value) | (right.constant_value)), call_location));
}

View file

@ -36,7 +36,9 @@ namespace PascalABCCompiler.TreeConverter
expression_node foreachCollection;
var_definition_node foreachVariable;
ForeachCheckAndConvert(_foreach_stmt, out foreachCollection, out foreachVariable);
type_node elementType;
bool isGeneric;
ForeachCheckAndConvert(_foreach_stmt, out foreachCollection, out foreachVariable, out elementType, out isGeneric);
definition_node dnind = null;
var_definition_node vdn = null;
@ -54,7 +56,14 @@ namespace PascalABCCompiler.TreeConverter
statements_list sl = new statements_list(get_location(_foreach_stmt.stmt));
convertion_data_and_alghoritms.statement_list_stack_push(sl);
foreach_node foreachNode = new foreach_node(foreachVariable, foreachCollection, null, get_location(_foreach_stmt));
foreach_node foreachNode = new foreach_node(
foreachVariable,
foreachCollection,
null,
elementType,
isGeneric,
get_location(_foreach_stmt)
);
context.enter_in_cycle(foreachNode);
context.loop_var_stack.Push(foreachVariable);
@ -115,8 +124,13 @@ namespace PascalABCCompiler.TreeConverter
}
private void ForeachCheckAndConvert(foreach_stmt _foreach_stmt, out expression_node foreachCollection,
out var_definition_node foreachVariable)
private void ForeachCheckAndConvert(
foreach_stmt _foreach_stmt,
out expression_node foreachCollection,
out var_definition_node foreachVariable,
out type_node elementType,
out bool isGenereic
)
{
var lambdaSearcher = new LambdaSearcher(_foreach_stmt.in_what);
if (lambdaSearcher.CheckIfContainsLambdas())
@ -135,6 +149,9 @@ namespace PascalABCCompiler.TreeConverter
if (!FindIEnumerableElementType(foreachCollection.type, ref elem_type, out sys_coll_ienum))
AddError(foreachCollection.location, "CAN_NOT_EXECUTE_FOREACH_BY_EXPR_OF_TYPE_{0}", foreachCollection.type.name);
elementType = elem_type;
isGenereic = !sys_coll_ienum;
var vars = _foreach_stmt.ext as ident_list;
if (vars != null)
{

View file

@ -2052,8 +2052,11 @@ namespace PascalABCCompiler.TreeConverter
SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.greq_name,tctn,SemanticTree.basic_function_type.enumgreq,SystemLibrary.SystemLibrary.bool_type);
SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.sm_name,tctn,SemanticTree.basic_function_type.enumsm,SystemLibrary.SystemLibrary.bool_type);
SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.smeq_name,tctn,SemanticTree.basic_function_type.enumsmeq,SystemLibrary.SystemLibrary.bool_type);
SystemLibrary.SystemLibrary.make_generated_type_conversion(tctn,SystemLibrary.SystemLibrary.byte_type,type_compare.greater_type,PascalABCCompiler.SemanticTree.basic_function_type.itob,false);
SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.or_name, tctn, SemanticTree.basic_function_type.enumsor, tctn);
SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.and_name, tctn, SemanticTree.basic_function_type.enumsand, tctn);
SystemLibrary.SystemLibrary.make_binary_operator(StringConstants.xor_name, tctn, SemanticTree.basic_function_type.enumsxor, tctn);
SystemLibrary.SystemLibrary.make_generated_type_conversion(tctn,SystemLibrary.SystemLibrary.byte_type,type_compare.greater_type,PascalABCCompiler.SemanticTree.basic_function_type.itob,false);
SystemLibrary.SystemLibrary.make_generated_type_conversion(tctn,SystemLibrary.SystemLibrary.sbyte_type,type_compare.greater_type,PascalABCCompiler.SemanticTree.basic_function_type.itosb,false);
SystemLibrary.SystemLibrary.make_generated_type_conversion(tctn,SystemLibrary.SystemLibrary.short_type,type_compare.greater_type,PascalABCCompiler.SemanticTree.basic_function_type.itos,false);
SystemLibrary.SystemLibrary.make_generated_type_conversion(tctn,SystemLibrary.SystemLibrary.ushort_type,type_compare.greater_type,PascalABCCompiler.SemanticTree.basic_function_type.itous,false);

View file

@ -3285,7 +3285,8 @@ namespace PascalABCCompiler.TreeConverter
ret_type = types[i];
else if (tc == type_compare.non_comparable_type)
{
AddError(lst[i].location, "UNCOMPARABLE_TYPES_IN_ARRAY_CONST");
if (!can_convert_type(types[i], ret_type))
AddError(lst[i].location, "UNCOMPARABLE_TYPES_IN_ARRAY_CONST");
}
}

View file

@ -25,6 +25,8 @@ using while_node = PascalABCCompiler.TreeRealization.while_node;
using TreeConverter.LambdaExpressions.Closure;
using TreeConverter.LambdaExpressions;
using PascalABCCompiler.TreeConverter.TreeConversion;
using System.Reflection;
using PascalABCCompiler.SemanticTree;
namespace PascalABCCompiler.TreeConverter
{
@ -1178,7 +1180,12 @@ namespace PascalABCCompiler.TreeConverter
left_type = SystemLibrary.SystemLibrary.integer_type;
left.type = left_type;
}
if (right_type == null && right is enum_const_node)
{
right_type = SystemLibrary.SystemLibrary.integer_type;
right.type = right_type;
}
if (left_type.semantic_node_type == semantic_node_type.delegated_method)
{
@ -3653,7 +3660,11 @@ namespace PascalABCCompiler.TreeConverter
cdn.const_value = new enum_const_node(num++, null, get_location(id));
else
{
constant_node cn = convert_strong_to_constant_node(en.value,SystemLibrary.SystemLibrary.integer_type);
constant_node cn = convert_strong_to_constant_node(en.value, SystemLibrary.SystemLibrary.integer_type);
if (cn is basic_function_call_as_constant bfcc && bfcc.method_call.function_node.compile_time_executor != null)
{
cn = convert_strong_to_constant_node(bfcc.method_call.function_node.compile_time_executor(bfcc.location, bfcc.method_call.parameters.ToArray()), SystemLibrary.SystemLibrary.integer_type);
}
check_for_strong_constant(cn,get_location(en.value));
cdn.const_value = new enum_const_node((cn as int_const_node).constant_value,null,get_location(id));
}
@ -3661,6 +3672,12 @@ namespace PascalABCCompiler.TreeConverter
}
common_type_node ctn = context.create_enum_type(null, get_location(_enum_type_definition)); //_enum_type_definition.values
num = 0;
foreach (constant_definition_node cdn in cnsts)
{
cdn.const_value.type = ctn;
}
int i = 0;
foreach (SyntaxTree.enumerator en in _enum_type_definition.enumerators.enumerators)
{
SyntaxTree.ident id = (en.name as named_type_reference).FirstIdent;
@ -3669,14 +3686,12 @@ namespace PascalABCCompiler.TreeConverter
cdn.const_value = new enum_const_node(num++, null, get_location(id));
else
{
constant_node cn = convert_strong_to_constant_node(en.value,SystemLibrary.SystemLibrary.integer_type);
check_for_strong_constant(cn,get_location(en.value));
cdn.const_value = new enum_const_node((cn as int_const_node).constant_value,null,get_location(id));
cdn.const_value = cnsts[i].const_value;
}
cdn.const_value.type = ctn;
i++;
}
foreach (constant_definition_node cdn in cnsts)
cdn.const_value.type = ctn;
internal_interface ii = SystemLibrary.SystemLibrary.integer_type.get_internal_interface(internal_interface_kind.ordinal_interface);
ordinal_type_interface oti_old = (ordinal_type_interface)ii;
enum_const_node lower_value = new enum_const_node(0, ctn, ctn.loc);
@ -3686,6 +3701,7 @@ namespace PascalABCCompiler.TreeConverter
oti_old.lower_eq_method, oti_old.greater_eq_method, oti_old.lower_method, oti_old.greater_method, lower_value, upper_value, oti_old.value_to_int, oti_old.ordinal_type_to_int);
ctn.add_internal_interface(oti_new);
//foreach (constant_definition_node cdn in cnsts)
// cdn.const_value.type = ctn;
//context.leave_block();
@ -13723,7 +13739,7 @@ namespace PascalABCCompiler.TreeConverter
cmc.parameters.AddElement(new int_const_node((prm.type.element_type.element_type as short_string_type_node).Length,null));
}
what_do.statements.AddElement(cmc);
foreach_node fn = new foreach_node(var,in_what,what_do,null);
foreach_node fn = new foreach_node(var, in_what,what_do, prm.type.element_type, true, null);
sl.statements.AddElementFirst(fn);
}
}
@ -18488,179 +18504,328 @@ namespace PascalABCCompiler.TreeConverter
return false;
}
private bool IsIEnumerableInterface(Type t)
{
var IEnumType = typeof(IEnumerable);
var IEnumTypedType = typeof(IEnumerable<>);
var isIEnumType = (t == IEnumType);
var isIEnumTypedType = t.IsGenericType
&& (t.GetGenericTypeDefinition() == IEnumTypedType
);
return isIEnumType || isIEnumTypedType;
}
private bool IsIEnumeratorInterface(Type t)
{
var IEnumType = typeof(IEnumerator);
var IEnumTypedType = typeof(IEnumerator<>);
var isIEnumType = (t == IEnumType);
var isIEnumTypedType = t.IsGenericType
&& (t.GetGenericTypeDefinition() == IEnumTypedType
);
return isIEnumType || isIEnumTypedType;
}
private Type FindIEnumerableInterfaceInCompiledType(Type compiledType)
{
var IEnumType = typeof(IEnumerable);
var IEnumTypedType = typeof(IEnumerable<>);
// если тип является интерфейсом IEnumerable или IEnumerable<T> то берём его
if (IsIEnumerableInterface(compiledType))
return compiledType;
// иначе ищем подходящие интерфейсы в иерархии
var filteredInterfaces = compiledType.FindInterfaces(
(item, _) => IsIEnumerableInterface(item),
null
);
var genericInterfaceCount = filteredInterfaces.Count(item => item.IsGenericType);
if (compiledType.IsInterface)
{
// интерфейс наследует несколько IEnumerable<T> с разными T
// невозможно выбрать. требуется явное приведение
if (genericInterfaceCount > 1)
return null;
if (genericInterfaceCount == 1)
return filteredInterfaces.First(item => item.IsGenericType);
else
return IEnumType;
}
// для класса/записи необходимо учитывать явные реализации GetEnumerator
var methods = compiledType.GetMethods().Where(item =>
item.Name == "GetEnumerator"
&& item.GetParameters().Length == 0
&& IsIEnumeratorInterface(item.ReturnType)
).ToArray();
switch (methods.Length)
{
case 0:
// тип реализует явно несколько IEnumerable<T>
// невозможно выбрать. требуется явное приведение
if (genericInterfaceCount > 1)
return null;
// тип реализует и IEnumerable и IEnumerable<T> явно
// выбираем IEnumerable<T>
if (genericInterfaceCount == 1)
return filteredInterfaces.First(item => item.IsGenericType);
// явно реализует IEnumerable
else
return IEnumType;
case 1:
var method = methods[0];
if (!method.ReturnType.IsGenericType)
return IEnumType;
else
{
var elementType = method.ReturnType.GetGenericArguments().First();
return IEnumTypedType.MakeGenericType(elementType);
}
default:
// в типе наследнике перекрыли GetEnumerator
// невозможно точно выбрать метод
return null;
}
}
private bool IsIEnumerableInterface(type_node t)
{
compiled_type_node orig;
if (t is compiled_type_node)
orig = t as compiled_type_node;
else if (t is compiled_generic_instance_type_node)
orig = (t as compiled_generic_instance_type_node).original_generic as compiled_type_node;
else
return false;
return IsIEnumerableInterface(orig.compiled_type);
}
/// <summary>
/// Собирает интерфейсы, реализованные типом и его предками
/// </summary>
private List<type_node> CollectInterfacesFromTypeNode(type_node node)
{
var result = new List<ITypeNode>();
result.AddRange(node.ImplementingInterfaces);
if (node.base_type != null)
{
var interfInBase = CollectInterfacesFromTypeNode(node.base_type);
result.AddRange(interfInBase);
}
return result.Cast<type_node>().ToList();
}
private bool IsIEnumeratorInterface(type_node t)
{
compiled_type_node orig;
if (t is compiled_type_node)
orig = t as compiled_type_node;
else if (t is compiled_generic_instance_type_node)
orig = (t as compiled_generic_instance_type_node).original_generic as compiled_type_node;
else
return false;
return IsIEnumeratorInterface(orig.compiled_type);
}
private type_node FindIEnumerableInterfaceInTypeNode(type_node node)
{
var IEnumType = compiled_type_node.get_type_node( typeof(IEnumerable) );
var IEnumTypedType = compiled_type_node.get_type_node( typeof(IEnumerable<>) );
var filteredInterfaces = CollectInterfacesFromTypeNode(node)
.Where(item => IsIEnumerableInterface(item))
.ToArray();
var genericInterfaceCount = filteredInterfaces.Count(item => item.is_generic_type_instance);
if (node.IsInterface)
{
// интерфейс наследует несколько IEnumerable<T> с разными T
// невозможно выбрать. требуется явное приведение
if (genericInterfaceCount > 1)
return null;
if (genericInterfaceCount == 1)
return filteredInterfaces.First(item => item.is_generic_type_instance);
else
return IEnumType;
}
var commonType = (common_type_node)node;
var methods = commonType.methods.Where(item =>
item.name.Equals("GetEnumerator", StringComparison.OrdinalIgnoreCase)
&& item.parameters.Count == 0
&& IsIEnumeratorInterface(item.return_value_type)
).ToArray();
switch (methods.Length)
{
case 0:
// тип реализует явно несколько IEnumerable<T>
// невозможно выбрать. требуется явное приведение
if (genericInterfaceCount > 1)
return null;
// тип реализует и IEnumerable и IEnumerable<T> явно
// выбираем IEnumerable<T>
if (genericInterfaceCount == 1)
return filteredInterfaces.First(item => item.is_generic_type_instance);
// явно реализует IEnumerable
else
return IEnumType;
case 1:
var method = methods[0];
if (!method.return_value_type.is_generic_type_instance)
return IEnumType;
else
return IEnumTypedType.get_instance(method.return_value_type.instance_params);
default:
// в типе наследнике перекрыли GetEnumerator
// невозможно точно выбрать метод
return null;
}
}
public bool FindIEnumerableElementType(type_node tn, ref type_node elem_type, out bool sys_coll_ienum)
{
sys_coll_ienum = false;
var IEnstring = "System.Collections.IEnumerable";
compiled_type_node ctn = compiled_type_node.get_type_node(NetHelper.NetHelper.FindType(IEnstring));
if (tn is compiled_type_node || tn is compiled_generic_instance_type_node) // Если этот тип зашит в .NET
// IEnumerable<integer>, Range(1,10), Dictionary<string,integer>: tn = compiled_type_node
// IEnumerable<T>: tn = compiled_generic_instance_type_node
// FibGen = class(IEnumerable,IEnumerator): tn = common_type_node, en = compiled_type_node
// array of Person: tn = common_type_node
// поиск в типе, объявленном в другой сборке
// и тип и типоаргументы объявлены в другой сборке
// Dictionary<string, integer>: tn = compiled_type_node
// IEnumerable<integer>: tn = compiled_type_node
//
// тип объявлен в другой сборке, а типоаргументы в коде
// Dictionary<string, MyType>: tn = compiled_generic_instance_type_node
// IEnumerable<T1>: tn = compiled_generic_instance_type_node (например в generic подпрогамме)
if (tn is compiled_type_node || tn is compiled_generic_instance_type_node)
{
compiled_type_node orig;
if (tn is compiled_type_node)
orig = tn as compiled_type_node;
else orig = (tn as compiled_generic_instance_type_node).original_generic as compiled_type_node;
//var pars = tn.instance_params;
System.Type ct = orig.compiled_type;
Type r;
var IEnTstring = "System.Collections.Generic.IEnumerable`1";
//if (ct.ToString().StartsWith(IEnTstring)) // SSM Ошибка!!! IEnumerable`1[] тоже начинается с IEnumerable`1, но это массив!
if (ct.Name.Equals("IEnumerable`1"))
r = ct;
else
r = ct.GetInterface(IEnTstring);
if (r != null)
else
orig = (tn as compiled_generic_instance_type_node).original_generic as compiled_type_node;
// непосредственно тип, от котоого разворачивается foreach
Type ct = orig.compiled_type;
var isEnumeratedType = typeof(IEnumerable).IsAssignableFrom(ct);
if (!isEnumeratedType)
return false;
// для массива
if (tn.element_type != null)
{
Type arg1 = r.GetGenericArguments().First(); // тип параметра IEnumerable
var str = arg1.GetGenericArguments().Count();
if (tn is compiled_type_node)
elem_type = tn.element_type;
if (ct.GetArrayRank() > 1)
sys_coll_ienum = true;
return true;
}
// в иных случаях ищем подходящий интерфейс
var desiredInterface = FindIEnumerableInterfaceInCompiledType(ct);
if (desiredInterface == null)
return false;
// обнаружен IEnumerable
if (!desiredInterface.IsGenericType)
{
elem_type = SystemLibrary.SystemLibrary.object_type;
sys_coll_ienum = true;
return true;
}
var foundElementType = desiredInterface.GetGenericArguments().First();
if (tn is compiled_type_node)
elem_type = compiled_type_node.get_type_node(foundElementType);
else
{
// для "tn is compiled_generic_instance_type_node" необходимо восстановить стёртые типы
// orig.instance_params содержит имена типоаргументов при объявлении
// tn.instance_params содержит фактические типоаргументы
// остаётся найти нужный индекс в orig и взять аргумент из tn
if (foundElementType.IsGenericParameter)
{
elem_type = compiled_type_node.get_type_node(arg1);
var ind = orig.instance_params.FindIndex(item => item.name == foundElementType.Name);
elem_type = tn.instance_params[ind];
}
else
{
if (arg1.GetGenericArguments().Count()>0)
{
elem_type = compiled_type_node.get_type_node(arg1.GetGenericTypeDefinition());
elem_type = elem_type.get_instance(tn.instance_params); // SSM 19/07/15 - работает!!!
}
else
{
var ip = tn.instance_params;
// значит элемент последовательности сам является generic типом
// нужно сопоставить все типоаргументы из orig типоаргументам из tn
// нельзя просто брать все, тк их количество может отличаться
var IGrTstring = "System.Linq.IGrouping`2";
if (ct.ToString().StartsWith(IGrTstring))
elem_type = ip[1];
else
{
var ln = tn.ImplementingInterfaces;
elem_type = null;
foreach (var x in ln)
{
var xctn = x as compiled_generic_instance_type_node;
if (xctn != null && xctn.name.StartsWith("IEnumerable<")) // Немного грубовато.
{
elem_type = xctn.instance_params[0];
break;
}
}
if (ct.Name == "ValueCollection" && ct.IsNested && ct.GetGenericArguments().Length == 2)
{
elem_type = ip[1];
}
else if (elem_type == null)
elem_type = ip[0];
}
//var Tname = ip[0].name;
//elem_type = convert_strong(new SyntaxTree.named_type_reference(Tname, _foreach_stmt.in_what.source_context));
}
var declaredTypes = foundElementType
.GetGenericArguments()
.Select(item=> item.Name)
.ToArray();
//elem_type.instance_params = tn.instance_params;
//var ip = tn.instance_params;
//var Tname = new string(tn.name.SkipWhile(c => c != '<').Skip(1).TakeWhile(c => c != ',' && c != '>').ToArray());
//var Tname = ip[0].name;
//var Tname = "System.Collections.Generic.KeyValuePair'2"; // <integer,TClass>
//elem_type = convert_strong(new SyntaxTree.named_type_reference(Tname, _foreach_stmt.in_what.source_context));
}
return true;
}
else
{
if (tn.element_type != null) // значит, это массив любой размерности - 02.02.16 SSM - еще может быть множество set of T - 22.02.16 SSM
{
elem_type = tn.element_type;
return true;
}
var actualTypes = tn.instance_params
.Where((item, i) => declaredTypes.Contains(orig.instance_params[i].name))
.ToList();
var ttt = tn.ImplementingInterfaces;
foreach (SemanticTree.ITypeNode itn in tn.ImplementingInterfaces)
{
if (itn == ctn)
{
elem_type = SystemLibrary.SystemLibrary.object_type;
sys_coll_ienum = true;
return true;
}
elem_type = compiled_type_node.get_type_node( foundElementType.GetGenericTypeDefinition() );
elem_type = elem_type.get_instance(actualTypes);
}
}
}
/*else if (tn is compiled_generic_instance_type_node)
{
var g = tn as compiled_generic_instance_type_node;
var og = g.original_generic;
var tt = og.ImplementingInterfaces;
if (_foreach_stmt.type_name != null && _foreach_stmt.type_name.GetType()!=typeof(SyntaxTree.no_type_foreach))
elem_type = convert_strong(_foreach_stmt.type_name);
else
{
var fn = tn.full_name;
}
return true;
} */
else // если мы самостоятельно определяем этот тип - можно реализовать в PascalABC.NET только IEnumerable. // Сейчас уже можно!!!!!
// Попытка реализовать IEnumerable<T> натыкается на необходимость определять GetEnumerator, возвращающий IEnumerator и IEnumerator<T>
{
if (tn == null || tn is null_type_node || tn.ImplementingInterfaces == null)
{
if (tn != null && tn.base_type != null)
return FindIEnumerableElementType(tn.base_type, ref elem_type, out sys_coll_ienum);
return false;
}
}
if (tn.element_type != null && tn.type_special_kind != SemanticTree.type_special_kind.typed_file) // еще может быть множество set of T - 22.02.16 SSM
// поиск в типе, объявленном в коде
// также сюда попадают set of T даже если они подтягиваются из библиотеки
else
{
// массивы и set of T
if (tn.element_type != null && tn.type_special_kind != SemanticTree.type_special_kind.typed_file)
{
elem_type = tn.element_type;
if ((tn as common_type_node).rank != 1)
sys_coll_ienum = true;
return true;
}
foreach (SemanticTree.ITypeNode itn in tn.ImplementingInterfaces) // Ищем интерфейс IEnumerable<T> и возвращаем T в качестве elem_type
{
if (itn is compiled_generic_instance_type_node)
{
var itnc = (itn as compiled_generic_instance_type_node);
var tt = (itnc.original_generic as compiled_type_node).compiled_type;
if (tt == typeof(System.Collections.Generic.IEnumerable<>))
{
elem_type = itnc.generic_parameters[0] as common_type_node;
return true;
}
}
}
var desiredInterface = FindIEnumerableInterfaceInTypeNode(tn);
foreach (SemanticTree.ITypeNode itn in tn.ImplementingInterfaces) // если не нашли - ищем интерфейс IEnumerable и возвращаем object в качестве elem_type
if (desiredInterface == null)
return false;
if (!desiredInterface.is_generic_type_instance)
{
if (itn is compiled_type_node) // Именно этот кусок отвечает за IEnumerable<integer> и мы его закомментировали
{
var itnc = (itn as compiled_type_node).compiled_type; /* SSM раскомментировал 15.05.2020 - пришла пора*/
if (itnc.IsGenericType)
{
var my = itnc.GetGenericTypeDefinition();// = typeof(System.Collections.Generic.IEnumerable<>)
if (my == typeof(System.Collections.Generic.IEnumerable<>))
{
var aarg1 = itnc.GetGenericArguments().First();
elem_type = compiled_type_node.get_type_node(aarg1);
return true;
}
}
else /* end SSM раскомментировал 15.05.2020 - пришла пора*/
if (itn == ctn)
{
elem_type = SystemLibrary.SystemLibrary.object_type;
sys_coll_ienum = true;
return true;
}
}
elem_type = SystemLibrary.SystemLibrary.object_type;
sys_coll_ienum = true;
}
else
elem_type = desiredInterface.instance_params[0];
return true;
}
if (tn != null && tn.base_type != null)
return FindIEnumerableElementType(tn.base_type, ref elem_type, out sys_coll_ienum);
return false;
}
private int GenIdNum = 0;

View file

@ -1754,12 +1754,23 @@ namespace PascalABCCompiler.TreeRealization
private var_definition_node _ident;
private expression_node _in_what;
private statement_node _what_do;
private type_node _element_type;
private bool _is_generic;
public foreach_node(var_definition_node _ident, expression_node _in_what, statement_node _what_do, location loc):base(loc)
public foreach_node(
var_definition_node _ident,
expression_node _in_what,
statement_node _what_do,
type_node _element_type,
bool _is_generic,
location loc
):base(loc)
{
this._ident = _ident;
this._in_what = _in_what;
this._what_do = _what_do;
this._element_type = _element_type;
this._is_generic = _is_generic;
}
public var_definition_node ident
@ -1798,6 +1809,18 @@ namespace PascalABCCompiler.TreeRealization
}
}
public type_node element_type
{
get { return _element_type; }
set { _element_type = value; }
}
public bool is_generic
{
get { return _is_generic; }
set { _is_generic = value; }
}
public SemanticTree.IStatementNode Body
{
get
@ -1821,6 +1844,17 @@ namespace PascalABCCompiler.TreeRealization
return _ident;
}
}
public SemanticTree.ITypeNode ElementType
{
get { return _element_type; }
}
public bool IsGeneric
{
get { return _is_generic; }
}
/// <summary>
/// Тип узла.
/// </summary>