Getting Started
Install with npm i -g entropy-script
Run a script with entropy-script <filename>.es
or jses <filename>.es
Installation
NPM
npm i -g entropy-script
To install Entropy Script globally on your computer, or
npm i entropy-script
To install the source code in the current directory as an NPM package
From Source
You can also use it from the source code on GitHub.
CLI
The CLI can be accessed with either entropy-script
or jses
commands. Note that jses
is used where either could be used.
Start the REPL with jses
. Type exit
to exit the REPL.
jses [script] [args]
The most common use case is, of course, a simple invocation of a script:
jses myscript.es
Syntax
The syntax of EntropyScript is very similar to JavaScript, except that is has slightly fewer brackets.
An EntropyScript script is a list of statements (a statements) seperated by the ;
. All lines must have semicolons except the last line in a statements.
Declaration
To declare a constant, say
let n = something;
To declare a mutable variable, say
let var n = something;
You must declare variables before using them. This would result in an InvalidSyntaxError:
n = something;
You can also declare global variables like this:
// global constant
let global n = something;
// global mutable variable
let global var n2 = somethingelse;
If
if expression {
}
Will run if expression
evaluates to true
. Can be combined with else
like so:
if expression {
// do something
} else if another_expression {
// do something else
} else {
// do a something different
}
You can also use if
s similarly to ternary operators, such as:
let my_val = if true { 'hello' } else { 'bye' };
my_val; // 'hello'
Loops
For
for i in expression {
}
The for loop is very versatile, as it can be used to iterate over an array but also over numbers, strings and the keys of objects.
// iterate from 0-9
for j in 10 {
}
// iterate from 3-9 with a step of 2
for l in range(3, 9, 2) {
}
let my_object = { a: 1, b: 2 };
// iterate over the array ['a', 'b']
for key in my_object {
let value = my_object[key];
}
While
while expression {
}
Will repeat until the expression something
evaluates to false
var a = false;
while !a {
a = true;
}
You cannot write for
, if
or while
statements in the common C-like way:
// InvalidSyntaxError
if (expression)
do_something();
You must have curly braces.
Comments
Like JavaScript, you write comments as follows
// single line comment
/*
Multi-line comment
*/
Functions
You can declare functions like so
func do_something () {
};
// Note the ';'
Or anonymously like this
let do_something = func () {};
Classes
Declare classes like so
class MyClass {};
// or
let MyOtherClass = class {};
All classes and types should be in PascalCase
Methods
The body of the class can only contain methods, which are declared like so:
let MyClass = class {
// method
do_something () {
// do something
}
};
All methods and properties are public.
Constructor
The constructor gets called once when the instance is created.
class MyClass {
// constructor
init () {
this.a = 1;
}
// method
get_a () {
return this.a;
}
};
let my_instance = MyClass();
my_instance.get_a(); // 1
Simply call the class like a function to create an instance. No new
keyword.
Operator overrides
class Num {
init (n: Number) {
this.a = n;
}
__add__ (to: Number) {
}
};
Num(1) + Num(2);
// Num(3);
The overrideable methods are:
Method Name | Operator |
---|---|
__add__ | + |
__subtract__ | - |
__multiply__ | * |
__divide__ | / |
__pow__ | ^ |
__eq__ | == |
__gt__ | > |
__lt__ | < |
__or__ | || |
__and__ | && |
__pipe__ | | |
__ampersand__ | & |
__bool__ | !! and any other bool conversion |
__set_property__ | [] and . |
__get_property__ | [] and . |
__call__ | () |
Built In
Global Constants
true
false
nil
Type
String
Number
Func
Array
Any
Bool
Object
Error
Undefined
Built-In Functions
* Only in Node runtimes
range
range: func (from: Number, to: ?Number, step: ?Number) Array[Number];
Same as Python's range
function. Returns an array of numbers.
parse_num
parse_num: func (value: String) Number;
Parse floats or integers into numbers
import
import: func (path: String) Any;
Imports a module and returns the value. Slightly different behaviour between Node and browser runtimes:
- All imports must be declared in config file for browsers, which then get preloaded before runtime
help
help: func (value: Any) String;
Returns a string with information on the passed object.
print: func (*: Array[Any]) nil;
Calls the specified print function. Often just native console.log
.
log
log: func (*: Array[Any]) nil;
Calls native console.log
delete
delete: func (symbol: String) nil;
Removes a symbol with the specified identifier.
path
__path__: func () String;
Returns The current path
symbols
__symbols__: func (recursive: ?Bool) Object;
Gets all symbols in the current scope. If recursive
is true
, then gets all symbols up the global context.
using
using: func (module: Any) nil;
Adds all symbols from object or namespace to the current scope.
throw
throw: func (name: String, detail: String) nil;
Throws an error of type name
.
sleep
sleep: func (ms: Number, then: func (*: Array[Any]) Any) nil;
open *
open: func (path: String, encoding: ?String = 'utf-8') ({
str: func () String,
write: func (data: String) nil,
append: func (data: String) nil
})};
Throws ImportError
if the file doesn't exist.
Built In Modules
json
ascii
time
math
promise
fs
https
http
mysql
path
Primitives
Everything in EntropyScript is a primitive. There are a few built in primitives, and then all new types inherit from primitive.
Methods
str
str: func () String;
Returns a stringified version of the primitive
cast
cast: func (t: Any) t | Error;
Tries to cast to that type. If you cannot cast the object or cannot cast to that type, then it will throw an error.
bool
bool: func () Bool
Evaluates the object as a boolean.
is
is: func (o: Any) Bool;
Returns true if the two are the same object.
let a = 1;
a.is(a); // true
a.is(1); // false
let b = a;
a.is(b); // true
b.is(a); // true
isa
isa: func (type: Any) Bool;
Returns true if the object is of type type
has_property
has_property: func (key: Any) Bool;
Returns true if the object has a key which is equal to key
describe
describe: func (description: String) Undefined;
Adds a description to the object. Does nothing when run on built in objects.
type_check
type_check: func (obj: Any) Bool;
Reverse of isa
. Returns true if obj
is of type of whatever was called on.
clone
clone: func () Any;
Returns a clone of the object
Properties
type
The object's type.
self
The object
info
The metadata about the object, including its description
value
The object
Type
Type: Type
Every EntropyScript class and built-in type is an instance of Type. Create an instance of a type by calling it. Call a built-in type to cast to that type.
Call Type
to get the string of the type of something, and without any parameters to create a new empty class.
Type(String); // 'Type'
Type('hello world'); // 'String'
Type(Type); // 'Type'
Type(Type(Type)); // 'String'
Type(); // new type
TypeUnion
Is the 'Union' of two types. Create with the pipe |
operator. Resolves true if the resolution of either child type resolves to true
TypeIntersection
Is the 'Intersection' of two types. Create with the pipe &
operator. Resolves true if the resolution of both child type resolves to true.
This is different from the TypeScript equivalent &
as it does not use the true intersection of the types, operating more like the &&
operator.
TypeNot
Is the 'Not' of a type expression. Create with the ~
before the type expression.
Number
Number: Type;
Number is for both integers and floating point numbers.
Methods
(None)
Properties
(None)
String
String: Type
Create a string with '
, `
or "
. All are equivalent. Declaring strings is similar to string literals in other languages.
'hi
';
Is fine and is equivalent to
'hi\n';
To escape the string, use \
backslash; for example
'Here\'s a string';
Methods
len
len: func () Number;
Returns the length of the string
Properties
(None)
Array
Array: Type;
Arrays can be declared with square brackets, elements delimited by a comma.
For example, an array of numbers:
let my_array = [0, 1, 2, 3];
You can mix types in array and even nest arrays.
let my_nested_array = [0, 'hello world', [2, 3, [4]]];
To type an array use this syntax:
let my_array_of_numbers: Array[Numbers] = [0, 1, 2];
// throws a TypeError
let my_erronious_array_of_numbers: Array[Numbers] = [0, 1, 'hi'];
// And then nested types
let my_nested_array_of_numbers: Array[Array[Numbers]] = [[0, 2], [1, 3]];
You can also declare Tuple types with arrays like so:
let tuple = [String, Number];
let my_tuple: tuple = ['hello', 0];
// TypeError
let my_bad_tuple: tuple = ['hello', 'world'];
Methods
len
len: func () Number;
The length of the array
contains
contains: func (element: Any): Bool;
Returns true if the array contains an element which is equivalent to element
Properties
Error
Error: Type;
Methods
(None)
Properties
name
name: String;
The name of the error, for example, 'TypeError' or 'InvalidSyntaxError'
detail
detail: String;
More details about the error
traceback
traceback: Array[String];
An array of strings which are the name and location of function from which the error was generated.
Function
Func: Type;
Declare a function with the func
keyword.
To type check against a function, you can simply check if something is a function:
let my_func: Func = func () {};
// TypeError
let not_a_func: Func = 0;
Or you can do a deeper type heck and check against the parameters and return type:
let my_func: (func () Undefined) = func (): Undefined {};
/*
Note the lack of a colon after the brackets in the type description.
The return type of the type function is simply a function which
returns the desired return type.
Technically, you could have side effects inside the type function,
although this is ill-advised.
*/
// TypeError
let my_func: (func () Undefined) = func (): Undefined {
return 1;
};
// Note that you must explicitely type the return value and parameters
// of both the type and the value:
// TypeError
let my_func: (func () Number) = func () 0;
// ok
let my_func: (func () Number) = func (): Number 0;
Examples
Here are some examples of EntropyScript in action.
FizzBuzz to n
let now = import('time').now;
const main = func (n) {
for i in range(1, n+1) {
div3 = i % 3 == 0;
div5 = i % 5 == 0;
if div3 && div5 {
print('fizzbuzz');
} else if div3 {
print('fizz');
} else if div5 {
print('buzz');
} else {
print(i);
}
}
};
// time how long it takes
let start = now();
main(1000);
print(now() - start, 'ms');
This typically runs in ~150ms, compared to ~50ms for Python and JavaScript
Fibonacci series up to n
let fib = func (n) {
var a = 0;
var b = 1;
while a < n {
print(a);
let t = a;
a = b;
b = t + b;
}
};
fib(1000);