Skip to content

Commit e0443ce

Browse files
committed
generic operator extensions (operator+<T>)
1 parent bd6ae86 commit e0443ce

File tree

9 files changed

+123
-21
lines changed

9 files changed

+123
-21
lines changed

CodeCompletion/DomSyntaxTreeVisitor.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,10 @@ public override void visit(procedure_header _procedure_header)
899899
ps.proc_realization = pr;
900900
pr.loc = cur_loc;
901901
pr.head_loc = loc;
902-
this.entry_scope.AddName("$method", pr);
902+
if (impl_scope != null)
903+
impl_scope.AddName("$method", pr);
904+
else
905+
this.entry_scope.AddName("$method", pr);
903906
}
904907
ps.head_loc = loc;
905908
if (!ps.is_extension)
@@ -1183,7 +1186,10 @@ public override void visit(function_header _function_header)
11831186
ps.proc_realization = pr;
11841187
pr.loc = cur_loc;
11851188
pr.head_loc = loc;
1186-
this.entry_scope.AddName("$method",pr);
1189+
if (impl_scope != null)
1190+
impl_scope.AddName("$method", pr);
1191+
else
1192+
this.entry_scope.AddName("$method", pr);
11871193
}
11881194
if (!ps.is_extension)
11891195
{
@@ -3634,6 +3640,7 @@ public override void visit(new_expr _new_expr)
36343640
(returned_scope as ArrayScope).is_dynamic_arr = true;
36353641
}
36363642
save_return_value();
3643+
if (_new_expr.params_list != null)
36373644
foreach (expression ex in _new_expr.params_list.expressions)
36383645
{
36393646
if (ex is function_lambda_definition)

SyntaxTree/tree/TreeHelper.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -704,8 +704,10 @@ public procedure_header(formal_parameters _parameters, procedure_attributes_list
704704
{
705705
var t = name.meth_name as template_type_name;
706706
template_args = t.template_args;
707-
ident id = new ident(name.meth_name.name, name.meth_name.source_context);
708-
name.meth_name = id;
707+
if (name.meth_name is template_operator_name)
708+
name.meth_name = new operator_name_ident((name.meth_name as template_operator_name).opname.operator_type, name.meth_name.source_context);
709+
else
710+
name.meth_name = new ident(name.meth_name.name, name.meth_name.source_context);
709711
}
710712
}
711713

TestSuite/CompilationSamples/PABCSystem.pas

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3127,6 +3127,14 @@ function System.Collections.Generic.IEnumerable<T>.operator*(n: integer; a: sequ
31273127
Result := a*n;
31283128
end;
31293129

3130+
/// Îáúåäèíÿåò äâà ìàññèâà
3131+
function operator+<T>(a, b: array of T): array of T; extensionmethod;
3132+
begin
3133+
Result := new T[a.Length+b.Length];
3134+
a.CopyTo(Result,0);
3135+
b.CopyTo(Result,a.Length);
3136+
end;
3137+
31303138
// -----------------------------------------------------
31313139
// Sequences
31323140
// -----------------------------------------------------

TestSuite/extensionmethods11.pas

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
begin
2+
var arr1 := Arr(1,2,3);
3+
var arr2 := Arr(4,5,6);
4+
var arr3: array of integer := arr1+arr2;
5+
assert(arr3[3]=4);
6+
var arr4 := Arr('aaa','bbb','ccc');
7+
var arr5 := Arr('ddd','eee','fff');
8+
var arr6: array of string;
9+
arr6 := arr4 + arr5;
10+
assert(arr6[5]='fff');
11+
12+
end.

TreeConverter/NetWrappers/NetHelper.cs

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ public static class NetHelper {
294294
public static Assembly SystemCoreAssembly;
295295
private static Dictionary<Type,MethodInfo[]> extension_methods = new Dictionary<Type,MethodInfo[]>();
296296
private static Dictionary<Type,List<MethodInfo>> type_extensions = new Dictionary<Type, List<MethodInfo>>();
297+
private static Dictionary<Type, Type> arrays_with_extension_methods = new Dictionary<Type, Type>();
298+
private static Dictionary<int, List<MethodInfo>> generic_array_type_extensions = new Dictionary<int, List<MethodInfo>>();
297299
public static Type PABCSystemType = null;
298300
public static Type PT4Type = null;
299301
public static Type StringType = typeof(string);
@@ -302,7 +304,9 @@ public static class NetHelper {
302304

303305
public static void reset()
304306
{
305-
cur_used_assemblies.Clear();
307+
if (cur_used_assemblies == null)
308+
cur_used_assemblies = new Hashtable();
309+
cur_used_assemblies.Clear();
306310
cur_used_assemblies[typeof(string).Assembly] = typeof(string).Assembly;
307311
cur_used_assemblies[typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly] = typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly;
308312
type_search_cache.Clear();
@@ -499,15 +503,59 @@ public static List<Type> init_namespaces(System.Reflection.Assembly _assembly)
499503
{
500504

501505
List<MethodInfo> mths = null;
506+
List<MethodInfo> mths2 = null;
502507
Type tmp = prms[0].ParameterType;
508+
bool generic_type = false;
503509
if (tmp.IsGenericType)
510+
{
504511
tmp = tmp.GetGenericTypeDefinition();
512+
generic_type = true;
513+
}
505514
if (!type_extensions.TryGetValue(tmp, out mths))
506515
{
507516
mths = new List<MethodInfo>();
508517
type_extensions.Add(tmp, mths);
509518
}
510519
mths.Add(mi);
520+
if (tmp.IsArray && !generic_array_type_extensions.TryGetValue(tmp.GetArrayRank(), out mths2))
521+
{
522+
mths2 = new List<MethodInfo>();
523+
generic_array_type_extensions.Add(tmp.GetArrayRank(), mths2);
524+
}
525+
if (mths2 != null)
526+
mths2.Add(mi);
527+
Dictionary<string, List<MemberInfo>> mht;
528+
if (members.TryGetValue(tmp, out mht))
529+
{
530+
List<MemberInfo> mis2 = null;
531+
string name = compiler_string_consts.GetNETOperName(mi.Name);
532+
if (name == null)
533+
name = mi.Name;
534+
if (!mht.TryGetValue(name, out mis2))
535+
{
536+
mis2 = new List<MemberInfo>();
537+
mht.Add(name, mis2);
538+
}
539+
if (!mis2.Contains(mi))
540+
mis2.Add(mi);
541+
}
542+
foreach (Type arr_t in arrays_with_extension_methods.Keys)
543+
{
544+
if (members.TryGetValue(arr_t, out mht))
545+
{
546+
List<MemberInfo> mis2 = null;
547+
string name = compiler_string_consts.GetNETOperName(mi.Name);
548+
if (name == null)
549+
name = mi.Name;
550+
if (!mht.TryGetValue(name, out mis2))
551+
{
552+
mis2 = new List<MemberInfo>();
553+
mht.Add(name, mis2);
554+
}
555+
if (!mis2.Contains(mi))
556+
mis2.Add(mi);
557+
}
558+
}
511559
}
512560
}
513561
extension_methods.Add(t, ext_meths.ToArray());
@@ -1110,20 +1158,27 @@ public static List<MemberInfo> GetMembers(Type t, string name)
11101158
{
11111159
List<MethodInfo> meths = null;
11121160
Type tmp_t = t;
1161+
if (tmp_t.IsArray)
1162+
arrays_with_extension_methods[tmp_t] = tmp_t;
11131163
cached_type_extensions[t] = t;
11141164
while (tmp_t != null)
11151165
{
1116-
if (type_extensions.TryGetValue(tmp_t, out meths) || tmp_t.IsGenericType && type_extensions.TryGetValue(tmp_t.GetGenericTypeDefinition(), out meths))
1166+
if (type_extensions.TryGetValue(tmp_t, out meths)
1167+
|| tmp_t.IsGenericType && type_extensions.TryGetValue(tmp_t.GetGenericTypeDefinition(), out meths)
1168+
|| tmp_t.IsArray && generic_array_type_extensions.TryGetValue(tmp_t.GetArrayRank(), out meths))
11171169
{
11181170
foreach (MethodInfo mi in meths)
11191171
{
11201172
if (cur_used_assemblies.ContainsKey(mi.DeclaringType.Assembly))
11211173
{
11221174
List<MemberInfo> al = null;
1123-
if (!ht.TryGetValue(mi.Name, out al))
1175+
string s = compiler_string_consts.GetNETOperName(mi.Name);
1176+
if (s == null)
1177+
s = mi.Name;
1178+
if (!ht.TryGetValue(s, out al))
11241179
{
11251180
al = new List<MemberInfo>();
1126-
ht[mi.Name] = al;
1181+
ht[s] = al;
11271182
}
11281183
al.Insert(0, mi);
11291184
}
@@ -1364,6 +1419,7 @@ public static SymbolInfo FindName(Type t, string name)
13641419
if (name == null) return null;
13651420
if (name == compiler_string_consts.assign_name) return null;
13661421
string s = compiler_string_consts.GetNETOperName(name);
1422+
string tmp_name = name;
13671423
if (s != null)
13681424
{
13691425
if (IsStandType(t)) return null;
@@ -1373,7 +1429,6 @@ public static SymbolInfo FindName(Type t, string name)
13731429
SymbolInfo si=null;
13741430

13751431
List<MemberInfo> mis = GetMembers(t,name);
1376-
13771432
//(ssyy) Èçìåíèë àëãîðèòì.
13781433
//Ó íàñ íåêîòîðûå àëãîðèòìû áàçèðóþòñÿ íà òîì, ÷òî âîçâðàù¸ííûå
13791434
//ñóùíîñòè áóäóò îäíîé ïðèðîäû (íàïðèìåð, âñå - ìåòîäû). Ýòî íåâåðíî,

TreeConverter/TreeConversion/syntax_tree_visitor.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8965,7 +8965,7 @@ private void visit_method_name(SyntaxTree.method_name _method_name)
89658965
}
89668966
else
89678967
{
8968-
if (is_operator && context.converted_type == null && context.converted_template_type == null)
8968+
if (is_operator && context.converted_type == null && context.converted_template_type == null && !(current_function_header != null && current_function_header.template_args != null && current_function_header.template_args.idents.Count > 0))
89698969
{
89708970
AddError(get_location(_method_name), "OVERLOADED_OPERATOR_MUST_BE_STATIC_FUNCTION");
89718971
}
@@ -11209,9 +11209,13 @@ internal void CheckOverrideOrReintroduceExpectedWarning(location loc)
1120911209
}
1121011210
}
1121111211

11212+
private procedure_header current_function_header = null;
11213+
1121211214
public override void visit(SyntaxTree.function_header _function_header)
1121311215
{
11216+
current_function_header = _function_header;
1121411217
hard_node_test_and_visit(_function_header.name);
11218+
current_function_header = null;
1121511219
if (context.converted_template_type != null)
1121611220
{
1121711221
return;
@@ -11337,9 +11341,11 @@ public override void visit(SyntaxTree.function_header _function_header)
1133711341
type_node ptn = p.type;
1133811342
if (ptn.is_generic_type_instance)
1133911343
ptn = ptn.original_generic;
11340-
if (ptn == cnfn.ConnectedToType)
11344+
if (ptn == cnfn.ConnectedToType || ptn == cnfn.ConnectedToType.original_generic)
1134111345
has_types = true;
1134211346
}
11347+
if (cnfn.ConnectedToType == null)
11348+
AddError(new SimpleSemanticError(cnfn.loc, "OPERATOR_SHOULD_BE_EXTENSION_METHOD"));
1134311349
if (!has_types)
1134411350
AddError(new SimpleSemanticError(cnfn.loc, "LEAST_ONE_PARAMETER_TYPE_SHOULD_EQ_DECLARING_TYPE_{0}",cnfn.ConnectedToType.name));
1134511351
}
@@ -11462,7 +11468,9 @@ private void visit_procedure_header(SyntaxTree.procedure_header _procedure_heade
1146211468
{
1146311469
AddError(get_location(_procedure_header), "CONSTRUCTOR_CAN_NOT_BE_GENERIC");
1146411470
}
11471+
current_function_header = _procedure_header;
1146511472
hard_node_test_and_visit(_procedure_header.name);
11473+
current_function_header = null;
1146611474
if (context.converted_template_type != null)
1146711475
{
1146811476
return;
@@ -11822,9 +11830,9 @@ public override void visit(SyntaxTree.procedure_attributes_list _procedure_attri
1182211830
AddError(get_location(_procedure_attributes_list), "EXTENSION_ATTRIBUTE_ONLY_FOR_NAMESPACE_FUNCTIONS_ALLOWED");
1182311831
if (context.top_function.parameters.Count == 0)
1182411832
AddError(context.top_function.loc, "EXTENSION_METHODS_MUST_HAVE_LEAST_ONE_PARAMETER");
11825-
if (context.top_function.parameters[0].parameter_type != SemanticTree.parameter_type.value)
11833+
if (!context.top_function.IsOperator && context.top_function.parameters[0].parameter_type != SemanticTree.parameter_type.value)
1182611834
AddError(context.top_function.loc, "FIRST_PARAMETER_SHOULDBE_ONLY_VALUE_PARAMETER");
11827-
if (context.top_function.parameters[0].name.ToLower() != compiler_string_consts.self_word)
11835+
if (!context.top_function.IsOperator && context.top_function.parameters[0].name.ToLower() != compiler_string_consts.self_word)
1182811836
AddError(context.top_function.loc,"FIRST_PARAMETER_MUST_HAVE_NAME_SELF");
1182911837
common_namespace_function_node top_function = context.top_function as common_namespace_function_node;
1183011838
top_function.ConnectedToType = context.top_function.parameters[0].type;

bin/Lib/PABCSystem.pas

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3127,6 +3127,14 @@ function System.Collections.Generic.IEnumerable<T>.operator*(n: integer; a: sequ
31273127
Result := a*n;
31283128
end;
31293129

3130+
/// Îáúåäèíÿåò äâà ìàññèâà
3131+
function operator+<T>(a, b: array of T): array of T; extensionmethod;
3132+
begin
3133+
Result := new T[a.Length+b.Length];
3134+
a.CopyTo(Result,0);
3135+
b.CopyTo(Result,a.Length);
3136+
end;
3137+
31303138
// -----------------------------------------------------
31313139
// Sequences
31323140
// -----------------------------------------------------

bin/Lng/Eng/SemanticErrors_ib.dat

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,14 @@ FIRST_PARAMETER_SHOULDBE_ONLY_VALUE_PARAMETER=var and const are not allowed for
100100
FIRST_PARAMETER_MUST_HAVE_NAME_SELF=Parameter with 'name' self expected
101101
EXTENSION_METHODS_FOR_CONSTRUCTED_TYPES_NOT_ALLOWED=Cannot extend this type
102102
EXTENSION_METHODS_IN_INTERFACE_PART_NOT_ALLOWED=Cannot declare extension methods in interface part of unit
103+
OPERATOR_SHOULD_BE_EXTENSION_METHOD=Operator should be extension method
104+
UNABLE_TO_CONVERT_FUNCTIONAL_TYPE_TO_PROCEDURAL_TYPE=Unable to convert functional type to procedural type
105+
ILLEGAL_PARAMETERS_IN_LAMBDA=Illegal parameters in lambda
106+
ILLEGAL_LAMBDA_VARIABLE_TYPE=Illegal lambda variable type
107+
ILLEGAL_LAMBDA_PARAMETERS_NUMBER=Illegal lambda parameters number
108+
IMPOSSIBLE_TO_INFER_TYPES_IN_LAMBDA=Unable to infer types in lambda
109+
ANONYMOUS_DELEGATE_IN_INTERFACE_NOT_ALLOWED=Using of anonymous delegate in interface is not allowed. Declare the delegate type explicitly.
110+
PARAMETER_REFERENCE_IN_DEFAULT_PARAMETER_NOT_ALLOWED=Parameter references in default parameter value are not allowed
103111
%PREFIX%=COMPILATIONERROR_
104112
UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Unit expected, library found
105-
ASSEMBLY_{0}_READING_ERROR=Error by reading assembly '{0}'
106-
UNABLE_TO_CONVERT_FUNCTIONAL_TYPE_TO_PROCEDURAL_TYPE="Unable to convert functional type to procedural type"
107-
ILLEGAL_PARAMETERS_IN_LAMBDA="Illegal parameters in lambda"
108-
ILLEGAL_LAMBDA_VARIABLE_TYPE="Illegal lambda variable type"
109-
ILLEGAL_LAMBDA_PARAMETERS_NUMBER="Illegal lambda parameters number"
110-
IMPOSSIBLE_TO_INFER_TYPES_IN_LAMBDA="Impossible to infer types in lambda"
111-
ANONYMOUS_DELEGATE_IN_INTERFACE_NOT_ALLOWED=Using of anonymous delegate in interface is not allowed. Declare the delegate type explicitly.
112-
PARAMETER_REFERENCE_IN_DEFAULT_PARAMETER_NOT_ALLOWED=Parameter references in default parameter value are not allowed
113+
ASSEMBLY_{0}_READING_ERROR=Error by reading assembly '{0}'

bin/Lng/Rus/SemanticErrors_ib.dat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ FIRST_PARAMETER_SHOULDBE_ONLY_VALUE_PARAMETER=Недопустимо испол
102102
FIRST_PARAMETER_MUST_HAVE_NAME_SELF=Первый параметр должен иметь имя self
103103
EXTENSION_METHODS_FOR_CONSTRUCTED_TYPES_NOT_ALLOWED=Нельзя расширять этот тип
104104
EXTENSION_METHODS_IN_INTERFACE_PART_NOT_ALLOWED=Объявление extension-методов в интерфейсной части модуля недопустимо
105+
OPERATOR_SHOULD_BE_EXTENSION_METHOD=Оператор должен быть помечен модификатором extensionmethod
105106
%PREFIX%=COMPILATIONERROR_
106107
UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Ожидался модуль, а встречена библиотека
107108
ASSEMBLY_{0}_READING_ERROR=Ошибка при чтении сборки '{0}'

0 commit comments

Comments
 (0)