Scripty: The Ultimate Scripting Language

by: Michael Stepp

Introduction:

This site is about the Scripty programming language. The basic idea behind this language is to allow very simple interop between multiple scripting languages in the same program. Within a single file, you can specify snippets of Bash, Perl, Python, Clojure, etc, and with a few simple annotations, get them to seamlessly call each other as subroutines. This includes passing parameters and capturing result output (stdout). In theory, this concept could be extended to include any scripting language, but currently we only support Bash, Python, Perl, and Clojure.

Sitemap:


File format:

The source for a Scripty program is a .scr file, which is an XML document with the following basic format:

        program := <program main="the id of the main script to start">
                      (bash | perl | clojure | python)*
                   </program>

        bash := <bash id="the id of this script">
                   (text | CDATA | param | run)*
                   <!-- all values here comprise the body of the script program -->
                </bash>
	
        perl := <perl id="the id of this script">
                   (text | CDATA | param | run)*
                   <!-- all values here comprise the body of the script program -->
                </perl>

        python := <python id="the id of this script">
                     (text | CDATA | param | run)*
                     <!-- all values here comprise the body of the script program -->
                  </python>

        clojure := <clojure id="the id of this script">
                      (text | CDATA | param | run)*
                      <!-- all values here comprise the body of the script program -->
                   </clojure>

        param := <param id="the id of a formal parameter of this script"/>

        run := <run id="the id of the script to run">
                  arg*
               </run>

        arg := <arg id="the id of a parameter for this actual parameter value">
                  (text | CDATA | param)*
                  // all values here will be taken as a string expression to be passed
               </arg>
    

Ranting about XML:

Why do we use XML? Because I love it!

Examples:

Interop:

Programs interact by adding run tags within the program text. A run tag names another script to run, and may include argument values passed as parameters to the script.

The way that a run tag is implemented differs by language, but is essentially just a call to the "system" command, or whichever built-in library command allows the language to execute a shell command. When script A wants to call script B, it builds up a shell command string to execute B, and passes it to the "system" command. Then script A captures the output from B's STDOUT stream and uses the resulting string as the result of the run tag in A. In each language, the result of a run tag will be a (non-literal) string expression, and can be manipulated as such.

The method we use for passing parameters is through the program environment variables. Each script defines the set of required parameters it expects, and each other script that attempts to run it must provide arg values for all of those parameters. Each program's parameters are ordered and numbered, and stored in environment variables with names like "__arg0", "__arg1", etc. These names are designed to be fairly unique so that they will not conflict with existing environment variables. When script A wants to pass a value for "__arg0" to script B, it makes a "system" call similar to the following:

env __arg0=THEARGVALUE __arg1=THEARGVALUE python -c THEPYTHONPROGRAMTEXT

This example would run a python script with 2 parameters. In addition to passing the parameter values through the environment, the text of scripts themselves are all passed through the environment as well. For a script with an id of "MYID", the script body text would be placed in environment variable "__PROGRAM_MYID". Again, this name is munged to be unlikely to conflict with existing variables.

Compilation:

Compilation is achieved by performing a source-to-source translation from a scripty file (*.scr) to a bash script (*.sh), no matter which types of languages are used. The text of each program is stored in a top-level bash variable named "__PROGRAM_xxx" for a given script with id "xxx". To avoid escaping issues between the source language and bash, we wrap the text of the program inside a multi-line string statement, as such:

__PROGRAM_xxx="$(cat<<"__EOF"
   // In here is the entire text of the program.
   // No manner of weird special characters should
   // cause a problem, except for __EOF.
__EOF
)";
      

(little-known bash fact: when you wrap quotes around the starting "__EOF", it prevents any kind of string expansion inside the program text).

The method by which each languages retrieves its parameters is as follows:

The method by which each language makes its system calls is as follows:

Downloads

TODO