Skip to content

Script Syntax

Oleg Shilo edited this page Jun 19, 2023 · 14 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>;
  • //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 users 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 import 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 script file containing the //css_include 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 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 There are also another two aliases //css_include and //css_inc. They are equivalents of //css_import <file>, preserve_main

This makes //css_import a more advanced version of //css_include. So you can use it to solve some more unusual runtime scenarios. It is recommended that you use //css_include if you can. And //css_import if you have to. The //css_include directive is simpler and requires no processing of the file being imported. This section only describes behavior specific for //css_import. Thus for the generic behavior of the directive go to the //css_include help.

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.
oldName - the name of a namespace to be renamed during importing
newName - the 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 import one script into another at compile time. Thus, code from one script can be exercised in another one. The 'rename_namespace` clause can appear in the directive multiple times.

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


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 targets 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 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.
 -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. 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 comma 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 a 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

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 the environment variable 'CSS_WINAPP' to a non-empty value and css.exe shim will redirect the execution to the csws.exe executable.


Directive //css_webapp

//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 freestyle 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 freestyle 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 from 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.

Examples:
//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: character ; in compiler options interferes with //css_... directives so try to avoid it. Thus, use -d:DEBUG -d:NET4 instead of -d:DEBUG;NET4

Examples:
//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 .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.

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 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:<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 by the default setting of 'location:<asm_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, 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.


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