Embeddable Scripting LAnguage (ESLA)
Rev 1.0.0-20030319

ESLA is a very simple scripting language that can be embedded within C++ applications. It comprises a set of global actions, such as for loop, conditional tests, and encapsulate the notion of namespace. The addition of namespace allows the wrapping of different actions specialized for a numerical code or other applications.
For this language, there’s no byte code produced, nor compilation. Sentences are executed as they are read.

1.	General comments:
•	In the following, 
[] means 'optional'
/ means 'or'
	
•	Always declare a variable before using it. Exception for the for/end loop

•	This scripting language uses namespaces to avoid conflict between wrapped numerical code (NC).
For example, the Poly3d NC uses the "poly3d" namespace, whereas the Poly3Dinv NC uses "poly3dinv"
You must write the action's name after its corresponding namespace, separated by a ‘.’ (point). Programmers can use as many namespaces as they want. A namespace can be comprise into a namepsace.
The general syntax is:
	namespace.action arguments
Example: 
poly3dinv.load test.txt
poly3d.load test.txt
In this example, the load actions are totally different, and refer to their appropriate namespace.

•	Comments for a single line are:
	#
	%
You can put comment on a new line, or after an expression.
Example:
	% This a comment in a new line
	# And this one as well
set $a 10 %this comment is working

•	To comment a bloc, use the following syntax:
	/*
	...
	*/
Example:
	/*
	This a comment ...
	... in multi-lines
	*/

•	This language uses local variable definition. Which means that variable declare inside function, loop, if statement etc, are local to where they are declared. The same principle applies for functions inside a function.

•	To print all actions inside the language, execute a script with the following single line:
	print_actions

2.	SET
	set $varName [value]
To declare a variable or change its value.
The value is optional, and if omitted, varName is initialized with 0.
To initialize a variable as an empty string, use the following declaration:
	set $varName “”

3.	To get the value of a previously declared variable:
	$(varName)

4.	= operator
•	set $varName newValue
•	$varName  = newValue
This keyword allows you to affect a new value for a variable.
Note 1: When you want to use the value of the variable, use $(varName)

5.	Passing a variable as a one-value:
Sometime it is interesting to pass to a function a value in one string, even if the value represents several tokens. For example, imagine a user function taking only one argument. If you declare a variable, which is a list of values separated by spaces and/or tabulations, and pass it to the function, you will have an error message because the variable name is replaced by its value (several values in that case), and is considered as several variables.
To overcome this problem, you can use the following syntax:
“$(list)” 	instead of 		$list

Example:
function display $a
	forall $i in $a
		println $i
	end
end

set $list 1 2 3 8 9 10
% The following will produce an error
display $list
% The following will work
display “$(list)”

In this example, the syntax “$(list)” (with quotes) forces the interpreter to replace the variable name by its value before the function is called. The quotes are important, because they tell the interpreter to consider the replaced value with a one-string value (“1 2 3 9 9 10”), instead of many values (1, 2, 3, 8, 9 and 10). The forall action takes care of this situation.

6.	Bloc definition ‘{’ and ‘}’
You can define local bloc definition by using ‘{’ and ‘}’. Variables and functions that are declared within a bloc are local and cannot be access outside. This can be useful to avoid definition of global variables when not needed.

Example:
{
	set $a 10
	set $b 20
	function test
		println $a $b
	end

	test
}
% The following doesn’t work
test
println $a

7.	FOR
•	for $varName = startValue : endValue
...
end
•	for $varName = startValue : stepValue : endValue
...
 end

Inside a for loop, you can use the following keyword to escape or skip a part of the code:
•	To escape from a loop:
break
•	To skip the rest of the code in the loop
	continue
	
Example:
	for $i=1:2:100
	  if $i=5
	    continue
	  end
	  println $(i)
	  if $i>=9
	    break
		end
	end

Calling this function should gives:
	1
	3
	7
	9

8.	FORALL
•	forall $varName in $(listName)
...
end

Inside a for loop, you can use the following keyword to escape or skip a part of the code:
•	To escape from a loop:
break
•	To skip the rest of the code in the loop
	continue
	
Example:
	set $list 10 32 573 999 
forall $i in $(list)
	  println $(i)
	end

Calling this function should gives:
	10
	32
	573
	999

9.	WHILE
	while expression
...
end

Inside a while loop, you can use the following keyword to escape or skip a part of the code:
•	To escape from a loop:
break
•	To skip the rest of the code in the loop
	continue
	
Example:
set $i 0
while $(i)<100
set $a cos($(i)/10)
  		println $(a)
  		inc $i
		if $(i)>10
			break
		end
end

10.	DO/WHILE
	do
...
while expression

Inside a do loop, you can use the following keyword to escape or skip a part of the code:
•	To escape from a loop: 
break
•	To skip the rest of the code in the loop
	continue
	
Example:
set $i 0
do
set $a cos($(i)/10)
  		println $(a)
  		inc $i
while $(i)<=10

11.	INC
This keyword is used to increment a vriable.
•	inc $varName [valueIncrement]
	If no value increment is supplied, varName is incremented by one.

•	$varName = $(varName) + valueIncrement

12.	IF
 - Available comparison operators (CO) are:  = != > < >= <=
Comparison operators = and != are working for string as well.
 - Available logical operators (LO) are: & |

	if value CO value   LO  value CO value ...
	  ...
	else
	  ...
	end

Examples:
	if $(a)=3 & $(b)!=2
		...
	end
	if $(a)=3 | $(a)=2
		...
	end

13.	TRY/CATCH
try
	  ...
	catch
	  ...
	end

Useful to catch errors and continue the execution of the script. When inside a try/catch block, error messages are disable. When an error is catch, the catch/end is executed. Indeed, you can use try/catch definitions inside a try/catch.

Example:
	try
		% Should failed because $a is undefined
		$a = 0
		% The following 3 lines will not execute
		for $i=0:100
			println $(i)
		end
	catch
		println Catching an error
	end
	println Can continue the rest of the script

14.	SWITCH
switch $(varName)
	case val11 val12 ...
		% your code
	end
	case val21 val22 ...
		% your code
	end
	.
	.
	.
	% The default keyword is optional
	default
		% your code
	end
end

Example:
set $i
prompt $i
switch $i
	case 1 3 5 7 9
	  		println Case 1
		end
	case 0 2 4 6 8
	  		println Case 2
		end
		default
			println Default
		end
	end 

15.	FUNCTION
	function fctName $var1 $var2 ....
	...
	end

Note 1: You can create functions inside functions.
Note 2: This is your responsibility to change the value of the passed arguments. Every passed variable can be changed.
Note 3: Functions are recursive.

Example:
	function sum $a $b $c
	  $c = $(a) + $(b)
	end

	set $var1 10
	set $result 0
	% Should change ‘result’ value to 10 + 5 = 15
	sum $(var1) 5 $(result)

16.	CALL
If you want to call a function, not directly by its name, but instead by a name stored into a variable, you can use the call action.
	call fctName arguments

Example:
function test1
	  println TEST 1
	end

function test2
	  println TEST 2
	end

	set $c
	print “Enter the name of the function to call: “
	prompt $c
	call $(c)

In this example, the user is prompt to enter the name of the function to call, and the parser call it (if exist).

17.	INCLUDE
	include filename
Useful if you have your functions saved into a specific file, and want to use it in several other source files.

Example:
	include my_algo.src
	...
	my_algo $i
	...

18.	TIMER
•	To start the timer
	timer_start
•	To stop the timer
	timer_stop
•	To display the elapsed time
	timer_display
•	To write the elapsed time in the variable varName
	timer_get $varName
Example:
	set $time 0
	set $ttime
	for $i=1:200
	  timer_start
	  ...
	  % your algorithm here
	  ...
	  timer_stop
	  timer_set $ttime
		println Inner elapsed time: $(ttime)
	  inc $time $(ttime)
	end

	println Total elapsed time: $(time)

19.	PRINT/PRINTLN
•	To print with a carriage return:
	println expression...
•	To print with no carriage return:
	print expression...
•	To print a formatted string, use quotes. The parser will use the quoted string as it is, replacing variable by their value, but preserving the word spacing and tabulation.
	print “string expression with variables” expression...

20.	PROMPT
	prompt $varName

21.	EXIT
exit

22.	RAND
rand $varName
Generate a random number between 0 and 1.
23.	HELP
help functionName
To have help onto an action or a a user function.

24.	EXEC
exec commandLine
To execute a line by line command interpreter.

25.	OPEN
open $(filename)
To open a file for writing.
Example:
	set $log log.txt	
open $(log)

26.	CLOSE
close $(filename)
To close an opened file.
Example:
	set $log log.txt	
open $(log)
...
close $(log)

27.	WRITE
write $(filename) expression
To write into an opened file.
Example:
	set $log log.txt
set $a 12.8765
set $b hello
open $(log)
write $(log) “This’s a test,    $(b) with $(a)”
write $(log) This’s a test,    $(b) with $(a)
close $(log)

28.	Manipulating Tokens
You can easily manipulate tokens of a sentence.
•	To get the number of token from a variable value or directly from a string expression:
	token_size $nbr expression/$(var)

Example:
	set $line “coucou c’est juste un test”
	set $nbr
token_size $nbr $(line)
println The number of tokens is $(nbr)

token_size $nbr “Here, we don’t use variable”
println The number of tokens is $(nbr)

•	To get the token at a specific position :
	get_token $token index/$(index) expression/$(expression)
The token value will be place into the $token variable.

Example:
	set $line “coucou c’est juste un test”
	set $nbr
	set $token
token_size $nbr $(line)

% Get the first token
get_token $token 1 $(line)
	println The first token is [$(token)]

% Get the last token
get_token $token $(nbr) $(line)
	println The last token is [$(token)]

	% Print all tokens
	for $i=1:S(nbr)
		get_token $token $(i) $(s)
		print [$(token)]
	end

println

•	To tokenize an expression given the token seperators
tokenize $result “char-Separators” expression/$(expression)

Example:
	set $line “coucou c’est juste un test”
	set $result

	% Use the space and characters‘e’ and ‘u’ as token separator.
	tokenize $result “ eu” $(line)
	println “INIT : $(line)”
	println “FINAL: $(result)”

Developer Guide 
This short chapter explains briefly how to wrap new actions, and specifically for the case of a numerical code and a graphical interface.

a)	Define your namespace
class Poly3DNamespace: public GenAction {
public:
	Poly3DNamespace() ;
static void init() ;
// Here, we define a poly3d namespace
  	virtual std::string name_space() const {return “poly3d”;}
} ;

Then, you can derive all actions, relative to the Poly3D numerical code, from this class.

b)	Wrap your new actions. Here, we want to open a file for the Poly3D numerical code:

// INTERFACE
class LoadInputAction: public Poly3DNamespace {
public:
	// Methods to be overridden
  		virtual RET_TYPE set_parameters(IfStream*, const std::string& params) ;
  		virtual RET_TYPE execute() ;
  		virtual std::string args() const ;
  		virtual std::string command_name() const ;
private:
  		std::string file_ ;
} ;
DECLARE_SMART_OBJECT(LoadInputAction) ;

	// IMPLEMENTATION
RET_TYPE LoadInputAction::set_parameters(IfStream* isf, const std::string& params) {
	// VERY IMPORTANT TO DO IT AT THE BEGENNING
  		set_ifstream(isf) ;

  		if(params.size()==0) {
    		send_error("Bad arguments for \""+command_name()+"\".") ;
    		return RT_FAIL ;
  		}
  		file_ = params ;
  		return RT_OK ;
}

std::string LoadInputAction::args() const {
  		return "inputFileName" ;
}

std::string LoadInputAction::command_name() const {
  		return "load_input" ;
}

RET_TYPE LoadInputAction::execute() {
  		std::string s ;
		// Parse the filename to replace the variables by their value.
  		if (!parse(file_,s)) {
    		send_error("Error: cannot parse \""+file_+"\".") ;
    		return RT_FAIL ;
  		}
		// Remove the spaces at the ends
  		s = trim_ends(s) ;
  		message("Loading \"" + s + "\" ...") ;

  		// Load your input file here...
		...
  		message("done.") ;
  		return RT_OK ;
}

c)	If your actions are already defined inside your own library, you can create a generic wrapper to those actions. 

Suppose that you designed a graphical interface, with a bunch of actions (with undo and redo capabilities). 

// Interface for an action within the GUI
class GenGUIAction : public GenGUIObject {
  	public:
		virtual bool Do() = 0 ;
		virtual bool Undo() = 0 ;
		virtual bool set_parameters(const std::string&) = 0 ;
} ;
DECLARE_SMART_OBJECT(GenGUIAction) ;

Suppose that your actions are called from a Model, with the following interface

// Interface for the GUI model
class Model {
  	public:
		bool execute(GenGUIAction*) ;
		bool undo(int nbr) ;
		bool redo(int nbr) ;
} ;

Suppose that your actions are registered inside a library
class ActionLibrary {
  	public:
		static bool bind(GenGUIAction *, const std::string& name) ;
		static GenGUIAction * resolve(const std::string& name) ;
		...
	private:
		...
} ;

Then, you can wrap all actions in once:

// Wrapper to the Model, because we can have several models defined.
class ModelWrapper {
public:
	static Model* model() {return model_ ;}
  		static void set_model(Model* model) {assert(m) ;model_ = m ;}
private:
		static Model_var model_ ;
} ;
Model* ModelWrapper::model_ = NULL ;

	// Definition of the action
// INTERFACE
class WGUIAction: public GenAction {
public:
  		virtual RET_TYPE set_parameters(IfStream*, const std::string& params) ;
  		virtual RET_TYPE execute() ;
  		virtual std::string args() const {return “actionName args” ;}
  		virtual std::string command_name() const {return “gui” ;}
private:
		std::string args_ ;
} ;
DECLARE_SMART_OBJECT(WGUIAction) ;

// IMPLEMENTATION
RET_TYPE WGUIAction::set_parameters(IfStream* isf, const std::string& params) {
		set_ifstream(isf) ;
  		if (params.size()==0) {
    		send_error("Bad arguments for \""+command_name()+"\".") ;
  			return RT_FAIL ;
  		}
		args_ = params ;
  		return RT_OK ;
}

RET_TYPE WGUIAction::execute() {
	// Check that there is a model already set
	if (!ModelWrapper::model()) {
		send_error(“Model not set!”) ;
		return RT_FAIL ;
	}

	// Tokenize params to get the action’s name and the args
		Tokens toks ;
		if (tokenize(params, toks, “ \t”, false)==RT_FAIL)
			return RT_FAIL ;
		if (toks.size()<1)
			return RT_FAIL ;

		// Action’s name if the first token
  		std::string action_name = toks[0] ;

		// The rest are arguments
		std::string targs = linearize(toks, 1) ;

// Parse the arguments to replace variables by their value
std::string args ;
		if (!parse(targs,args))
			return RT_FAIL ;

		// Get the action
		GenGUIAction* action = ActionLibrary::resolve(action_name) ;
		if (!action)
			return RT_FAIL ;

		// Set the parameters
		if (!action->set_parameter(args))
			return RT_FAIL ;

		// Register the action within the model (it will do the action)
		if (!ModelWrapper::model()->execute(action))
			return RT_FAIL ;

  		return RT_OK ;
}