Introduction

CraneScript is a data-flow script language.

CraneScript describes a software system or a program in a data flow perspective.

In data flow perspective a system is consisted of three kinds of elements: data, data processing unit(module) and data-flow. The work of programming is to describe which data or modules consist the system and how connect them using data-flow.

A typical "hello world" craneScript code is:

import (stdCRN); flow(flwMAIN,Module){ stdCRN::mdlSTDOUT cPrint; "Hello world!" >> cPrint.out; };

In craneScript, a program also can be describe as a data flow diagram.

Syntax

CraneScript is derived from C++ and is designed to be compliant with C++. So more of its keywords are derived from C++.

keywords & operator

$ // ///* //*/ #include import struct module flow flwMAIN thread
char short int long float double unsigned number string any array
* . , ; () [] {} <> " ' >
< >> << INP IOP OUTP

Keyword "$" is preserved for announce of a new possible keyword when it start with "$".

Keyword "//" indicates a comment line.

Pair of keywords "///*" and "//*/" indicate a comment block.

Keyword "." is the member access notation for module or struct which have members.

Keyword ";" is used to close a clause.

Pair of keywords "{" and "}" is used to denote a clauses body for struct, module and flow.

Data type

CraneScript is a strong type language. CraneScript provides a set of basic data types and user defined data type struct. CraneScript also provides a template container array for more complex data type.

Basic number data type

Crane provides almost all basic number data type of C/C++. The basic data type can use to declare a variance, a member of struct or a port type of module.

Type length Range
char 8 bits -128~127, usally use for indicating an ASC-II character
unsigned char 8 bits 0~255
short 16 bits -32768~32767
unsigned short 16 bits 0~65535
int 32 bits -2147483648~2147483647
unsigned int 32 bits 0~4294967295
long 32/64 bits -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807(64 bits)
unsigned long 32/64 bits 0 ~ 18,446,744,073,709,551,615(64 bits)
float 32 bits single-precision float
double 64 bits double-precision float

Immediate

CraneScript accepts four types of immediate.

immediate format note
char one character included by ' ', for example: 'h', or a hexal format '\xFF' where A~F must be uppercase corresponding to a char type
string any characters included by "", for example: "hello world" corresponding to an char array
int an integer value, for example:10 corresponding to int type
double a numeric value, for example:10.1 or 123.456 corresponding to double type

struct

Keyword struct is used to indicate an user defined data type. It is a pure data structure and any member function will not be permmited. Its member type can be a basic data type or other predefined struct.

struct SExampleA{ int x,y; }; struct SExampleB{ SExampleA a,b; double c; };

array

Array is a system defined container. It has a template parameter included by pair "<" and ">" to indicate the type of data.

array<int> i_arr; array<float> f_arr; array<double> d_arr; array<char> str; array<array<unsigned char> > dataBlock;

CraneScript provides a set of system defined modules for operating an array container.

module

Module is the keyword used to declare the interface of a data processing unit. Usually, make a module work needs some input data, and when module works completely, it will product some output data. CraneScript use keyword INP to denote data input port and OUTP for output port. When a data port is IOP means the data port is a input&output port where the input data will be modified in module.

module(mdlINC){ INP<int> x; OUTP<int> y; };
module(mdlINCfilter){ IOP<int> y; };

virtual data type

CraneScript provides two kinds of virual data type number & any for defining module port type. When an INP or IOP port is declared as a number type, it means the port accept any type of basic number data from char to double. When it is any means any type can be accept. When an OUTP is declared as number type means its output data will change following input data type in the range of basic number types. An any OUTP port means the output data will be any type corresponding to the input data.

module(mdlADD){ INP<number> x0,x1; OUTP<number> y; }; module(mdlArraySize){ INP<array<any> > aX; OUTP<int> size; };

Stream operator

There are two kinds of streams in craneScript: data stream and control stream.

Data stream

A data steam is denoted by operator >>. When two ports are linked by >> means the data is transformed from left port to right port. Operator >> also can be used to link more than one ports means a broadcast data transform from the first port to others.

10 >> ADD0.x0; 9.5 >> ADD0.x1; ADD0.y >> ADD1.x0; 20 >> ADD1.x1;

The default transform type of data stream is by reference but when target port is a struct member means the data will be used to construct a new data struct where the data will be copyed from source to target.

When data transform in a reference manner, it requires both data are the same type. However when data copy emerges, data value transform from defferent types will be accepted.

Control stream

Operators > and < denote control streams used to link modules.

Operators > denotes a succuessful control stream, it works not in broadcast manner but a transfer manner means right module will run when left one is sucessful.

Operator < denotes a failed broadcast control stream means the first left module will be trigger when any one of right modules go failed.

ADD0 > ADD2; ADD1 > ADD2; ADD3 < ADD2;

Both of data stream and control stream are multi-triggered means a port or module can has multiple left trigger when one of them becomes active it will be triggered.

flow

The keyword flow is used to define a data processing procedure. To define a flow procedure needs two parameters: the first is the flow name, the second is an existing module name used to declare the flow interfaces. That is to say, when a flow is assigned a module the flow will have the same input and output ports as the module. The flow procedure should be put between a pair of "{" and "}".

flow(flowADD,mdlADD){ mdlADD ADD0,ADD1; x0 >> ADD0.x0 >> ADD1.x0; x1 >> ADD0.x1 >> ADD1.x1; ADD0.y >> y; ADD0 > ADD1; ADD1 < ADD0; };

Extension operator

In craneScript, user can write craneScript code in different craneScript files and refrence each other by the keword "#include".

#include "another.crn";

In order to provide more efficient data processing ability, craneScript supports to import exntened modules (usually written by C++) from a dynamic lib by using the keyword "import". A typical example is the lib "stdCRN" provided by craneScript. In which, craneScript defines a set of basic operators.

import(stdCRN);

When refrence an outside module the file/lib name(without extension) must be provided before module name sperated by "::", just like the usage of namespace in C++.

stdCRN::mdlSTDOUT cPrint;

Entrance of a program

In craneScript, the entrance of a program is the flow procedure which name is flwMAIN and interface is Module. The module Module is a system predefined empty module without input and output.

module(Module){}; flow(flwMAIN,Module){ ... ... };

System defined modules

CraneScript provides a set of system defined modules for basic data operating by an extended dynamic lib. The system predefined modules are collected in "stdCRN.h".

Arithmetic operation

Instead of symbolic definition explicitly in language system, Crane defines arithmetic operators as a set of relative data processing modules as following.

system module definition action
mdlADD
module(mdlADD){ INP<number> x0,x1; OUTP<number> y; };
  • y=x0+x1;
  • fail while overflow
  • mdlSUB
    module(mdlSUB){ INP<number> x0,x1; OUTP<number> y; };
  • y=x0-x1;
  • fail while overflow
  • mdlMUL
    module(mdlMUL){ INP<number> x0,x1; OUTP<number> y; };
  • y=x0*x1;
  • fail while overflow
  • mdlDIV
    module(mdlDIV){ INP<number> x0,x1; OUTP<number> y; };
  • y=x0/x1;
  • fail while x1 is 0
  • mdlINCfilter
    module(mdlINCfilter){ IOP<int> y; };
    y=y+1
    mdlINC
    module(mdlINC){ INP<int> x; OUTP<int> y; };
    y=x+1
    mdlDECfilter
    module(mdlDECfilter){ IOP<int> y; };
    y=y-1
    mdlDEC
    module(mdlDEC){ INP<int> x; OUTP<int> y; };
    y=x-1
    mdlCntDOWNfilter
    module(mdlCntDOWNfilter){ IOP<int> y; };
    when y<=0 go to failed otherwise y=y-1
    mdlCntDOWN
    module(mdlCntDOWN){ INP<int> x; OUTP<int> y; };
    when x<=0 go to failed otherwise y=x-1
    mdlMODfilter
    module(mdlMODfilter){ IOP<int> y; IOP<int> y; INP<int> x; };
    y=y mod x
    mdlMOD
    module(mdlMOD){ INP<int> x0,x1; OUTP<int> y; };
    y=x0 mod x1
    mdlString
    module(mdlString){ INP<number> x; OUTP<string> y; };
    convert number input x to string output y

    Bit operation

    The modules of bitwise operations are provided as the following.

    system module definition action
    mdlAND
    module(mdlAND){ INP<int> x0,x1; OUTP<int> y; };
  • y=x0 & x1
  • fail while y is 0
  • mdlOR
    module(mdlOR){ INP<int> x0,x1; OUTP<int> y; };
  • y=x0 | x1
  • fail while y is 0
  • mdlNOT
    module(mdlNOT){ INP<int> x; OUTP<int> y; };
  • y is bitwise nagation of x
  • mdlXOR
    module(mdlXOR){ INP<int> x; OUTP<int> y; };
  • y is XOR of x
  • Logic operation

    The modules of logic operations are defined as the following.

    system module definition action
    mdlTRUE
    module(mdlTRUE){ INP<int> i; };
    fail while x is 0
    mdlFALSE
    module(mdlFALSE){ INP<int> i; };
    fail while x is not 0
    mdlEQ
    module(mdlEQ){ INP<number> x0,x1; };
    fail while x0!=x1
    mdlGT
    module(mdlGT){ INP<number> x0,x1; };
    fail while x0<=x1
    mdlGE
    module(mdlGE){ INP<number> x0,x1; };
    fail while x0<x1

    String operation

    The modules of string operations are provided as the following.

    system module definition action
    mdlStringSize
    module(mdlStringSize){ INP<string> x; OUTP<int> size; };
  • Get the size of string x
  • mdlStringCHAR
    module(mdlStringCHAR){ INP<string> x; INP<int> idx; OUTP<char> c; };
  • get the char at position idx in string x
  • mdlStringPushfilter
    module(mdlStringPushfilter){ IOP<string> y; INP<string> sub; };
    Push string sub at end of string y
    mdlStringPush
    module(mdlStringPush){ INP<string> x; INP<string> sub; OUTP<string> y; };
    string y=x+sub
    mdlStringSub
    module(mdlStringSub){ INP<string> x; INP<int> left; INP<int> right; OUTP<string> y; };
  • output y which is substring of string x from posiiton left to right
  • mdlStringFirstCHAR
    module(mdlStringFirstCHAR){ INP<string> x; INP<int> start; INP<string> Cs; OUTP<int> y; OUTP<char> c; };
    find the first char c which is one of Cs and its position y >=start
    mdlStringLastCHAR
    module(mdlStringLastCHAR){ INP<string> x; INP<int> start; INP<string> Cs; OUTP<int> y; OUTP<char> c; };
    find the last char c which is one of Cs and its position y <=start
    mdlStringFirstSub
    module(mdlStringFirstSub){ INP<string> x; INP<int> start; INP<string> sub; OUTP<int> y; };
    find the first position y of substring sub in string x
    mdlStringLastSub
    module(mdlStringLastSub){ INP<string> x; INP<int> start; INP<string> sub; OUTP<int> y; };
    find the last position of substring sub in string x
    mdlStringReplacefilter
    module(mdlStringReplacefilter){ IOP<string> y; INP<int> left; INP<int> right; INP<string> sub; };
    replace substring of string y between left and right with sub
    mdlStringReplace
    module(mdlStringReplace){ IOP<string> x; INP<int> left; INP<int> right; INP<string> sub; OUTP<string> y; };
    replace substring of string x between left and right with sub and put the result in y
    mdlStringSplit
    module(mdlStringSplit){ INP<string> x; INP<string> SEG; OUTP<array<string> > aY; };
    split string x with string SEG and put the results into array aY
    mdlStringLink
    module(mdlStringLink){ INP<array<string> > aX; INP<string> SEG; OUTP<string> y; };
    link all strings in array aY into one string x
    mdlStringUppercasefilter
    module(mdlStringUppercasefilter){ IOP<string> y; };
    Convert all lowcase char of y to uppercase
    mdlStringUppercase
    module(mdlStringUppercase){ INP<string> x; OUTP<string> y; };
    Convert all lowcase char to uppercase in string x and put result to y
    mdlStringLowcasefilter
    module(mdlStringLowcasefilter){ IOP<string> y; };
    Convert all uppercase char of y to lowcase
    mdlStringLowcase
    module(mdlStringLowcase){ INP<string> x; OUTP<string> y; };
    Convert all uppercase char to lowcase in string x and put the result to y

    Array operation

    The modules of array operations are provided as the following.

    system module definition action
    mdlArrayINITfilter
    module(mdlArrayINITfilter){ IOP<array<any> > aX; INP<int> size; };
  • initilize array aX with assigned size
  • mdlArraySize
    module(mdlArraySize){ INP<array<any> > aX; OUTP<int> size; };
  • get the size of array aX
  • mdlArrayItem
    module(mdlArrayItem){ INP<array<any> > aX; INP<int> idx; OUTP<any> x; };
  • x=aX[idx]
  • fail while idx is out of range
  • mdlArrayInsert
    module(mdlArrayInsert){ IOP<array<any> > aX; INP<int> idx; INP<any> x; };
  • aX[i+1]=aX[i]; when i>idx
  • aX[idx]=x;
  • fail while idx<0 or idx>=size
  • mdlArrayRemove
    module(mdlArrayRemove){ IOP<array<any> > aX; INP<int> idx; };
  • aX[i]=aX[i+1] when i>=idx
  • fail while i out of range
  • mdlArrayPush
    module(mdlArrayPush){ IOP<array<any> > aX; INP<any> x; };
    insert x to the end of aX
    mdlArrayPop
    module(mdlArrayPop){ IOP<array<any> > aX; };
    remove the last item of aX

    System IO operation

    The modules for interacting with system stdin & stdout are defined as the following.

    system module definition action
    mdlSTDIN
    module(mdlSTDIN){ OUTP<string> in; };
  • read string in from stdin
  • mdlSTDOUT
    module(mdlSTDOUT){ INP<string> out; };
  • write string out to stdout
  • mdlGetCHAR
    module(mdlGetCHAR){ OUTP<char> c; };
  • read a char from stdin
  • File operation

    The modules file operations are defined as the following.

    system module definition action
    mdlFileExist
    module(mdlFileExist){ INP<string> path; OUTP<int> size; OUTP<int> isDIR; OUTP<int> READable; OUTP<int> WRITEable; };
  • Get a file size
  • Check whether the file is a dir
  • Check whether the file can be read or write
  • Fail when file not exists
  • mdlFileOpen
    module(mdlFileOpen){ INP<string> path; INP<int> Creatable; INP<int> ReadONLY; INP<int> isAppend; OUTP<long> fileHandle; OUTP<int> READable; OUTP<int> WRITEable; };
  • Open a file
  • ReadONLY: indicate the opened file whether can be write
  • Creatable: when file not exists whether can be created
  • isAppend: whether write file with an append mode
  • mdlFileClose
    module(mdlFileClose){ INP<long> fileHandle; };
  • close an opened file
  • mdlFileGetC
    module(mdlFileGetC){ INP<long> fileHandle; OUTP<char> outC; };
  • read a char outC from an opened file
  • mdlFilePutC
    module(mdlFilePutC){ INP<long> fileHandle; INP<char> inC; };
  • write a char inC to an opened file
  • mdlFileReadLine
    module(mdlFileReadLine){ INP<long> fileHandle; OUTP<string> outLINE; };
  • read a line outLINE from an opened file
  • mdlFileWriteLine
    module(mdlFileWriteLine){ INP<long> fileHandle; INP<string> inLINE; };
  • write a line inLINE to an opened file
  • mdlFileReadArray
    module(mdlFileReadArray){ INP<long> fileHandle; INP<int> n; OUTP<array<char> > aY; };
  • read n chars from an opened file
  • mdlFileWriteArray
    module(mdlFileWriteArray){ INP<long> fileHandle; INP<array<char> > aX; };
  • write chars in array aX to an opened file
  • Type operation

    In crane, sometimes user need known the exact data type of an output port declared with a virtual type. For this purpose crane provide several type operation modules.

    system module definition action
    mdlType
    module(mdlType){ INP<any> x; OUTP<string> y; };
    y is typename of x
    mdlTypeIS
    module(mdlTypeIS){ INP<any> x; INP<string> y; };
    if type of x is not y go failed
    mdlTypeEQ
    module(mdlTypeIS){ INP<any> x; INP<any> y; };
    if type of x is not equal to type of y go failed

    System modules

    Except operating module, craneScript also predefined two usually used modules.

    system module definition action
    Module
    module(Module){};
  • empty module without input & output
  • mdlCmdLine
    module(mdlCmdLine){ OUTP<array<string> > ARGs; };
  • get the command line arguments
  • mdlSystem
    module(mdlSystem){ INP<string> cmd; };
  • run a system shell command
  • mdlPopen
    module(mdlPopen){ INP<string> cmd; OUTP<string> y; };
  • run a system shell command and read its std output to y
  • mdlCACHE
    module(mdlCACHE){ INP<any> x; OUTP<any> y; };
  • directly output the input x to y without any operation
  • mdlSETfilter
    module(mdlSETfilter){ IOP<any> y; INP<any> x; };
  • y=x where data is copyed from x to y
  • The above is the smallest necessary module defininitions embeded in interpreter. Find more modules in download.

    Programming with craneScript

    CraneScript has no definition of flow control keywords such as "if", "else", "switch", "for", "while", "until", and so on. The flow control in craneScript is archieved in two ways: data stream and control stream.

    Data stream

    Data stream is a data-driven flow control machnism. It works in a hidden way.

    When a module run sucessful, it will launch its output data to the following module.

    When all input data of the following module go ready it will be put into scheduling queue.

    Specially, at the beginning of program, the modules without any input data will first put into scheduling queue.

    Inversely, when a module went failed it will not launch any output data which implys the modules depending its output will lost chance to be scheduled.

    This is the data-driven machnism of craneScript.

    import(stdCRN); flow(flwMAIN,Module){ stdCRN::mdlSTDOUT p; stdCRN::mdlStringPush str0,str1,str2; "A" >> str0.x; "B" >> str1.x; "C" >> str2.x; "x\n" >> str0.sub; str0.y >> str1.sub >> p.out; str1.y >> str2.sub >> p.out; str2.y >> p.out; };

    The output of this code is:

    Ax

    BAx

    CBAx

    Control stream

    Control stream is the another way of flow control in craneScript. It is an obervious, user directly defined runing order of modules.

    import(stdCRN); flow(flwMAIN,Module){ stdCRN::mdlSTDOUT p0,p1,p2; "A" >> p0.out; "B" >> p1.out; "C" >> p2.out;
    p2 > p1 > p0; };

    If without control stream code line 7, the output of this will be:

    ABC

    , otherwise the output is:

    CBA

    Data relaunch

    In some scenes some data usually need to be relaunched to trigger its following modules repeatly. Module 'mdlCACHE' is the system defined module for such situation which only cache the input data and can be trigger by an arbitrary module in control stream.

    import(stdCRN); flow(flwMAIN,Module) { stdCRN::mdlCACHE c0, c1, c2; "line:" >> c0.x; "\n" >> c2.x;
    stdCRN::mdlString str; str.y >> c1.x;
    stdCRN::mdlGT loopEND; 5 >> loopEND.x;
    stdCRN::mdlINC inc; 0 >> inc.x; inc.y >> loopEND.y >> inc.x >> str.x;
    stdCRN::mdlSTDOUT p; c0.y >> p.out; c1.y >> p.out; c2.y >> p.out;
    Module START;
    START > inc > loopEND > str > c0 > c1 > c2 > inc; };

    In this code, use mdlCACHE c0,c1 to repeat lanuch data, and c0,c1,c2 to control the data trigger order to STDOUT p, the output of this code is:

    line: 1

    line: 2

    line: 3

    line: 4

    Q & A

    Due to the limited level, there are inadequate, any question or suggestion please let us known.

    Copyright © 2022-2024 All Rights Reserved.
    Contact: fengzhui.LIN@qq.com