Skip to content

XSilverTH/XScripTH

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

58 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

XScripTH

XScripTH is a command-based scripting language and execution engine for .NET. Every command is a normal registry entry: shipping with the language does not give var, func, use, or any other command compiler-only privileges. Commands discovered later through import participate through the same public contracts.

Commands

Commands take comma-separated inputs and end with a terminator:

command input1, input2, input3;

Use ; when the next command should wait for this one to finish.

print "Hello, World!";

Use ;; to start a command without waiting for it to finish:

long-running-task;;
print "This can run straight away";

A command does not get special treatment just because it is built into the language. For example, if is still just a command with two inputs: a condition and something to run.

if (1 == 1), {
    print "Condition met!";
};

Inputs and types

Commands expect inputs of particular types. An input can be a literal, variable, expression, block, function, or the result of another command, as long as it produces the type the command needs.

That means there can be a few unusual but valid-looking ways to write the same idea:

if true, { print "Condition met!"; };

if (1 == 1), { print "Condition met!"; };

if { return true; }, { print "Condition met!"; };

if { return true; }, print "Condition met!"; ;

All four conditions result in a boolean value.

XScripTH checks types, but it does not silently convert values between unrelated types. For example, an integer is not automatically turned into a string.

Use an explicit cast command when a value should be converted. Casts are normal commands named after the target type, so they compose anywhere a command output is accepted:

int input; ;
string (5 + 5);

Command authors can mark trailing inputs as optional with Optional<T> in the command signature:

[CommandTypes([typeof(string), typeof(Optional<int>)], [typeof(string)])]

The optional marker affects compile-time validation only. When the optional input is provided, the command receives an ordinary int; when it is omitted, the command receives fewer input values.

Built-in literal types

Type identifiers are case-insensitive.

Type Example
String "Hello"
Char 'A'
Boolean true, false
Integer 42
Long 42l
Float 3.14f
Double 3.14d
Decimal 3.14m

Expressions

Use parentheses for math and boolean expressions:

print (2 + 3 * 4);

if (($count > 0) && true), {
    print "count is positive";
};

Expressions can contain literals, variables, nested commands, function calls, blocks, and other expressions.

Variables

Declare a variable with var, update it with set, then reference it with $:

var $message, "Hello";
print $message;

set $message, "Goodbye";
print $message;

var $size, length $message; ;

Blocks and returns

A block groups commands without running them immediately. Blocks are useful when a command needs something to run later, such as the body of an if or while.

{
    print "Doing some work...";
    return true;
}

By default a block returns the result of its last entry. Use return to control what value that block produces.

Functions

Functions are named reusable blocks. Declare one with func, then refer to it with @.

func "greet_user", {
    param $name, "string";
    print $name;
};

@greet_user "Alice";

Functions must be declared before they are used.

Dependencies

Load another script at a specific point with use or bundle:

use "lib/math.xs";
bundle "lib/format.xs";

Both commands accept source (.xs) and compiled (.xsc) files. An unnamed dependency behaves as though its commands were pasted at that location. use keeps a runtime dependency load; bundle includes the dependency graph in the built root artifact, so the bundled artifact can run after dependency files are removed.

Pass a second string to expose a dependency under a dotted namespace without running its top-level statements immediately:

use "lib/math.xs", "math";

@math.run;
print $math.answer;
@math.describe;

Namespaced functions are available as @namespace.function; top-level initialization and side effects are deferred until the zero-argument @namespace.run; call. Call the runner before functions that read initialized namespace variables. use and bundle are registered commands, so imported assemblies can provide equivalent dependency behavior.

DLL imports

Import a command assembly with import. Pass an optional second string to expose every command from that assembly under a dotted namespace:

import "plugins/text.dll", "text";
text.imported-text;

The namespace prefixes the command's declared name. A namespaced import does not also register the command globally, and the same DLL can be imported under separate namespaces.

Control flow

if takes a boolean condition and something to run when the condition is true:

if true, {
    print "Condition met!";
};

while takes a boolean condition and a something to run. The condition is evaluated before every iteration:

while true, {
    print "Still running";
};

Language Server

Run xscripth lsp to serve .xs files over standard input and output using the Language Server Protocol. Standard output is reserved exclusively for protocol frames; diagnostics and host logging belong on standard error.

The VS Code client is in editors/vscode. Configure xscripth.server.path when the xscripth executable is not on PATH.

Where to look next

This README covers the language's main syntax and ideas. To see how the language works and how to add commands see TECHNICAL.

About

a personal project made for fun. a simple programming language made in c#

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors