/////////////////////////////////////////////////////////////////////// public virtual string ToString( string format, int limit, bool strict ) { return(FormatOps.Ellipsis( String.Format(format, this.X, this.Y), limit, strict)); }
/////////////////////////////////////////////////////////////////////////////////////////////// #region IExecute Members public override ReturnCode Execute( Interpreter interpreter, IClientData clientData, ArgumentList arguments, ref Result result ) { ReturnCode code = ReturnCode.Ok; if (interpreter != null) { if (arguments != null) { if (arguments.Count >= 2) { // // NOTE: lambdaExpr must be a two element list {args body} or a three element // list {args body namespace}. // StringList lambdaExpr = null; code = Parser.SplitList( interpreter, arguments[1], 0, Length.Invalid, true, ref lambdaExpr, ref result); if (code == ReturnCode.Ok) { if ((lambdaExpr.Count == 2) || (lambdaExpr.Count == 3)) { byte[] hashValue = arguments[1].GetHashValue(ref result); if (hashValue != null) { INamespace @namespace = null; if (lambdaExpr.Count == 3) { @namespace = NamespaceOps.Lookup( interpreter, lambdaExpr[2], true, false, ref result); if (@namespace == null) { code = ReturnCode.Error; } } if (code == ReturnCode.Ok) { // // NOTE: Parse the arguments into a list and make sure there are enough // supplied to satisfy the request. // StringList list = null; code = Parser.SplitList( interpreter, lambdaExpr[0], 0, Length.Invalid, true, ref list, ref result); if (code == ReturnCode.Ok) { StringPairList list2 = new StringPairList(); for (int argumentIndex = 0; argumentIndex < list.Count; argumentIndex++) { StringList list3 = null; code = Parser.SplitList( interpreter, list[argumentIndex], 0, Length.Invalid, true, ref list3, ref result); if (code != ReturnCode.Ok) { break; } if (list3.Count > 2) { result = String.Format( "too many fields in argument specifier \"{0}\"", list[argumentIndex]); code = ReturnCode.Error; break; } else if ((list3.Count == 0) || String.IsNullOrEmpty(list3[0])) { result = "argument with no name"; code = ReturnCode.Error; break; } else if (!Parser.IsSimpleScalarVariableName(list3[0], String.Format(Interpreter.ArgumentNotSimpleError, list3[0]), String.Format(Interpreter.ArgumentNotScalarError, list3[0]), ref result)) { code = ReturnCode.Error; break; } string argName = list3[0]; string argDefault = (list3.Count >= 2) ? list3[1] : null; list2.Add(new StringPair(argName, argDefault)); } if (code == ReturnCode.Ok) { // // NOTE: We *MUST* have the formal arguments in an actual ArgumentList // container now. The variadic and optional argument semantics // depend on it. // ArgumentList formalArguments = new ArgumentList( list2, ArgumentFlags.NameOnly); // // NOTE: Compare lambda argument count with the total outer argument // count minus the "apply" and "lambdaExpr" arguments. // bool hasArgs = formalArguments.IsVariadic(true); int totalArgs = hasArgs ? formalArguments.Count - 1 : formalArguments.Count; int optionalArgs = formalArguments.GetOptionalCount(); if ((((arguments.Count - 2) >= (totalArgs - optionalArgs)) && ((arguments.Count - 2) <= totalArgs)) || (hasArgs && ((arguments.Count - 2) >= (totalArgs - optionalArgs)))) { string name = NextName(interpreter, @namespace); ICallFrame frame = null; try { frame = interpreter.NewProcedureCallFrame( name, CallFrameFlags.Procedure | CallFrameFlags.Lambda, new ClientData(hashValue), this, arguments); VariableDictionary variables = frame.Variables; frame.ProcedureArguments = new ArgumentList(arguments[0]); for (int argumentIndex = 0; argumentIndex < formalArguments.Count; argumentIndex++) { string varName = formalArguments[argumentIndex].Name; if (!variables.ContainsKey(varName)) { ArgumentFlags flags = ArgumentFlags.None; object varValue; if (hasArgs && (argumentIndex == (formalArguments.Count - 1))) { // // NOTE: This argument is part of an argument list. // flags |= ArgumentFlags.ArgumentList; // // NOTE: Build the list for the final formal argument value, // which consists of all the remaining argument values. // ArgumentList argsArguments = new ArgumentList(); for (int argsArgumentIndex = argumentIndex + 2; argsArgumentIndex < arguments.Count; argsArgumentIndex++) { // // NOTE: Sync up the argument name and flags for use when // debugging (below). // Argument argsArgument = Argument.GetOrCreate( interpreter, arguments[argsArgumentIndex].Flags | flags, String.Format("{0}{1}{2}", varName, Characters.Space, argsArguments.Count), arguments[argsArgumentIndex], interpreter.HasNoCacheArgument()); argsArguments.Add(argsArgument); } varValue = argsArguments; } else { if ((argumentIndex + 2) < arguments.Count) { // // NOTE: Sync up the argument name for use when // debugging (below) and use the value // supplied by the caller. // varValue = Argument.GetOrCreate(interpreter, arguments[argumentIndex + 2].Flags | flags, varName, arguments[argumentIndex + 2], interpreter.HasNoCacheArgument()); } else { // // NOTE: We cannot sync up the argument name here // because we are out-of-bounds on that list // and it cannot be extended (i.e. it would // break [info level]); therefore, we punt // on that for now. Use the default value // for this argument, if any; otherwise, use // an empty string. // object @default = formalArguments[argumentIndex].Default; varValue = (@default != null) ? @default : Argument.NoValue; } } code = interpreter.SetVariableValue2(VariableFlags.Argument, frame, varName, varValue, ref result); if (code != ReturnCode.Ok) { break; } // // BUGFIX: Now, also keep track of this argument in the procedure // arguments list. Primarily because we do not want to // have to redo this logic later (i.e. for [scope]). // frame.ProcedureArguments.Add(Argument.GetOrCreate( interpreter, flags, varName, varValue, interpreter.HasNoCacheArgument())); } } // // NOTE: Make sure we succeeded in creating the call frame. // if (code == ReturnCode.Ok) { ICallFrame savedFrame = null; interpreter.PushProcedureCallFrame(frame, true, ref savedFrame); try { #if DEBUGGER && DEBUGGER_EXECUTE if (DebuggerOps.CanHitBreakpoints(interpreter, EngineFlags.None, BreakpointType.BeforeLambdaBody)) { code = interpreter.CheckBreakpoints( code, BreakpointType.BeforeLambdaBody, this.Name, null, null, this, null, clientData, arguments, ref result); } #endif if (code == ReturnCode.Ok) { interpreter.ReturnCode = ReturnCode.Ok; code = interpreter.EvaluateScript(lambdaExpr[1], arguments[1], ref result); #if DEBUGGER && DEBUGGER_EXECUTE if (DebuggerOps.CanHitBreakpoints(interpreter, EngineFlags.None, BreakpointType.AfterLambdaBody)) { code = interpreter.CheckBreakpoints( code, BreakpointType.AfterLambdaBody, this.Name, null, null, this, null, clientData, arguments, ref result); } #endif // // BUGFIX: If an opaque object handle is being returned, add // a reference to it now. // if ((code == ReturnCode.Ok) || (code == ReturnCode.Return)) { code = interpreter.AddObjectReference( code, result, ObjectReferenceType.Return, ref result); } if (code == ReturnCode.Return) { code = Engine.UpdateReturnInformation(interpreter); } else if (code == ReturnCode.Error) { Engine.AddErrorInformation(interpreter, result, String.Format("{0} (lambda term \"{1}\" line {2})", Environment.NewLine, FormatOps.Ellipsis(arguments[1]), Interpreter.GetErrorLine(interpreter))); } } } finally { /* IGNORED */ interpreter.PopProcedureCallFrame(frame, ref savedFrame); } } } finally { if (frame != null) { IDisposable disposable = frame as IDisposable; if (disposable != null) { disposable.Dispose(); disposable = null; } frame = null; } } } else { result = String.Format( "wrong # args: should be \"apply lambdaExpr {0}\"", formalArguments.ToRawString(ToStringFlags.Decorated, Characters.Space.ToString())); code = ReturnCode.Error; } } } } } else { code = ReturnCode.Error; } } else { result = String.Format( "can't interpret \"{0}\" as a lambda expression", arguments[1]); code = ReturnCode.Error; } } } else { result = "wrong # args: should be \"apply lambdaExpr ?arg1 arg2 ...?\""; code = ReturnCode.Error; } } else { result = "invalid argument list"; code = ReturnCode.Error; } } else { result = "invalid interpreter"; code = ReturnCode.Error; } return(code); }
public override ReturnCode Execute( Interpreter interpreter, IClientData clientData, ArgumentList arguments, ref Result result ) { ReturnCode code = ReturnCode.Ok; if (interpreter != null) { if (arguments != null) { if (arguments.Count >= 2) { string fileName = arguments[1]; if (interpreter.HasChannels(ref result)) { MapOpenAccess access = MapOpenAccess.Default; int permissions = 0; // NOTE: This is ONLY parsed, NOT used for opening the file. string type = null; if (arguments.Count >= 3) { Result enumString = arguments[2]; if (!String.IsNullOrEmpty(enumString)) { // // HACK: Translate illegal mode char "+" to what our Enum uses. // This strategy will backfire later if we ever decide to // allow parsing of the access mode as "flags" (via GetOptions). // enumString = enumString.Replace(Characters.PlusSign.ToString(), "Plus"); } code = StringOps.StringToEnumList(interpreter, enumString, ref enumString); if (code == ReturnCode.Ok) { object enumValue = EnumOps.TryParseEnum( typeof(MapOpenAccess), enumString, true, true); if (enumValue is MapOpenAccess) { access = (MapOpenAccess)enumValue; } else { enumString = ScriptOps.BadValue( "invalid", "access mode", arguments[2], Enum.GetNames(typeof(MapOpenAccess)), null, null); code = ReturnCode.Error; } } if (code != ReturnCode.Ok) { // // NOTE: Transfer local result from above and add to the error info. // result = enumString; Engine.AddErrorInformation(interpreter, result, String.Format("{0} while processing open access modes \"{1}\"", Environment.NewLine, FormatOps.Ellipsis(arguments[2]))); } } if ((code == ReturnCode.Ok) && (arguments.Count >= 4)) { code = Value.GetInteger2( (IGetValue)arguments[3], ValueFlags.AnyInteger, interpreter.CultureInfo, ref permissions, ref result); } if (code == ReturnCode.Ok) { if (arguments.Count >= 5) { type = arguments[4]; } OptionDictionary options = new OptionDictionary( new IOption[] { #if CONSOLE new Option(null, OptionFlags.None, 1, Index.Invalid, "-stdin", null), new Option(null, OptionFlags.None, 1, Index.Invalid, "-stdout", null), new Option(null, OptionFlags.None, 1, Index.Invalid, "-stderr", null), #else new Option(null, OptionFlags.Unsupported, 1, Index.Invalid, "-stdin", null), new Option(null, OptionFlags.Unsupported, 1, Index.Invalid, "-stdout", null), new Option(null, OptionFlags.Unsupported, 1, Index.Invalid, "-stderr", null), #endif new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-channelid", null), new Option(null, OptionFlags.MustHaveIntegerValue, Index.Invalid, Index.Invalid, "-buffersize", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-autoflush", null), new Option(typeof(HostStreamFlags), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-streamflags", new Variant(HostStreamFlags.Default)), new Option(typeof(FileOptions), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-options", new Variant(FileOptions.None)), new Option(typeof(FileShare), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-share", new Variant(FileShare.Read)) }); int argumentIndex = Index.Invalid; if (arguments.Count > 5) { code = interpreter.GetOptions(options, arguments, 0, 5, Index.Invalid, true, ref argumentIndex, ref result); } else { code = ReturnCode.Ok; } if (code == ReturnCode.Ok) { if (argumentIndex == Index.Invalid) { Variant value = null; string channelId = null; if (options.IsPresent("-channelid", ref value)) { channelId = value.ToString(); } if ((channelId == null) || (interpreter.DoesChannelExist(channelId) != ReturnCode.Ok)) { #if CONSOLE if (options.IsPresent("-stdin")) { // // NOTE: Enforce the proper access for the standard input // channel. // if (access == MapOpenAccess.RdOnly) { try { IStreamHost streamHost = interpreter.Host; // // NOTE: *WARNING* This option causes the "fileName", // "access", "permissions", and "type" arguments // to be ignored. // lock (interpreter.SyncRoot) /* TRANSACTIONAL */ { if (streamHost.In == null) { int?bufferSize = null; if (options.IsPresent("-buffersize", ref value)) { bufferSize = (int)value.Value; } streamHost.In = (bufferSize != null) ? Console.OpenStandardInput((int)bufferSize) : Console.OpenStandardInput(); } } code = interpreter.ModifyStandardChannels( streamHost, channelId, ChannelType.Input | ChannelType.ErrorOnExist, ref result); if (code == ReturnCode.Ok) { result = (channelId != null) ? channelId : StandardChannel.Input; } } catch (Exception e) { Engine.SetExceptionErrorCode(interpreter, e); result = e; code = ReturnCode.Error; } } else { result = String.Format( "illegal access mode \"{0}\", standard input " + "can only be opened using access mode \"{1}\"", access, MapOpenAccess.RdOnly); code = ReturnCode.Error; } } else if (options.IsPresent("-stdout")) { // // NOTE: Enforce the proper access for the standard output // channel. // if (access == MapOpenAccess.WrOnly) { try { IStreamHost streamHost = interpreter.Host; // // NOTE: *WARNING* This option causes the "fileName", // "access", "permissions", and "type" arguments // to be ignored. // lock (interpreter.SyncRoot) /* TRANSACTIONAL */ { if (streamHost.Out == null) { int?bufferSize = null; if (options.IsPresent("-buffersize", ref value)) { bufferSize = (int)value.Value; } streamHost.Out = (bufferSize != null) ? Console.OpenStandardOutput((int)bufferSize) : Console.OpenStandardOutput(); } } code = interpreter.ModifyStandardChannels( streamHost, channelId, ChannelType.Output | ChannelType.ErrorOnExist, ref result); if (code == ReturnCode.Ok) { result = (channelId != null) ? channelId : StandardChannel.Output; } } catch (Exception e) { Engine.SetExceptionErrorCode(interpreter, e); result = e; code = ReturnCode.Error; } } else { result = String.Format( "illegal access mode \"{0}\", standard output " + "can only be opened using access mode \"{1}\"", access, MapOpenAccess.WrOnly); code = ReturnCode.Error; } } else if (options.IsPresent("-stderr")) { // // NOTE: Enforce the proper access for the standard error // channel. // if (access == MapOpenAccess.WrOnly) { try { IStreamHost streamHost = interpreter.Host; // // NOTE: *WARNING* This option causes the "fileName", // "access", "permissions", and "type" arguments // to be ignored. // lock (interpreter.SyncRoot) /* TRANSACTIONAL */ { if (streamHost.Error == null) { int?bufferSize = null; if (options.IsPresent("-buffersize", ref value)) { bufferSize = (int)value.Value; } streamHost.Error = (bufferSize != null) ? Console.OpenStandardError((int)bufferSize) : Console.OpenStandardError(); } } code = interpreter.ModifyStandardChannels( streamHost, channelId, ChannelType.Error | ChannelType.ErrorOnExist, ref result); if (code == ReturnCode.Ok) { result = (channelId != null) ? channelId : StandardChannel.Error; } } catch (Exception e) { Engine.SetExceptionErrorCode(interpreter, e); result = e; code = ReturnCode.Error; } } else { result = String.Format( "illegal access mode \"{0}\", standard error " + "can only be opened using access mode \"{1}\"", access, MapOpenAccess.WrOnly); code = ReturnCode.Error; } } else #endif { Stream stream = null; bool autoFlush = false; switch (type) { case null: /* FALL-THROUGH */ case /* String.Empty */ "": /* FALL-THROUGH */ case "file": { try { HostStreamFlags hostStreamFlags = HostStreamFlags.OpenCommand; FileAccess fileAccess = FileOps.FileAccessFromAccess(access); FileMode fileMode = FileOps.FileModeFromAccess(access); FileShare fileShare = FileShare.Read; if (options.IsPresent("-streamflags", ref value)) { hostStreamFlags = (HostStreamFlags)value.Value; } if (options.IsPresent("-share", ref value)) { fileShare = (FileShare)value.Value; } int bufferSize = Channel.DefaultBufferSize; if (options.IsPresent("-buffersize", ref value)) { bufferSize = (int)value.Value; } FileOptions fileOptions = FileOptions.None; if (options.IsPresent("-options", ref value)) { fileOptions = (FileOptions)value.Value; } if (options.IsPresent("-autoflush")) { autoFlush = true; } bool seekToEof = false; // // HACK: Check for special case where they want to Append // and Read/ReadWrite. // if (((fileAccess == FileAccess.Read) || (fileAccess == FileAccess.ReadWrite)) && (FlagOps.HasFlags(access, MapOpenAccess.SeekToEof, true) || FlagOps.HasFlags(access, MapOpenAccess.Append, true))) { seekToEof = true; } code = interpreter.GetStream( fileName, fileMode, fileAccess, fileShare, bufferSize, fileOptions, Channel.StrictGetStream, ref hostStreamFlags, ref stream, ref result); if (code == ReturnCode.Ok) { if ((stream != null) && seekToEof) { stream.Seek(0, SeekOrigin.End); } } } catch (Exception e) { Engine.SetExceptionErrorCode(interpreter, e); result = e; code = ReturnCode.Error; } break; } default: { result = String.Format( "unsupported channel type \"{0}\"", type); code = ReturnCode.Error; break; } } // // NOTE: Did we manage to open the file successfully? // if (code == ReturnCode.Ok) { StreamFlags flags = StreamFlags.PreventClose; if (channelId == null) { channelId = FormatOps.Id("file", null, interpreter.NextId()); } code = interpreter.AddFileOrSocketChannel( channelId, stream, options, flags, FlagOps.HasFlags(access, MapOpenAccess.Append, true), autoFlush, null, ref result); if (code == ReturnCode.Ok) { result = channelId; } } } } else { result = String.Format( "can't add \"{0}\": channel already exists", channelId); code = ReturnCode.Error; } } else { result = "wrong # args: should be \"open fileName ?access? ?permissions? ?type? ?options?\""; code = ReturnCode.Error; } } } } else { code = ReturnCode.Error; } } else { result = "wrong # args: should be \"open fileName ?access? ?permissions? ?type? ?options?\""; code = ReturnCode.Error; } } else { result = "invalid argument list"; code = ReturnCode.Error; } } else { result = "invalid interpreter"; code = ReturnCode.Error; } return(code); }
public override ReturnCode Execute( Interpreter interpreter, IClientData clientData, ArgumentList arguments, ref Result result ) { ReturnCode code = ReturnCode.Ok; if (interpreter != null) { if (arguments != null) { OptionDictionary options = new OptionDictionary( new IOption[] { new Option(null, OptionFlags.None, 1, Index.Invalid, "-exact", null), new Option(null, OptionFlags.None, 3, Index.Invalid, "-integer", null), new Option(null, OptionFlags.None, 3, Index.Invalid, "-substring", null), new Option(null, OptionFlags.None, 1, Index.Invalid, "-glob", null), new Option(null, OptionFlags.None, 1, Index.Invalid, "-regexp", null), new Option(null, OptionFlags.None, 2, Index.Invalid, "-subst", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocase", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null) }); int argumentIndex = Index.Invalid; if (arguments.Count > 1) { code = interpreter.GetOptions(options, arguments, 0, 1, Index.Invalid, false, ref argumentIndex, ref result); } else { code = ReturnCode.Ok; } if (code == ReturnCode.Ok) { if ((argumentIndex != Index.Invalid) && ((argumentIndex + 1) < arguments.Count)) { MatchMode mode = StringOps.DefaultSwitchMatchMode; if (options.IsPresent("-integer")) { mode = MatchMode.Integer; } else if (options.IsPresent("-regexp")) { mode = MatchMode.RegExp; } else if (options.IsPresent("-glob")) { mode = MatchMode.Glob; } else if (options.IsPresent("-substring")) { mode = MatchMode.SubString; } else if (options.IsPresent("-exact")) { mode = MatchMode.Exact; } if (options.IsPresent("-subst")) { mode |= MatchMode.Substitute; } bool noCase = false; if (options.IsPresent("-nocase")) { noCase = true; } bool splitList = false; StringList list = null; IScriptLocation location = null; // // NOTE: Is there only one argument following the string to match? // if ((argumentIndex + 2) == arguments.Count) { code = Parser.SplitList( interpreter, arguments[argumentIndex + 1], 0, Length.Invalid, true, ref list); if (code == ReturnCode.Ok) { if (list.Count > 0) { location = arguments[argumentIndex + 1]; splitList = true; } else { result = "wrong # args: should be \"switch ?switches? string {pattern body ... ?default body?}\""; code = ReturnCode.Error; } } } else { // // TODO: Make sure this is always accurate. // code = ScriptOps.GetLocation( interpreter, arguments, argumentIndex + 1, ref location, ref result); if (code == ReturnCode.Ok) { list = ArgumentList.GetRangeAsStringList(arguments, argumentIndex + 1); } } // // NOTE: Ok, now we should have a list of patterns and bodies // if everything went Ok above. // if (code == ReturnCode.Ok) { // // NOTE: Complain if there is an odd number of words in the // list of patterns and bodies. // if ((list.Count % 2) == 0) { // // NOTE: Complain if the last body is a continuation. // if (String.Compare(list[list.Count - 1], Characters.MinusSign.ToString(), StringOps.SystemStringComparisonType) != 0) { // // NOTE: Get the text to match against. // string input = arguments[argumentIndex]; // // NOTE: We need to return an empty string if we do not // match anything. // result = String.Empty; // // NOTE: Search the patterns for a match. // for (int index = 0; index < list.Count; index += 2) { Result pattern = list[index]; bool match = false; if ((index == (list.Count - 2)) && (String.Compare(pattern, Switch.Default, StringOps.SystemStringComparisonType) == 0)) { // // NOTE: Default pattern at end always matches. // match = true; } else { if ((mode & MatchMode.Substitute) == MatchMode.Substitute) { code = interpreter.SubstituteString(pattern, ref pattern); } if (code != ReturnCode.Ok) { result = pattern; break; } code = StringOps.Match( interpreter, mode, input, pattern, noCase, ref match, ref result); if (code != ReturnCode.Ok) { break; } } if (!match) { continue; } // // NOTE: We've got a match. Find a body to execute, skipping // bodies that are "-". // for (int index2 = index + 1; ; index2 += 2) { if (index2 >= list.Count) { result = "fall-out when searching for body to match pattern"; code = ReturnCode.Error; goto switch_done; } if (String.Compare(list[index2], Characters.MinusSign.ToString(), StringOps.SystemStringComparisonType) != 0) { code = interpreter.EvaluateScript(list[index2], location, ref result); if (code == ReturnCode.Error) { Engine.AddErrorInformation(interpreter, result, String.Format("{0} (\"{1}\" arm line {2})", Environment.NewLine, FormatOps.Ellipsis(pattern), Interpreter.GetErrorLine(interpreter))); } goto switch_done; } } } switch_done: ; } else { result = String.Format( "no body specified for pattern \"{0}\"", list[list.Count - 2]); code = ReturnCode.Error; } } else { result = "extra switch pattern with no body"; code = ReturnCode.Error; if (splitList) { /* * Check if this can be due to a badly placed comment * in the switch block. * * The following is an heuristic to detect the infamous * "comment in switch" error: just check if a pattern * begins with '#'. */ for (int index = 0; index < list.Count; index++) { if (!String.IsNullOrEmpty(list[index]) && (list[index][0] == Characters.NumberSign)) { result += ", this may be due to a comment incorrectly placed " + "outside of a switch body - see the \"switch\" documentation"; break; } } } } } } else { if ((argumentIndex != Index.Invalid) && Option.LooksLikeOption(arguments[argumentIndex])) { result = OptionDictionary.BadOption(options, arguments[argumentIndex]); } else { result = "wrong # args: should be \"switch ?switches? string pattern body ... ?default body?\""; } code = ReturnCode.Error; } } } else { result = "invalid argument list"; code = ReturnCode.Error; } } else { result = "invalid interpreter"; code = ReturnCode.Error; } return(code); }
/////////////////////////////////////////////////////////////////////// #region IExecute Members public override ReturnCode Execute( Interpreter interpreter, IClientData clientData, ArgumentList arguments, ref Result result ) { ReturnCode code = ReturnCode.Ok; if (interpreter != null) { if (arguments != null) { IScriptLocation location = null; code = ScriptOps.GetAndCheckProcedureLocation( interpreter, this, ref location, ref result); if (code == ReturnCode.Ok) { string procedureName = this.Name; ArgumentList procedureArguments = this.Arguments; if (procedureArguments != null) { bool hasArgs = procedureArguments.IsVariadic(true); int totalArgs = hasArgs ? procedureArguments.Count - 1 : procedureArguments.Count; int optionalArgs = procedureArguments.GetOptionalCount(); if ((arguments.Count > 0) && ((((arguments.Count - 1) >= (totalArgs - optionalArgs)) && ((arguments.Count - 1) <= totalArgs)) || (hasArgs && ((arguments.Count - 1) >= (totalArgs - optionalArgs))))) { ICallFrame frame = null; try { frame = interpreter.NewProcedureCallFrame( procedureName, CallFrameFlags.Procedure, null, this, arguments); VariableDictionary variables = frame.Variables; frame.ProcedureArguments = new ArgumentList(arguments[0]); for (int argumentIndex = 0; argumentIndex < procedureArguments.Count; argumentIndex++) { string varName = procedureArguments[argumentIndex].Name; if (!variables.ContainsKey(varName)) { ArgumentFlags flags = ArgumentFlags.None; object varValue; if (hasArgs && (argumentIndex == (procedureArguments.Count - 1))) { // // NOTE: This argument is part of an argument list. // flags |= ArgumentFlags.ArgumentList; // // NOTE: Build the list for the final formal argument value, // which consists of all the remaining argument values. // ArgumentList argsArguments = new ArgumentList(); for (int argsArgumentIndex = argumentIndex + 1; argsArgumentIndex < arguments.Count; argsArgumentIndex++) { // // NOTE: Sync up the argument name and flags for use when // debugging (below). // Argument argsArgument = Argument.GetOrCreate( interpreter, arguments[argsArgumentIndex].Flags | flags, String.Format("{0}{1}{2}", varName, Characters.Space, argsArguments.Count), arguments[argsArgumentIndex], interpreter.HasNoCacheArgument()); argsArguments.Add(argsArgument); } varValue = argsArguments; } else { if ((argumentIndex + 1) < arguments.Count) { // // NOTE: Sync up the argument name for use when // debugging (below) and use the value // supplied by the caller. // varValue = Argument.GetOrCreate(interpreter, arguments[argumentIndex + 1].Flags | flags, varName, arguments[argumentIndex + 1], interpreter.HasNoCacheArgument()); } else { // // NOTE: We cannot sync up the argument name here // because we are out-of-bounds on that list // and it cannot be extended (i.e. it would // break [info level]); therefore, we punt // on that for now. Use the default value // for this argument, if any; otherwise, use // an empty string. // object @default = procedureArguments[argumentIndex].Default; varValue = (@default != null) ? @default : Argument.NoValue; } } code = interpreter.SetVariableValue2(VariableFlags.Argument, frame, varName, varValue, ref result); if (code != ReturnCode.Ok) { break; } // // BUGFIX: Now, also keep track of this argument in the procedure // arguments list. Primarily because we do not want to // have to redo this logic later (i.e. for [scope]). // frame.ProcedureArguments.Add(Argument.GetOrCreate( interpreter, flags, varName, varValue, interpreter.HasNoCacheArgument())); } } // // NOTE: Make sure we succeeded in creating the call frame. // if (code == ReturnCode.Ok) { ICallFrame savedFrame = null; interpreter.PushProcedureCallFrame(frame, true, ref savedFrame); try { #if DEBUGGER && DEBUGGER_EXECUTE if (DebuggerOps.CanHitBreakpoints(interpreter, EngineFlags.None, BreakpointType.BeforeProcedureBody)) { code = interpreter.CheckBreakpoints( code, BreakpointType.BeforeProcedureBody, procedureName, null, null, this, null, clientData, arguments, ref result); } #endif if (code == ReturnCode.Ok) { bool locked = false; try { bool atomic = EntityOps.IsAtomic(this); if (atomic) { interpreter.InternalTryLock(ref locked); /* TRANSACTIONAL */ } if (!atomic || locked) { #if ARGUMENT_CACHE || PARSE_CACHE EngineFlags savedEngineFlags = EngineFlags.None; bool nonCaching = EntityOps.IsNonCaching(this); if (nonCaching) { interpreter.BeginProcedureBodyNoCaching( ref savedEngineFlags); } try { #endif string body = this.Body; interpreter.ReturnCode = ReturnCode.Ok; code = interpreter.EvaluateScript( body, location, ref result); #if ARGUMENT_CACHE || PARSE_CACHE } finally { if (nonCaching) { interpreter.EndProcedureBodyNoCaching( ref savedEngineFlags); } } #endif } else { result = "could not lock interpreter"; code = ReturnCode.Error; } } finally { interpreter.InternalExitLock(ref locked); /* TRANSACTIONAL */ } #if DEBUGGER && DEBUGGER_EXECUTE if (DebuggerOps.CanHitBreakpoints(interpreter, EngineFlags.None, BreakpointType.AfterProcedureBody)) { code = interpreter.CheckBreakpoints( code, BreakpointType.AfterProcedureBody, procedureName, null, null, this, null, clientData, arguments, ref result); } #endif // // BUGFIX: If an opaque object handle is being returned, add // a reference to it now. // if ((code == ReturnCode.Ok) || (code == ReturnCode.Return)) { code = interpreter.AddObjectReference( code, result, ObjectReferenceType.Return, ref result); } if (code == ReturnCode.Return) { code = Engine.UpdateReturnInformation(interpreter); } else if (code == ReturnCode.Error) { Engine.AddErrorInformation(interpreter, result, String.Format("{0} (procedure \"{1}\" line {2})", Environment.NewLine, FormatOps.Ellipsis(procedureName), Interpreter.GetErrorLine(interpreter))); } } } finally { /* IGNORED */ interpreter.PopProcedureCallFrame(frame, ref savedFrame); } } } finally { if (frame != null) { IDisposable disposable = frame as IDisposable; if (disposable != null) { disposable.Dispose(); disposable = null; } frame = null; } } } else { if (procedureArguments.Count > 0) { result = String.Format( "wrong # args: should be \"{0} {1}\"", Parser.Quote(procedureName), procedureArguments.ToRawString(ToStringFlags.Decorated, Characters.Space.ToString())); } else { result = String.Format( "wrong # args: should be \"{0}\"", Parser.Quote(procedureName)); } code = ReturnCode.Error; } } else { result = "invalid procedure argument list"; code = ReturnCode.Error; } } } else { result = "invalid argument list"; code = ReturnCode.Error; } } else { result = "invalid interpreter"; code = ReturnCode.Error; } return(code); }
public string ToString(string format, int limit, bool strict) { return(FormatOps.Ellipsis( String.Format(format, ToString(this, null)), limit, strict)); }