Getting Started
An overview of Spider, how to download and use, and language features.
An overview of Spider, how to download and use, and language features.
Spider is a programming language that compiles to JavaScript. It takes the best ideas of Swift, Python, C# and CoffeeScript.
It's just JavaScript, but better.
func TimeMachine(pilot) {
this.pilot = pilot;
this.go = func (noise) {
::console.log(noise);
};
}
func Tardis()
extends TimeMachine("The Doctor") {
this.go = () ->
super.go("vorp vorp");
}
func DeLorean()
extends TimeMachine("Marty") {
this.go = () ->
super.go("One point twenty-one gigawatts!");
}
for timeMachine in ::getTimeMachines() {
timeMachine?.go();
}
Note: Spider is still work in progress. Make sure to star the project in GitHub if you are interested!
There are many languages that compile to JavaScript. The most popular ones are CoffeeScript, TypeScript and Dart.
But all of them have problems:
Spider tries to learn from its predecessors and build a real programming language that will make developers and teams happy:
==
is automatically compiled to ===
, and the typeof operator supports array
, date
, regexp
and more.Spider also has great debugging support:
Install Spider via npm, the node.js package manager:
npm install -g spider-script
To execute a script, run:
spider /path/to/script.spider
To compile a script:
spider -c /path/to/script.spider
The compiler will generate the output JavaScript file and a source map file for debugging. Note that the original spider file and the source map file aren't necessary for production.
All Spider code is compiled to JavaScript strict mode and wrapped in Immediately-Invoked Function Expression (IIFE).
In Spider, all uses of the global scope must be explicit. Use ::
to access the global scope.
::console.log("Hello world!");
You can also pull global variables into the local scope with the use
statement:
use console;
// 'console' doesn't need '::' before it because of 'use'
console.log("Hello world!");
For convenience, you can also use :browser
to automatically import DOM global variables, and use :node
to automatically import Node.js-related global variables.
:browser | :node |
---|---|
console | console |
window | global |
document | require |
screen | exports |
location | module |
navigator | process |
alert |
The Spider compiler will raise an error if you try to refer to a variable that doesn't exist in the current scope or in one of its parents.
Scoping just works, without any surprises. Spider will protect you against any unintended behaviour.
In Spider, logical operators always result in a boolean value regardless of the types passed to it. In addition, ==
is automatically compiled to ===
.
x = false or 5; // x == true;
x = 5 and 4; // x == true;
x = 1 == "1"; // false (== compiles to ===)
Note that Spider adds the and
and or
operators that behave exactly like &&
and ||
respectively.
Spider provides the null-coalescing operator to replace the useful options.property || defaultValue
idiom.
Spider's typeof
operator returns the lowered-cased constructor name of the argument.
typeof { a: 4 }; // "object"
typeof [1, 2, 3]; // "array"
typeof new Date; // "date"
typeof new Number(4); // "number"
typeof new String("abc"); // "string"
typeof new Boolean(true); // "boolean"
String interpolation is a way to construct a new string from a mix of constants, variables, literals, and expressions by including their values inside a string literal.
var multiplier = 3;
var message = "\(multiplier) times 2.5 is \(multiplier * 2.5)";
// message is "3 times 2.5 is 7.5"
Functions in Spider are declared using the func
keyword:
func square(x) {
return x * x;
}
var cube = func (x) {
return square(x) * x;
};
Functions can also be expressed using the arrow syntax:
var isEven = (x) -> x % 2 == 0;
app.controller("MyCtrl", ($scope, MyService) -> {
$scope.items = [];
});
Functions may also have default values for arguments, which will be used if the incoming argument is missing (null
or undefined
).
func legCount(animal = "spider") {
switch animal {
case "spider": {
return 8;
},
default: {
return 2;
}
}
}
The JavaScript arguments object is a useful way to work with functions that accept variable numbers of arguments. Spider provides splats ...
, both for function definition as well as invocation, making variable numbers of arguments a little bit more palatable.
var gold, silver, rest;
func awardMedals(first, second, others...) {
// others is an array
gold = first;
silver = second;
rest = others;
}
var contenders = [
"Michael Phelps"
"Liu Xiang"
"Yao Ming"
];
awardMedals(contenders...);
Instead of just adding classes, Spider embraces JavaScript prototypes and makes them much easier to use. Spider's inheritance is compatible with almost any JavaScript class implementation out there.
func Animal(name) {
this.move = func (distance) {
alert("\(name) moved \(distance)m.");
};
}
func Snake(name)
extends Animal(name) {
this.move = func() {
alert("Slithering...");
super.move(5);
};
}
func Horse(name)
extends Animal(name) {
this.move = func() {
alert("Galloping...");
super.move(45);
};
}
var sam = new Snake("Sammy the Python");
var tom = new Horse("Tommy the Palomino");
sam.move();
tom.move();
In Spider, if statements (as well as most other statements) can be written without the use of parentheses.
if happy and knowsIt {
clapHands();
} else {
showIt();
}
There's no ternary operator (?:) in Spider. Instead, Spider provides Python-like if
expressions:
var date = sue if friday else jill;
Spider provides 3 types of for
statements. The first type allows a block of code to be executed repeatedly while incrementing a counter, as long as a condition remains true.
for var i = 0; i < 5; i++ {
::console.log(i);
}
A for-in
statement allows a block of code to be executed once for each item in an array.
var foods = ['broccoli', 'spinach', 'chocolate'];
for food in foods {
eat(food);
}
You can also get the index of the item by adding another variable:
for food, i in foods {
console.log("Eating food number \(i).");
eat(food);
}
A for-of
statement allows a block of code to be executed once for each property in an object.
var player = {
"name": "Daniel",
"address": "Tel Aviv",
"age": 18
};
for key of player {
console.log("Found property \(key).");
}
You can also get the value of the key by adding another variable:
for key, value of player {
console.log("\(key): \(value)");
}
Spider provides a while
loop that behaves exactly like the JavaScript equivalent except parenthesis aren't required:
while supply > demand {
buy();
}
For readability, Spider also provides an until
loop that is equivalent to while not
:
until supply > demand {
sell();
}
Spider provides Python-like list comprehensions. List comprehensions provide a concise way to create list from existing list.
var list = [1, 2, 3, 5, 6, 7];
var doubles = [x * 2 for x in list];
You can also filter elements with a condition:
var doubles = [x * 2 for x in list if x % 2 == 0];
It's a little difficult to check for the existence of a variable in JavaScript. if (variable) ...
comes close, but fails for zero, the empty string, and false. The existential operator ?
returns true unless a variable is null or undefined
if game? {
play();
}
The accessor variant of the existential operator ?.
can be used to soak up null references in a chain of properties. Use it instead of the dot accessor .
in cases where the base value may be null or undefined. If all of the properties exist then you'll get the expected result, if the chain is broken, undefined is returned instead of the TypeError that would be raised otherwise.
var zip = lottery.drawWinner?().address?.zipcode;
The null-coalescing operator ??
returns the right expression if the left expression is null or undefined.
var name = options.name ?? "default name";
The in
operator checks if an array contains an specific item, or if an object contains a specific property.
var people = [billy, robin, daniel];
var details = {
"price": 45,
"address": "New York, USA",
"age": 27
};
console.log(billy in people); // => true
console.log("address" in details) // => true
Chained comparisons make it easy to test if a value falls within a certain range.
var isHealthy = 200 > cholesterol > 60;
To simplify math expressions, **
can be used for exponentiation.
var volume = a ** 3; // => Math.pow(a, 3)
The #
operator performs integer division.
var floor = a # b; // => Math.floor(a / b)
The #
operator provides true mathematical modulo.
var modulo = a %% b; // => (a % b + b) % b
The range literal provides a simple way to generate a numbers array. With two dots (3..6)
, the range is inclusive (3, 4, 5, 6
); with three dots (3...6
), the range excludes the end (3, 4, 5
)
var a = [1..5]; // => [1, 2, 3, 4, 5]
var b = [1...5]; // => [1, 2, 3, 4]
It can also work in the opposite direction:
var c = [5..1]; // => [5, 4, 3, 2, 1]
var d = [5...1]; // => [5, 4, 3, 2]
Ranges can also be used to extract slices of arrays.
var numbers = [1...10];
var start = numbers[0..2];
var middle = numbers[3...-2];
var end = numbers[-2..];
var copy = numbers[..];
The same syntax can be used with assignment to replace a segment of an array with new values, splicing it.
numbers[3..6] = [-3, -4, -5, -6];
The switch
statement in Spider is much more powerful than the JavaScript equivalent:
switch day {
case "Monday": {
go(work);
},
case "Tuesday": {
go(relax);
},
case "Friday", "Saturday": {
go(bingo);
},
default: {
go(work);
}
}
Note that break
is not required.
Switch statements can also be used with ranges:
switch score {
case ..60: {
return "F";
},
case 60..70: {
return "D";
},
case 70..80: {
return "C";
},
case 80..90: {
return "B";
}
default: {
return "A";
}
}