Skip to content

Commit

Permalink
generic operator extensions (operator+<T>)
Browse files Browse the repository at this point in the history
  • Loading branch information
ibond84 committed Dec 9, 2015
1 parent bd6ae86 commit e0443ce
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 21 deletions.
11 changes: 9 additions & 2 deletions CodeCompletion/DomSyntaxTreeVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,10 @@ public override void visit(procedure_header _procedure_header)
ps.proc_realization = pr;
pr.loc = cur_loc;
pr.head_loc = loc;
this.entry_scope.AddName("$method", pr);
if (impl_scope != null)
impl_scope.AddName("$method", pr);
else
this.entry_scope.AddName("$method", pr);
}
ps.head_loc = loc;
if (!ps.is_extension)
Expand Down Expand Up @@ -1183,7 +1186,10 @@ public override void visit(function_header _function_header)
ps.proc_realization = pr;
pr.loc = cur_loc;
pr.head_loc = loc;
this.entry_scope.AddName("$method",pr);
if (impl_scope != null)
impl_scope.AddName("$method", pr);
else
this.entry_scope.AddName("$method", pr);
}
if (!ps.is_extension)
{
Expand Down Expand Up @@ -3634,6 +3640,7 @@ public override void visit(new_expr _new_expr)
(returned_scope as ArrayScope).is_dynamic_arr = true;
}
save_return_value();
if (_new_expr.params_list != null)
foreach (expression ex in _new_expr.params_list.expressions)
{
if (ex is function_lambda_definition)
Expand Down
6 changes: 4 additions & 2 deletions SyntaxTree/tree/TreeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -704,8 +704,10 @@ public procedure_header(formal_parameters _parameters, procedure_attributes_list
{
var t = name.meth_name as template_type_name;
template_args = t.template_args;
ident id = new ident(name.meth_name.name, name.meth_name.source_context);
name.meth_name = id;
if (name.meth_name is template_operator_name)
name.meth_name = new operator_name_ident((name.meth_name as template_operator_name).opname.operator_type, name.meth_name.source_context);
else
name.meth_name = new ident(name.meth_name.name, name.meth_name.source_context);
}
}

Expand Down
8 changes: 8 additions & 0 deletions TestSuite/CompilationSamples/PABCSystem.pas
Original file line number Diff line number Diff line change
Expand Up @@ -3127,6 +3127,14 @@ function System.Collections.Generic.IEnumerable<T>.operator*(n: integer; a: sequ
Result := a*n;
end;

/// Îáúåäèíÿåò äâà ìàññèâà
function operator+<T>(a, b: array of T): array of T; extensionmethod;
begin
Result := new T[a.Length+b.Length];
a.CopyTo(Result,0);
b.CopyTo(Result,a.Length);
end;

// -----------------------------------------------------
// Sequences
// -----------------------------------------------------
Expand Down
12 changes: 12 additions & 0 deletions TestSuite/extensionmethods11.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
begin
var arr1 := Arr(1,2,3);
var arr2 := Arr(4,5,6);
var arr3: array of integer := arr1+arr2;
assert(arr3[3]=4);
var arr4 := Arr('aaa','bbb','ccc');
var arr5 := Arr('ddd','eee','fff');
var arr6: array of string;
arr6 := arr4 + arr5;
assert(arr6[5]='fff');

end.
65 changes: 60 additions & 5 deletions TreeConverter/NetWrappers/NetHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ public static class NetHelper {
public static Assembly SystemCoreAssembly;
private static Dictionary<Type,MethodInfo[]> extension_methods = new Dictionary<Type,MethodInfo[]>();
private static Dictionary<Type,List<MethodInfo>> type_extensions = new Dictionary<Type, List<MethodInfo>>();
private static Dictionary<Type, Type> arrays_with_extension_methods = new Dictionary<Type, Type>();
private static Dictionary<int, List<MethodInfo>> generic_array_type_extensions = new Dictionary<int, List<MethodInfo>>();
public static Type PABCSystemType = null;
public static Type PT4Type = null;
public static Type StringType = typeof(string);
Expand All @@ -302,7 +304,9 @@ public static class NetHelper {

public static void reset()
{
cur_used_assemblies.Clear();
if (cur_used_assemblies == null)
cur_used_assemblies = new Hashtable();
cur_used_assemblies.Clear();
cur_used_assemblies[typeof(string).Assembly] = typeof(string).Assembly;
cur_used_assemblies[typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly] = typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly;
type_search_cache.Clear();
Expand Down Expand Up @@ -499,15 +503,59 @@ public static List<Type> init_namespaces(System.Reflection.Assembly _assembly)
{

List<MethodInfo> mths = null;
List<MethodInfo> mths2 = null;
Type tmp = prms[0].ParameterType;
bool generic_type = false;
if (tmp.IsGenericType)
{
tmp = tmp.GetGenericTypeDefinition();
generic_type = true;
}
if (!type_extensions.TryGetValue(tmp, out mths))
{
mths = new List<MethodInfo>();
type_extensions.Add(tmp, mths);
}
mths.Add(mi);
if (tmp.IsArray && !generic_array_type_extensions.TryGetValue(tmp.GetArrayRank(), out mths2))
{
mths2 = new List<MethodInfo>();
generic_array_type_extensions.Add(tmp.GetArrayRank(), mths2);
}
if (mths2 != null)
mths2.Add(mi);
Dictionary<string, List<MemberInfo>> mht;
if (members.TryGetValue(tmp, out mht))
{
List<MemberInfo> mis2 = null;
string name = compiler_string_consts.GetNETOperName(mi.Name);
if (name == null)
name = mi.Name;
if (!mht.TryGetValue(name, out mis2))
{
mis2 = new List<MemberInfo>();
mht.Add(name, mis2);
}
if (!mis2.Contains(mi))
mis2.Add(mi);
}
foreach (Type arr_t in arrays_with_extension_methods.Keys)
{
if (members.TryGetValue(arr_t, out mht))
{
List<MemberInfo> mis2 = null;
string name = compiler_string_consts.GetNETOperName(mi.Name);
if (name == null)
name = mi.Name;
if (!mht.TryGetValue(name, out mis2))
{
mis2 = new List<MemberInfo>();
mht.Add(name, mis2);
}
if (!mis2.Contains(mi))
mis2.Add(mi);
}
}
}
}
extension_methods.Add(t, ext_meths.ToArray());
Expand Down Expand Up @@ -1110,20 +1158,27 @@ public static List<MemberInfo> GetMembers(Type t, string name)
{
List<MethodInfo> meths = null;
Type tmp_t = t;
if (tmp_t.IsArray)
arrays_with_extension_methods[tmp_t] = tmp_t;
cached_type_extensions[t] = t;
while (tmp_t != null)
{
if (type_extensions.TryGetValue(tmp_t, out meths) || tmp_t.IsGenericType && type_extensions.TryGetValue(tmp_t.GetGenericTypeDefinition(), out meths))
if (type_extensions.TryGetValue(tmp_t, out meths)
|| tmp_t.IsGenericType && type_extensions.TryGetValue(tmp_t.GetGenericTypeDefinition(), out meths)
|| tmp_t.IsArray && generic_array_type_extensions.TryGetValue(tmp_t.GetArrayRank(), out meths))
{
foreach (MethodInfo mi in meths)
{
if (cur_used_assemblies.ContainsKey(mi.DeclaringType.Assembly))
{
List<MemberInfo> al = null;
if (!ht.TryGetValue(mi.Name, out al))
string s = compiler_string_consts.GetNETOperName(mi.Name);
if (s == null)
s = mi.Name;
if (!ht.TryGetValue(s, out al))
{
al = new List<MemberInfo>();
ht[mi.Name] = al;
ht[s] = al;
}
al.Insert(0, mi);
}
Expand Down Expand Up @@ -1364,6 +1419,7 @@ public static SymbolInfo FindName(Type t, string name)
if (name == null) return null;
if (name == compiler_string_consts.assign_name) return null;
string s = compiler_string_consts.GetNETOperName(name);
string tmp_name = name;
if (s != null)
{
if (IsStandType(t)) return null;
Expand All @@ -1373,7 +1429,6 @@ public static SymbolInfo FindName(Type t, string name)
SymbolInfo si=null;

List<MemberInfo> mis = GetMembers(t,name);

//(ssyy) Èçìåíèë àëãîðèòì.
//Ó íàñ íåêîòîðûå àëãîðèòìû áàçèðóþòñÿ íà òîì, ÷òî âîçâðàù¸ííûå
//ñóùíîñòè áóäóò îäíîé ïðèðîäû (íàïðèìåð, âñå - ìåòîäû). Ýòî íåâåðíî,
Expand Down
16 changes: 12 additions & 4 deletions TreeConverter/TreeConversion/syntax_tree_visitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8965,7 +8965,7 @@ private void visit_method_name(SyntaxTree.method_name _method_name)
}
else
{
if (is_operator && context.converted_type == null && context.converted_template_type == null)
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))
{
AddError(get_location(_method_name), "OVERLOADED_OPERATOR_MUST_BE_STATIC_FUNCTION");
}
Expand Down Expand Up @@ -11209,9 +11209,13 @@ internal void CheckOverrideOrReintroduceExpectedWarning(location loc)
}
}

private procedure_header current_function_header = null;

public override void visit(SyntaxTree.function_header _function_header)
{
current_function_header = _function_header;
hard_node_test_and_visit(_function_header.name);
current_function_header = null;
if (context.converted_template_type != null)
{
return;
Expand Down Expand Up @@ -11337,9 +11341,11 @@ public override void visit(SyntaxTree.function_header _function_header)
type_node ptn = p.type;
if (ptn.is_generic_type_instance)
ptn = ptn.original_generic;
if (ptn == cnfn.ConnectedToType)
if (ptn == cnfn.ConnectedToType || ptn == cnfn.ConnectedToType.original_generic)
has_types = true;
}
if (cnfn.ConnectedToType == null)
AddError(new SimpleSemanticError(cnfn.loc, "OPERATOR_SHOULD_BE_EXTENSION_METHOD"));
if (!has_types)
AddError(new SimpleSemanticError(cnfn.loc, "LEAST_ONE_PARAMETER_TYPE_SHOULD_EQ_DECLARING_TYPE_{0}",cnfn.ConnectedToType.name));
}
Expand Down Expand Up @@ -11462,7 +11468,9 @@ private void visit_procedure_header(SyntaxTree.procedure_header _procedure_heade
{
AddError(get_location(_procedure_header), "CONSTRUCTOR_CAN_NOT_BE_GENERIC");
}
current_function_header = _procedure_header;
hard_node_test_and_visit(_procedure_header.name);
current_function_header = null;
if (context.converted_template_type != null)
{
return;
Expand Down Expand Up @@ -11822,9 +11830,9 @@ public override void visit(SyntaxTree.procedure_attributes_list _procedure_attri
AddError(get_location(_procedure_attributes_list), "EXTENSION_ATTRIBUTE_ONLY_FOR_NAMESPACE_FUNCTIONS_ALLOWED");
if (context.top_function.parameters.Count == 0)
AddError(context.top_function.loc, "EXTENSION_METHODS_MUST_HAVE_LEAST_ONE_PARAMETER");
if (context.top_function.parameters[0].parameter_type != SemanticTree.parameter_type.value)
if (!context.top_function.IsOperator && context.top_function.parameters[0].parameter_type != SemanticTree.parameter_type.value)
AddError(context.top_function.loc, "FIRST_PARAMETER_SHOULDBE_ONLY_VALUE_PARAMETER");
if (context.top_function.parameters[0].name.ToLower() != compiler_string_consts.self_word)
if (!context.top_function.IsOperator && context.top_function.parameters[0].name.ToLower() != compiler_string_consts.self_word)
AddError(context.top_function.loc,"FIRST_PARAMETER_MUST_HAVE_NAME_SELF");
common_namespace_function_node top_function = context.top_function as common_namespace_function_node;
top_function.ConnectedToType = context.top_function.parameters[0].type;
Expand Down
8 changes: 8 additions & 0 deletions bin/Lib/PABCSystem.pas
Original file line number Diff line number Diff line change
Expand Up @@ -3127,6 +3127,14 @@ function System.Collections.Generic.IEnumerable<T>.operator*(n: integer; a: sequ
Result := a*n;
end;

/// Îáúåäèíÿåò äâà ìàññèâà
function operator+<T>(a, b: array of T): array of T; extensionmethod;
begin
Result := new T[a.Length+b.Length];
a.CopyTo(Result,0);
b.CopyTo(Result,a.Length);
end;

// -----------------------------------------------------
// Sequences
// -----------------------------------------------------
Expand Down
17 changes: 9 additions & 8 deletions bin/Lng/Eng/SemanticErrors_ib.dat
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,14 @@ FIRST_PARAMETER_SHOULDBE_ONLY_VALUE_PARAMETER=var and const are not allowed for
FIRST_PARAMETER_MUST_HAVE_NAME_SELF=Parameter with 'name' self expected
EXTENSION_METHODS_FOR_CONSTRUCTED_TYPES_NOT_ALLOWED=Cannot extend this type
EXTENSION_METHODS_IN_INTERFACE_PART_NOT_ALLOWED=Cannot declare extension methods in interface part of unit
OPERATOR_SHOULD_BE_EXTENSION_METHOD=Operator should be extension method
UNABLE_TO_CONVERT_FUNCTIONAL_TYPE_TO_PROCEDURAL_TYPE=Unable to convert functional type to procedural type
ILLEGAL_PARAMETERS_IN_LAMBDA=Illegal parameters in lambda
ILLEGAL_LAMBDA_VARIABLE_TYPE=Illegal lambda variable type
ILLEGAL_LAMBDA_PARAMETERS_NUMBER=Illegal lambda parameters number
IMPOSSIBLE_TO_INFER_TYPES_IN_LAMBDA=Unable to infer types in lambda
ANONYMOUS_DELEGATE_IN_INTERFACE_NOT_ALLOWED=Using of anonymous delegate in interface is not allowed. Declare the delegate type explicitly.
PARAMETER_REFERENCE_IN_DEFAULT_PARAMETER_NOT_ALLOWED=Parameter references in default parameter value are not allowed
%PREFIX%=COMPILATIONERROR_
UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Unit expected, library found
ASSEMBLY_{0}_READING_ERROR=Error by reading assembly '{0}'
UNABLE_TO_CONVERT_FUNCTIONAL_TYPE_TO_PROCEDURAL_TYPE="Unable to convert functional type to procedural type"
ILLEGAL_PARAMETERS_IN_LAMBDA="Illegal parameters in lambda"
ILLEGAL_LAMBDA_VARIABLE_TYPE="Illegal lambda variable type"
ILLEGAL_LAMBDA_PARAMETERS_NUMBER="Illegal lambda parameters number"
IMPOSSIBLE_TO_INFER_TYPES_IN_LAMBDA="Impossible to infer types in lambda"
ANONYMOUS_DELEGATE_IN_INTERFACE_NOT_ALLOWED=Using of anonymous delegate in interface is not allowed. Declare the delegate type explicitly.
PARAMETER_REFERENCE_IN_DEFAULT_PARAMETER_NOT_ALLOWED=Parameter references in default parameter value are not allowed
ASSEMBLY_{0}_READING_ERROR=Error by reading assembly '{0}'
1 change: 1 addition & 0 deletions bin/Lng/Rus/SemanticErrors_ib.dat
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ FIRST_PARAMETER_SHOULDBE_ONLY_VALUE_PARAMETER=Недопустимо испол
FIRST_PARAMETER_MUST_HAVE_NAME_SELF=Первый параметр должен иметь имя self
EXTENSION_METHODS_FOR_CONSTRUCTED_TYPES_NOT_ALLOWED=Нельзя расширять этот тип
EXTENSION_METHODS_IN_INTERFACE_PART_NOT_ALLOWED=Объявление extension-методов в интерфейсной части модуля недопустимо
OPERATOR_SHOULD_BE_EXTENSION_METHOD=Оператор должен быть помечен модификатором extensionmethod
%PREFIX%=COMPILATIONERROR_
UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Ожидался модуль, а встречена библиотека
ASSEMBLY_{0}_READING_ERROR=Ошибка при чтении сборки '{0}'

0 comments on commit e0443ce

Please sign in to comment.