object ExecuteFunction(Command cmd, object instance, bool useDefaultVar) { object result = null; string origName = ((Literal)cmd.Args[0]).Value; string assemblyName = null; string className = null; string methodName = null; string[] splitName = origName.ToLowerInvariant().Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries); if (splitName.Length == 1) { methodName = splitName[0]; } else if (splitName.Length == 2) { className = splitName[0]; methodName = splitName[1]; } else if (splitName.Length == 3) { assemblyName = splitName[0]; className = splitName[1]; methodName = splitName[2]; } else { throw new Exception("Invalid function name: " + origName + "()"); } if (methodName == LoadPluginName) { string path; if (useDefaultVar) { path = (string)defaultVar; } else { path = (string)ExecuteExpr(cmd.Args[1]); } PluginManager.LoadPlugin(path); } else if (methodName == ImportName) { string path; if (useDefaultVar) { path = (string)defaultVar; } else { path = (string)ExecuteExpr(cmd.Args[1]); } ScriptParser parser = new ScriptParser(path); string prevCWD = Environment.CurrentDirectory; Environment.CurrentDirectory = parser.CWD; ExecuteExpr(parser.CommandRoot); Environment.CurrentDirectory = prevCWD; } else { List<FunctionBase> plugins; if (!PluginManager.Functions.TryGetValue(methodName, out plugins) || (plugins.Count <= 0)) { throw new Exception("Couldn't find plugin for " + origName + "()"); } if (assemblyName != null) { for (int i = 0; i < plugins.Count; ) { string pluginAssemblyName = Path.GetFileNameWithoutExtension(plugins[i].Type.Assembly.CodeBase).ToLowerInvariant(); if (assemblyName == pluginAssemblyName) { i++; } else { plugins.RemoveAt(i); } } } if (className != null) { for (int i = 0; i < plugins.Count; ) { string pluginClassName = plugins[i].Type.Name.ToLowerInvariant(); if (className == pluginClassName) { i++; } else { plugins.RemoveAt(i); } } } if (plugins.Count <= 0) { throw new Exception("Couldn't find plugin for " + origName + "()"); } ScriptArg[] scriptArgs; int argIdx = 0; if (useDefaultVar) { scriptArgs = new ScriptArg[cmd.Args.Count]; ScriptArg scriptArg = new ScriptArg(); scriptArg.Value = defaultVar; scriptArgs[argIdx] = scriptArg; argIdx++; } else { scriptArgs = new ScriptArg[cmd.Args.Count - 1]; } for (int cmdIdx = 1; cmdIdx < cmd.Args.Count; cmdIdx++) { ScriptArg scriptArg = new ScriptArg(); Expr cmdArg = cmd.Args[cmdIdx]; if (cmdArg.Type == ExprType.Assign) { Command assign = (Command)cmdArg; scriptArg.Name = ((Literal)assign.Args[0]).Value; cmdArg = assign.Args[1]; } if (cmdArg.Type == ExprType.Name) { scriptArg.Variable = ((Literal)cmdArg).Value; } scriptArg.Value = ExecuteExpr(cmdArg); scriptArgs[argIdx] = scriptArg; argIdx++; } bool instanceExactMatch = false; int minConversions = Int32.MaxValue; FunctionArg[] pluginArgs = null; FunctionBase plugin = null; for (int i = 0; i < plugins.Count; i++) { int numConversions; FunctionArg[] matchArgs = plugins[i].Match(scriptArgs, useDefaultVar, out numConversions); if ((matchArgs != null) && (numConversions < minConversions)) { if (instance == null) { pluginArgs = matchArgs; plugin = plugins[i]; minConversions = numConversions; } else { Type instanceType = instance.GetType(); if (plugins[i].Type.Equals(instanceType)) { pluginArgs = matchArgs; plugin = plugins[i]; minConversions = numConversions; instanceExactMatch = true; } else if (!instanceExactMatch && plugins[i].Type.IsAssignableFrom(instanceType)) { pluginArgs = matchArgs; plugin = plugins[i]; minConversions = numConversions; } } } } if (pluginArgs == null) { throw new Exception("Couldn't match args for " + origName + "()"); } List<FunctionArg> changedVars; result = plugin.RunPlugin(instance, pluginArgs, out changedVars); for (int i = 0; i < changedVars.Count; i++) { FunctionArg pluginArg = changedVars[i]; if (pluginArg.DefaultVar) { defaultVar = pluginArg.Value; } else { Variables[pluginArg.Variable] = pluginArg.Value; } } } return result; }
public FunctionArg[] Match(ScriptArg[] args, bool useDefaultVar, out int numConversions) { FunctionArg[] result = null; numConversions = 0; if (args.Length == Parameters.Length) { FunctionArg[] objArgs = new FunctionArg[args.Length]; List<int> unfilledPos = new List<int>(args.Length); for (int i = 0; i < args.Length; i++) { unfilledPos.Add(i); } List<ScriptArg> nondefault = new List<ScriptArg>(args); if (useDefaultVar && (DefaultVarPos >= 0)) { Type paramType = Parameters[DefaultVarPos].ParameterType; if (MatchParameter(objArgs, args[0], paramType, DefaultVarPos, ref numConversions)) { objArgs[DefaultVarPos].DefaultVar = paramType.IsByRef; unfilledPos.Remove(DefaultVarPos); nondefault.RemoveAt(0); } else { return null; } } List<ScriptArg> unnamed = new List<ScriptArg>(nondefault.Count); for (int i = 0; i < nondefault.Count; i++) { ScriptArg arg = nondefault[i]; if (arg.Name == null) { unnamed.Add(arg); } else { ParameterInfo info; if (ParameterDic.TryGetValue(arg.Name.ToLowerInvariant(), out info)) { if (MatchParameter(objArgs, arg, info.ParameterType, info.Position, ref numConversions)) { unfilledPos.Remove(info.Position); } else { return null; } } else { return null; } } } for (int i = 0; i < unnamed.Count; i++) { int pos = unfilledPos[i]; if (!MatchParameter(objArgs, unnamed[i], Parameters[pos].ParameterType, pos, ref numConversions)) { return null; } } result = objArgs; } return result; }
object ExecuteFunction(Command cmd, object instance, bool useDefaultVar) { object result = null; string origName = ((Literal)cmd.Args[0]).Value; string assemblyName = null; string className = null; string methodName = null; string[] splitName = origName.ToLowerInvariant().Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries); if (splitName.Length == 1) { methodName = splitName[0]; } else if (splitName.Length == 2) { className = splitName[0]; methodName = splitName[1]; } else if (splitName.Length == 3) { assemblyName = splitName[0]; className = splitName[1]; methodName = splitName[2]; } else { throw new Exception("Invalid function name: " + origName + "()"); } if (methodName == LoadPluginName) { string path; if (useDefaultVar) { path = (string)defaultVar; } else { path = (string)ExecuteExpr(cmd.Args[1]); } PluginManager.LoadPlugin(path); } else if (methodName == ImportName) { string path; if (useDefaultVar) { path = (string)defaultVar; } else { path = (string)ExecuteExpr(cmd.Args[1]); } ScriptParser parser = new ScriptParser(path); string prevCWD = Environment.CurrentDirectory; Environment.CurrentDirectory = parser.CWD; ExecuteExpr(parser.CommandRoot); Environment.CurrentDirectory = prevCWD; } else { List <FunctionBase> plugins; if (!PluginManager.Functions.TryGetValue(methodName, out plugins) || (plugins.Count <= 0)) { throw new Exception("Couldn't find plugin for " + origName + "()"); } if (assemblyName != null) { for (int i = 0; i < plugins.Count;) { string pluginAssemblyName = Path.GetFileNameWithoutExtension(plugins[i].Type.Assembly.CodeBase).ToLowerInvariant(); if (assemblyName == pluginAssemblyName) { i++; } else { plugins.RemoveAt(i); } } } if (className != null) { for (int i = 0; i < plugins.Count;) { string pluginClassName = plugins[i].Type.Name.ToLowerInvariant(); if (className == pluginClassName) { i++; } else { plugins.RemoveAt(i); } } } if (plugins.Count <= 0) { throw new Exception("Couldn't find plugin for " + origName + "()"); } ScriptArg[] scriptArgs; int argIdx = 0; if (useDefaultVar) { scriptArgs = new ScriptArg[cmd.Args.Count]; ScriptArg scriptArg = new ScriptArg(); scriptArg.Value = defaultVar; scriptArgs[argIdx] = scriptArg; argIdx++; } else { scriptArgs = new ScriptArg[cmd.Args.Count - 1]; } for (int cmdIdx = 1; cmdIdx < cmd.Args.Count; cmdIdx++) { ScriptArg scriptArg = new ScriptArg(); Expr cmdArg = cmd.Args[cmdIdx]; if (cmdArg.Type == ExprType.Assign) { Command assign = (Command)cmdArg; scriptArg.Name = ((Literal)assign.Args[0]).Value; cmdArg = assign.Args[1]; } if (cmdArg.Type == ExprType.Name) { scriptArg.Variable = ((Literal)cmdArg).Value; } scriptArg.Value = ExecuteExpr(cmdArg); scriptArgs[argIdx] = scriptArg; argIdx++; } bool instanceExactMatch = false; int minConversions = Int32.MaxValue; FunctionArg[] pluginArgs = null; FunctionBase plugin = null; for (int i = 0; i < plugins.Count; i++) { int numConversions; FunctionArg[] matchArgs = plugins[i].Match(scriptArgs, useDefaultVar, out numConversions); if ((matchArgs != null) && (numConversions < minConversions)) { if (instance == null) { pluginArgs = matchArgs; plugin = plugins[i]; minConversions = numConversions; } else { Type instanceType = instance.GetType(); if (plugins[i].Type.Equals(instanceType)) { pluginArgs = matchArgs; plugin = plugins[i]; minConversions = numConversions; instanceExactMatch = true; } else if (!instanceExactMatch && plugins[i].Type.IsAssignableFrom(instanceType)) { pluginArgs = matchArgs; plugin = plugins[i]; minConversions = numConversions; } } } } if (pluginArgs == null) { throw new Exception("Couldn't match args for " + origName + "()"); } List <FunctionArg> changedVars; result = plugin.RunPlugin(instance, pluginArgs, out changedVars); for (int i = 0; i < changedVars.Count; i++) { FunctionArg pluginArg = changedVars[i]; if (pluginArg.DefaultVar) { defaultVar = pluginArg.Value; } else { Variables[pluginArg.Variable] = pluginArg.Value; } } } return(result); }
private bool MatchParameter(FunctionArg[] pluginArgs, ScriptArg scriptArg, Type parameterType, int parameterPos, ref int numConversions) { FunctionArg pluginArg = new FunctionArg(scriptArg.Value, scriptArg.Variable); if (parameterType.IsByRef) { parameterType = parameterType.GetElementType(); } else { pluginArg.Variable = null; } if (pluginArg.Value == null) { if (parameterType.IsValueType) { if (Nullable.GetUnderlyingType(parameterType) == null) { //not nullable return false; } else { //nullable pluginArgs[parameterPos] = pluginArg; } } else { //nullable pluginArgs[parameterPos] = pluginArg; } } else { if (parameterType.IsAssignableFrom(pluginArg.Value.GetType())) { pluginArgs[parameterPos] = pluginArg; } else { if (!(pluginArg.Value is IConvertible)) { return false; } try { pluginArg.Value = Convert.ChangeType(pluginArg.Value, parameterType); pluginArgs[parameterPos] = pluginArg; numConversions++; } catch { return false; } } } return true; }