~akarle/fisl

refactor: Use aslist-ref instead of assoc/cadr

The joys of learning the base library over time :)
refactor: Update for-loop extraction and desugaring to use composition

This updates the for loop parser to go from a bunch of if-trees to a
bunch of functions, each taking the previous values as input, which
results in a very flat tree (dare I say more testable too?).
refactor: Add `assert-type!` to avoid many `(if (top-type?))` trees

This is a nice readability enhancement. It's safe since assert-type!
calls parse-err! which in turn call/cc's its way to safety (aborting
the current parse.
refactor: Allow top-type? to take in symbol or list

Might as well use dynamic typing to its fullest!
ch9.5: Implement an ugly version of for-loops

I realized knee deep into the desugaring that these cascading 'let's
should just be function composition... I'll refactor in a subsequent
commit. For now I need to go for a jog!
ch9.4: Implement 'while' loops

Another fun one to see come together!

~/src/fisl $ cat examples/while.lox
var x = 10;
while (x > 0) {
    print x;
    x = x - 1;
}
~/src/fisl $ ./fisl.scm examples/while.lox
10
9
8
7
6
5
4
3
2
1
assignment: Fix assignment vs definition bug

I had intermingled assignment and definition such that

var x = 5;

and

x = 5;

did the same thing, when really the first should create a new binding
in the current environment and the second should update the value in
*whichever environment has x defined (the closest one)*.

This was found while implementing 'while' since the following was an
infinite loop:

var x = 10;
while (x > 0) {
    print x;
    x = x - 1;
}

With the splitting of var -> env-def! and = -> env-set! in this patch,
it works as expected!
ch9.3: Implement 'and' and 'or' operators

It feels a little weird that these return the _value_ and not #t or #f.

Let's see what scheme does :thinking:

> (and "hi" "hello")
"hello"
> (or "hi" "hello")
"hi"

Well, you learn something new every day.
ch9.2: Implement if statements

Pretty cool to see this shake out :)

> var x = 3;
3
> if (x == 3) { print "woo"; } else { print "else"; }
woo
Add full block environments! (ch8.5)

This implements the parser for blocks as well as the necessary
interpreter bits!

Check it out!

$ cat examples/scope.lox
var a = "global a";
var b = "global b";
var c = "global c";
{
  var a = "outer a";
  var b = "outer b";
  {
    var a = "inner a";
    print a;
    print b;
    print c;
  }
  print a;
  print b;
  print c;
}
print a;
print b;
print c;

$ ./fisl.scm examples/scope.lox
inner a
outer b
global c
outer a
outer b
global c
global a
global b
global c
interpreter: Add custom 'env' object for nested envs

This sets the stage for block scope, but keeps the existing
"everything is global" behavior.

I'm 85% sure the (make-env) returning a proc that returns procs is
something I've seen in SICP (as a means of creating objects with methods).
parser: Fix synchronization at end of input

In Scheme, only #f is falsey:

> (if 0 (print "truthy"))
truthy

> (if '() (print "truthy"))
truthy

So checking (and toks ...) wasn't doing the empty list check I was intending!
parser: Add synchronization at declaration level

Before the parser stopped entirely at the first parse error:

$ cat examples/sync.lox
print 1 + for;
print 2 + 2;
print 1 + this;

$ ./fisl.scm examples/sync.lox
examples/sync.lox:1:Error at for. Unknown token

Now it synchronizes by going to the next statement and finds all parse
errors (but does NOT execute them):

$ ./fisl.scm examples/sync.lox
examples/sync.lox:1:Error at for. Unknown token
examples/sync.lox:3:Error at this. Unknown token
docs: Fix some TODO's and comment indentation

Emacs likes to put single-; comments way to the right :(

Mostly back in Vim now, if anyone is curious.
repl: Print expr-stmts and drop need for ';'

In the repl, we can drop the requirements on using ';' for most
statements.

By allowing execute to evaluate and print expr-statemtents we go from
this:

> var x = 1;
> print x = 2;
2

to

> var x = 1;
> x = 2
2
> x
2

Nice!
cleanup: Remove repl logging at startup
interpreter: Fix assignment not evaluating RHS

This was a funny find :)

Before

$ ./fisl.scm
> var x = 1;
> print x = 1 + 1;
(+ 1 1)

After:
> var x;
> print x = 1 + 1;
2
> print x;
2
refactor: let-values, fname global, less nested functions

This is a large overhaul of the parser.scm code to:

* Use let-values / values instead of (let*) and (cons).
* Renaming all parsing functions to (parse-*) to indicate they.. parse
* Making fname a global for util so that I don't have to keep passing it
* Removing the nesting of all the parsing functions (to better support
  repl development!)
* Rewriting all the generic binary / statement code to follow a general
  form with functions as parameters to "descend"
repl: Add threads and nrepl for live image updates

This was a deep rabbit hole, mostly because (read-line) is blocking I/O
and _all_ threads block when blocking I/O is hit (except tcp). This was
counterintuitive (isn't the whole point of threads to swap when on I/O?)
but nevertheless, I got it to work!

Here's my setup:

1. Start the CHICKEN interpreter via the executable (drops into Lox
   interpreter):

$ ./fisl.scm
> print 1 + 1;
2
>

2. In another tmux split, create a fifo and connect to the 1234 nrepl
   port (credit: http://www.foldling.org/hacking.html#2012-08-05):

$ mkfifo repl
$ cat > repl & nc localhost 1234 < repl

3. Lastly, in Vim, run the following to send the current paragraph to
   the repl on C-c C-c:

:nnoremap <C-c><C-c> vap:w >> repl<CR>

---

Demo:

* Go to (prompt), update s/display "> "/display ">> "/
* C-c C-c
* Hit enter in fisl -- notice prompt is changed!
Add support for assignment

ch8.4

> var x = 2;
> print x = 1;
1
Next