public ObjectsFunctionCallExpression(ObjectMemberExpression callee, EvaluableExpression[] arguments, int startIndex, int endIndex) : base("ObjectsFunctionCall", startIndex, endIndex) { Callee = callee; Arguments = arguments; }
private static EvaluableExpression TryGenerateObjectMemberIL(Type stateType, ObjectMemberExpression objectMemberExpression, ILGenerator iLGenerator, CompileContext compileContext) { var unresolvedExpression = objectMemberExpression; var stack = new Stack <(string memberName, object indexerValue)>(); while (true) { var target = unresolvedExpression.Object; if (target is IdentifierExpression maybeIdentifier) { if (unresolvedExpression.IsIndexer) { if (unresolvedExpression.Member is ConstantExpression constantExpression) { stack.Push(("", constantExpression.Value)); stack.Push((maybeIdentifier.Name, null)); break; } if (unresolvedExpression.Member is LiteralExpression literalExpression && literalExpression.LiteralValue.Value != null) { stack.Push(("", literalExpression.LiteralValue.Value)); stack.Push((maybeIdentifier.Name, null)); break; } } else { var identifierExpression = (IdentifierExpression)unresolvedExpression.Member; stack.Push((identifierExpression.Name, null)); stack.Push((maybeIdentifier.Name, null)); break; } stack.Clear(); return(objectMemberExpression); } var member = unresolvedExpression.Member; if (unresolvedExpression.IsIndexer) { switch (member) { case ConstantExpression constantExpression: stack.Push(("", constantExpression.Value)); break; case LiteralExpression literalExpression when literalExpression.LiteralValue.Value != null: stack.Push(("", literalExpression.LiteralValue.Value)); break; default: stack.Clear(); return(objectMemberExpression); } } else { var identifierExpression = (IdentifierExpression)unresolvedExpression.Member; stack.Push((identifierExpression.Name, null)); } if (target is ObjectMemberExpression objectMember) { unresolvedExpression = objectMember; } else { stack.Clear(); return(objectMemberExpression); } } var currentType = stateType; var first = stack.Peek(); if (string.Equals("this", first.memberName, StringComparison.Ordinal)) { stack.Pop(); } var readers = new List <Action <CompileContext, ILGenerator> > { (c, il) => il.Emit(OpCodes.Ldarg_1) }; while (stack.Count > 0) { var(memberName, indexerValue) = stack.Pop(); if (indexerValue != null) { var indexerType = indexerValue.GetType(); var method = currentType.GetMethod("Get", new[] { indexerType }) ?? currentType.GetMethod("get_Item", new[] { indexerType }); if (method != null) { currentType = method.ReturnType; readers.Add((context, il) => { var valueName = $"_v{NameCounter.GetCurrentCount()}"; GenerateValue(il, indexerValue, context, valueName, false); il.Emit(OpCodes.Callvirt, method); }); continue; } if (indexerValue is string stringValue) { memberName = stringValue; } else { return(objectMemberExpression); } } if (!string.IsNullOrWhiteSpace(memberName)) { var propertyInfo = currentType.GetProperty(memberName); if (propertyInfo != null && propertyInfo.CanRead) { var getter = propertyInfo.GetGetMethod(); if (getter != null) { currentType = propertyInfo.PropertyType; readers.Add((context, il) => il.Emit(OpCodes.Callvirt, getter)); continue; } } var fieldInfo = currentType.GetField(memberName); if (fieldInfo != null) { currentType = fieldInfo.FieldType; readers.Add((context, il) => il.Emit(OpCodes.Ldfld, fieldInfo)); continue; } var method = currentType.GetMethod("get_Item", new[] { typeof(string) }) ?? currentType.GetMethod("Get", new[] { typeof(string) }) ?? currentType.GetInterfaces().FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary <,>) && x.GetGenericArguments()[0] == typeof(string))?.GetMethod("get_Item"); if (method != null) { currentType = method.ReturnType; readers.Add((context, il) => { il.Emit(OpCodes.Ldstr, memberName); il.Emit(OpCodes.Callvirt, method); }); continue; } var methodInfo = currentType.GetMethod(memberName); if (methodInfo != null) { var type = currentType; readers.Add((context, il) => GenerateNestedFunc2(type, methodInfo)(il)); currentType = typeof(Func <object[], object>); continue; } } return(objectMemberExpression); } foreach (var reader in readers) { reader(compileContext, iLGenerator); } if (currentType.IsValueType) { iLGenerator.Emit(OpCodes.Box, currentType); } return(null); }
private static void FormatObjectMemberExpression(int prefixLength, StringBuilder builder, ObjectMemberExpression objectMemberExpression, int count) { builder.AppendLine(AddPrefix(prefixLength, "object:")); Format(objectMemberExpression.Object, prefixLength + count, builder); builder.AppendLine(AddPrefix(prefixLength, $"member:indexer-{objectMemberExpression.IsIndexer}")); Format(objectMemberExpression.Member, prefixLength + count, builder); }
private EvaluableExpression GetVariable() { var chr = se[index]; var expr = chr == openParen?GetGroup() : GetIdentifier(); SkipSpaces(); chr = se[index]; var start = index; while (true) { if (chr == period) { if (option.NotAllowedMemberExpression) { throw new ParseException($"Member expression is not allowed at character {index}"); } index++; SkipSpaces(); expr = new ObjectMemberExpression(expr, GetIdentifier(), start, index, false); SkipSpaces(); chr = se[index]; } else if (chr == openSquareBracket) { if (option.NotAllowedIndexerExpression) { throw new ParseException($"Indexer expression is not allowed at character {index}"); } index++; expr = new ObjectMemberExpression(expr, GetExpression(), start, index, true); SkipSpaces(); chr = se[index]; if (chr != closeSquareBracket) { throw new ParseException($"Unclosed [ at character {index}"); } index++; SkipSpaces(); chr = se[index]; } else if (chr == openParen) { index++; switch (expr) { case ObjectMemberExpression callee: expr = new ObjectsFunctionCallExpression(callee, GetArguments(closeParen), start, index); break; case IdentifierExpression identifier: var name = identifier.Name; var function = option.NakedFunctions.FirstOrDefault(f => f.Name == name); if (function == null) { throw new ParseException($"Can not find naked function ({name}) at character {index - name.Length - 1}"); } expr = new NakedFunctionCallExpression(function, GetArguments(closeParen), start, index); break; } SkipSpaces(); chr = se[index]; } else { break; } } return(expr); }