generic operator extensions (operator+<T>)
This commit is contained in:
parent
bd6ae86526
commit
e0443cea7a
|
|
@ -899,7 +899,10 @@ namespace CodeCompletion
|
|||
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)
|
||||
|
|
@ -1183,7 +1186,10 @@ namespace CodeCompletion
|
|||
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)
|
||||
{
|
||||
|
|
@ -3634,6 +3640,7 @@ namespace CodeCompletion
|
|||
(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)
|
||||
|
|
|
|||
|
|
@ -704,8 +704,10 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3127,6 +3127,14 @@ begin
|
|||
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
|
||||
// -----------------------------------------------------
|
||||
|
|
|
|||
12
TestSuite/extensionmethods11.pas
Normal file
12
TestSuite/extensionmethods11.pas
Normal 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.
|
||||
|
|
@ -294,6 +294,8 @@ namespace PascalABCCompiler.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);
|
||||
|
|
@ -302,7 +304,9 @@ namespace PascalABCCompiler.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();
|
||||
|
|
@ -499,15 +503,59 @@ namespace PascalABCCompiler.NetHelper
|
|||
{
|
||||
|
||||
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());
|
||||
|
|
@ -1110,20 +1158,27 @@ namespace PascalABCCompiler.NetHelper
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
|
@ -1364,6 +1419,7 @@ namespace PascalABCCompiler.NetHelper
|
|||
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;
|
||||
|
|
@ -1373,7 +1429,6 @@ namespace PascalABCCompiler.NetHelper
|
|||
SymbolInfo si=null;
|
||||
|
||||
List<MemberInfo> mis = GetMembers(t,name);
|
||||
|
||||
//(ssyy) Èçìåíèë àëãîðèòì.
|
||||
//Ó íàñ íåêîòîðûå àëãîðèòìû áàçèðóþòñÿ íà òîì, ÷òî âîçâðàù¸ííûå
|
||||
//ñóùíîñòè áóäóò îäíîé ïðèðîäû (íàïðèìåð, âñå - ìåòîäû). Ýòî íåâåðíî,
|
||||
|
|
|
|||
|
|
@ -8965,7 +8965,7 @@ namespace PascalABCCompiler.TreeConverter
|
|||
}
|
||||
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");
|
||||
}
|
||||
|
|
@ -11209,9 +11209,13 @@ namespace PascalABCCompiler.TreeConverter
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -11337,9 +11341,11 @@ namespace PascalABCCompiler.TreeConverter
|
|||
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));
|
||||
}
|
||||
|
|
@ -11462,7 +11468,9 @@ namespace PascalABCCompiler.TreeConverter
|
|||
{
|
||||
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;
|
||||
|
|
@ -11822,9 +11830,9 @@ namespace PascalABCCompiler.TreeConverter
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -3127,6 +3127,14 @@ begin
|
|||
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
|
||||
// -----------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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}'
|
||||
|
|
@ -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}'
|
||||
Loading…
Reference in a new issue