Dead-simple functional JavaScript
transpiler.
SaurScript
looks like this:
String myName = "Computer"
fun sayHi(String name) > String {
return concat("Hello ", name)
}
String greeting = sayHi(myName)
logger.log(greeting)
It compiles to JavaScript
:
const myName = "Computer";
const greeting = (function(name = myName) {
return "Hello " + name;
})();
console.log(greeting)
- Functional
- Pure
- Statically typed
- Lazy
- Easy to learn
A lot of functional programming languages use unfamiliar syntax:
myName = "Computer"
sayHi :: String -> String
sayHi name = "Hello " ++ name
greeting = sayHi myName
main = print greeting
This can make it hard to learn. SaurScript
uses more familiar syntax, making it easier to learn.
To learn how to use SaurScript
we're going to create a thesaurus.
Usually you'll want to import either the common
or browser
library to start.
These give you access to logger
, document
, storage
, map
, strConcat
, filter
, and other useful tools.
You can also import other .saur
files.
// The common lib:
@import 'common'
// The browser lib (this includes common, but is only for frontend dev. Don't use both):
@import 'browser'
// Another `.saur` file:
@import 'myOtherFile'
Variables in SaurScript
are immutable and statically typed.
Int myVar = 5
This will compile to:
const myVar = 5;
You must specify a type to create the variable. Once you create the variable, you cannot change it.
Don't think of variables as boxes where you can take things in and out. Think of the variable name as a word in our thesaurus, and the value is the synonyms.
Let's create an entry for our thesaurus:
Dictionary<String:Array<String>> entries = ["Dinosaur": "Dino", "Raptor", "Big Lizard"]
Here we declare a new variable named entries
. It's type is a Dictionary
.
The key of the dictionary is a String
(a word), and the value is an Array
of String
s (synonyms).
Functions are lazy. If we don't use the function, it won't show up in our JavaScript
code.
fun myFunction(Int arg1, Float arg2) -> Bool {
logger.log(arg1 + arg2)
return true
}
Since we don't use this function, our JavaScript
file is empty.
Let's add a function to our thesaurus to get the synonyms for any given word.
fun synonyms(String word) -> Array<String> {
return entries[word]
}
Classes are an experimental feature of SaurScript
. They mix the Functional
and Object Oriented
paradigms.
@class MyClass
@property Int id = 0
fun whoami() -> String {
return "A Computer"
}
@endclass
@new MyClass myInstance(5)
logger.log(myInstance.whoami())
This will compile to:
function MyClass(id = 0) {
this.id = id;
};
MyClass.prototype = {
whoami: function() {
return "A Computer"
}
}
const myInstance = new MyClass(5)
console.log(myInstance.whoami())
Now we can create a class for each entry in our thesaurus:
@class Entry
@property String word = ""
@property Array<String> synonyms = []
@endclass
And a class for the thesaurus itself:
@class Thesaurus
@property String name = ""
@property String publisher = ""
@property Array<Any> entries = []
@endclass
And we can create a thesaurus!
@new Entry dino("Dino", ["Dinosaur", "Raptor", "T-Rex"]
@new Entry lizard("Lizard", ["Iguana", "Gecko", "Monitor"]
@new Entry paradigm("Paradigm", ["Functional", "Imperative", "Object Oriented"]
@new Thesaurus thesaurus("SaurScript Thesaurus", "SaurScript Language", [dino, lizard, paradigm])
if myCondition == "yes" {
logger.log("Agreed")
} elif myCondition != "maybe" {
logger.log("So you're telling me there's a chance")
} else {
logger.log("Not at all")
}
SaurScript
doesn't have for
or while
loops. Instead, you can use recursion, or repeat
.
repeat 3 {
logger.log("Hi")
}
Output:
Hi
Hi
Hi
We can use recursion to print all of the synonyms in our thesaurus:
@class Thesaurus
...
fun allSynonyms(Int index = 0, Array<String> soFar) {
if entries[index] != null {
allSynonyms(index + 1, arrConcat(soFar, entries[index])
} else {
logger.log(soFar)
}
}
@endclass
Sometimes you want to export something for use in another .saur
file.
You can add @export
in front of a variable, class, function, etc. to make it available outside the file.
@export String myName = "Carson"
@export @class myClass
@property String greeting = "Hello World"
@endclass
@export @new myClass greeter(strConcat("Hello ", myName))
@export fun sayHi(Any greeterClass) > String {
return greeterClass.greeting
}
It can now be imported from another .saur
file:
@import 'myFile'
// We can now access everything @exported from the other file:
logger.log(sayHi(greeter))