tsar 0.2.13

Tsar programming language
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
# tsar

Tsar is a dynamically typed, ahead of time compiled programming language. Tsar targets the [Xasm intermediate representation](https://github.com/adam-mcdaniel/xasm), which can compile to either Golang or Rust. As a result, if a Tsar program fails to build with Golang (the primary target language), Rust is used as a fallback.

![Rust Fallback](resources/rust_fallback.png)

## Features

- Dynamic Typing
- Golang and Rust foreign function interface
- Package management system
- First class object and function programming
- Pretty error messages
- Rust inspired syntax
- Python inspired programming

```
tsar x.x.x
adam-mcdaniel <adam.mcdaniel17@gmail.com>
Compiler for the Tsar programming langauge

USAGE:
    tsar [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    build    Build a Tsar package
    help     Prints this message or the help of the given subcommand(s)
    new      Create new Tsar package
    run      Run a Tsar package
```

## Installation
TODO: Make a document for each respective OS

### Install Rust (and optionally Go)

#### MacOS / Debian / Ubuntu
First, install [Rust](https://www.rust-lang.org/tools/install).
```bash
# For *nix only
# Installs Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

Then install [git](https://git-scm.com/downloads).
```bash
# For debian based OS only
sudo apt install git
```

If you want to target golang (highly recommended), install it [here](https://golang.org/dl/)
```bash
# For debian based OS only
sudo apt install golang-go

# For MacOS, use the golang link above.
```

#### Windows

Note that Tsar builds significantly slower on Windows. Expect a couple of seconds of extra time when compiling / running your tsar packages. Using Tsar on linux is recommended.

Before you start, you must install [visual studio](https://visualstudio.microsoft.com/downloads/), and [git](https://git-scm.com/downloads). You will not be able to compile without these!


Be sure to follow the instructions carefully, and use the defaults for both installers.

- Install [Rust]https://www.rust-lang.org/tools/install.
- Install [Golang]https://golang.org/dl/

### Install Tsar

After following the instructions for your respective operating system, run the following in your shell.

```bash
cargo install -f tsar
```

After the installation completes, you will be able to create a tsar package!


## Getting Started
TODO: This will become its own book / document in the future

To start, create a tsar package and test it.

```bash
# Where I will create my package
cd ~/Documents/tsar

# This will create a package named `test` under a folder with the same name
tsar new test
# Enter the folder
cd test

# Edit your program
nano src/bin.ts

# Compile your package
tsar build
# Your executable is in the `target` folder!

# Alternatively, you can `run` your package
tsar run
```

![Hello World!](resources/hello_world.png)

Now we can start programming!

## Syntax

Although Tsar is meant to behave somewhat like Python, its syntax is inspired by Rust.

![Clock Example](resources/clock.png)

If you do somehow make a syntactical mistake, Tsar will try to help correct you.

![Error Message](resources/error_msg.png)


### Use statements

`Use` statements allow you to import objects from imported modules.

`Use` statements MUST ONLY be at the top of your file! You may not use `use` statements anywhere else in your code because of code cleanliness. This allows for more readable code.

Use statements must import by name only, you may not use the `*` symbol like in Python.

You can `use` one object from a module like so.
```rust
use core::string::fmt;
```

You can also import multiple objects.
```rust
use core::math::{sin, cos, tan};
```

### Identifiers

There are two major kinds of identifiers: unscoped and scoped names.

Unscoped names are just regular identifiers like `abc123`, `tsar`, `i`, `hey_jude71`.

Scoped names use the `::` operator. This operator lets you access names from within modules.

If I want to call the `hour` function from the `time` module in the `std` module, I can do it like so.

```rust
println(std::time::hour());
```

### Assignment

Assignment in Tsar is done with the `=` operator. Variables are declared when they are first assigned to.

```rust
a = 5;
a = "String";
println(a);
```

### Loops and If Statements

Loops and If Statements are the structures for control flow in Tsar.

If statements are either single or double pronged like so.

```rust
fn odd(n) => n % 2;

fn collatz(n) {
    if odd(n) { 3 * n + 1 }
    else { n / 2 }
}

if true {
    println(collatz(5));
}
```

Parentheses are not required for loop or if statements.

While loops are executed until the test expression is false.

```rust
n = 10
while n isnt 0 {
    println(n);
    n = n - 1;
}

println("loop finished");
```

For loops iterate over each index and value in a list.

```rust
use core::string::fmt;

for index, element in range(0, 10) {
    println("Index of element: " + fmt(index));
    println("Element itself: " + fmt(element));
}
```

For unused index or element values when iterating, use the `_` variable for good convention sake.

### Functions

In Tsar, the stack is shared across different scopes. This means that values returned by functions are simply pushed onto the stack to be retrieved later.

To return a value from a function, just leave the expression to return at the end of your function.

The last line of the function does not require a semicolon.

```rust
fn function_name(a, b) {
    result = a + b;
    result
}
```

Functions that only do one computation can be written like so.

```rust
fn sum(array) => reduce(array, add, 0);
```

Functions written like this do require a semicolon, though.

Anonymous functions can be expressed with the following syntax.

```rust
|a, b| {
    result = a + b;
    result
};
```
This function takes two arguments `a` and `b`, and returns `a + b`.

Functions can be called with the `()` operators like in most other languages.

```rust
f = |a, b| { a + b };
fn increment(n) => n + 1;

println(f(4, 5));
println(increment(0));
```

### Objects

Objects are very useful for encapsulating mutating code. To maintain code cleanliness, Tsar does away with class inheritance.

Objects are defined like so.

The `new` method is used as the constructor for an object. THe `new` method takes at least one argument (the reference to the current instance), and returns that instance.

YOU MUST RETURN YOUR INSTANCE AT THE END OF THE `new` METHOD!!!

```rust
impl Point {
    fn new(self, x, y) {
        self.x = x;
        self.y = y;

        self
    }

    fn goto(self, x, y) {
        self.x = x;
        self.y = y;
    }
}
```

To instantiate your object, use the `new` function.

```rust
p1 = new(Point, 5, 6);
println(p1);
```

Attributes of an object can be accessed similarly to lists with the `[]` operators as well as the `.` operator.

```rust
impl Example {
    fn new(self) {
        self.a = 5;
        self
    }
}

e = new(Example);
println(e["a"]);
println(e.a);
```

## The Prelude

Before you start programming, you should know your available builtin functions imported from the `core` and `std` modules.

#### print
This function prints an object without printing a newline.

```rust
print("test\n");
```

#### println
This function prints an object and a newline.

```rust
println("test");
```

#### list
The following segment creates a list with 3 elements, `[1, 2, 3]`. The `[]` syntax to create a list is just shorthand for creating a call to the `list` functions.

```rust
n = 3
l = list(n, 1, 2, 3);
println(l);
```

#### len
This function returns the length of a list or string.

```rust
println(len("testing"));
println(len([1, 2, 3]));
```

#### push
This function returns a list with an object appended to the end.

```rust
println(push([1], 2) is [1, 2]);
```


#### pop
This function returns
- a list with the last object popped off
- the popped object

```rust
impl List {
    fn new(self) { self.items = []; self }
    fn push(self, item) {
        self.items = push(self.items, item);
    }

    fn pop(self) {
        self.items = pop(self.items);
    }
}

l = new(List);
l.push(5);
println(l.pop());
```


#### range
This function returns a list of values from one number to another (exclusive).

```rust
println(range(0, 3))
```


#### reverse
This function returns a reversed list.

```rust
println(reverse(range(0, 3)));
```


#### map
This function maps a list into another using a function.

```rust
fn increment(n) => n + 1;

println(
    map([0, 0, 0, 0], increment)
);
```


#### filter
This function is used to filter a list for accepted values. It takes a list and a function. For each element in the list, if `f(element)` is true, the item will be placed in the resulting list.

The following will print a list with only odd numbers.
```rust
fn odd(n) => (n % 2) is 1;

println(filter([1, 2, 3, 4, 5], odd));
```


#### reduce
This function is used to reduce a list into an atomic value. Reduce takes a list, a function to reduce with (that takes two arguments itself), and an initial value.

```rust
fn sum(values) => reduce(values, add, 0);
fn factorial(n) => reduce(range(1, n+1), mul, 1);

println(sum([1, 2, 3]));
println(factorial(5));
```


#### new
This function creates an instance of an object.

```rust
impl Point {
    fn new(self, x, y) {
        self.x = x;
        self.y = y;
        self
    }
}

p1 = new(Point, 1, 1);
println(p1);
```