# Standard Features

Most programming languages offer a standard set of functionality - here's a list of Sprig offers:

### Variables

Sprig allows you to declare variables in three different ways: `const`, `var` and `let`.

{% code overflow="wrap" %}

```javascript
const name = "Amy"
name = "Allan" 
// Error: Cannot reassign value of const variable 'name'
const name = "Allan" 
// Error: Variable 'name' is already defined
```

{% endcode %}

```javascript
var name = "Amy"
name = "Allan" 
// No error, var variables can be reassigned
var name = "Allan" 
// Error: Variable 'name' is already defined
```

```javascript
let name = "Amy"
name = "Allan" 
// No error, let variables can be reassigned
let name = "Allan" 
// No error, let variables can be redefined
```

### Branching

Sprig offers a familiar approach to branching logic.

{% code overflow="wrap" %}

```javascript
const x = 100

if (x < 50) {
    print("a")
} else if (x < 80) {
    print("b")
} else {
    print("c")
}

// c
```

{% endcode %}

### Loops

Sprig offers multiple types of loops: `for`, `loop`, `while`.

#### `for (<List>, [optional] value, [optional] index)`

These are the most common loops found in Sprig code.

```javascript
const arr = [1, 2, 3]

for (arr, value, index) {
    print(`{{value}}: {{index}}`)
}

/*
1: 0
2: 1
3: 2
*/
```

#### `loop (<let decl>, <end check>, <expr>)`

These follow the traditional for loop approach.

```javascript
loop (let i = 0, i <= 3, i += 1) {
    print(i)
}

/*
0
1
2
*/
```

#### `while (<expr>)`

These follow the traditional while loop approach.

```javascript
while (x < 3) {
    print(x)
    x += 1
}

/*
0
1
2
*/
```

### Objects

Sprig allows the construction of objects.

{% code overflow="wrap" %}

```javascript
const key = "id"
const person = {
    token: "_-_",
    nums: (1...3),
    bloop: {
        a: 10 + 4,
        b: 20,
        c: (1...4),
        d: (const d = 1200) + (const e = 1.4)
    },
    [key]: 3.14
}

person.nums[0] = 100
person.bloop.c[0] = person.token * person.bloop.a
person.bloop.e = person.bloop.d + d

print(person.token) // _-_
print(person.id) // 3.14
print(person.bloop.e) // 2401.4
print(person.bloop.d) // 1201.4
```

{% endcode %}

Objects can be merged together through addition.

```javascript
const merged = { name: "Jack", age: 34 } + { id: "0001" }
print(merged) // { name: "Jack", age: 34, id: "0001" }
```

Objects can be constructed using shorthand syntax.

```javascript
const name = "Jack"
const age = 34

const person = { name, age, id: "0001" }
print(person) // { name: "Jack", age: 34, id: "0001" }
```

Object properties can be deleted.

```javascript
const person = { name: "Jack", age: 34, id: "0001" }
person->delete("id")

print(person) // { name: "Jack", age: 34 }
```

### Lists

Sprig allows the construction of lists.

```javascript
const arr = [1, 2, 3 + 5]
print(arr) // [1, 2, 8]
```

Sprig provides common list functionality to the global scope.

```javascript
const arr = [1, 2, 3]
arr->append(10)->print // [1, 2, 3, 10]
arr->insert(20)->print // [20, 1, 2, 3, 10]
arr->insert(100, 1)->print // [20, 100, 1, 2, 3, 10]
arr->remove(2)->print // [20, 100, 2, 3, 10]
```

Lists can be created dynamically through the range operators.

```javascript
const arrInclusive = 0...5 // [0, 1, 2, 3, 4, 5]
const arrExclusive = 0..5 // [0, 1, 2, 3, 4]
```

Lists can be merged by either addition or through the spread operator.

```javascript
const arr1 = 1...10
const arr2 = 20...30

print(arr1 + arr2)
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]

print([0, ...arr2, ...arr1, 0])
// [0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0]
```

Functional methods are also provided globally.

```javascript
const arr = [1, 2, 3]

arr->forEach((/* optional */ value, /* optional */ index) => {
    print(`{{value}}: {{index}}`)
})

/*
1: 0
2: 1
3: 2
*/

const doubleArr = arr->map((value) => value * 2)
doubleArr->print // [2, 4, 6]

const filteredArr = arr->filter((value) => value % 2 == 0)
filteredArr->print // [2]

const sum = arr->reduce((a, b) => a + b, /* optional: initial_value */)
sum->print // 6

arr->includes(2)->print // true
arr->includes(20)->print // false
```

### Functions

Sprig allows you to define your own functions.

```javascript
const add = (a, b) => a + b
add(10, 20)->print // 30
```

Functions can have default parameters.

```javascript
const add = (a, b = 100) => a + b
add(10)->print // 110
```

Functions can have a catch-all parameter. The arguments provided are turned into a List.

```javascript
const printStuff = (a, b, ...args) => args->print
printStuff(1, 2, 3, "hi") // [3, hi]
```

When calling functions, we can provide the parameter names to be more verbose.

```javascript
const blah = (a, b) => {
    print(a)
    print(b)
}

blah(b: 1, a: 2)

/*
2
1
*/
```

Functions have an implicit return, meaning they return the last thing on the stack (unless a return is explicitly defined).

```javascript
const thisReturns5 = () => {
    5
}

// is the same as

const thisReturns5 = () => {
    return 5
}

// and

const thisReturns5 = () => 5
```

### Coroutines

Sprig allows you to create coroutines. Coroutines are functions that can suspend their execution, yield a value and resume execution at a later point.

Any function that contains a yield statement is automatically identified as a coroutine.

{% code overflow="wrap" %}

```javascript
const coro = () => {
    var x = 0
    while (true) {
        yield x += 1
    }
}

const c1 = coro();

while ((let c = c1()) <= 10) {
    // do nothing
}

print(c) // 11

const coroAdvanced = (init, value) => {
    var x = init
    while (true) {
        yield x += value
    }
}

const cAdvanced = coroAdvanced(100);
const res = cAdvanced(20)

print(res) // 120
```

{% endcode %}
