Skip to content

Commit

Permalink
Get the notes building with ziggy.
Browse files Browse the repository at this point in the history
  • Loading branch information
dvanhorn committed Jul 10, 2023
1 parent 7a5a4a5 commit 06574e5
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 195 deletions.
44 changes: 22 additions & 22 deletions www/notes/abscond.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,10 @@ parse the concrete expression as an s-expression.
While not terribly useful for a language as overly simplistic as Abscond, we use
an AST datatype for representing expressions and another syntactic categories.
For each category, we will have an appropriate constructor. In the case of Abscond
all expressions are integers, so we have a single constructor, @racket[Int].
all expressions are integers, so we have a single constructor, @racket[Lit].

@(define-language A-concrete
(e ::= (Int i))
(e ::= (Lit i))
(i ::= integer))

@centered{@render-language[A-concrete]}
Expand All @@ -171,7 +171,7 @@ it is, otherwise it signals an error:
@section{Meaning of Abscond programs}

The meaning of an Abscond program is simply the number itself. So
@racket[(Int 42)] evaluates to @racket[42].
@racket[(Lit 42)] evaluates to @racket[42].

We can write an ``interpreter'' that consumes an expression and
produces it's meaning:
Expand All @@ -180,8 +180,8 @@ produces it's meaning:

@#reader scribble/comment-reader
(examples #:eval ev
(interp (Int 42))
(interp (Int -8))
(interp (Lit 42))
(interp (Lit -8))
)

We can add a command line wrapper program for interpreting Abscond
Expand Down Expand Up @@ -213,15 +213,15 @@ language, just a single inference rule suffices:
#:mode (𝑨 I O)
#:contract (𝑨 e i)
[----------
(𝑨 (Int i) i)])
(𝑨 (Lit i) i)])

@(centered (render-judgment-form 𝑨))

Here, we are defining a binary relation, called
@render-term[A 𝑨], and saying every integer literal
expression is paired with the integer itself in the
relation. So @math{((Int 2),2)} is in @render-term[A 𝑨],
@math{((Int 5),5)} is in @render-term[A 𝑨], and so on.
relation. So @math{((Lit 2),2)} is in @render-term[A 𝑨],
@math{((Lit 5),5)} is in @render-term[A 𝑨], and so on.

The inference rules define the binary relation by defining the
@emph{evidence} for being in the relation. The rule makes use of
Expand Down Expand Up @@ -419,8 +419,8 @@ Writing the @racket[compile] function is easy:

@#reader scribble/comment-reader
(examples #:eval ev
(compile (Int 42))
(compile (Int 38))
(compile (Lit 42))
(compile (Lit 38))
)

To convert back to the concrete NASM syntax, we use
Expand All @@ -432,7 +432,7 @@ appropriately.}

@#reader scribble/comment-reader
(examples #:eval ev
(asm-display (compile (Int 42))))
(asm-display (compile (Lit 42))))

Putting it all together, we can write a command line compiler much
like the command line interpreter before, except now we emit assembly
Expand Down Expand Up @@ -533,17 +533,17 @@ compilation within Racket:


@examples[#:eval ev
(asm-interp (compile (Int 42)))
(asm-interp (compile (Int 37)))
(asm-interp (compile (Int -8)))
(asm-interp (compile (Lit 42)))
(asm-interp (compile (Lit 37)))
(asm-interp (compile (Lit -8)))
]

This of course agrees with what we will get from the interpreter:

@examples[#:eval ev
(interp (Int 42))
(interp (Int 37))
(interp (Int -8))
(interp (Lit 42))
(interp (Lit 37))
(interp (Lit -8))
]

We can turn this in a @bold{property-based test}, i.e. a function that
Expand All @@ -554,9 +554,9 @@ correctness claim:
(check-eqv? (interp e)
(asm-interp (compile e))))

(check-compiler (Int 42))
(check-compiler (Int 37))
(check-compiler (Int -8))
(check-compiler (Lit 42))
(check-compiler (Lit 37))
(check-compiler (Lit -8))
]

This is a powerful testing technique when combined with random
Expand All @@ -565,11 +565,11 @@ Abscond programs, we can randomly generate @emph{any} Abscond program
and check that it holds.

@examples[#:eval ev
(check-compiler (Int (random 100)))
(check-compiler (Lit (random 100)))

; test 10 random programs
(for ([i (in-range 10)])
(check-compiler (Int (random 10000))))
(check-compiler (Lit (random 10000))))
]

The last expression is taking 10 samples from the space of Abscond
Expand Down
54 changes: 27 additions & 27 deletions www/notes/blackmail.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ The grammar of abstract Backmail expressions is:

@centered{@render-language[B]}

So, @racket[(Int 0)], @racket[(Int 120)], and
@racket[(Int -42)] are Blackmail AST expressions, but so are
@racket[(Prim1 'add1 (Int 0))], @racket[(Sub1 (Int 120))],
@racket[(Prim1 'add1 (Prim1 'add1 (Prim1 'add1 (Int -42))))].
So, @racket[(Lit 0)], @racket[(Lit 120)], and
@racket[(Lit -42)] are Blackmail AST expressions, but so are
@racket[(Prim1 'add1 (Lit 0))], @racket[(Sub1 (Lit 120))],
@racket[(Prim1 'add1 (Prim1 'add1 (Prim1 'add1 (Lit -42))))].

A datatype for representing expressions can be defined as:

Expand Down Expand Up @@ -129,7 +129,7 @@ contrast to the first rule, which applies unconditionally.

We can understand these rules as saying the following:
@itemlist[
@item{For all integers @math{i}, @math{((Int i),i)} is in @render-term[B 𝑩].}
@item{For all integers @math{i}, @math{((Lit i),i)} is in @render-term[B 𝑩].}

@item{For expressions @math{e_0} and all integers @math{i_0} and
@math{i_1}, if @math{(e_0,i_0)} is in @render-term[B 𝑩] and @math{i_1
Expand Down Expand Up @@ -157,11 +157,11 @@ interpreter, one for each form of expression:
@codeblock-include["blackmail/interp.rkt"]

@examples[#:eval ev
(interp (Int 42))
(interp (Int -7))
(interp (Prim1 'add1 (Int 42)))
(interp (Prim1 'sub1 (Int 8)))
(interp (Prim1 'add1 (Prim1 'add1 (Prim1 'add1 (Int 8)))))
(interp (Lit 42))
(interp (Lit -7))
(interp (Prim1 'add1 (Lit 42)))
(interp (Prim1 'sub1 (Lit 8)))
(interp (Prim1 'add1 (Prim1 'add1 (Prim1 'add1 (Lit 8)))))
]

Here's how to connect the dots between the semantics and interpreter:
Expand All @@ -172,7 +172,7 @@ expression, which determines which rule of the semantics applies.

@itemlist[

@item{if @math{e} is an integer @math{(Int i)}, then we're done: this is the
@item{if @math{e} is an integer @math{(Lit i)}, then we're done: this is the
right-hand-side of the pair @math{(e,i)} in @render-term[B 𝑩].}

@item{if @math{e} is an expression @RACKET[(Prim1 'add1 (UNSYNTAX
Expand Down Expand Up @@ -241,9 +241,9 @@ recursion, much like the interpreter.
We can now try out a few examples:

@ex[
(compile (Prim1 'add1 (Prim1 'add1 (Int 40))))
(compile (Prim1 'sub1 (Int 8)))
(compile (Prim1 'add1 (Prim1 'add1 (Prim1 'sub1 (Prim1 'add1 (Int -8))))))
(compile (Prim1 'add1 (Prim1 'add1 (Lit 40))))
(compile (Prim1 'sub1 (Lit 8)))
(compile (Prim1 'add1 (Prim1 'add1 (Prim1 'sub1 (Prim1 'add1 (Lit -8))))))
]

And give a command line wrapper for parsing, checking, and compiling
Expand All @@ -264,9 +264,9 @@ the same @racket[asm-interp] function to encapsulate running
assembly code:

@ex[
(asm-interp (compile (Prim1 'add1 (Prim1 'add1 (Int 40)))))
(asm-interp (compile (Prim1 'sub1 (Int 8))))
(asm-interp (compile (Prim1 'add1 (Prim1 'add1 (Prim1 'add1 (Prim1 'add1 (Int -8)))))))
(asm-interp (compile (Prim1 'add1 (Prim1 'add1 (Lit 40)))))
(asm-interp (compile (Prim1 'sub1 (Lit 8))))
(asm-interp (compile (Prim1 'add1 (Prim1 'add1 (Prim1 'add1 (Prim1 'add1 (Lit -8)))))))
]

@section{Correctness and random testing}
Expand Down Expand Up @@ -332,10 +332,10 @@ x86 does. Let's see:
@ex[
(define max-int (sub1 (expt 2 63)))
(define min-int (- (expt 2 63)))
(asm-interp (compile (Int max-int)))
(asm-interp (compile (Prim1 'add1 (Int max-int))))
(asm-interp (compile (Int min-int)))
(asm-interp (compile (Prim1 'sub1 (Int min-int))))]
(asm-interp (compile (Lit max-int)))
(asm-interp (compile (Prim1 'add1 (Lit max-int))))
(asm-interp (compile (Lit min-int)))
(asm-interp (compile (Prim1 'sub1 (Lit min-int))))]

Now there's a fact you didn't learn in grade school: in the
first example, adding 1 to a number made it smaller; in the
Expand All @@ -344,18 +344,18 @@ second, subtracting 1 made it bigger!
This problem doesn't exist in the interpreter:

@ex[
(interp (Int max-int))
(interp (Prim1 'add1 (Int max-int)))
(interp (Int min-int))
(interp (Prim1 'sub1 (Int min-int)))
(interp (Lit max-int))
(interp (Prim1 'add1 (Lit max-int)))
(interp (Lit min-int))
(interp (Prim1 'sub1 (Lit min-int)))
]

So we have found a counter-example to the claim of compiler
correctness:

@ex[
(check-compiler (Prim1 'add1 (Int max-int)))
(check-compiler (Prim1 'sub1 (Int min-int)))
(check-compiler (Prim1 'add1 (Lit max-int)))
(check-compiler (Prim1 'sub1 (Lit min-int)))
]

What can we do? This is the basic problem of a program not
Expand Down
2 changes: 1 addition & 1 deletion www/notes/con.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ The complete compiler code is:
Mirroring the change we made to the interpreter, we separate out a
module for compiling primitives:

@codeblock-include["con/compile-prim.rkt"]
@codeblock-include["con/compile-ops.rkt"]

Let's take a look at a few examples:
@ex[
Expand Down
16 changes: 8 additions & 8 deletions www/notes/dodger.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -114,27 +114,27 @@ The meaning of characters and their operations are just lifted from Racket.
We can try out some examples:

@ex[
(interp (Char #\a))
(interp (Char #\b))
(interp (Prim1 'char? (Char #\a)))
(interp (Prim1 'char? (Bool #t)))
(interp (Prim1 'char->integer (Char #\a)))
(interp (Prim1 'integer->char (Prim1 'char->integer (Char #\a))))
(interp (Lit #\a))
(interp (Lit #\b))
(interp (Prim1 'char? (Lit #\a)))
(interp (Prim1 'char? (Lit #t)))
(interp (Prim1 'char->integer (Lit #\a)))
(interp (Prim1 'integer->char (Prim1 'char->integer (Lit #\a))))
]

Just as in Dupe, type errors result in the interpreter crashing:


@ex[
(eval:error (interp (Prim1 'char->integer (Bool #f))))
(eval:error (interp (Prim1 'char->integer (Lit #f))))
]

Also, not every integer corresponds to a character, so when
@racket[integer->char] is given an invalid input, it crashes
(more on this in a minute):

@ex[
(eval:error (interp (Prim1 'integer->char (Int -1))))
(eval:error (interp (Prim1 'integer->char (Lit -1))))
]

@section{Ex uno plures iterum: Out of One, Many... Again}
Expand Down
Loading

0 comments on commit 06574e5

Please sign in to comment.