SimpleScript – Simple structure
SimpleScript allows programming in Java in a simple way. In this post, I will explain more about the structure of a script.
SimpleScript was designed to do many things. Executing Java script files is just one of the features. You can use SS to write other executables (functions, macros, scripts and main) but since I only showed you how to write main executable, this article will only focus on parts of structure that are relevant to main.
What is main, anyway?
main is a kind of executables that will be executed as a standalone program. Think of it as that the code is translated to main function of a class. This means that main has no return type and have one parameter final String ... $Args which you can access it directly.
Structure of main
The main script can be separated into seven sections. One of which are mandatory and two more are not mandatory but you almost always needed them. These sections MUST be in the given SPECIFIC ORDER as show in the table below or the script won’t compile.
| Ignored | Lines of text that are ignored by SimpleScript |
| Signature | Signature of this executable |
| Imports | Import statements |
| Elements | Variables and functions |
| Annotations | Annotations for the code |
| Code | The program code |
| Compiled Code | Text representation of the compiled program code for faster load |
Ignored
All lines of text at the beginning of the script file that starts with ‘#‘ or ends with ‘##‘ are ignored by SimpleScript. This section is there for two reasons: 1) to enable Linux/Unix shebang, and 2) to allow users to add comments about the script at the beginning of the script file (even before the required Signature section).
Linux/Unix shebang of a script file always starts with ‘#!‘ so this line will be ignored by SS. So by having any line that starts with ‘#‘ to be ignored allows SS script code to have shebang line.
For the second case, marking comments at the end of a line makes it possible for user to use any text structure at the beginning of the line just in case they want to do parsing later on.
Also note that, the ignored section MUST not contains any non-ignored line including an empty or a whitespace line.
Example of Ignored
The followings are some examples of ignored text:
# This line will be ignored. # This line will also be ignored. This line will also be ignored. ## # But this like will not be. Neither is this line ##
Signature
Signature is a one line section. It is the only required section. It tells SS about the engine for this script (engine signature) and the signature of this executable (executable signature).
The line can starts with anything. SS will ignore anything until it finds the character ‘@‘. After that an engine signature must be presented. The engine signature must ends with a colon. After the colon, the executable signature may be presented.
Engine signature
Engine signature tells SS what script engine to be used. The signature is in the following format:
[Ignored]@<Engine-Name>[(engine-parameter)]:
The following regular expression is used to parse the engine signature.
\n*[^@\n]*@([a-zA-Z][a-zA-Z0-9]*(\\.[a-zA-Z][a-zA-Z0-9]*)*)(\\([^\\)\\n]+\\)|\\(\\))?: ^-^^-----^^^----------------------------------------------^^------------------------^^ | || ||+---------------- Engine name -----------------++--- Engine Parameter ---+| | || |+== Signature begin End colon ==+ | |+-----+=== Ignored prefix +-+========== Ignored empty lines
The ignored prefix allows any text to be put in the front of the signature. This is because the signature line will be included in to the final code. The user will likely to need to make this line a comment. In case of Java (as seen in all example scripts), the new line comment marker ‘//‘ is used.
Executable signature
Executable signature defines the interface of the executable this script is implementing. As briefly mentioned, SS supports four kinds of executables: functions, macros, scripts and main. Functions and Macros are executables with customizable parameters and return type. Script are executable without parameters nor return type. main is a special function that return void and have an array of string as a parameter.
Executable signature is specified just after the engine signature and within a pair curl brackets. If no executable signature is specified, main will be used. The executable signature will be discuss in more detail later when functions and macros are discussed. For now, we only talk about main.
Examples of Signature
// @Java: { main }
or
// @Java:
are both main for a script in Java.
Imports
Import section contains a set of import statements. The section is identified by the keyword "import" immediately follows by at least one whitespace. Comments and whitespaces are allowed between import statements just like in Java. In fact, the whole chunk of the section will be used as is in the translated code. Therefore, it is subject to the semantic checking by Java compiler.
Example of Imports
The following is a valid Imports section.
import java.io.*; import static java.lang.Math.PI; import java.util.Vector;
Elements
"Everything in Java is object," I bet that you have heard this quote. Although it is not perfectly correct by it is very close. Almost everything in Java is object. Thus, a SimpleScript executable is also an object. As an object, an executable can have elements just like other objects. The elements can be fields or methods. They can also be static. They can have public, private, protected or package accessibility (although this does not seems to matter as they make no different). They can also be final (again, no different).
Since there is no class structure in script files, SimpleScript identifies elements section by checking the position and keywords. After SS identify the imports, it looks for a valid Java statements which either ends with ';' or a body '{'...'}'. If SS finds a statement, it checks if the beginning word is one of the following: static, public, private or protected as these keywords are only used for elements. Then it looks for more elements until no more element is found.
Script writers can create functions (methods) to be used with in the script either as sub-routine or as a mean to document a part of the code. Since these functions will not likely to be called from any other piece of code (except through reflection), it does not make any difference what its accessibility and modifier are. However, script writer may choose to make a function non static if it is needed to access to pre-defined elements which are non-static.
By default, an executable is created (or loaded) once and may be executed more than one time. Because of this nature, it makes almost no difference if a field should be static or non-static with only one exception that is if the field is to be accessed by static functions, it cannot be non-static. Generally, fields have two uses in script: 1) to hold constants and 2) to hold cached values.
Examples of Elements
// Use private as an indicator that this is a field and not a regular variable as part of the code. private int non_static_field = 0; // It does not matter private or public, they just indications for elements. public int non_static_field2 = 5; // This is for a constant static final int static_field = 10; // This is for a complex constant static final Vectorints = new Vector (); static { ints.add(5); ints.add(10); } // function as documentation private String[] getFileList(final String $PathName) { // Get file list and return return ...; } // function as subroutine (in this case for, for recursive) private int factorial(int I) { // Find factorial and return return ...; } // An annotation for functions must be put after the indicator. private @annotate int getInt() { } // You can even create a class static class Task1 implements Runnable { // implements Runnable }
Annotations
This section allows script writers to declare annotation for the code. Annotation such as '@SuppressWarnings('...')' is needed to hide certain compilation warnings. Other annotation such as '@Test' may also be used.
Examples of Annotations
// @Java:
import java.util.*;
// Tell compiler to produce no warning about unchecked generic-type
@SuppressWarnings("unchecked")
// A warning should be generated here but it is suppressed
final Class C = this.getClass();
System.out.println(C);
Code
This section is where the actions are. SimpleScript recognizes this section simply by checking if it is not an import, an element, an annotation nor a compiled code. The text in this section will be put into a body of a method in its entirety. In other words, writing this section is like writing a body of a method -- a non-static method to be precise.
Since this part of code is copied to the final code without any modification and it is compiled directly by the Java compiler, you can be sure that the code will be 100% Java compatible. Everything that can be done in a Java method can be done here. This includes things like calling other classes' methods to creating inner classes. So, bring it on.
Compiled Code
This section of the code is not to be written but rather generated by SimpleScript. It contains a text representation of the compiled code. Information provided here is used when the code the is executed. Starting by checking of the compiled code is synchronized with the code. This is done by checking the hash and the length of both the code and the compiled code. If hash or length of either ones changed, the code will be recompiled.
Compiled code section will always three empty lines away from the last line of the code and it always with in a long comment block. SS starts parsing by looks at the last two lines after the last line finding "##:HASHES" and "##:COUNT". Using count, SS can locate the beginning of the compile code. It is, then, looks for "##:COMPILED" that the beginning. At this point, SS can separate the code from the compiled code and checking hashes can commence. If the checking is success, the compiled code will be obtained by converting from its Base64 and loaded as a serializable object. Casted and wrapped, it is then a ready to be used as an executable object.
Of course, you don't need to care about all this if you are just using SS for scripting (not modifying nor writing a script engine for it). The importance here is that when a script is first run, its code is compiled and the resulted byte code will be recorded at the end of the script. If the byte code can't be saved or the script file content has changed, the code will be recompiled again in the next run.
An implication for this is that, there is a performance overload for loading a script and a little bit for invoking it (parameter handling) but there is absolutely no performance different between code written with script or a regular Java code when the code is actually running.
Put all of these together
Let see the code that has every section. Just to remind that the last section is generated by SimpleScript and script writers does not need to write it.
#!/usr/bin/ss --run
# This line will be ignored as it starts with "#"
This line will be ignored as it ends with "##" ##
This line will be also ignored as it also ends with "##" ##
# The line is the signature
// @Java:
// Imports
import java.io.*;
import java.util.*;
// Elements
static int I = 0;
private int factorial(int $I) {
return ($I <= 1) ? 1 : $I * factorial($I - 1);
}
// Annotations
@SuppressWarnings("unchecked");
// The program start here
System.out.println("Hello World!!!");
System.out.println();
System.out.println("Main Args = " + Arrays.toString($Args)); // Access Args
System.out.println();
System.out.println("static int I = " + I);
System.out.println();
System.out.println("Working Dir: " + (new File(".")).getAbsolutePath());
System.out.println();
final Class C = this.getClass();
System.out.println("This class: " + C.getCanonicalName());
System.out.println();
System.out.println("Factorial using local method");
for(int i = 0; i < 10; i++)
System.out.println(i+"! = " + factorial(i));
System.out.println();
System.out.println("DONE!!!");
/*******************************************************************************
##:COMPILED::BASE64 {
rO0ABXcmACJuZXQubmF3YW1hbi5zY3JpcHQuamF2YS5KYXZhRW5naW5lAAB1cgACW0Ks8xf4BghU
4AIAAHhwAAAPvqztAAV3GQAKSkNPLU5FRURFRAADSkNPAAAAZAAAAAF1cgACW0Ks8xf4BghU4AIA
AHhwAAAM36ztAAVzcgAibmV0Lm5hd2FtYW4uamF2YWNvbXBpbGVyLkNsYXNzRGF0YVFeHaOMW6kD
AgAGWwAFYnl0ZXN0AAJbQkwABGNvZGV0ABJMamF2YS9sYW5nL1N0cmluZztbAA9lbmNsb3NlZENs
YXNzZXN0ACVbTG5ldC9uYXdhbWFuL2phdmFjb21waWxlci9DbGFzc0RhdGE7TAAOZW5jbG9zaW5n
Q2xhc3N0ACRMbmV0L25hd2FtYW4vamF2YWNvbXBpbGVyL0NsYXNzRGF0YTtMAARuYW1lcQB+AAJM
AARwYXRocQB+AAJ4cHVyAAJbQqzzF/gGCFTgAgAAeHAAAAuHyv66vgAAADIAkgoAJgBKCQAlAEsJ
ACUATAgATQkATgBPCgAlAFAKAE4AUQoATgBSCgAlAFMKACUAVAoAJQBVBwBWCQBXAFgIAFkKAFoA
WwoAWgBcBwBdCgARAEoIAF4KABEAXwoAYABhCgARAGIIAGMJACUAZAoAEQBlCABmBwBnCABoCgAb
AGkKABsAagoAJgBrCABsCgBtAG4IAG8IAHAIAHEHAHIHAHMHAHQHAHYBAAUkQ29kZQEAEkxqYXZh
L2xhbmcvU3RyaW5nOwEACiRTaWduYXR1cmUBAB5MbmV0L25hd2FtYW4vc2NyaXB0L1NpZ25hdHVy
ZTsBAAFJAQAGPGluaXQ+AQBNKExuZXQvbmF3YW1hbi9zY3JpcHQvU2lnbmF0dXJlO0xqYXZhL2xh
bmcvU3RyaW5nO0xuZXQvbmF3YW1hbi9zY3JpcHQvU2NvcGU7KVYBAARDb2RlAQAPTGluZU51bWJl
clRhYmxlAQANZ2V0RW5naW5lTmFtZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAJZ2V0RW5naW5l
AQAjKClMbmV0L25hd2FtYW4vc2NyaXB0L1NjcmlwdEVuZ2luZTsBAAdnZXRDb2RlAQAMZ2V0U2ln
bmF0dXJlAQAgKClMbmV0L25hd2FtYW4vc2NyaXB0L1NpZ25hdHVyZTsBAAlmYWN0b3JpYWwBAAQo
SSlJAQANU3RhY2tNYXBUYWJsZQEABSRTZWxmAQAWKFtMamF2YS9sYW5nL09iamVjdDspVgEAA3J1
bgcAeAEABlNpbXBsZQEADElubmVyQ2xhc3NlcwEASShMbmV0L25hd2FtYW4vc2NyaXB0L0Z1bmN0
aW9uJFNpbXBsZTtbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvVm9pZDsBADsoSUxuZXQv
bmF3YW1hbi9zY3JpcHQvRnVuY3Rpb24kU2ltcGxlO1tMamF2YS9sYW5nL09iamVjdDspVgcAeQEA
SyhMbmV0L25hd2FtYW4vc2NyaXB0L0Z1bmN0aW9uJFNpbXBsZTtbTGphdmEvbGFuZy9PYmplY3Q7
KUxqYXZhL2xhbmcvT2JqZWN0OwEACDxjbGluaXQ+AQADKClWAQAKU291cmNlRmlsZQEAOG5ldC5u
YXdhbWFuLmphdmFjb21waWxlci5KYXZhQ29kZU1lbW9yeUZpbGVPYmplY3RAZDBhZjliDAAuAEcM
ACsALAwAKQAqAQAESmF2YQcAegwAewB8DAAyADMMAH0AfgwAfwCADAA5ADoMAD4AQgwAPgBDAQAT
W0xqYXZhL2xhbmcvU3RyaW5nOwcAgQwAggCDAQAOSGVsbG8gV29ybGQhISEHAIQMAIUAhgwAhQBH
AQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIBAAxNYWluIEFyZ3MgPSAMAIcAiAcAiQwAigCLDACK
ADMBAA9zdGF0aWMgaW50IEkgPSAMAC0ALQwAhwCMAQANV29ya2luZyBEaXI6IAEADGphdmEvaW8v
RmlsZQEAAS4MAC4AhgwAjQAzDACOAI8BAAxUaGlzIGNsYXNzOiAHAHkMAJAAMwEAHEZhY3Rvcmlh
bCB1c2luZyBsb2NhbCBtZXRob2QBAAQhID0gAQAHRE9ORSEhIQEAD21haW5fMTMwNTgyMjEwOQEA
EGphdmEvbGFuZy9PYmplY3QBACduZXQvbmF3YW1hbi9zY3JpcHQvRnVuY3Rpb24kU2ltcGxlJEJv
ZHkBAARCb2R5AQAUamF2YS9pby9TZXJpYWxpemFibGUHAJEBACJuZXQvbmF3YW1hbi9zY3JpcHQv
RnVuY3Rpb24kU2ltcGxlAQAPamF2YS9sYW5nL0NsYXNzAQAgbmV0L25hd2FtYW4vc2NyaXB0L1Nj
cmlwdE1hbmFnZXIBAAhJbnN0YW5jZQEAIkxuZXQvbmF3YW1hbi9zY3JpcHQvU2NyaXB0TWFuYWdl
cjsBABhnZXRFbmdpbmVDbGFzc05hbWVCeU5hbWUBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZh
L2xhbmcvU3RyaW5nOwEAEmdldERlZmF1bHRFbmdpbmVPZgEANShMamF2YS9sYW5nL1N0cmluZzsp
TG5ldC9uYXdhbWFuL3NjcmlwdC9TY3JpcHRFbmdpbmU7AQAQamF2YS9sYW5nL1N5c3RlbQEAA291
dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxu
AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylM
amF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAQamF2YS91dGlsL0FycmF5cwEACHRvU3RyaW5nAQAn
KFtMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9TdHJpbmc7AQAcKEkpTGphdmEvbGFuZy9T
dHJpbmdCdWlsZGVyOwEAD2dldEFic29sdXRlUGF0aAEACGdldENsYXNzAQATKClMamF2YS9sYW5n
L0NsYXNzOwEAEGdldENhbm9uaWNhbE5hbWUBABtuZXQvbmF3YW1hbi9zY3JpcHQvRnVuY3Rpb24A
IQAlACYAAgAnACgAAwAQACkAKgAAABAAKwAsAAAACAAtAC0AAAALAAEALgAvAAEAMAAAACcAAgAE
AAAADyq3AAEqK7UAAiostQADsQAAAAEAMQAAAAYAAQAAAAoAAQAyADMAAQAwAAAAGwABAAEAAAAD
EgSwAAAAAQAxAAAABgABAAAACgABADQANQABADAAAAAmAAIAAQAAAA6yAAUqtgAGuAAHtgAIsAAA
AAEAMQAAAAYAAQAAAAoAAQA2ADMAAQAwAAAAHQABAAEAAAAFKrQAA7AAAAABADEAAAAGAAEAAAAK
AAEANwA4AAEAMAAAAB0AAQABAAAABSq0AAKwAAAAAQAxAAAABgABAAAACgACADkAOgABADAAAAA2
AAQAAgAAABMbBKMABwSnAAwbKhsEZLcACWisAAAAAgAxAAAABgABAAAADwA7AAAABQACCUgBAIIA
PAA9AAEAMAAAACAAAwACAAAACCoBK7YAClexAAAAAQAxAAAABgABAAAAEACBAD4AQgABADAAAAAh
AAQAAwAAAAkqAysstgALAbAAAAABADEAAAAGAAEAAAAQAIEAPgBDAAEAMAAAAW8ABQAHAAAA+i0D
MsAADMAADDoEsgANEg62AA+yAA22ABCyAA27ABFZtwASEhO2ABQZBLgAFbYAFLYAFrYAD7IADbYA
ELIADbsAEVm3ABISF7YAFLIAGLYAGbYAFrYAD7IADbYAELIADbsAEVm3ABISGrYAFLsAG1kSHLcA
HbYAHrYAFLYAFrYAD7IADbYAECq2AB86BbIADbsAEVm3ABISILYAFBkFtgAhtgAUtgAWtgAPsgAN
tgAQsgANEiK2AA8DNgYVBhAKogAssgANuwARWbcAEhUGtgAZEiO2ABQqFQa3AAm2ABm2ABa2AA+E
BgGn/9OyAA22ABCyAA0SJLYAD7EAAAACADEAAABOABMAAAATAAsAFgATABcAGQAZADYAGgA8ABwA
VwAdAF0AHwCBACAAhwAiAI0AIwCqACQAsAAmALgAJwDCACgA5QAnAOsAKQDxACsA+QAuADsAAAAP
AAL+ALsHAAwHAEQB+gAvEEEAPgBFAAEAMAAAAB8AAwADAAAAByorLLYACrAAAAABADEAAAAGAAEA
AAAKAAgARgBHAAEAMAAAAB0AAQAAAAAABQOzABixAAAAAQAxAAAABgABAAAADQACAEgAAAACAEkA
QQAAABIAAgA/AHcAQAAJACcAPwB1BglwdXIAJVtMbmV0Lm5hd2FtYW4uamF2YWNvbXBpbGVyLkNs
YXNzRGF0YTtNrZe+1EeILwIAAHhwAAAAAHB0ABVtYWluXzEzMDU4MjIxMDkuY2xhc3N0AAB1cQB+
AAAAAAKfrO0ABXNyACRuZXQubmF3YW1hbi5zY3JpcHQuamF2YS5KYXZhRnVuY3Rpb274Eu8wtf3r
NQMAAHhyACJuZXQubmF3YW1hbi5zY3JpcHQuRnVuY3Rpb24kU2ltcGxlCAyTcwOU3z4CAAJMAAdG
VkluZm9zdAAoTG5ldC9uYXdhbWFuL3NjcmlwdC9Gcm96ZW5WYXJpYWJsZUluZm9zO1sAClBhcmFt
TmFtZXN0ABNbTGphdmEvbGFuZy9TdHJpbmc7eHBzcgAmbmV0Lm5hd2FtYW4uc2NyaXB0LkZyb3pl
blZhcmlhYmxlSW5mb3NDjm+xSyvbpwIAAHhwdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17
RwIAAHhwAAAAAXQABSRBcmdzc3IAD21haW5fMTMwNTgyMjEwOY0DmsiacTWQAgACTAAFJENvZGV0
ABJMamF2YS9sYW5nL1N0cmluZztMAAokU2lnbmF0dXJldAAeTG5ldC9uYXdhbWFuL3NjcmlwdC9T
aWduYXR1cmU7eHBwc3IAI25ldC5uYXdhbWFuLnNjcmlwdC5TaWduYXR1cmUkU2ltcGxlJmsgDzRS
ghUCAARaAAlJc1ZhckFyZ3NMAAROYW1lcQB+AAtbAApQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcv
Q2xhc3M7TAAKUmV0dXJuVHlwZXQAEUxqYXZhL2xhbmcvQ2xhc3M7eHABdAAEbWFpbnVyABJbTGph
dmEubGFuZy5DbGFzczurFteuy81amQIAAHhwAAAAAXZyABBqYXZhLmxhbmcuU3RyaW5noPCkOHo7
s0ICAAB4cHZyAA5qYXZhLmxhbmcuVm9pZAAAAAAAAAAAAAAAeHB4dAAIICAgMTVCRkE=
}
##:HASHES:0x 15BFA-0x 6EC94;
##:COUNTS:0x 443-0x 15B8;
*******************************************************************************/
Enough for now
I hope this post should provide some interesting insight into the structure of scripts as well as how SimpleScript processes it. Next time, I will talk about what happen when things go wrong.
NawaMan
Bye bye.


Recent Comments