On this page:
Code
7.4.0.4

12 Lab Languages and Readers

Matthew Flatt

Start with "pfsh/main.rkt".

Exercise 28. The result of this program may seem confusing:
#lang pfsh
 
(define x "hello")
(echo x)
The problem is that pfsh as specified so far takes over define to be output capture, and the expression "hello" has no output.

Let’s pick a better syntax for program-output capture, and then we can change define to behave more normally so that the program above echoes “hello.” For output capture, let’s use > followed by an identifier after a command:
#lang pfsh
(whoami > me)
(echo Hello me)
A command can have both < and > redirection, but report an error unless the > part is second.

Exercise 29. If < or > is used anywhere other than a program-running command, then pfsh should report an error that the < or > is misplaced.

A good way to implement that constraint is to bind < and > as macros that always raise a syntax error. Meanwhile, #%app already recognizes uses that are in the right place and takes care of them (so no syntax error will be reported). Still, you can and should adjust #%app to use #:literals instead of #:datum-literals.

Exercise 30. Our pfsh language is parenthesis-friendly, but also parenthesis-insistent. Consider a variant of pfsh where parentheses are implicit: if a non-comment line’s first non-whitespace element isn’t parenthesized, parentheses are added around the whole line.
#lang pfsh
 
; Parentheses are implicit around the next line
ls -l
 
; No implicit parentheses if they're explicit
(ls -l)
 
; Strings are allowed with implicit parentheses
echo "Hello, world!"
 
; Ok to rely on implicit parentheses for a single-line definition
define greeting "Hello"
echo greeting
 
; Use explicit parentheses for a multi-line expression
(whoami
  > me)
echo -n Hello to me
 
; A lone identifier still has implicit parentheses
racket

Change pfsh to allow implicit parentheses by changing #%module-begin to add them. You can determine when syntax objects are on the same line by using the syntax-line function. You can infer that parentheses are present when syntax-e produces a value for which pair? produces a true value.

Changing #%module-begin isn’t really the right idea, as we explore in the next exercise, but try this bad idea, first.

Exercise 31. The problem with adding implicit parentheses in #%module-begin is that it confuses two layers: The existence of tokens on the same line is properly a reader-level decision, since it’s about sequences of characters.

As an illustration of the problem, consider this program:
#lang racket
(require (for-syntax syntax/parse
                     syntax/strip-context))
 
(define-syntax (main-submodule stx)
  (syntax-parse stx
    [(_ word)
     (with-syntax ([word (strip-context #'word)])
       #'(module main pfsh
           echo word))]))
 
(main-submodule hello)
There’s a little subtlety here in making hello have the right binding by using strip-context, but making it have the right source location to line up with echo would be much more trouble.

The racket language is not set up for implicit parentheses, so a better and more consistent strategy for pfsh is to make implicit parentheses part of the reader. Move your strategy in the previous exercise from #%module-begin to the reader. You can use #:wrapper1 in syntax/module-reader to adjust the result that the reader would otherwise return.

Exercise 32. Install the turnstile package on your laptop.

You can install a package by selecting Install Package... from DrRacket’s File menu or by running raco pkg install turnstile at the command line.

Survey link: https://forms.gle/3MANRhmf3NQWNDGW8

Code

Code and solutions