# SAI
## A Humane Language
### For the node ecosystem

---

## Compiles to plain JS
### Real-Time or Bulid-Ahead

---

# Just-in-time compiler 

    const SAI = require('sai-language')
    const objectNameProto = SAI.create('ObjectName')
    
# Compiles __ObjectName.sai__ 

## Resulting prototype is pure JS

Compiles once per prototype, caches result

---

# Build-ahead compiler

    > sai-build -o lib src
    
## Compile __.SAI__ files in _src_ to __.JS__ files in _lib_
### Now it's all just Javascript

    const ObjectNameProto = require('ObjectName')


---

# Bad News

## The generated JS is efficient but ugly

> Basically
> __It's object code__
> You can debug with it
> But not strictly intended for human consumption

## There are (will be) source maps, though

---

# Design Goals

- Readable
- Maintainable
- Object oriented
- Easy to integrate
- Minimal speed penalty
- Modern & Extensible

---

# Tutorial

---

# Code goes in objects

    $ cat HelloWorld.sai        // Just regular text files

    object HelloWorld main      // One object per source file
                                // "main" object is the program start point
    Instantiate task            // Instantiate invoked on object creation
      debug 'Hello World!'      // A "task" is a standard function
                                // Level of indent replaces {}
                                // debug is a verb invoking console.log

    $ sai-run HelloWorld        // Just-in-time compiler
    Hello World!

_Future short examples omit the `object` wrapper for brevity._

---

# Every line starts with an action

    ply corpus as line                // ply (iterator)
      set weight to 1                 // set (assignment)
      ply line as word                // ply (iterator)
        if number word                // if (conditional)
          set weight to trial         // set (assignment)
        elsif word.length >= window   // elsif (conditional)
          push! valid word            // push (Array method)
          if word.length > window     // if (conditional)
            AddWord it, weight        // AddWord (own method)

_Level of indent replaces the use of structural braces {}._

---






# Readable

- few structural symbols
- expressive keywords
- whitespace significant
- conversational syntax
- bareword instance variables 

---

# Maintainable

- simple coding style
- compile/runtime sanity checks
- debugging hooks
- source maps

---

# Object oriented

- multiple parent inheritance
- `super` method calls
- static initializers, `singleton`
- Contracts a.k.a. "virtual methods" 
- Natural `this` binding & orphan code checks

---

# Easy integration

- Just-in-time compiler: for full SAI/JS integration
- Build-ahead compiler: for lightweight/fast deploy
- One run-time package needed: `sai-library`
- No other external dependencies
- Both compilers produce native JS prototypes
- Easy to include and integrate in any project

---

# Minimal speed penalty

- Most constructs compile to simple JS
- Extensive use of temp variables and clear syntax
- Modern JS compilers optimize SAI very well
- Runtime library `sai-library` is light weight
- No other dependencies needed
- SAI projects are self-contained and run fast

---

# Modern & Extensible

- Full support for generators & promises
- Here documents, string composition
- Value chaining & pipe-like operators
- User-defined globals, constructs, operators

---

# Okay but
## What does it look like?

---

#### Whitespace matters

    while results's length < wordcount and duplicate > 0
      set word from GetWord
      unless tally\word or word's length < minimum
        push'd results word
      else
        dec duplicate
      inc tally\word
      
---

#### Every line begins with a verb.

    ply corpus as line
      set weight to 1
      ply line as word
        if number word 
          set weight to trial
        elsif word's length >= window
          push'd valid word
          if word's length > window
            AddWord it, weight



---
    
#### Just read it.

    ProcessArg task given path, branch
      if IsDirectory(path)
        every FS.readdirSync(path) as leaf
          local candidate PATH.join(path, leaf)
          if '.sai' is PATH.extname(leaf)
            ProcessArg candidate, branch
          elsif leaf isnt '.' and leaf isnt '..' and IsDirectory(candidate)
            ProcessArg candidate, PATH.join(branch, leaf)
      else 
        Build path, DestPath(path, branch)

---

Inline function calls use `from` before the verb clause.

    set path from PATH.join basepath, filename

Use `;` if necessary, to end a verb clause.

    



---

````
object Permutations main 1.0.0

AllHands to process given cards
  local Pick process given hand, deck
    if deck count
      every deck as card, index
        yielding !Pick hand concat card, deck delete index
    else
      yield hand
  yielding !Pick empty, cards

Instantiate to task
  debug "Permutation sample: three fruit."
  every !@AllHands list apple, banana, cherry
    debug .
````

