Skip to content

Script Syntax

Oleg Shilo edited this page Jul 28, 2024 · 17 revisions

CS-Script specific syntax


Engine directives:

  • //css_include <file>;
  • //css_import <file>[, preserve_main][, rename_namespace(<oldName>, <newName>)];
  • //css_nuget [-noref] [-force[:delay]] [-ver:<version>] [-rt:<runtime>] [-ng:<nuget arguments>] package0[,package1]..[,packageN];
  • //css_args arg0[,arg1]..[,argN];
  • //css_reference <file>;
  • //css_precompiler <file 1>,<file 2>;
  • //css_searchdir <directory>;
  • //css_winapp
  • //css_webapp
  • //css_autoclass [style]
  • //css_resource <file>[, <out_file>];
  • //css_co <options>;
  • //css_engine <csc|dotnet|roslyn>;
  • //css_ignore_namespace <namespace>;
  • //css_ac_end
  • //css_prescript file([arg0][,arg1]..[,argN])[ignore];
  • //css_postscript file([arg0][,arg1]..[,argN])[ignore];

Engine directives can be controlled (enabled/disabled) with compiler conditional symbols and environment variables via the inline #if syntax:

  //css_include #if DEBUG debug_utils.cs
  //css_dir #if (DEBUG) .\bin\Debug
  //css_reference #if PRODUCTION_PC d:\temp\build\certificates.dll

The script engine also always defines special compiler conditional symbol CS_SCRIPT:

  #if CS_SCRIPT
       Console.WriteLine("Running as a script...");
  #endif

The script engine also defines another conditional symbol NETCORE to allow userto distinguish between executions under .NET (full) and .NET Core


Directive //css_include

//css_include <file>;

Alias - //css_inc

file - name of a script file to be included at compile-time.

This directive is available for both CLI and hosted script execution.

This directive is used to import/include one script into another one. It is a logical equivalent of '#include' in C++.

If a relative file path is specified with a single-dot prefix it will be automatically converted into the absolute path with respect to the location of the script file containing the //css_include directive. Otherwise it will be resolved with respect to the process current directory.

If for whatever reason it is preferred to always resolve path expression with respect to the parent script location you can configure the script engine to do it with the following command:

   cscs -config:set:ResolveRelativeFromParentScriptLocation = true

Note, if you use a wildcard in the imported script name (e.g. /_build.cs) the directive will only import from the first probing directory where the matching file(s) is found. Be careful with the wide wildcard as '.cs' as they may lead to unpredictable behavior. For example they may match everything from the very first probing directory, which is typically a current directory. Using more specific wildcards is arguably more practical (e.g. 'utils/*.cs', 'Helper.cs', './.cs')


Directive //css_import

//css_import <file>[, preserve_main][, rename_namespace(<oldName>, <newName>)];

Alias - //css_imp

This is a more specialized version of the default script importing directive //css_include (//css_inc) with some extra renaming functionality. While //css_include simply includes a script file in the execution as is, //css_import analyzes the file being imported and renames namespaces and static Main(...) to avoid naming collisions. Thus you should use it only if you have naming collision problems.

file             - name of a script file to be imported at compile-time.
preserve_main    - do not rename 'static Main'.
                   .NET allows only one entry point 'static Main' method per application. Thus it is a problem if the primary and the imported scripts both contain 'static Main'.To avoid this the script engine searches the imported script for 'static Main' method and renames it in 'i_Main' and then
                   uses a temporary copy of the processed imported script during the execution. If you need to use the imported script as is, then you should use 'preserve_main' argument with the '//css_import' directive.
rename_namespace - rename namespace clause, it can appear in the directive multiple times
oldName          - name of a namespace to be renamed during importing
newName          - new name of a namespace to be renamed during importing

Directive //css_nuget

//css_nuget [-noref] [-force[:delay]] [-ver:<version>] [-rt:<runtime>] [-ng:<nuget arguments>] package0[,package1]..[,packageN];

Downloads/Installs the NuGet package. It also automatically references the downloaded package assemblies. Note: The directive switches need to be in the order as above. A new NuGet support available from version 4.7.0 will obsolete some of the options of this directive New NuGet support can be enabled by setting LegacyNugetSupport option to false with css -config:set:LegacyNugetSupport=false) Read more: https://github.com/oleg-shilo/cs-script/wiki/NuGet-Support

By default, the package is not downloaded again if it was already downloaded. If no version is specified then the highest downloaded version (if any) will be used. Referencing the downloaded packages can only handle simple dependency scenarios when all downloaded assemblies are to be referenced. You should use '-noref' switch and reference assemblies manually for all other cases. For example multiple assemblies with the same file name that target different CLRs (e.g. v3.5 vs v4.0) in the same package. Switches:

 -noref         - switch for individual packages if automatic referencing isn't desired.
                  You can use 'css_nuget' environment variable for further referencing package content (e.g. //css_dir %css_nuget%\WixSharp\**)
                  (Not available with new NuGet support)
 -force[:delay] - switch to force individual packages downloading even when they were already downloaded.
                  You can optionally specify a delay for the next forced downloading by the number of seconds since last download.
                  '-force:3600' will delay it for one hour. This option is useful for preventing frequent download interruptions during active script development.
                  (Not available with new NuGet support)
 -ver:<version> - switch to download/reference a specific package version.
 -rt:<runtime>  - switch to use specific runtime binaries (e.g. '-rt:netstandard1.3').
                  (Not available with new NuGet support)
 -ng:<args>     - switch to pass `nuget.exe`/`dotnet restore` arguments for every individual package.
                  (`-restore:` as an alias of this switch)

Example: //css_nuget cs-script; //css_nuget -restore:"-v minimal" -ver:4.1.2 NLog //css_nuget -ver:4.1.2 -restore:"-f --no-cache" NLog //css_nuget -ver:"4.1.1-rc1" -rt:netstandard2.0 -ng:"-f --no-cache" NLog

This directive will install CS-Script NuGet package. (see http://www.csscript.net/help/script_nugets.html)


Directive //css_args

//css_args arg0[,arg1]..[,argN];

Embedded script arguments. Both script and engine arguments are allowed except "/noconfig" engine command switch.

Example: //css_args -dbg, -inmem; This directive will always force the script engine to execute the script in debug mode. Note: the arguments must be coma separated.


Directive //css_reference

//css_reference <file>;

Alias - //css_ref

file - name of the assembly file to be loaded at run-time. This directive is used to reference assemblies required at run time. The assembly must be in GAC, the same folder with the script file or in the 'Script Library' folders (see 'CS-Script settings').

Note if you use wildcard in the referenced assembly name (e.g. socket..dll) the directive will only reference from the first probing directory where the matching file(s) is found. Be careful with the wide wildcard as '.dll' as they may lead to unpredictable behavior. For example they may match everything from the very first probing directory, which is typically a current directory. Using more specific wildcards is arguably more practical (e.g. 'utils/*.dll', 'Helper.dll', './.dll')


Directive //css_precompiler

//css_precompiler <file 1>,<file 2>;

Alias - //css_pc

file - name of the script or assembly file implementing precompiler.

This directive is used to specify the CS-Script precompilers to be loaded and exercised against script at run time just before compiling it. Precompilers are typically used to alter the script coder before the execution. Thus CS-Script uses built-in precompiler to decorate classless scripts executed with -autoclass switch. (see http://www.csscript.net/help/precompilers.html


Directive //css_searchdir

//css_searchdir <directory>;

Alias - //css_dir

directory - name of the directory to be used for script and assembly probing at run-time.

This directive is used to extend set of search directories (script and assembly probing). The directory name can be a wildcard based expression.In such a case all directories matching the pattern will be this case all directories will be probed. The special case when the path ends with '**' is reserved to indicate 'sub directories' case. Examples:

    //css_dir packages\ServiceStack*.1.0.21\lib\net40
    //css_dir packages\**

Directive `//css_winapp``

//css_winapp

Alias - //css_winapp

Adds search directories required for running WinForm and WPF scripts. Note: you need to use csws.exe engine to run WPF scripts. Alternatively you can set environment variable 'CSS_WINAPP' to non empty value and css.exe shim will redirect the execution to the csws.exe executable.


Directive `//css_webapp``

//css_webapp

Alias - //css_webapp

Indicates that the script app needs to be compiled against Microsoft.AspNetCore.App framework. A typical example is a WebAPI script application.


Directive //css_autoclass

//css_autoclass [style]

Alias - //css_ac

OBSOLETE, use top-class native C# 9 feature instead Automatically generates 'static entry point' class if the script doesn't define any.

    //css_ac
    using System;

    void Main()
    {
        Console.WriteLine("Hello World!");
    }

Using an alternative 'instance entry point' is even more convenient (and reliable). The acceptable 'instance entry point' signatures are:

    void main()
    void main(string[] args)
    int main()
    int main(string[] args)

The convention for the classless (auto-class) code structure is as follows:

A special case of auto-class use case is a free style C# code that has no entry point 'main' at all:

    //css_autoclass freestyle
    using System;

    Console.WriteLine(Environment.Version);

Since it's problematic to reliable auto-detect free style auto-classes, they must be defined with the special parameter 'freestyle' after the '//css_ac' directive

By default, CS-Script decorates the script by adding a class declaration statement to the start of the script routine and a class-closing bracket to the end. This may have an unintended effect as any class declared in the script becomes a 'nested class'. While it is acceptable for practically all use-cases it may be undesired for just a few scenarios. For example, any class containing method extensions must be a top-level static class, which conflicts with the auto-class decoration algorithm.

An additional '//css_autoclass_end' ('//css_ac_end') directive can be used to solve this problem.

It's nothing else but a marker indicating the end of the code that needs to be decorated as (wrapped into) an auto-class. This directive allows defining top level static classes in the class-less scripts, which is required for implementing extension methods.

 //css_ac
 using System;

 void main()
 {
     ...
 }

 //css_ac_end

 static class Extensions
 {
     static public string Convert(this string text)
     {
         ...
     }
 }

Directive //css_resource

//css_resource <file>[, <out_file>];

Alias - //css_res

file - name of the compiled resource file (.resources) to be used with the script. Alternatively, it can be the name of the XML resource file (.resx) that will be compiled on-fly. `out_file - Optional name of the compiled resource file (.resources) to be generated form the .resx input.If not supplied then the compiled file will have the same name as the input file but the file extension '.resx' changed to '.resources'.

This directive is used to reference resource file for script. Example: //css_res Scripting.Form1.resources; //css_res Resources1.resx; //css_res Form1.resx, Scripting.Form1.resources;


Directive //css_co

//css_co <options>;

options - options string.

This directive is used to pass compiler options string directly to the language-specific CLR compiling engine. Note:

  • the options may not be compatible with the compiling engine of your choice (see //css_engine).Thus //css_co /define:CS_SCRIPT will work for csc engine but will not for dotnet since it does not support /define.
  • character ; in compiler options interferes with //css_... directives so try to avoid it. Thus use -d:DEBUG -d:NET4 instead of -d:DEBUG;NET4 Example: //css_co /d:TRACE pass /d:TRACE option to C# compiler //css_co /platform:x86 to produce Win32 executable //css_co -nullable:enable -warnaserror:nullable to enable nullable reference types.

Directive //css_engine

//css_engine <csc|dotnet|roslyn>;

Alias - //css_ng

This directive is used to select compiler services for building a script into an assembly.

 dotnet - use `dotnet.exe` and on-fly .NET projects.
          This is a default compiler engine that handles well even complicated heterogeneous multi-file scripts like WPF scripts.
 csc    - use `csc.exe`.
          This compiler shows much better performance. Though it is not suitable for WPF scripts.
This feature is conceptually similar to the VBCSCompiler.exe build server, which is not available in in .NET5/.NET-Core. Even though available on .NET-Fx (Roslyn).
          Using this option can in order of magnitude improve compilation speed. However it's not suitable for compiling WPF scripts because csc.exe cannot compile XAML.
          While this feature is useful it will be deprecated when .NET5+ starts distributing its own properly working build server VBCSCompiler.exe.
roslyn - use `Microsoft.CodeAnalysis.CSharp.Scripting.dll` (Roslyn).
         This compiler shows good performance and does not require .NET SDK. Though, it is not suitable for WPF scripts. See [this wiki](https://github.com/oleg-shilo/cs-script/wiki/Choosing-Compiler-Engine) for details.

Example: //css_engine csc


Directive //css_ignore_namespace

//css_ignore_namespace <namespace>;

Alias - //css_ignore_ns

namespace - name of the namespace. Use '*' to completely disable namespace resolution

This directive is used to prevent CS-Script from resolving the referenced namespace into the assembly.


Directive `//css_ac_end``

//css_ac_end

This directive is only applicable for class-less scripts executed with '-autoclass' CLI argument. It's nothing else but a marker indicating the end of the code that needs to be decorated as (wrapped into) an auto-class. This directive allows achieving top-level static classes in the class-less scripts, which is required for implementing extension methods.

 //css_args -autoclass
 using System;

 void main()
 {
     ...
 }

 //css_ac_end

 static class Extensions
 {
     static public void Convert(this string text)
     {
         ...
     }
 }

Directive //css_prescript

//css_prescript file([arg0][,arg1]..[,argN])[ignore];

Alias - //css_pre

file - script file (extension is optional) arg0..N - script string arguments ignore - continue execution of the main script in case of error

These directives are used to execute secondary pre-execution scripts. If $this (or $this.name) is specified as arg0..N it will be replaced at execution time with the main script full name (or file name only). You may find that in many cases precompilers (//css_pc and -pc) are a more powerful and flexible alternative to the pre-execution script.


Directive //css_postscript

//css_postscript file([arg0][,arg1]..[,argN])[ignore]; Alias - //css_post

file - script file (extension is optional) arg0..N - script string arguments ignore - continue execution of the main script in case of error

These directives are used to execute secondary post-execution scripts. If $this (or $this.name) is specified as arg0..N it will be replaced at execution time with the main script full name (or file name only).


Note the script engine always sets the following environment variables: pid - host processId (e.g. Environment.GetEnvironmentVariable("pid") CSScriptRuntime - script engine version CSScriptRuntimeLocation - script engine location cscs_exe_dir - script engine directory EntryScript - location of the entry script EntryScriptAssembly - location of the compiled script assembly location:<asm_hash> - location of the compiled script assembly.

This variable is particularly useful as it allows finding the compiled assembly file from the inside of the script code. Even when the script loaded in-memory (InMemoryAssembly setting) but not from the original file. (e.g. var location = Environment.GetEnvironmentVariable("location:" + Assembly.GetExecutingAssembly().GetHashCode());

Note that the default setting of 'location:<asm_hash>' is disabled. You can enable it by setting 'CSS_SCRIPTLOCATIONREFLECTION' environment variable to non empty string.

The following is the optional set of environment variables that the script engine uses to improve the user experience:

'CSS_NUGET' location of the NuGet packages, which scripts can load/reference

'CSSCRIPT_ROOT' script engine location. Used by the engine to locate dependencies (e.g. resgen.exe). Typically this variable is during the CS-Script installation.

'CSSCRIPT_CONSOLE_ENCODING_OVERWRITE' script engine output encoding if the one from the css_confix.xml needs to be overwritten.

'CSSCRIPT_INC' a system-wide include directory for the all frequently used user scripts.

'CSSCRIPT_CSC_CMD_LOG' the location of the log file that will be created during the script execution with the 'csc' compiler engine.the file will contain the command line that is used to start csc.exe to compile the script. This behavior is useful for the advanced debugging scenarios. Of the environment variable is not set or the value is not a valid file path then no log file will be created.


During the script execution CS-Script always injects a little object inspector class 'dbg'. This class contains static printing methods that mimic Python's 'print()'. It is particularly useful for object inspection in the absence of a proper debugger.

Examples: dbg.print("Now:", DateTime.Now) - prints concatenated objects. dbg.print(DateTime.Now) - prints object and values of its properties. dbg.printf("Now: {0}", DateTime.Now) - formats and prints object and values of its fields and properties.


Any directive has to be written as a single line in order to have no impact on compiling by CLI compliant compiler.It also must be placed before any namespace or class declaration.


Example:

 //css_include web_api_host.cs;
 //css_reference media_server.dll;
 //css_nuget Newtonsoft.Json;

 using System;
 using static dbg;

 class MediaServer
 {
     static void Main(string[] args)
     {
         print(args);

         WebApi.SimpleHost(args)
               .StartAsConosle("http://localhost:8080");
   }
 }

Or shorter form:

 //css_args -ac
 //css_inc web_api_host.cs
 //css_ref media_server.dll
 //css_nuget Newtonsoft.Json

 using System;

 void main(string[] args)
 {
     print(args);

     WebApi.SimpleHost(args)
           .StartAsConosle("http://localhost:8080");
 }

Project Website: https://github.com/oleg-shilo/cs-script