generic operator extensions (operator+<T>)

This commit is contained in:
Бондарев Иван 2015-12-09 22:11:38 +01:00
parent bd6ae86526
commit e0443cea7a
9 changed files with 123 additions and 21 deletions

View file

@ -899,6 +899,9 @@ namespace CodeCompletion
ps.proc_realization = pr; ps.proc_realization = pr;
pr.loc = cur_loc; pr.loc = cur_loc;
pr.head_loc = loc; pr.head_loc = loc;
if (impl_scope != null)
impl_scope.AddName("$method", pr);
else
this.entry_scope.AddName("$method", pr); this.entry_scope.AddName("$method", pr);
} }
ps.head_loc = loc; ps.head_loc = loc;
@ -1183,6 +1186,9 @@ namespace CodeCompletion
ps.proc_realization = pr; ps.proc_realization = pr;
pr.loc = cur_loc; pr.loc = cur_loc;
pr.head_loc = loc; pr.head_loc = loc;
if (impl_scope != null)
impl_scope.AddName("$method", pr);
else
this.entry_scope.AddName("$method", pr); this.entry_scope.AddName("$method", pr);
} }
if (!ps.is_extension) if (!ps.is_extension)
@ -3634,6 +3640,7 @@ namespace CodeCompletion
(returned_scope as ArrayScope).is_dynamic_arr = true; (returned_scope as ArrayScope).is_dynamic_arr = true;
} }
save_return_value(); save_return_value();
if (_new_expr.params_list != null)
foreach (expression ex in _new_expr.params_list.expressions) foreach (expression ex in _new_expr.params_list.expressions)
{ {
if (ex is function_lambda_definition) if (ex is function_lambda_definition)

View file

@ -704,8 +704,10 @@ namespace PascalABCCompiler.SyntaxTree
{ {
var t = name.meth_name as template_type_name; var t = name.meth_name as template_type_name;
template_args = t.template_args; template_args = t.template_args;
ident id = new ident(name.meth_name.name, name.meth_name.source_context); if (name.meth_name is template_operator_name)
name.meth_name = id; 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);
} }
} }

View file

@ -3127,6 +3127,14 @@ begin
Result := a*n; Result := a*n;
end; 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 // Sequences
// ----------------------------------------------------- // -----------------------------------------------------

View file

@ -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.

View file

@ -294,6 +294,8 @@ namespace PascalABCCompiler.NetHelper
public static Assembly SystemCoreAssembly; public static Assembly SystemCoreAssembly;
private static Dictionary<Type,MethodInfo[]> extension_methods = new Dictionary<Type,MethodInfo[]>(); 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,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 PABCSystemType = null;
public static Type PT4Type = null; public static Type PT4Type = null;
public static Type StringType = typeof(string); public static Type StringType = typeof(string);
@ -302,6 +304,8 @@ namespace PascalABCCompiler.NetHelper
public static void reset() public static void reset()
{ {
if (cur_used_assemblies == null)
cur_used_assemblies = new Hashtable();
cur_used_assemblies.Clear(); cur_used_assemblies.Clear();
cur_used_assemblies[typeof(string).Assembly] = typeof(string).Assembly; cur_used_assemblies[typeof(string).Assembly] = typeof(string).Assembly;
cur_used_assemblies[typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly] = typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly; cur_used_assemblies[typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly] = typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly;
@ -499,15 +503,59 @@ namespace PascalABCCompiler.NetHelper
{ {
List<MethodInfo> mths = null; List<MethodInfo> mths = null;
List<MethodInfo> mths2 = null;
Type tmp = prms[0].ParameterType; Type tmp = prms[0].ParameterType;
bool generic_type = false;
if (tmp.IsGenericType) if (tmp.IsGenericType)
{
tmp = tmp.GetGenericTypeDefinition(); tmp = tmp.GetGenericTypeDefinition();
generic_type = true;
}
if (!type_extensions.TryGetValue(tmp, out mths)) if (!type_extensions.TryGetValue(tmp, out mths))
{ {
mths = new List<MethodInfo>(); mths = new List<MethodInfo>();
type_extensions.Add(tmp, mths); type_extensions.Add(tmp, mths);
} }
mths.Add(mi); 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()); extension_methods.Add(t, ext_meths.ToArray());
@ -1110,20 +1158,27 @@ namespace PascalABCCompiler.NetHelper
{ {
List<MethodInfo> meths = null; List<MethodInfo> meths = null;
Type tmp_t = t; Type tmp_t = t;
if (tmp_t.IsArray)
arrays_with_extension_methods[tmp_t] = tmp_t;
cached_type_extensions[t] = t; cached_type_extensions[t] = t;
while (tmp_t != null) 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) foreach (MethodInfo mi in meths)
{ {
if (cur_used_assemblies.ContainsKey(mi.DeclaringType.Assembly)) if (cur_used_assemblies.ContainsKey(mi.DeclaringType.Assembly))
{ {
List<MemberInfo> al = null; 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>(); al = new List<MemberInfo>();
ht[mi.Name] = al; ht[s] = al;
} }
al.Insert(0, mi); al.Insert(0, mi);
} }
@ -1364,6 +1419,7 @@ namespace PascalABCCompiler.NetHelper
if (name == null) return null; if (name == null) return null;
if (name == compiler_string_consts.assign_name) return null; if (name == compiler_string_consts.assign_name) return null;
string s = compiler_string_consts.GetNETOperName(name); string s = compiler_string_consts.GetNETOperName(name);
string tmp_name = name;
if (s != null) if (s != null)
{ {
if (IsStandType(t)) return null; if (IsStandType(t)) return null;
@ -1373,7 +1429,6 @@ namespace PascalABCCompiler.NetHelper
SymbolInfo si=null; SymbolInfo si=null;
List<MemberInfo> mis = GetMembers(t,name); List<MemberInfo> mis = GetMembers(t,name);
//(ssyy) Èçìåíèë àëãîðèòì. //(ssyy) Èçìåíèë àëãîðèòì.
//Ó íàñ íåêîòîðûå àëãîðèòìû áàçèðóþòñÿ íà òîì, ÷òî âîçâðàù¸ííûå //Ó íàñ íåêîòîðûå àëãîðèòìû áàçèðóþòñÿ íà òîì, ÷òî âîçâðàù¸ííûå
//ñóùíîñòè áóäóò îäíîé ïðèðîäû (íàïðèìåð, âñå - ìåòîäû). Ýòî íåâåðíî, //ñóùíîñòè áóäóò îäíîé ïðèðîäû (íàïðèìåð, âñå - ìåòîäû). Ýòî íåâåðíî,

View file

@ -8965,7 +8965,7 @@ namespace PascalABCCompiler.TreeConverter
} }
else 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"); AddError(get_location(_method_name), "OVERLOADED_OPERATOR_MUST_BE_STATIC_FUNCTION");
} }
@ -11209,9 +11209,13 @@ namespace PascalABCCompiler.TreeConverter
} }
} }
private procedure_header current_function_header = null;
public override void visit(SyntaxTree.function_header _function_header) public override void visit(SyntaxTree.function_header _function_header)
{ {
current_function_header = _function_header;
hard_node_test_and_visit(_function_header.name); hard_node_test_and_visit(_function_header.name);
current_function_header = null;
if (context.converted_template_type != null) if (context.converted_template_type != null)
{ {
return; return;
@ -11337,9 +11341,11 @@ namespace PascalABCCompiler.TreeConverter
type_node ptn = p.type; type_node ptn = p.type;
if (ptn.is_generic_type_instance) if (ptn.is_generic_type_instance)
ptn = ptn.original_generic; ptn = ptn.original_generic;
if (ptn == cnfn.ConnectedToType) if (ptn == cnfn.ConnectedToType || ptn == cnfn.ConnectedToType.original_generic)
has_types = true; has_types = true;
} }
if (cnfn.ConnectedToType == null)
AddError(new SimpleSemanticError(cnfn.loc, "OPERATOR_SHOULD_BE_EXTENSION_METHOD"));
if (!has_types) if (!has_types)
AddError(new SimpleSemanticError(cnfn.loc, "LEAST_ONE_PARAMETER_TYPE_SHOULD_EQ_DECLARING_TYPE_{0}",cnfn.ConnectedToType.name)); AddError(new SimpleSemanticError(cnfn.loc, "LEAST_ONE_PARAMETER_TYPE_SHOULD_EQ_DECLARING_TYPE_{0}",cnfn.ConnectedToType.name));
} }
@ -11462,7 +11468,9 @@ namespace PascalABCCompiler.TreeConverter
{ {
AddError(get_location(_procedure_header), "CONSTRUCTOR_CAN_NOT_BE_GENERIC"); AddError(get_location(_procedure_header), "CONSTRUCTOR_CAN_NOT_BE_GENERIC");
} }
current_function_header = _procedure_header;
hard_node_test_and_visit(_procedure_header.name); hard_node_test_and_visit(_procedure_header.name);
current_function_header = null;
if (context.converted_template_type != null) if (context.converted_template_type != null)
{ {
return; return;
@ -11822,9 +11830,9 @@ namespace PascalABCCompiler.TreeConverter
AddError(get_location(_procedure_attributes_list), "EXTENSION_ATTRIBUTE_ONLY_FOR_NAMESPACE_FUNCTIONS_ALLOWED"); AddError(get_location(_procedure_attributes_list), "EXTENSION_ATTRIBUTE_ONLY_FOR_NAMESPACE_FUNCTIONS_ALLOWED");
if (context.top_function.parameters.Count == 0) if (context.top_function.parameters.Count == 0)
AddError(context.top_function.loc, "EXTENSION_METHODS_MUST_HAVE_LEAST_ONE_PARAMETER"); 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"); 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"); 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; common_namespace_function_node top_function = context.top_function as common_namespace_function_node;
top_function.ConnectedToType = context.top_function.parameters[0].type; top_function.ConnectedToType = context.top_function.parameters[0].type;

View file

@ -3127,6 +3127,14 @@ begin
Result := a*n; Result := a*n;
end; 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 // Sequences
// ----------------------------------------------------- // -----------------------------------------------------

View file

@ -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 FIRST_PARAMETER_MUST_HAVE_NAME_SELF=Parameter with 'name' self expected
EXTENSION_METHODS_FOR_CONSTRUCTED_TYPES_NOT_ALLOWED=Cannot extend this type 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 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_ %PREFIX%=COMPILATIONERROR_
UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Unit expected, library found UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Unit expected, library found
ASSEMBLY_{0}_READING_ERROR=Error by reading assembly '{0}' 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

View file

@ -102,6 +102,7 @@ FIRST_PARAMETER_SHOULDBE_ONLY_VALUE_PARAMETER=Недопустимо испол
FIRST_PARAMETER_MUST_HAVE_NAME_SELF=Первый параметр должен иметь имя self FIRST_PARAMETER_MUST_HAVE_NAME_SELF=Первый параметр должен иметь имя self
EXTENSION_METHODS_FOR_CONSTRUCTED_TYPES_NOT_ALLOWED=Нельзя расширять этот тип EXTENSION_METHODS_FOR_CONSTRUCTED_TYPES_NOT_ALLOWED=Нельзя расширять этот тип
EXTENSION_METHODS_IN_INTERFACE_PART_NOT_ALLOWED=Объявление extension-методов в интерфейсной части модуля недопустимо EXTENSION_METHODS_IN_INTERFACE_PART_NOT_ALLOWED=Объявление extension-методов в интерфейсной части модуля недопустимо
OPERATOR_SHOULD_BE_EXTENSION_METHOD=Оператор должен быть помечен модификатором extensionmethod
%PREFIX%=COMPILATIONERROR_ %PREFIX%=COMPILATIONERROR_
UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Ожидался модуль, а встречена библиотека UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Ожидался модуль, а встречена библиотека
ASSEMBLY_{0}_READING_ERROR=Ошибка при чтении сборки '{0}' ASSEMBLY_{0}_READING_ERROR=Ошибка при чтении сборки '{0}'