Lisp middle-tags

Motivation

Lisp syntax has many advantages over infix notation and other syntax-heavy notations. But one disadvantage that Lisp has is difficulty detecting terminator errors.

If, say, you are compiling C and you just didn't close a block, or closed it when you shouldn't have, there's little uncertainty about where the error happened. It's on or shortly before first line in the big list of frantic error messages. Pretty much always. But in Lisp, the error often manifests a fair distance after the missing or extra terminator.

True, you can re-indent your code (if your editor doesn't do this, switch to emacs now) and look for what changes. Manually. If the code in question fits on a page, if you've already narrowed it down to one function, if it isn't already nested in a larger form, eg a `let' to declare private variables, etc.

A proposal

Overview

There would be optional middle-tags. They would remind both the user and the Lisp reader of which form was properly being read. It would be an error if a middle-tag didn't match the head of the current form.

Syntax

A middle-tag could be written at any point in a form. A suggested syntax is:

      #@(head)

    

where HEAD is a single symbol corresponding to the head of the form being read.

The following example show several middle-tags in context. It is much more dense than actual code would be.

      (progn
	(let* 
	  #@(let*)
	  (
	    (a (car 
		 #@(car)
		 mylist))))
	#@(progn))
      
    

Behavior

Mismatch makes errors

A middle-tag error occurs if a middle-tag doesn't match the head of the current form. Matching is purely lexical, so macro heads must be matched as themselves, not as the code they produce.

*middle-tag-strategy* controls what happens on errors.

Suggested uses

List of new code required

Possible extensions

To place the form in more context

One possible extension would be to allow a list of form heads instead of just one, to place the form in context. The first head would always refer to the exact form currently being read. Successive heads would refer to other enclosing forms, smallest first, but not neccessarily contiguous.

To place the form in richer context

This is different than placing it in more context. To place the form in richer context, each element would be allowed to include, not just the form's head, but other following elements. EG:

(when my-test-p ... ... #@((when my-test-p)))

To allow some degree of recovery

Recovery could be useful in a text-formatting language (eg Latte), and in machine-generated code of which some sections are not vital.

Conceivably, the reader could pop out to a matching level, if it's within a few steps. It would be much more difficult, perhaps impossible, to push back into a level already left, but if the tag pertains to a recently-finished form and the reader knows this, the reader could ignore as many terminators as need to be skipped.