/// <summary> /// Exit a parse tree produced by the <c>fnCallExp</c> /// labeled alternative in <see cref="ChessVCParser.postfixExpr"/>. /// <para>The default implementation does nothing.</para> /// </summary> /// <param name="context">The parse tree.</param> public virtual void ExitFnCallExp([NotNull] ChessVCParser.FnCallExpContext context) { }
/// <summary> /// Visit a parse tree produced by the <c>fnCallExp</c> /// labeled alternative in <see cref="ChessVCParser.postfixExpr"/>. /// <para> /// The default implementation returns the result of calling <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/> /// on <paramref name="context"/>. /// </para> /// </summary> /// <param name="context">The parse tree.</param> /// <return>The visitor result.</return> public virtual Result VisitFnCallExp([NotNull] ChessVCParser.FnCallExpContext context) { return(VisitChildren(context)); }
public override object VisitFnCallExp([NotNull] ChessVCParser.FnCallExpContext context) { string s = context.GetText(); object fnobj = Visit(context.postfixExpr()); if (fnobj is Reference) { Reference fnref = (Reference)fnobj; if (fnref.IsFunction) { // load all the function arguments var argListCtx = context.argumentList(); object[] arglist = argListCtx == null ? new Reference[] { } : (object[])Visit(context.argumentList()); // case of non-overloaded function if (fnref.FunctionMember != null) { ParameterInfo[] pi = fnref.FunctionMember.GetParameters(); int calledFunctionArgCount = fnref.FunctionMember.GetParameters().Length; if (calledFunctionArgCount != arglist.Length) { // we didn't supply all the arguments, but maybe the rest are optional bool allRemainingArgsAreOptional = false; if (arglist.Length < calledFunctionArgCount) { allRemainingArgsAreOptional = true; for (int x = arglist.Length; x < calledFunctionArgCount; x++) { if (!fnref.FunctionMember.GetParameters()[x].IsOptional) { allRemainingArgsAreOptional = false; } } } if (!allRemainingArgsAreOptional) { throw new Exception("Incorrect number of arguments specified for function: " + context.postfixExpr().GetText()); } } if (!canMatchSignature(fnref.FunctionMember.GetParameters(), arglist)) { // before we decide we can't call this function, check to see if // there is only one argument, that argument is a type, that type // has a constructor taking no arguments, and if, after construction, // the object is of the required type. If all this pans out, // we'll just construct a new object of this type. if (arglist.Length == 1 && arglist[0].GetType() is Type && ((Type)arglist[0]).IsSubclassOf(fnref.FunctionMember.GetParameters()[0].ParameterType)) { Type t = (Type)arglist[0]; ConstructorInfo ci = t.GetConstructor(new Type[] { }); if (ci != null) { object[] arg = new object[1]; arg[0] = ci.Invoke(null); return(fnref.GetValue(arg)); } } throw new Exception("Arguments of incorrect type provided for function: " + context.postfixExpr().GetText()); } object[] args = new object[calledFunctionArgCount]; for (int x = 0; x < arglist.Length; x++) { args[x] = arglist[x]; } for (int y = arglist.Length; y < calledFunctionArgCount; y++) { args[y] = Type.Missing; } return(fnref.GetValue(args)); } else if (fnref.FunctionOverloads != null) { // we have overloaded functions - search for one that works foreach (MethodInfo mi in fnref.FunctionOverloads) { if (canMatchSignature(mi.GetParameters(), arglist)) { ParameterInfo[] parameters = mi.GetParameters(); object[] args = new object[parameters.Length]; for (int x = 0; x < parameters.Length; x++) { args[x] = x < arglist.Length ? arglist[x] : Type.Missing; } return(mi.Invoke(fnref.ReferencedObject, args)); } } throw new Exception("No overloaded found with compatible arguments for function: " + context.postfixExpr().GetText()); } } else if (fnref.ReferencedObject.GetType().IsSubclassOf(typeof(Type))) { // load the constructor arguments var argListCtx = context.argumentList(); object[] arglist = argListCtx == null ? new Reference[] { } : (object[])Visit(context.argumentList()); // our function call is really calling a constructor Type tp = (Type)fnref.ReferencedObject; foreach (ConstructorInfo ci in tp.GetConstructors()) { if (canMatchSignature(ci.GetParameters(), arglist)) { ParameterInfo[] parameters = ci.GetParameters(); object[] args = new object[parameters.Length]; for (int x = 0; x < parameters.Length; x++) { args[x] = x < arglist.Length ? arglist[x] : Type.Missing; } return(ci.Invoke(args)); } } throw new Exception("No constructor found with compatible arguments for type: " + context.postfixExpr().GetText()); } } throw new Exception("Function call attempted with object that is not a function: " + context.postfixExpr().GetText()); }