private void VisitAccessMethod( AccessMethodNode node, Func <FunctionToken, Node, ArgsListNode, MethodInfo, string, bool, AccessMethodNode> func) { var args = Nodes.Pop() as ArgsListNode; var groupArgs = new List <Type> { typeof(string) }; groupArgs.AddRange(args.Args.Skip(1).Select(f => f.ReturnType)); var alias = !string.IsNullOrEmpty(node.Alias) ? node.Alias : _identifier; var tableSymbol = _currentScope.ScopeSymbolTable.GetSymbol <TableSymbol>(alias); var schemaTablePair = tableSymbol.GetTableByAlias(alias); var canSkipInjectSource = false; if (!schemaTablePair.Schema.TryResolveAggreationMethod(node.Name, groupArgs.ToArray(), out var method)) { if (!schemaTablePair.Schema.TryResolveMethod(node.Name, args.Args.Select(f => f.ReturnType).ToArray(), out method)) { if (!schemaTablePair.Schema.TryResolveRawMethod(node.Name, args.Args.Select(f => f.ReturnType).ToArray(), out method)) { var types = args.Args.Length > 0 ? args.Args.Select(f => f.ReturnType.ToString()).Aggregate((a, b) => a + ", " + b) : string.Empty; throw new UnresolvableMethodException($"{node.Name}({types}) cannot be resolved."); } canSkipInjectSource = true; } } var isAggregateMethod = method.GetCustomAttribute <AggregationMethodAttribute>() != null; AccessMethodNode accessMethod; if (isAggregateMethod) { accessMethod = func(node.FToken, args, node.ExtraAggregateArguments, method, alias, false); var identifier = accessMethod.ToString(); var newArgs = new List <Node> { new WordNode(identifier) }; newArgs.AddRange(args.Args.Skip(1)); var newSetArgs = new List <Node> { new WordNode(identifier) }; newSetArgs.AddRange(args.Args); var setMethodName = $"Set{method.Name}"; var argTypes = newSetArgs.Select(f => f.ReturnType).ToArray(); if (!schemaTablePair.Schema.TryResolveAggreationMethod( setMethodName, argTypes, out var setMethod)) { var names = argTypes.Length == 0 ? string.Empty : argTypes.Select(arg => arg.Name).Aggregate((a, b) => a + ", " + b); throw new NotSupportedException($"Cannot resolve method {setMethodName} with parameters {names}"); } if (setMethod.IsGenericMethodDefinition) { var setParams = setMethod.GetParameters(); var genericArguments = setMethod.GetGenericArguments(); var genericArgumentsMap = new Dictionary <int, Type>(); var genericArgumentsDistinct = new List <Type>(); foreach (var genericArgument in genericArguments) { for (int i = 0; i < setParams.Length; i++) { var setParam = setParams[i]; if (setParam.ParameterType == genericArgument) { genericArgumentsMap.Add(i, genericArgument); genericArgumentsDistinct.Add(newSetArgs.Where((arg, index) => index == i - 1).Single().ReturnType); } } } var genericArgumentsConcreteTypes = genericArgumentsDistinct.Distinct().ToArray(); method = method.MakeGenericMethod(genericArgumentsConcreteTypes); setMethod = setMethod.MakeGenericMethod(genericArgumentsConcreteTypes); } var setMethodNode = func(new FunctionToken(setMethodName, TextSpan.Empty), new ArgsListNode(newSetArgs.ToArray()), null, setMethod, alias, false); _refreshMethods.Add(setMethodNode); accessMethod = func(node.FToken, new ArgsListNode(newArgs.ToArray()), null, method, alias, canSkipInjectSource); } else { accessMethod = func(node.FToken, args, new ArgsListNode(new Node[0]), method, alias, canSkipInjectSource); } AddAssembly(method.DeclaringType.Assembly); AddAssembly(method.ReturnType.Assembly); node.ChangeMethod(method); Nodes.Push(accessMethod); }
private void VisitAccessMethod(AccessMethodNode node, Func <FunctionToken, Node, ArgsListNode, MethodInfo, string, AccessMethodNode> func) { var args = Nodes.Pop() as ArgsListNode; var groupArgs = new List <Type> { typeof(string) }; groupArgs.AddRange(args.Args.Where((f, i) => i < args.Args.Length - 1).Select(f => f.ReturnType)); var alias = !string.IsNullOrEmpty(node.Alias) ? node.Alias : _identifier; var tableSymbol = _currentScope.ScopeSymbolTable.GetSymbol <TableSymbol>(alias); var schemaTablePair = tableSymbol.GetTableByAlias(alias); if (!schemaTablePair.Schema.TryResolveAggreationMethod(node.Name, groupArgs.ToArray(), out var method)) { method = schemaTablePair.Schema.ResolveMethod(node.Name, args.Args.Select(f => f.ReturnType).ToArray()); } var isAggregateMethod = method.GetCustomAttribute <AggregationMethodAttribute>() != null; AccessMethodNode accessMethod; if (isAggregateMethod) { accessMethod = func(node.FToken, args, node.ExtraAggregateArguments, method, alias); var identifier = accessMethod.ToString(); var newArgs = new List <Node> { new WordNode(identifier) }; newArgs.AddRange(args.Args.Where((f, i) => i < args.Args.Length - 1)); var newSetArgs = new List <Node> { new WordNode(identifier) }; newSetArgs.AddRange(args.Args); var setMethodName = $"Set{method.Name}"; if (!schemaTablePair.Schema.TryResolveAggreationMethod( setMethodName, newSetArgs.Select(f => f.ReturnType).ToArray(), out var setMethod)) { throw new NotSupportedException(); } var setMethodNode = func(new FunctionToken(setMethodName, TextSpan.Empty), new ArgsListNode(newSetArgs.ToArray()), null, setMethod, alias); _refreshMethods.Add(setMethodNode); accessMethod = func(node.FToken, new ArgsListNode(newArgs.ToArray()), null, method, alias); } else { accessMethod = func(node.FToken, args, new ArgsListNode(new Node[0]), method, alias); } AddAssembly(method.DeclaringType.Assembly); AddAssembly(method.ReturnType.Assembly); node.ChangeMethod(method); Nodes.Push(accessMethod); }