Programming Languages: Application and Interpretation
This is the documentation for the software accompanying the textbook Programming Languages: Application and Interpretation (PLAI). The full book can be found on the Web at:
http://www.cs.brown.edu/~sk/Publications/Books/ProgLangs/
In DrScheme, under the Language menu, select Choose Language.... Under the section Programming Languages: Application and Interpretation, you will find the following languages:
PLAI Scheme - #lang planet plai/plai:1:16
GC Collector Scheme - #lang planet plai/plai:1:16/collector
GC Mutator Scheme - #lang planet plai/plai:1:16/mutator
Web Application Scheme - #lang planet plai/plai:1:16/web
1 PLAI Scheme
PLAI Scheme is derived from the scheme langauge. In addition, it includes the define-type and type-case forms and testing support.
1.1 Defining Types: define-type
(define-type type-id variant ...) | |||||
|
The value of each field is checked by its associated contract-expr. A contract-expr may be an arbitrary predicate or a contract.
In addition to the contructors, a define-type expression also defines:
a predicate type-id? that returns true for instances of the datatype, and false for any other value,
for each variant, a predicate variant-id? that returns true when applied to a value of the same variant and false for any other value,
for each field of each variant, an accessor variant-id-field-id that returns the value of the field, and
for each field of each variant, a mutator set-variant-id-field-id! that set the value of the field.
1.2 Deconstructing Data Structures: type-case
| ||||||||||
|
If a branch is not specified for each variant, you may use an else branch to create a catch-all branch. An else branch must be the last branch in the sequence of branches. type-case signals a compile-time error if all variants are not covered and the else branch is missing. Similarly, type-case signals a compile-time error if an else branch is unreachable because a branch exists for all variants.
1.3 Testing Infrastructure
PLAI Scheme provides the following syntactic forms for testing.
(test result-expr expected-expr) |
(good result-expr result-value expected-value location).
If they do not evaluate to the same value, the test prints
(bad result-expr result-value expected-value location).
If evaluating result-expr signals an error, the test prints
(exception result-expr exception-message <no-expected-value> location)
If evaluating expected-expr signals an error, the test prints
(pred-exception result-expr exception-message <no-expected-value> location)
(test/pred result-expr pred?) |
If evaluating pred? signals an error, the test prints
(pred-exception result-expr exception-message <no-expected-value> location)
The syntax of pred? is considered expected-value for the purposes of test reporting.
(test/exn result-expr error-message) |
For example, the following test succeeds:
(test/exn (error "/: division by zero") "by zero")
The error message is "/: division by zero", and "by zero" is a substring of the error message. However, the following test fails:
Although the expression raises an exception and the error string contains "by zero", since the error was not explicitly raised by user-written code, the test fails.
The evaluation of error-message is considered expected-value for the purposes of test reporting.
(test/regexp result-expr error-message-regexp) |
The evaluation of error-message-regexp is considered expected-value for the purposes of test reporting.
1.3.1 Test Flags
(abridged-test-output [abridge?]) → void? |
abridge? : boolean? = false |
(plai-catch-test-exn [catch?]) → void? |
catch? : boolean? = true |
(halt-on-errors [halt?]) → void? |
halt? : boolean? = true |
(print-only-errors [print?]) → void? |
print? : boolean? = true |
(test-inexact-epsilon epsilon) → void? |
epsilon : number? |
(plai-ignore-exn-strings ignore?) → void? |
ignore? : boolean? |
2 GC Collector Scheme
#lang planet plai/plai:1:16/collector
GC Collector Scheme is based on PLAI Scheme. It provides additional procedures and syntax for writing garbage collectors.
2.1 Garbage Collector Interface
The GC Collector Scheme language provides the following functions that provide access to the heap and root set:
(heap-value? v) → boolean? |
v : any/c |
(heap-set! loc val) → void? |
loc : location? |
val : heap-value? |
(heap-ref loc) → heap-value? |
loc : location? |
(get-root-set id ...) |
(procedure-roots proc) → (listof root?) |
proc : procedure? |
(with-heap heap expr ...) | ||||||
|
(test (with-heap (make-vector 20) |
(init-allocator) |
(gc:deref (gc:alloc-flat 2))) |
2) |
2.2 Garbage Collector Exports
A garbage collector must define the following functions:
(init-allocator) → void? |
(gc:deref loc) → heap-value? |
loc : location? |
(gc:alloc-flat val) → location? |
val : heap-value? |
Note that closures are flat values. The environment of a closure is internally managed, but contains references to values on the heap. Therefore, during garbage collection, the environment of reachable closures must be updated. The language exposes the environment via the procedure-roots function.
(gc:set-first! cons-cell first-value) → void? |
cons-cell : location? |
first-value : location? |
(gc:set-rest! cons-cell rest-value) → void? |
cons-cell : location? |
rest-value : location? |
(gc:cons? loc) → boolean? |
loc : location? |
Returns true if loc refers to a cons cell. This function should never signal an error.
3 GC Mutator Scheme
#lang planet plai/plai:1:16/mutator
The GC Mutator Scheme language is used to test garbage collectors written with the GC Collector Scheme language. Since collectors support a subset of Scheme’s values, the GC Mutator Scheme language supports a subset of procedures and syntax. In addition, many procedures that can be written in the mutator are omitted as they make good test cases. Therefore, the mutator language provides only primitive procedures, such as +, cons, etc.
3.1 Building Mutators
The first expression of a mutator must be:
| |||||
|
The rest of a mutator module is a sequence of definitions, expressions and test cases. The GC Mutator Scheme language transforms these definitions and statements to use the collector specified in allocator-setup. In particular, many of the primitive forms, such as cons map directly to procedures such as gc:cons, written in the collector.
3.2 Mutator API
The GC Mutator Scheme language supports the following syntactic forms:
if and or cond case define define-values let let-values let* set! lambda λ quote error begin
The language also defines the following procedures:
add1 sub1 zero? + - * / even? odd? = < > <= >= cons first rest |
set-first! set-rest! cons? symbol? number? boolean? empty? eq? |
(set-first! c v) → void |
c : cons? |
v : any/c |
The identifier empty is defined to invoke (gc:alloc-flat empty) wherever it is used.
Other common procedures are left undefined as they can be defined in terms of the primitives and may be used to test collectors.
Additional procedures from scheme may be imported with:
(import-primitives id ...) |
For example, the GC Mutator Scheme language does not define modulo:
(import-primitives modulo) |
(test/value=? (modulo 5 3) 2) |
3.3 Testing Mutators
GC Mutator Scheme provides two forms for testing mutators:
(test/location=? mutator-expr1 mutator-expr2) |
(test/value=? mutator-expr scheme-datum/quoted) |
(printf format mutator-expr ...) | |||||
|
4 Web Application Scheme
#lang planet plai/plai:1:16/web
The Web Application Scheme language allows you to write server-side Web applications for the PLT Web Server.
For more information about writing Web applications, see: Web: PLT Web Applications.
A Web application must define a procedure start:
(start initial-request) → response? |
initial-request : request? |
When you click on the Run button in DrScheme, your Web application is launched in the Web server.
The application is available at http://localhost:8000/servlets/standalone.ss.
The Web Application Scheme language will automatically load this URL in your Web browser.
You may use no-web-browser to prevent the browser from being launched and static-files-path to serve additional static files.