Debugging scripts

You are on a machine via Remote Desktop, there is no Visual Studio in sight, nor you can install, nor you want to install anything, and script does not work. What's next?

Enable script debug output (you'll need DebugView for Windows to see the output)

xsharper hello.xsh //debug

If //debug is specified, if script fails with exception, a complete error message is produced. For example, there is a script:
You are on a machine via Remote Desktop, there is no Visual Studio in sight, nor you can install, nor you want to install anything, and script does not work. What's next?

Enable script debug output (you'll need DebugView for Windows to see the output)

xsharper hello.xsh //debug

If //debug is specified, if script fails with exception, a complete error message is produced. For example, there is a script:

<print newline="false">Enter an expression:</print>
<set expr="${=c.ReadLine()}" />
<print outTo="^debug">Expression: ${expr}</print>
<print>Result: ${=c.Eval($expr)}</print>

which when executed attempts to divide by 0:

C:\xsharper eval.xsh
Enter an expression: (50+20)/0
Error: Attempted to divide by zero.

C:\xsharper eval.xsh //debug
Enter an expression: (50+20)/0
Error: System.DivideByZeroException: Attempted to divide by zero.
   at XSharper.Core.EvalHelper.runAgainstObject(Object obj, Type objType, String func, Array a, RunFlags flags, Object& retVal)
   at XSharper.Core.Operations.OperationCall.Eval(IEvaluationContext context, Stack`1 stack)
   at XSharper.Core.Operations.OperationExpression.Eval(IEvaluationContext context, Stack`1 stack)
   at XSharper.Core.Operations.OperationVariableAccess.Eval(IEvaluationContext context, Stack`1 stack)
   at XSharper.Core.ScriptContext.EvaluateMulti(ParsingReader r)
   at XSharper.Core.ScriptContext.expandVars(TransformRules rules, String s)
   at XSharper.Core.ScriptContext.Transform(Object source, TransformRules rules)
   at XSharper.Core.ValueBase.GetTransformedValueStr()
   at XSharper.Core.Print.execute()
   at XSharper.Core.ScriptContext.<>c__DisplayClass13.<Execute>b__12()
   at XSharper.Core.ScriptContext.RunOnStack(ScriptOperation operation, IScriptAction action, ScriptExecuteMethod method)
At script location:
  [Executing] print(value="Result: ${=c.Eval($expr)}")
  [Executing] xsharper(location="C:\eval.xsh")

To enable debug output and print it to console there is //debugc switch (debugc= debug to console)

C:\>xsharper eval.xsh //debugc 
Enter an expression: 4+5

Expression: 4+5
Result: 9

Same, but enable debug output and print it to console, including script engine details, is done via //verbose:

C:\>xsharper eval.xsh //debugc //verbose
# OpenStream> Reading from file C:\eval.xsh
# Context> Executing script C:\eval.xsh with isolation High
Enter an expression: 4+5

Expression: 4+5
Result: 9

Same, as above, but also trace lines of code as they execute

xsharper hello.xsh //debugc //verbose //trace
C:\>xsharper eval.xsh //debugc //verbose //trace
# OpenStream> Reading from file C:\eval.xsh
# @ [Loading] xsharper(location="C:\eval.xsh")
# @ [Initializing] xsharper(location="C:\eval.xsh")
# @ [Initializing] xsharper(location="C:\eval.xsh") >> print(newLine="False", value="Enter an expression:")
# @ [Initializing] xsharper(location="C:\eval.xsh") >> set(name="expr", ="${=c.ReadLine()}")
# @ [Initializing] xsharper(location="C:\eval.xsh") >> print(outTo="^debug", value="Expression: ${expr}")
# @ [Initializing] xsharper(location="C:\eval.xsh") >> print(value="Result: ${=c.Eval($expr)}")
# @ [Compiling] xsharper(location="C:\eval.xsh")
# Context> Executing script C:\eval.xsh with isolation High
# @ [ParsingArguments] xsharper(location="C:\eval.xsh")
# @ [Executing] xsharper(location="C:\eval.xsh")
# @ [Executing] xsharper(location="C:\eval.xsh") >> print(newLine="False", value="Enter an expression:")
Enter an expression:
@ [Executing] xsharper(location="C:\eval.xsh") >> set(name="expr", ="${=c.ReadLine()}")
4+5
# @ [Executing] xsharper(location="C:\eval.xsh") >> print(outTo="^debug", value="Expression: ${expr}")
# Expression: 4+5
# @ [Executing] xsharper(location="C:\eval.xsh") >> print(value="Result: ${=c.Eval($expr)}")
Result: 9

Measure script execution time, display exit code and ask for a key press before exit

xsharper #/hash //wait

Using ToDump

Using the previous steps you may determine where the program throws an exception, how execution goes, how to print debug messages etc.

It is as important to see variables defined at critical script points. Of couse, can use the usual ToString method, but it often produces rather useless results for complex objects.

XSharper has a few special methods for converting objects variables:

Shortcut name Full method name Description
.ToDump Dump.ToDump Convert a .NET object graph to string
.ToDumpAll ScriptContext.ToDumpAll Convert all defined XSharper variables to string (a filter may be specified to dump only some variables
.Dump ContextWriter.Dump Shortcut for ContextWriter.WriteDump.ToDump(object))
.Dump ScriptContext.Dump Shortcut for Out.Write(Dump.ToDump(object))

What it all means is easier to demonstrate:

<set a="Hello" />
<set b="${=new DirectoryInfo('c:\windows')}" />
<set c="${=new string[] { 'This', 'is','a','string','array'}  }" />
<print outTo="^bold">Dumping a to standard output</print>
<eval>c.Dump($a);</eval>
<print outTo="^bold">Dumping b to error output</print>
<eval>c.Error.Dump($b);</eval>
<print outTo="^bold">Dumping b and c to info</print>
<eval>c.Out.WriteLine(c.ToDumpAll('b;c*'))</eval>

prints

Dumping a to standard output
(string) "Hello"
Dumping b to error output
(DirectoryInfo) { /* #1, 03553390 */
  Name = (string) "windows"
  Parent = (DirectoryInfo) "" /* ToString */
  Exists = (bool) true
  Root = (DirectoryInfo) "c:\" /* ToString */
  FullName = (string) "c:\windows"
  Extension = (string) ""
  CreationTime = (DateTime) 2009-03-03T08:30:25.3750000-05:00
  CreationTimeUtc = (DateTime) 2009-03-03T13:30:25.3750000Z
  LastAccessTime = (DateTime) 2009-12-10T13:12:37.1088672-05:00
  LastAccessTimeUtc = (DateTime) 2009-12-10T18:12:37.1088672Z
  LastWriteTime = (DateTime) 2009-12-07T19:51:20.7933162-05:00
  LastWriteTimeUtc = (DateTime) 2009-12-08T00:51:20.7933162Z
  Attributes = (FileAttributes) [Directory] /* 0x00000010 */
}
Dumping b and c to info
b  = (DirectoryInfo) "c:\windows" /* ToString */
c  = (string[]) "System.String[]" /* ToString */