Skip to content

Script Syntax

oleg.shilo edited this page Oct 4, 2021 · 21 revisions
Since porting CS-Script on .NET 5 the documentation is still in the process of being refined and cleared from the legacy content.
Thus it may contain some minor inaccuracies until both statuses below are set to full and complete or this disclaimer is removed.
.NET 5 accuracy status: full
Review/update status: completed

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>;
  • //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 user to 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 include one script into another one. It is a logical equivalent of '#include' in C++. This directive is a full but more convenient equivalent of //css_import <file>, preserve_main;

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 file containing the directive being resolved. 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 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 There are also another two aliases //css_include and //css_inc. They are equivalents of //css_import <file>, preserve_main If $this (or $this.name) is specified as part of <file> it will be replaced at execution time with the main script full name (or file name only).

file - name of a script file to be imported at compile-time. <preserve_main> - do not rename 'static Main' oldName - name of a namespace to be renamed during importing newName - new name of a namespace to be renamed during importing

This directive is available for both CLI and hosted script execution

This directive is used to inject one script into another at compile time. Thus code from one script can be exercised in another one.'Rename' clause can appear in the directive multiple times.


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.

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\**)
 -force[:delay] - switch to force individual packages downloading even when they were already downloaded.
                  You can optionally specify delay for the next forced downloading by 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.
 -ver:<version> - switch to download/reference a specific package version.
 -rt:<runtime>  - switch to use specific runtime binaries (e.g. '-rt:netstandard1.3').
 -ng:<args>     - switch to pass NuGet arguments for every individual package.
 
Example: //css_nuget cs-script;
         //css_nuget -ver:4.1.2 NLog
         //css_nuget -ver:"4.1.1-rc1" -rt:netstandard2.0 -ng:"-Pre -NoCache" NLog

Directive //css_args

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

Embedded script arguments. The both script and engine arguments are allowed except "/noconfig" engine command switch. Example: //css_args -dbg, -inmem; This directive will always force 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 available for both CLI and hosted script execution

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 https://www.cs-script.net/cs-script/help-legacy/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, what 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 compiler. Note: charecter ; 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 passes /d:TRACE option to C# compiler //css_co /platform:x86 to produce Win32 executable


Directive //css_engine

//css_engine <csc|dotnet>;

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 useful it will be deprecated when .NET5+ starts distributing its own properly working build server VBCSCompiler.exe.

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 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 -acutoclass
using System;

void main()
{
    ...
}

//css_ac_end

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

Directive //css_prescript and //css_postscript

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

Aliases - //css_pre and //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 pre- and 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). You may find that in many cases precompilers (//css_pc and -pc) are a more powerful and flexible alternative to the pre-execution script.


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:<assm_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 by default setting of 'location:<assm_hash>' is disabled. You can enable it by calling 'CSScript.EnableScriptLocationReflection = true'.

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 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.


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");
 }