/////////////////////////////////////////////////////////////////////// #region Background Error Executor private static ReturnCode ExecuteBackgroundError( Interpreter interpreter, string handlerName, IExecute execute, IClientData clientData, ArgumentList arguments, ref Result result, ref int errorLine ) { if (interpreter == null) { result = "invalid interpreter"; return(ReturnCode.Error); } // // NOTE: Create a new call frame for the background error handler // and push it. // ICallFrame frame = interpreter.NewTrackingCallFrame( StringList.MakeList("bgerror", handlerName), CallFrameFlags.BackgroundError); interpreter.PushAutomaticCallFrame(frame); try { // // NOTE: Save current engine flags and then enable external // execution. // EngineFlags savedEngineFlags = interpreter.BeginExternalExecution(); try { // // NOTE: If the interpreter is configured to reset the // script cancellation flags prior to executing // the background error handler, do that now. // if (ScriptOps.HasFlags( interpreter, InterpreterFlags.BgErrorResetCancel, true)) { /* IGNORED */ Engine.ResetCancel(interpreter, CancelFlags.BgError); } // // NOTE: Evaluate the script and then check the result to // see if the background error handler failed or // canceled further background error handling for // this invocation of ProcessEvents. // ReturnCode code; code = interpreter.Execute( handlerName, execute, clientData, arguments, ref result); // // NOTE: Maybe grab the new error line number, if any. // if (code != ReturnCode.Ok) { errorLine = Interpreter.GetErrorLine(interpreter); } // // NOTE: We are done now, return. // return(code); } finally { // // NOTE: Restore saved engine flags, disabling external // execution as necessary. // /* IGNORED */ interpreter.EndAndCleanupExternalExecution( savedEngineFlags); } } finally { // // NOTE: Pop the original call frame that we pushed above // and any intervening scope call frames that may be // leftover (i.e. they were not explicitly closed). // /* IGNORED */ interpreter.PopScopeCallFramesAndOneMore(); } }
/////////////////////////////////////////////////////////////////////// public static ReturnCode HandleBackgroundError( Interpreter interpreter, ReturnCode code, Result result, ref bool bgError ) { if (interpreter == null) { ReportBackgroundError(interpreter /* null */, null, "cannot handle background error, interpreter is " + "invalid.", "Original error", code, result, 0, null, ReturnCode.Ok, null, 0); return(ReturnCode.Error); } // // BUGFIX: Acquire the interpreter lock here; however, do not use // the public property just in case the interpreter may be // disposed at this point. // lock (interpreter.InternalSyncRoot) /* TRANSACTIONAL */ { // // BUGFIX: Do not try to handle any background errors with a // deleted or disposed interpreter. // if (Interpreter.IsDeletedOrDisposed(interpreter)) { ReportBackgroundError(interpreter /* disposed? */, null, "cannot handle background error, interpreter is " + "deleted or disposed.", "Original error", code, result, 0, null, ReturnCode.Ok, null, 0); return(ReturnCode.Error); } int errorLine = Interpreter.GetErrorLine(interpreter); string handlerName = interpreter.BackgroundError; // // NOTE: If there is an invalid background error handler set, // ignore the error. // if (!String.IsNullOrEmpty(handlerName)) { // // NOTE: Must hold lock while processing the error. // // TODO: Need to more carefully analyze this lock usage at // some point. // lock (interpreter.SyncRoot) /* TRANSACTIONAL */ { // // NOTE: Should a failure to handle the background // error simply be ignored? // bool ignoreFailure = ScriptOps.HasFlags(interpreter, InterpreterFlags.IgnoreBgErrorFailure, true); // // NOTE: We do not yet know if the background error // handler can actually be resolved. // bool haveBgError = false; // // NOTE: Construct a new argument list to pass along // to the actual error handler command, e.g. // "[list bgerror <message>]". // ArgumentList bgArguments = new ArgumentList( handlerName, result); // // NOTE: Attempt to lookup the background error // handler via the current command resolvers // for the interpreter. If this lookup fails // the default background error processing // will be used. // ReturnCode resolveCode; Result resolveError = null; IExecute bgExecute = null; resolveCode = interpreter.GetIExecuteViaResolvers( interpreter.GetResolveEngineFlags(true), handlerName, bgArguments, LookupFlags.Default, ref bgExecute, ref resolveError); if (resolveCode == ReturnCode.Ok) { // // NOTE: We found a background error handler. // haveBgError = true; // // NOTE: Execute the background error handler now // and save the results. // ReturnCode bgCode; Result bgResult = null; int bgErrorLine = 0; bgCode = ExecuteBackgroundError( interpreter, handlerName, bgExecute, null, bgArguments, ref bgResult, ref bgErrorLine); // // NOTE: Now we handle the return code for the // background error handler. // if (bgCode == ReturnCode.Break) { // // NOTE: A return code of "Break" indicates // that we should not call the background // error handler until the next time // ProcessEvents is invoked. // bgError = false; } else if (!ignoreFailure && (bgCode != ReturnCode.Ok)) { // // NOTE: Any other non-"Ok" return code is an // error an gets reported to the standard // error channel of the host, if any. // ReportBackgroundError(interpreter, handlerName, "handler {0} failed for background error.", "Original error", code, result, errorLine, "Handler error", bgCode, bgResult, bgErrorLine); } } // // NOTE: If there is no background error handler setup // just write the errorInfo to the error channel // (if possible). If failures should be ignored, // skip reporting the problem. // if (!ignoreFailure && !haveBgError) { ReportBackgroundError(interpreter, handlerName, "handler {0} missing for background error.", "Original error", code, result, errorLine, "Resolver error", resolveCode, resolveError, 0); } } } return(ReturnCode.Ok); } }
/////////////////////////////////////////////////////////////////////////////////////////////// #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) { string subCommand = arguments[1]; bool tried = false; code = ScriptOps.TryExecuteSubCommandFromEnsemble( interpreter, this, clientData, arguments, true, false, ref subCommand, ref tried, ref result); if ((code == ReturnCode.Ok) && !tried) { switch (subCommand) { case "forget": { if (arguments.Count >= 2) { code = interpreter.PkgForget( new StringList(arguments, 2), ref result); } else { result = "wrong # args: should be \"package forget ?package package ...?\""; code = ReturnCode.Error; } break; } case "ifneeded": { if ((arguments.Count == 4) || (arguments.Count == 5)) { Version version = null; code = Value.GetVersion( arguments[3], interpreter.CultureInfo, ref version, ref result); if (code == ReturnCode.Ok) { string text = null; if (arguments.Count == 5) { text = arguments[4]; } code = interpreter.PkgIfNeeded( arguments[2], version, text, interpreter.PackageFlags, ref result); } } else { result = "wrong # args: should be \"package ifneeded package version ?script?\""; code = ReturnCode.Error; } break; } case "indexes": { if ((arguments.Count == 2) || (arguments.Count == 3)) { string pattern = null; if (arguments.Count == 3) { pattern = arguments[2]; } code = interpreter.PkgIndexes( pattern, false, ref result); } else { result = "wrong # args: should be \"package indexes ?pattern?\""; code = ReturnCode.Error; } break; } case "info": { if (arguments.Count == 3) { IPackage package = null; code = interpreter.GetPackage( arguments[2], LookupFlags.Default, ref package, ref result); if (code == ReturnCode.Ok) { bool scrub = interpreter.IsSafe(); PackageFlags flags = package.Flags; Guid id = AttributeOps.GetObjectId(package); result = StringList.MakeList( "kind", package.Kind, "id", package.Id.Equals(Guid.Empty) ? id : package.Id, "name", package.Name, "description", package.Description, "indexFileName", scrub ? PathOps.ScrubPath( GlobalState.GetBasePath(), package.IndexFileName) : package.IndexFileName, "provideFileName", scrub ? PathOps.ScrubPath( GlobalState.GetBasePath(), package.ProvideFileName) : package.ProvideFileName, "flags", flags, "loaded", (package.Loaded != null) ? package.Loaded : null, "ifNeeded", (!scrub && (package.IfNeeded != null)) ? package.IfNeeded.KeysAndValuesToString(null, false) : null); } } else { result = "wrong # args: should be \"package info name\""; code = ReturnCode.Error; } break; } case "loaded": { if ((arguments.Count == 2) || (arguments.Count == 3)) { string pattern = null; if (arguments.Count == 3) { pattern = arguments[2]; } code = interpreter.PkgLoaded( pattern, false, false, ref result); } else { result = "wrong # args: should be \"package loaded ?pattern?\""; code = ReturnCode.Error; } break; } case "names": { if ((arguments.Count == 2) || (arguments.Count == 3)) { string pattern = null; if (arguments.Count == 3) { pattern = arguments[2]; } code = interpreter.PkgNames( pattern, false, ref result); } else { result = "wrong # args: should be \"package names ?pattern?\""; code = ReturnCode.Error; } break; } case "present": { if (arguments.Count >= 3) { OptionDictionary options = new OptionDictionary( new IOption[] { new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-exact", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null) }); int argumentIndex = Index.Invalid; code = interpreter.GetOptions(options, arguments, 0, 2, Index.Invalid, false, ref argumentIndex, ref result); if (code == ReturnCode.Ok) { if ((argumentIndex != Index.Invalid) && ((argumentIndex + 2) >= arguments.Count)) { bool exact = false; if (options.IsPresent("-exact")) { exact = true; } Version version = null; if ((argumentIndex + 1) < arguments.Count) { code = Value.GetVersion( arguments[argumentIndex + 1], interpreter.CultureInfo, ref version, ref result); } if (code == ReturnCode.Ok) { code = interpreter.PresentPackage( arguments[argumentIndex], version, exact, ref result); } } else { if ((argumentIndex != Index.Invalid) && Option.LooksLikeOption(arguments[argumentIndex])) { result = OptionDictionary.BadOption(options, arguments[argumentIndex]); } else { result = "wrong # args: should be \"package present ?-exact? package ?version?\""; } code = ReturnCode.Error; } } } else { result = "wrong # args: should be \"package present ?-exact? package ?version?\""; code = ReturnCode.Error; } break; } case "provide": { if ((arguments.Count == 3) || (arguments.Count == 4)) { PackageFlags flags = interpreter.PackageFlags; if (!FlagOps.HasFlags(flags, PackageFlags.NoProvide, true)) { Version version = null; if (arguments.Count == 4) { code = Value.GetVersion(arguments[3], interpreter.CultureInfo, ref version, ref result); } if (code == ReturnCode.Ok) { code = interpreter.PkgProvide(arguments[2], version, flags, ref result); } } else { // // HACK: Do nothing, provide no package, and return nothing. // result = String.Empty; code = ReturnCode.Ok; } } else { result = "wrong # args: should be \"package provide package ?version?\""; code = ReturnCode.Error; } break; } case "relativefilename": { if ((arguments.Count == 3) || (arguments.Count == 4)) { PathComparisonType pathComparisonType = PathComparisonType.Default; if (arguments.Count == 4) { object enumValue = EnumOps.TryParseFlagsEnum( interpreter, typeof(PathComparisonType), pathComparisonType.ToString(), arguments[3], interpreter.CultureInfo, true, true, true, ref result); if (enumValue is EventFlags) { pathComparisonType = (PathComparisonType)enumValue; } else { code = ReturnCode.Error; } } if (code == ReturnCode.Ok) { string fileName = null; code = PackageOps.GetRelativeFileName( interpreter, arguments[2], pathComparisonType, ref fileName, ref result); if (code == ReturnCode.Ok) { result = fileName; } } } else { result = "wrong # args: should be \"package relativefilename fileName ?type?\""; code = ReturnCode.Error; } break; } case "require": { if (arguments.Count >= 3) { OptionDictionary options = new OptionDictionary( new IOption[] { new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-exact", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null) }); int argumentIndex = Index.Invalid; code = interpreter.GetOptions(options, arguments, 0, 2, Index.Invalid, false, ref argumentIndex, ref result); if (code == ReturnCode.Ok) { if ((argumentIndex != Index.Invalid) && ((argumentIndex + 2) >= arguments.Count)) { bool exact = false; if (options.IsPresent("-exact")) { exact = true; } Version version = null; if ((argumentIndex + 1) < arguments.Count) { code = Value.GetVersion( arguments[argumentIndex + 1], interpreter.CultureInfo, ref version, ref result); } if (code == ReturnCode.Ok) { code = interpreter.RequirePackage( arguments[argumentIndex], version, exact, ref result); } // // NOTE: This is a new feature. If the initial attempt to // require a package fails, call the package fallback // delegate for the interpreter and then try requiring // the package again. // if ((code != ReturnCode.Ok) && !ScriptOps.HasFlags( interpreter, InterpreterFlags.NoPackageFallback, true)) { PackageCallback packageFallback = interpreter.PackageFallback; if (packageFallback != null) { code = packageFallback( interpreter, arguments[argumentIndex], version, null, interpreter.PackageFlags, exact, ref result); if (code == ReturnCode.Ok) { code = interpreter.RequirePackage( arguments[argumentIndex], version, exact, ref result); } } } // // BUGFIX: This is really a new feature. In the event of a failure // here, we now fallback to the "unknown package handler", // just like Tcl does. // if ((code != ReturnCode.Ok) && !ScriptOps.HasFlags( interpreter, InterpreterFlags.NoPackageUnknown, true)) { string text = interpreter.PackageUnknown + Characters.Space + Parser.Quote(arguments[argumentIndex]); if (version != null) { text += Characters.Space + Parser.Quote(version.ToString()); } code = interpreter.EvaluateScript(text, ref result); /* EXEMPT */ if (code == ReturnCode.Ok) { code = interpreter.RequirePackage( arguments[argumentIndex], version, exact, ref result); } } } else { if ((argumentIndex != Index.Invalid) && Option.LooksLikeOption(arguments[argumentIndex])) { result = OptionDictionary.BadOption(options, arguments[argumentIndex]); } else { result = "wrong # args: should be \"package require ?-exact? package ?version?\""; } code = ReturnCode.Error; } } } else { result = "wrong # args: should be \"package require ?-exact? package ?version?\""; code = ReturnCode.Error; } break; } case "reset": { if (arguments.Count == 2) { code = interpreter.ResetPkgIndexes(ref result); if (code == ReturnCode.Ok) { result = String.Empty; } } else { result = "wrong # args: should be \"package reset\""; code = ReturnCode.Error; } break; } case "scan": { if (arguments.Count >= 2) { OptionDictionary options = new OptionDictionary( new IOption[] { new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-interpreter", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-preferfilesystem", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-preferhost", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-host", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-normal", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nonormal", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-recursive", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-resolve", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-refresh", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-autopath", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null) }); int argumentIndex = Index.Invalid; if (arguments.Count > 2) { code = interpreter.GetOptions(options, arguments, 0, 2, Index.Invalid, true, ref argumentIndex, ref result); } else { code = ReturnCode.Ok; } if (code == ReturnCode.Ok) { lock (interpreter.SyncRoot) /* TRANSACTIONAL */ { PackageIndexFlags flags; if (options.IsPresent("-interpreter")) { flags = interpreter.PackageIndexFlags; } else { flags = PackageIndexFlags.Default; } if (options.IsPresent("-preferfilesystem")) { flags |= PackageIndexFlags.PreferFileSystem; } if (options.IsPresent("-preferhost")) { flags |= PackageIndexFlags.PreferHost; } if (options.IsPresent("-host")) { flags |= PackageIndexFlags.Host; } if (options.IsPresent("-normal")) { flags |= PackageIndexFlags.Normal; } if (options.IsPresent("-nonormal")) { flags |= PackageIndexFlags.NoNormal; } if (options.IsPresent("-recursive")) { flags |= PackageIndexFlags.Recursive; } if (options.IsPresent("-refresh")) { flags |= PackageIndexFlags.Refresh; } if (options.IsPresent("-resolve")) { flags |= PackageIndexFlags.Resolve; } bool autoPath = false; if (options.IsPresent("-autopath")) { autoPath = true; } StringList paths; if (argumentIndex != Index.Invalid) { // // NOTE: Refresh the specified path list. // paths = new StringList(arguments, argumentIndex); } else { // // NOTE: Refresh the default path list. // paths = GlobalState.GetAutoPathList(interpreter, autoPath); // // NOTE: Did they request the auto-path be rebuilt? // if (autoPath) { // // NOTE: Since the actual auto-path may have changed, // update the variable now. We disable traces // here because we manually rescan, if necessary, // below. // code = interpreter.SetLibraryVariableValue( VariableFlags.SkipTrace, TclVars.AutoPath, (paths != null) ? paths.ToString() : null, ref result); } } if (code == ReturnCode.Ok) { PackageIndexDictionary packageIndexes = interpreter.CopyPackageIndexes(); if (code == ReturnCode.Ok) { code = PackageOps.FindAll( interpreter, paths, flags, ref packageIndexes, ref result); } if (code == ReturnCode.Ok) { interpreter.PackageIndexes = packageIndexes; result = String.Empty; } } } } } else { result = "wrong # args: should be \"package scan ?options? ?dir dir ...?\""; code = ReturnCode.Error; } break; } case "unknown": { if ((arguments.Count == 2) || (arguments.Count == 3)) { if (arguments.Count == 3) { interpreter.PackageUnknown = arguments[2]; result = String.Empty; } else { result = interpreter.PackageUnknown; } code = ReturnCode.Ok; } else { result = "wrong # args: should be \"package unknown ?command?\""; code = ReturnCode.Error; } break; } case "vcompare": { if (arguments.Count == 4) { Version version1 = null; code = Value.GetVersion( arguments[2], interpreter.CultureInfo, ref version1, ref result); Version version2 = null; if (code == ReturnCode.Ok) { code = Value.GetVersion( arguments[3], interpreter.CultureInfo, ref version2, ref result); } if (code == ReturnCode.Ok) { result = PackageOps.VersionCompare(version1, version2); } } else { result = "wrong # args: should be \"package vcompare version1 version2\""; code = ReturnCode.Error; } break; } case "versions": { if (arguments.Count == 3) { code = interpreter.PkgVersions( arguments[2], ref result); } else { result = "wrong # args: should be \"package versions package\""; code = ReturnCode.Error; } break; } case "vloaded": { if ((arguments.Count == 2) || (arguments.Count == 3)) { string pattern = null; if (arguments.Count == 3) { pattern = arguments[2]; } code = interpreter.PkgLoaded( pattern, false, true, ref result); } else { result = "wrong # args: should be \"package vloaded ?pattern?\""; code = ReturnCode.Error; } break; } case "vsatisfies": { if (arguments.Count == 4) { PackageFlags flags = interpreter.PackageFlags; if (!FlagOps.HasFlags(flags, PackageFlags.AlwaysSatisfy, true)) { Version version1 = null; code = Value.GetVersion(arguments[2], interpreter.CultureInfo, ref version1, ref result); Version version2 = null; if (code == ReturnCode.Ok) { code = Value.GetVersion( arguments[3], interpreter.CultureInfo, ref version2, ref result); } if (code == ReturnCode.Ok) { result = PackageOps.VersionSatisfies( version1, version2, false); } } else { // // HACK: Always fake that this was a satisfied package request. // result = true; code = ReturnCode.Ok; } } else { result = "wrong # args: should be \"package vsatisfies version1 version2\""; code = ReturnCode.Error; } break; } case "withdraw": { if ((arguments.Count == 3) || (arguments.Count == 4)) { Version version = null; if (arguments.Count == 4) { code = Value.GetVersion( arguments[3], interpreter.CultureInfo, ref version, ref result); } if (code == ReturnCode.Ok) { code = interpreter.WithdrawPackage( arguments[2], version, ref result); } } else { result = "wrong # args: should be \"package withdraw package ?version?\""; code = ReturnCode.Error; } break; } default: { result = ScriptOps.BadSubCommand( interpreter, null, null, subCommand, this, null, null); code = ReturnCode.Error; break; } } } } else { result = "wrong # args: should be \"package arg ?arg ...?\""; 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; if (interpreter != null) { if (arguments != null) { // // try {<tryBody>} // [finally {<finallyBody>}] // if ((arguments.Count == 2) || (arguments.Count == 4)) { if ((arguments.Count < 3) || (String.Compare(arguments[2], Try.Finally, StringOps.SystemStringComparisonType) == 0)) { string name = StringList.MakeList("try"); ICallFrame frame = interpreter.NewTrackingCallFrame(name, CallFrameFlags.Try); interpreter.PushAutomaticCallFrame(frame); ReturnCode tryCode; Result tryResult = null; tryCode = interpreter.EvaluateScript(arguments[1], ref tryResult); if (tryCode == ReturnCode.Error) { Engine.AddErrorInformation(interpreter, tryResult, String.Format("{0} (\"try\" body line {1})", Environment.NewLine, Interpreter.GetErrorLine(interpreter))); } // // NOTE: Pop the original call frame that we pushed above and // any intervening scope call frames that may be leftover // (i.e. they were not explicitly closed). // /* IGNORED */ interpreter.PopScopeCallFramesAndOneMore(); Result finallyResult = null; ReturnCode finallyCode = ReturnCode.Ok; if (arguments.Count == 4) { name = StringList.MakeList("finally"); frame = interpreter.NewTrackingCallFrame(name, CallFrameFlags.Finally); interpreter.PushAutomaticCallFrame(frame); // // BUGFIX: Preserve any and all existing error related // information during evaluation of the finally // block. // Engine.SetNoResetError(interpreter, true); // // NOTE: If there was an error during the try block as well, // keep them somewhat organized in the final error // information. // if (tryCode == ReturnCode.Error) { Engine.AddErrorInformation(interpreter, null, String.Format("{0} ... continued ...", Environment.NewLine)); } // // NOTE: If the appropriate flag is set, call into the // Engine.ResetCancel method (with "force" enabled) // prior to evaluating the finally block script. // It should be noted here that even though the // return code of this call is checked by the code, // it basically cannot fail at this point. // Result canceledResult = null; bool canceled = false; bool unwound = false; bool resetCancel = false; // // NOTE: If the appropriate flag is set, reset the Exit // property prior to evaluating the finally block // script. // bool exit = false; bool resetExit = false; try { if (ScriptOps.HasFlags(interpreter, InterpreterFlags.FinallyResetCancel, true)) { ReturnCode resetCode; Result resetError = null; resetCode = Engine.ResetCancel( interpreter, CancelFlags.TryBlock, ref canceledResult, ref canceled, ref unwound, ref resetCancel, ref resetError); if (resetCode != ReturnCode.Ok) { DebugOps.Complain(interpreter, resetCode, resetError); } } if (ScriptOps.HasFlags(interpreter, InterpreterFlags.FinallyResetExit, true)) { exit = interpreter.Exit; if (exit) { interpreter.Exit = false; resetExit = true; } } ReturnCode timeoutCode; Result timeoutResult = null; timeoutCode = Interpreter.StartFinallyTimeoutThread( interpreter, false, true, ref timeoutResult); if (timeoutCode != ReturnCode.Ok) { DebugOps.Complain(interpreter, timeoutCode, timeoutResult); } try { // // NOTE: Evaluate the finally block. // finallyCode = interpreter.EvaluateScript( arguments[3], ref finallyResult); } finally { timeoutCode = Interpreter.InterruptFinallyTimeoutThread( interpreter, false, ref timeoutResult); if (timeoutCode != ReturnCode.Ok) { DebugOps.Complain(interpreter, timeoutCode, timeoutResult); } } } finally { if (exit && resetExit) { if (ScriptOps.HasFlags(interpreter, InterpreterFlags.FinallyRestoreExit, true)) { interpreter.Exit = true; } } if ((canceled || unwound) && resetCancel) { if (ScriptOps.HasFlags(interpreter, InterpreterFlags.FinallyRestoreCancel, true)) { CancelFlags cancelFlags = CancelFlags.FinallyBlock; if (unwound) { cancelFlags |= CancelFlags.Unwind; } ReturnCode cancelCode; Result cancelError = null; cancelCode = Engine.CancelEvaluate( interpreter, canceledResult, cancelFlags, ref cancelError); if (cancelCode != ReturnCode.Ok) { DebugOps.Complain(interpreter, cancelCode, cancelError); } } } } if (finallyCode == ReturnCode.Error) { Engine.AddErrorInformation(interpreter, finallyResult, String.Format("{0} (\"finally\" body line {1})", Environment.NewLine, Interpreter.GetErrorLine(interpreter))); } // // NOTE: Restore normal result reset semantics. // Engine.SetNoResetError(interpreter, false); // // NOTE: Pop the original call frame that we pushed above and // any intervening scope call frames that may be leftover // (i.e. they were not explicitly closed). // /* IGNORED */ interpreter.PopScopeCallFramesAndOneMore(); } // // NOTE: Initially, the overall command return code and result // is that of the try block; however, if the finally block // fails, that will be the return code and result. // if (finallyCode == ReturnCode.Ok) { result = tryResult; code = tryCode; } else { result = finallyResult; code = finallyCode; } } else { result = String.Format( "expected \"finally\" but got \"{0}\"", arguments[2]); code = ReturnCode.Error; } } else { result = "wrong # args: should be \"try script ?finally script?\""; code = ReturnCode.Error; } } else { result = "invalid argument list"; return(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 >= 4) { StringList list = null; // // WARNING: Cannot cache list representation here, the list // is modified below. // code = Parser.SplitList( interpreter, arguments[1], 0, Length.Invalid, false, ref list, ref result); if (code == ReturnCode.Ok) { int firstIndex = Index.Invalid; code = Value.GetIndex( arguments[2], list.Count, ValueFlags.AnyIndex, interpreter.CultureInfo, ref firstIndex, ref result); if (code == ReturnCode.Ok) { int lastIndex = Index.Invalid; code = Value.GetIndex( arguments[3], list.Count, ValueFlags.AnyIndex, interpreter.CultureInfo, ref lastIndex, ref result); if (code == ReturnCode.Ok) { if (firstIndex < 0) { firstIndex = 0; } if ((firstIndex < list.Count) || (list.Count == 0)) { if (list.Count > 0) { if (lastIndex >= list.Count) { lastIndex = list.Count - 1; } int numToDelete; if (firstIndex <= lastIndex) { numToDelete = (lastIndex - firstIndex + 1); } else { numToDelete = 0; } list.RemoveRange(firstIndex, numToDelete); if (arguments.Count >= 5) { list.InsertRange(firstIndex, arguments, 4); } result = list; } else if (ScriptOps.HasFlags(interpreter, InterpreterFlags.ReplaceEmptyListOk, true)) { result = list; } else { result = String.Format( "list doesn't contain element {0}", arguments[2]); code = ReturnCode.Error; } } else { result = String.Format( "list doesn't contain element {0}", arguments[2]); code = ReturnCode.Error; } } } } } else { result = "wrong # args: should be \"lreplace list first last ?value ...?\""; 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 == 5) || (arguments.Count == 6)) { /////////////////////////////////////////////////////////////////////////////////////////////// // // test name description ?constraints? body result // /////////////////////////////////////////////////////////////////////////////////////////////// string name = arguments[1]; #if DEBUGGER if (DebuggerOps.CanHitBreakpoints(interpreter, EngineFlags.None, BreakpointType.Test)) { code = interpreter.CheckBreakpoints( code, BreakpointType.Test, name, null, null, this, null, clientData, arguments, ref result); } if (code == ReturnCode.Ok) #endif { string description = arguments[2]; string constraints; string body; IScriptLocation bodyLocation; string expectedResult; if (arguments.Count == 6) { constraints = arguments[3]; body = arguments[4]; bodyLocation = arguments[4]; expectedResult = arguments[5]; } else { constraints = null; body = arguments[3]; bodyLocation = arguments[3]; expectedResult = arguments[4]; } ReturnCodeList returnCodes = new ReturnCodeList(new ReturnCode[] { ReturnCode.Ok, ReturnCode.Return }); MatchMode mode = StringOps.DefaultResultMatchMode; bool noCase = false; /////////////////////////////////////////////////////////////////////////////////////////////// int testLevels = interpreter.EnterTestLevel(); try { // // NOTE: Create a place to put all the output of the this command. // StringBuilder testData = StringOps.NewStringBuilder(); // // NOTE: Are we going to skip this test? // bool skip = false; bool fail = true; code = TestOps.CheckConstraints( interpreter, testLevels, name, constraints, false, false, testData, ref skip, ref fail, ref result); // // NOTE: Track the fact that we handled this test. // int[] testStatistics = null; if (code == ReturnCode.Ok) { testStatistics = interpreter.TestStatistics; if ((testStatistics != null) && (testLevels == 1) && skip) { Interlocked.Increment(ref testStatistics[ (int)TestInformationType.Total]); } } if ((code == ReturnCode.Ok) && !skip) { code = TestOps.RecordInformation( interpreter, TestInformationType.Counts, name, null, true, ref result); } // // NOTE: Check test constraints to see if we should run the test. // if ((code == ReturnCode.Ok) && !skip) { ReturnCode bodyCode = ReturnCode.Ok; Result bodyResult = null; // // NOTE: Only run the test body if the setup is successful. // if (body != null) { TestOps.AppendFormat( interpreter, testData, TestOutputType.Start, "---- {0} start", name); TestOps.AppendLine( interpreter, testData, TestOutputType.Start); int savedPreviousLevels = interpreter.BeginNestedExecution(); try { ICallFrame frame = interpreter.NewTrackingCallFrame( StringList.MakeList(this.Name, "body", name), CallFrameFlags.Test); interpreter.PushAutomaticCallFrame(frame); try { bodyCode = interpreter.EvaluateScript( body, bodyLocation, ref bodyResult); if ((bodyResult == null) && ScriptOps.HasFlags( interpreter, InterpreterFlags.TestNullIsEmpty, true)) { bodyResult = String.Empty; } if (bodyCode == ReturnCode.Error) { /* IGNORED */ interpreter.CopyErrorInformation( VariableFlags.None, ref bodyResult); } } finally { // // NOTE: Pop the original call frame that we pushed above // and any intervening scope call frames that may be // leftover (i.e. they were not explicitly closed). // /* IGNORED */ interpreter.PopScopeCallFramesAndOneMore(); } } catch (Exception e) { bodyResult = e; bodyCode = ReturnCode.Error; } finally { interpreter.EndNestedExecution(savedPreviousLevels); } } // // NOTE: Did we fail to match the return code? // bool codeFailure = !returnCodes.Contains(bodyCode); // // NOTE: Does the actual result match the expected result? // bool scriptFailure = false; ReturnCode scriptCode = ReturnCode.Ok; Result scriptResult = null; if (!codeFailure) { if (expectedResult != null) { scriptCode = TestOps.Match( interpreter, mode, bodyResult, expectedResult, noCase, null, TestOps.RegExOptions, false, ref scriptFailure, ref scriptResult); if (scriptCode == ReturnCode.Ok) { scriptFailure = !scriptFailure; } else { scriptFailure = true; } } } // // NOTE: If any of the important things failed, the test fails. // if (!(codeFailure || scriptFailure)) { // // PASS: Test ran with no errors and the results match // what we expected. // if ((testStatistics != null) && (testLevels == 1)) { Interlocked.Increment(ref testStatistics[ (int)TestInformationType.Passed]); Interlocked.Increment(ref testStatistics[ (int)TestInformationType.Total]); } TestOps.AppendFormat( interpreter, testData, TestOutputType.Pass, "++++ {0} PASSED", name); TestOps.AppendLine( interpreter, testData, TestOutputType.Pass); } else { // // FAIL: Test ran with errors or the result does not match // what we expected. // if ((testStatistics != null) && (testLevels == 1)) { if (fail) { Interlocked.Increment(ref testStatistics[ (int)TestInformationType.Failed]); Interlocked.Increment(ref testStatistics[ (int)TestInformationType.Total]); } } // // NOTE: Keep track of each test that fails. // if (testLevels == 1) { TestOps.RecordInformation( interpreter, TestInformationType.FailedNames, name, null, true); } TestOps.AppendLine( interpreter, testData, TestOutputType.Fail); TestOps.AppendFormat( interpreter, testData, TestOutputType.Fail, "==== {0} {1} {2}", name, description.Trim(), fail ? "FAILED" : "IGNORED"); TestOps.AppendLine( interpreter, testData, TestOutputType.Fail); if (body != null) { TestOps.AppendLine( interpreter, testData, TestOutputType.Body, "==== Contents of test case:"); TestOps.AppendLine( interpreter, testData, TestOutputType.Body, body); } if (scriptFailure) { if (scriptCode == ReturnCode.Ok) { TestOps.AppendLine( interpreter, testData, TestOutputType.Reason, "---- Result was:"); TestOps.AppendLine( interpreter, testData, TestOutputType.Reason, bodyResult); TestOps.AppendFormat( interpreter, testData, TestOutputType.Reason, "---- Result should have been ({0} matching):", mode); TestOps.AppendLine( interpreter, testData, TestOutputType.Reason); TestOps.AppendLine( interpreter, testData, TestOutputType.Reason, expectedResult); } else { TestOps.Append( interpreter, testData, TestOutputType.Reason, "---- Error testing result: "); TestOps.AppendLine( interpreter, testData, TestOutputType.Reason, scriptResult); if ((scriptResult != null) && (scriptResult.ErrorInfo != null)) { TestOps.Append( interpreter, testData, TestOutputType.Error, "---- errorInfo(matchResult): "); TestOps.AppendLine( interpreter, testData, TestOutputType.Error, scriptResult.ErrorInfo); TestOps.Append( interpreter, testData, TestOutputType.Error, "---- errorCode(matchResult): "); TestOps.AppendLine( interpreter, testData, TestOutputType.Error, scriptResult.ErrorCode); } } } if (codeFailure) { ReturnCodeDictionary returnCodeMessages = interpreter.TestReturnCodeMessages; string codeMessage; if ((returnCodeMessages == null) || (!returnCodeMessages.TryGetValue( bodyCode, out codeMessage) && !returnCodeMessages.TryGetValue( ReturnCode.Invalid, out codeMessage))) { codeMessage = "Unknown"; } TestOps.AppendFormat( interpreter, testData, TestOutputType.Reason, "---- {0}; Return code was: {1}", codeMessage, bodyCode); TestOps.AppendLine( interpreter, testData, TestOutputType.Reason); TestOps.Append( interpreter, testData, TestOutputType.Reason, "---- Return code should have been one of: "); TestOps.AppendLine( interpreter, testData, TestOutputType.Reason, returnCodes.ToString()); if ((bodyResult != null) && (bodyResult.ErrorInfo != null) && !returnCodes.Contains(ReturnCode.Error)) { TestOps.Append( interpreter, testData, TestOutputType.Error, "---- errorInfo(body): "); TestOps.AppendLine( interpreter, testData, TestOutputType.Error, bodyResult.ErrorInfo); TestOps.Append( interpreter, testData, TestOutputType.Error, "---- errorCode(body): "); TestOps.AppendLine( interpreter, testData, TestOutputType.Error, bodyResult.ErrorCode); } } TestOps.AppendFormat( interpreter, testData, TestOutputType.Fail, "==== {0} {1}", name, fail ? "FAILED" : "IGNORED"); TestOps.AppendLine( interpreter, testData, TestOutputType.Fail); } } // // NOTE: Did the above code succeed? // if (code == ReturnCode.Ok) { // // NOTE: The result is the complete output produced by the // entire test. // if (testData != null) { result = testData; } else { result = String.Empty; } } } catch (Exception e) { Engine.SetExceptionErrorCode(interpreter, e); result = e; code = ReturnCode.Error; } finally { interpreter.ExitTestLevel(); } } } else { result = String.Format( "wrong # args: should be \"{0} name description constraints body result\"", this.Name); 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 ) { if (interpreter == null) { result = "invalid interpreter"; return(ReturnCode.Error); } if (arguments == null) { result = "invalid argument list"; return(ReturnCode.Error); } if ((arguments.Count < 2) || (arguments.Count > 4)) { result = ScriptOps.WrongNumberOfArguments(this, 1, arguments, "script ?resultVarName? ?optionsVarName?"); return(ReturnCode.Error); } string name = StringList.MakeList(this.Name); ICallFrame frame = interpreter.NewTrackingCallFrame(name, CallFrameFlags.Catch); interpreter.PushAutomaticCallFrame(frame); EngineFlags engineFlags = interpreter.EngineFlags; if (Engine.HasNoResetError(engineFlags)) { engineFlags |= EngineFlags.ErrorAlreadyLogged; } ReturnCode code; Result localResult = null; int errorLine = 0; /* IGNORED */ interpreter.EnterCatchLevel(); try { code = interpreter.EvaluateScript( arguments[1], engineFlags, ref localResult, ref errorLine); } finally { if (interpreter.ExitCatchLevel() == 0) { if (ScriptOps.HasFlags(interpreter, InterpreterFlags.CatchResetCancel, true)) { ReturnCode resetCode; Result resetError = null; resetCode = Engine.ResetCancel( interpreter, CancelFlags.CatchBlock, ref resetError); if (resetCode != ReturnCode.Ok) { DebugOps.Complain( interpreter, resetCode, resetError); } } if (ScriptOps.HasFlags(interpreter, InterpreterFlags.CatchResetExit, true)) { bool exit = interpreter.Exit; if (exit) { interpreter.Exit = false; } } } } // // BUGFIX: Prevent messing up the custom errorInfo from the [error] // command by checking to see if the "error already logged" // flag has been set. // engineFlags = interpreter.EngineFlags; if ((code == ReturnCode.Error) && !Engine.HasErrorAlreadyLogged(engineFlags) && !Engine.HasNoResetError(engineFlags)) { Engine.AddErrorInformation(interpreter, localResult, String.Format("{0} (\"catch\" body line {1})", Environment.NewLine, errorLine)); } // // NOTE: Pop the original call frame that we pushed above and any // intervening scope call frames that may be leftover (i.e. // they were not explicitly closed). // /* IGNORED */ interpreter.PopScopeCallFramesAndOneMore(); // // NOTE: The result of this command is the integer conversion of // the return code received from the evaluated script. // Engine.ResetResult(interpreter, ref result); result = ConversionOps.ToInt(code); result.ReturnCode = code; /* NOTE: For ease of use. */ // // NOTE: See if the caller wants to save the result and/or error // message in a variable. // if (arguments.Count >= 3) { Result error = null; code = interpreter.SetVariableValue( VariableFlags.NoReady, arguments[2], localResult, null, ref error); if (code != ReturnCode.Ok) { Engine.ResetResult(interpreter, ref result); result = String.Format( "couldn't save command result in variable: {0}", error); return(code); } } // // NOTE: See if the caller wants to save the "return options" in a // variable. // if (arguments.Count >= 4) { StringList list = new StringList(); Result error = null; if (result.ReturnCode == ReturnCode.Return) { int level = 0; code = interpreter.GetInfoLevel( null, ref level, ref error); if (code != ReturnCode.Ok) { Engine.ResetResult(interpreter, ref error); result = String.Format( "couldn't get current level: {0}", error); return(code); } list.Add("-code", ((int)interpreter.ReturnCode).ToString()); list.Add("-level", level.ToString()); } else { list.Add("-code", result.String); list.Add("-level", Value.ZeroString); } if (result.ReturnCode == ReturnCode.Error) { Result errorCode = null; Result errorInfo = null; ResultList errors = null; code = interpreter.CopyErrorInformation( VariableFlags.None, true, ref errorCode, ref errorInfo, ref errors); if (code != ReturnCode.Ok) { Engine.ResetResult(interpreter, ref result); result = errors; return(code); } list.Add("-errorcode", errorCode); list.Add("-errorinfo", errorInfo); list.Add("-errorline", errorLine.ToString()); } code = interpreter.SetVariableValue( VariableFlags.NoReady, arguments[3], list.ToString(), null, ref error); if (code != ReturnCode.Ok) { Engine.ResetResult(interpreter, ref result); result = String.Format( "couldn't save return options in variable: {0}", error); return(code); } } // // NOTE: We are "catching" (masking) the error; therefore, do not // propogate it. // return(ReturnCode.Ok); }