|
| 1 | +# `SaurScript` |
| 2 | +Dead-simple functional `JavaScript` transpiler. |
| 3 | + |
| 4 | +`SaurScript` looks like this: |
| 5 | +```kotlin |
| 6 | +String myName = "Computer" |
| 7 | +fun sayHi(String name) > String { |
| 8 | + return concat("Hello ", name) |
| 9 | +} |
| 10 | +String greeting = sayHi(myName) |
| 11 | +logger.log(greeting) |
| 12 | +``` |
| 13 | +It compiles to `JavaScript`: |
| 14 | +```javascript |
| 15 | +const myName = "Computer"; |
| 16 | +const greeting = (function(name = myName) { |
| 17 | + return "Hello " + name; |
| 18 | +})(); |
| 19 | +console.log(greeting) |
| 20 | +``` |
| 21 | + |
| 22 | +### Features |
| 23 | +* Functional |
| 24 | +* Pure |
| 25 | +* Statically typed |
| 26 | +* Lazy |
| 27 | +* Easy to learn |
| 28 | + |
| 29 | +### Concept |
| 30 | +A lot of functional programming languages use unfamiliar syntax: |
| 31 | +```haskell |
| 32 | +myName = "Computer" |
| 33 | + |
| 34 | +sayHi :: String -> String |
| 35 | +sayHi name = "Hello " ++ name |
| 36 | + |
| 37 | +greeting = sayHi myName |
| 38 | +main = print greeting |
| 39 | +``` |
| 40 | +This can make it hard to learn. `SaurScript` uses more familiar syntax, making it easier to learn. |
| 41 | + |
| 42 | +# Learn `SaurScript` |
| 43 | +To learn how to use `SaurScript` we're going to create a the**saur**us. |
| 44 | + |
| 45 | +### Imports |
| 46 | +Usually you'll want to import either the `common` or `browser` library to start. |
| 47 | +These give you access to `logger`, `document`, `storage`, `map`, `strConcat`, `filter`, and other useful tools. |
| 48 | +You can also import other `.saur` files. |
| 49 | +```kotlin |
| 50 | +// The common lib: |
| 51 | +@import 'common' |
| 52 | +// The browser lib (this includes common, but is only for frontend dev. Don't use both): |
| 53 | +@import 'browser' |
| 54 | +// Another `.saur` file: |
| 55 | +@import 'myOtherFile' |
| 56 | +``` |
| 57 | + |
| 58 | +### Variables |
| 59 | +Variables in `SaurScript` are immutable and statically typed. |
| 60 | +```kotlin |
| 61 | +Int myVar = 5 |
| 62 | +``` |
| 63 | +This will compile to: |
| 64 | +```javascript |
| 65 | +const myVar = 5; |
| 66 | +``` |
| 67 | +You must specify a type to create the variable. Once you create the variable, you cannot change it. |
| 68 | + |
| 69 | +Don't think of variables as boxes where you can take things in and out. |
| 70 | +Think of the variable name as a word in our thesaurus, and the value is the synonyms. |
| 71 | + |
| 72 | +Let's create an entry for our thesaurus: |
| 73 | +```kotlin |
| 74 | +Dictionary<String:Array<String>> entries = ["Dinosaur": "Dino", "Raptor", "Big Lizard"] |
| 75 | +``` |
| 76 | +Here we declare a new variable named `entries`. It's type is a `Dictionary`. |
| 77 | +The key of the dictionary is a `String` (a word), and the value is an `Array` of `String`s (synonyms). |
| 78 | + |
| 79 | +### Functions |
| 80 | +Functions are lazy. If we don't use the function, it won't show up in our `JavaScript` code. |
| 81 | +```kotlin |
| 82 | +fun myFunction(Int arg1, Float arg2) -> Bool { |
| 83 | + logger.log(arg1 + arg2) |
| 84 | + return true |
| 85 | +} |
| 86 | +``` |
| 87 | +Since we don't use this function, our `JavaScript` file is empty. |
| 88 | + |
| 89 | +Let's add a function to our thesaurus to get the synonyms for any given word. |
| 90 | +```kotlin |
| 91 | +fun synonyms(String word) -> Array<String> { |
| 92 | + return entries[word] |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +### Classes |
| 97 | +Classes are an experimental feature of `SaurScript`. They mix the `Functional` and `Object Oriented` paradigms. |
| 98 | +```kotlin |
| 99 | +@class MyClass |
| 100 | + @property Int id = 0 |
| 101 | + fun whoami() -> String { |
| 102 | + return "A Computer" |
| 103 | + } |
| 104 | +@endclass |
| 105 | +@new MyClass myInstance(5) |
| 106 | +logger.log(myInstance.whoami()) |
| 107 | +``` |
| 108 | +This will compile to: |
| 109 | +```javascript |
| 110 | +function MyClass(id = 0) { |
| 111 | + this.id = id; |
| 112 | +}; |
| 113 | +MyClass.prototype = { |
| 114 | + whoami: function() { |
| 115 | + return "A Computer" |
| 116 | + } |
| 117 | +} |
| 118 | +const myInstance = new MyClass(5) |
| 119 | +console.log(myInstance.whoami()) |
| 120 | +``` |
| 121 | +Now we can create a class for each entry in our thesaurus: |
| 122 | +```kotlin |
| 123 | +@class Entry |
| 124 | + @property String word = "" |
| 125 | + @property Array<String> synonyms = [] |
| 126 | +@endclass |
| 127 | +``` |
| 128 | +And a class for the thesaurus itself: |
| 129 | +```kotlin |
| 130 | +@class Thesaurus |
| 131 | + @property String name = "" |
| 132 | + @property String publisher = "" |
| 133 | + @property Array<Any> entries = [] |
| 134 | +@endclass |
| 135 | +``` |
| 136 | +And we can create a thesaurus! |
| 137 | +```kotlin |
| 138 | +@new Entry dino("Dino", ["Dinosaur", "Raptor", "T-Rex"] |
| 139 | +@new Entry lizard("Lizard", ["Iguana", "Gecko", "Monitor"] |
| 140 | +@new Entry paradigm("Paradigm", ["Functional", "Imperative", "Object Oriented"] |
| 141 | +@new Thesaurus thesaurus("SaurScript Thesaurus", "SaurScript Language", [dino, lizard, paradigm]) |
| 142 | +``` |
| 143 | + |
| 144 | +### If, Else If, and Else |
| 145 | +```kotlin |
| 146 | +if myCondition == "yes" { |
| 147 | + logger.log("Agreed") |
| 148 | +} elif myCondition != "maybe" { |
| 149 | + logger.log("So you're telling me there's a chance") |
| 150 | +} else { |
| 151 | + logger.log("Not at all") |
| 152 | +} |
| 153 | +``` |
| 154 | + |
| 155 | +### Repeat |
| 156 | +`SaurScript` doesn't have `for` or `while` loops. Instead, you can use recursion, or `repeat`. |
| 157 | +```kotlin |
| 158 | +repeat 3 { |
| 159 | + logger.log("Hi") |
| 160 | +} |
| 161 | +``` |
| 162 | +Output: |
| 163 | +```sh |
| 164 | +Hi |
| 165 | +Hi |
| 166 | +Hi |
| 167 | +``` |
| 168 | +We can use recursion to print all of the synonyms in our thesaurus: |
| 169 | +```kotlin |
| 170 | +@class Thesaurus |
| 171 | + ... |
| 172 | + fun allSynonyms(Int index = 0, Array<String> soFar) { |
| 173 | + if entries[index] != null { |
| 174 | + allSynonyms(index + 1, arrConcat(soFar, entries[index]) |
| 175 | + } else { |
| 176 | + logger.log(soFar) |
| 177 | + } |
| 178 | + } |
| 179 | +@endclass |
| 180 | +``` |
| 181 | +
|
| 182 | +### Exports |
| 183 | +Sometimes you want to export something for use in another `.saur` file. |
| 184 | +You can add `@export` in front of a variable, class, function, etc. to make it available outside the file. |
| 185 | +```kotlin |
| 186 | +@export String myName = "Carson" |
| 187 | +
|
| 188 | +@export @class myClass |
| 189 | + @property String greeting = "Hello World" |
| 190 | +@endclass |
| 191 | +
|
| 192 | +@export @new myClass greeter(strConcat("Hello ", myName)) |
| 193 | +
|
| 194 | +@export fun sayHi(Any greeterClass) > String { |
| 195 | + return greeterClass.greeting |
| 196 | +} |
| 197 | +``` |
| 198 | +It can now be imported from another `.saur` file: |
| 199 | +```kotlin |
| 200 | +@import 'myFile' |
| 201 | +// We can now access everything @exported from the other file: |
| 202 | +logger.log(sayHi(greeter)) |
| 203 | +``` |
0 commit comments