Skip to content

Commit

Permalink
# This is a combination of 7 commits.
Browse files Browse the repository at this point in the history
# This is the 1st commit message:

Labels for all loop varieties

more parser tests

# This is the commit message coalton-lang#2:

doh

# This is the commit message coalton-lang#3:

Fix: bad codgen for bare loop

# This is the commit message coalton-lang#4:

Fix: bad parse of while-let node after label feature

# This is the commit message coalton-lang#5:

Add: loop documentation to intro doc

# This is the commit message coalton-lang#6:

requested malarchy

# This is the commit message coalton-lang#7:

more tests; no break/continue from lambdas
  • Loading branch information
macrologist committed Oct 10, 2023
1 parent c9ca660 commit afd9882
Show file tree
Hide file tree
Showing 27 changed files with 610 additions and 298 deletions.
4 changes: 3 additions & 1 deletion coalton.asd
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
(:file "settings")
(:file "utilities")
(:file "global-lexical")
(:file "constants")
(:module "algorithm"
:serial t
:components ((:file "tarjan-scc")
Expand Down Expand Up @@ -318,4 +319,5 @@
(:file "red-black-tests")
(:file "seq-tests")
(:file "unused-variables")
(:file "pattern-matching-tests")))
(:file "pattern-matching-tests")
(:file "looping-native-tests")))
117 changes: 117 additions & 0 deletions docs/intro-to-coalton.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,123 @@ Structs can also be parametric:
(second :a)))
```

## Looping & Iteration

Coalton supports infinite looping, conditional looping, and `for`-loop styled iteration.

### `loop`, `while`, `while-let`, and `for`

You can loop forever

```lisp
(loop (trace "hi"))
```

You can loop while some condition is true

```lisp
(coalton
(let ((counter (cell:new 0))
(limit 10))
(while (< (cell:read counter) limit)
(trace "hi")
(cell:increment! counter))))
```

You can loop so long as a pattern matches

```lisp
(coalton
(let ((xs (vector:make 4 3 2 1)))
(while-let (Some x) = (vector:pop! xs)
(traceobject "x" x))))
```

You can loop over instances of `IntoIterator`

```lisp
(coalton
(for x in "coalton"
(traceobject "x" x)))
```


### `break` and `continue`

Each of the above looping forms supports `break` and `continue`.

The `break` form immediately terminates iteration. The following
prints out `c`, `o`, and `a` and then terminates.

```lisp
(coalton
(for x in "coalton"
(when (== x #\l)
(break))
(traceobject "x" x)))
```

The `continue` form skips the remainder of the loop's body and starts
on its next iteration. The following prints out `c`, `o`, `a`, `t`,
`o`, and `n`, having skipped the printing of `l`.

```lisp
(coalton
(for x in "coalton"
(when (== x #\l)
(continue))
(traceobject "x" x)))
```


### Loop Labels

Each of the above looping forms takes an optional loop label
keyword. These labels can be used in conjunction with `break` and
`continue` to acheive complex control flow.

For each of the looping forms, a label may immediately follow the
opening term of the loop:

```lisp
(loop :outer (do-stuff))
(while :a-label (is-true?) (do-stuff))
(while-let :another-label
(Some thing) = (get-something)
(do-stuff thing))
(for :iter word in words
(do-stuff-with word))
```

In the following entirely artificial example, the outermost loop is
labelled `:outer`. This label is passed to `break` from inside the
inner `while` loop to terminate iteration whenever the sum of the
accumulator and the counter exceeds 500. Without the `:outer` label,
`break` would have only broken out of the inner `while` loop.

```lisp
(coalton
(let ((counter (cell:new 0))
(acc (cell:new Nil)))
(loop :outer
(while (< (cell:increment! counter) 10)
(let x = (fold + (cell:read counter) (cell:read acc)))
(when (< 500 x)
(break :outer))
(when (== 0 (mod (cell:read counter) 3))
(continue))
(cell:push! acc x))
(when (< (length (cell:read acc)) 500)
(cell:swap! counter 0)
Unit))
(cell:read acc)))
```

## Numbers

Coalton supports a few numeric types. The main ones are `Integer`, `Single-Float`, and `Double-Float`.
Expand Down
30 changes: 18 additions & 12 deletions src/codegen/ast.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,18 @@
#:node-match-branches ; ACCESSOR
#:node-while ; STRUCT
#:make-node-while ; CONSTRUCTOR
#:node-while-label ; ACCESSOR
#:node-while-expr ; ACCESSOR
#:node-while-body ; ACESSOR
#:node-while-let ; STRUCT
#:make-node-while-let ; CONSTRUCTOR
#:node-while-let-label ; ACESSOR
#:node-while-let-pattern ; ACCESSPR
#:node-while-let-expr ; ACCESSOR
#:node-while-let-body ; ACESSOR
#:node-for ; STRUCT
#:make-node-for ; CONSTRUCTOR
#:node-for-label ; ACCESSOR
#:node-for-pattern ; ACCESSPR
#:node-for-iter ; ACCESSOR
#:node-for-body ; ACESSOR
Expand Down Expand Up @@ -191,36 +194,39 @@

(defstruct (node-while (:include node))
"A looping construct. Executes a body until an expression is false."
(expr (util:required 'expr) :type node :read-only t)
(body (util:required 'body) :type node :read-only t))
(label (util:required 'label) :type keyword :read-only t)
(expr (util:required 'expr) :type node :read-only t)
(body (util:required 'body) :type node :read-only t))

(defstruct (node-while-let (:include node))
"A looping construct. Executes a body until a pattern match fails."
(pattern (util:required 'pattern) :type pattern :read-only t)
(expr (util:required 'expr) :type node :read-only t)
(body (util:required 'body) :type node :read-only t))
(label (util:required 'label) :type keyword :read-only t)
(pattern (util:required 'pattern) :type pattern :read-only t)
(expr (util:required 'expr) :type node :read-only t)
(body (util:required 'body) :type node :read-only t))

(defstruct (node-for (:include node))
"A looping construct. Consumes an iterator, matching a pattern against
its elements, and executes body in the context of any variables bond
in the match."
(pattern (util:required 'pattern) :type pattern :read-only t)
(iter (util:required 'iter) :type node :read-only t)
(body (util:required 'body) :type node :read-only t))
(label (util:required 'label) :type keyword :read-only t)
(pattern (util:required 'pattern) :type pattern :read-only t)
(iter (util:required 'iter) :type node :read-only t)
(body (util:required 'body) :type node :read-only t))

(defstruct (node-loop (:include node))
"A labelled looping construct. Loops forever until broken out of by a
call to (break)."
(label (util:required 'label) :type (or keyword null) :read-only t)
(body (util:required 'body) :type node :read-only t))
(label (util:required 'label) :type keyword :read-only t)
(body (util:required 'body) :type node :read-only t))

(defstruct (node-break (:include node))
"A break statment used to exit a loop."
(label (util:required 'label) :type (or null keyword) :read-only t))
(label (util:required 'label) :type keyword :read-only t))

(defstruct (node-continue (:include node))
"A continue statment used to skip to the next iteration of a loop."
(label (util:required 'label) :type (or null keyword) :read-only t))
(label (util:required 'label) :type keyword :read-only t))

(defstruct (node-seq (:include node))
"A series of statements to be executed sequentially"
Expand Down
Loading

0 comments on commit afd9882

Please sign in to comment.