parsing.ss
(module parsing mzscheme
  (provide parse)
  
  (require (lib "yacc.ss" "parser-tools")
           (only (lib "lex.ss" "parser-tools")
                 token-name
                 position-token-token
                 position-line
                 position-col)
           "structs.ss"
           "lexing.ss")
  
  (define template-parser
    (parser (error (lambda (token-ok token-name token-value start-pos end-pos)
                     (error 'parser "Error at ~s ~s (~a:~a)"
                            token-name token-value
                            (position-line start-pos)
                            (position-col start-pos))))
            
            (tokens template-tokens)
            
            (src-pos)
            
            (start document)
            
            (end eof)
            
            (grammar [document
                      ((element-list)
                       (make-document $1))]
                     
                     [element-list
                      ((element-list/rev)
                       (reverse $1))
                      (() '())]
                     
                     [element-list/rev
                      ((element-list/rev element)
                       (cons $2 $1))
                      
                      ((element)
                       (list $1))]
                     
                     [element
                      ((non-delimiter)
                       (make-normal-text $1))
                      
                      ((delimiter expression delimiter)
                       $2)]
                     
                     [expression
                      ((string) (make-normal-text $1))
                      
                      ((identifier)
                       (make-variable-reference $1))
                      
                      ((identifier semicolon identifier equals expression)
                       (cond
                         [(string=? $3 "separator")
                          (make-variable-reference/separator $1 $5)]
                         [else
                          (error 'template-parser
                                 "Unsupported option ~s"
                                 $3)]))])))
  
  
  ;; parse: input-port -> document
  (define (parse inp)
    (define in-expression? #f)
    
    (define (choose-lexer)
      (cond
        [in-expression? expression-lexer]
        [else toplevel-lexer]))
    
    (define (get-token)
      (let ([next-token ((choose-lexer) inp)])
        (when (eq? (token-name (position-token-token next-token))
                   'delimiter)
          (set! in-expression? (not in-expression?)))
        next-token))
    
    (template-parser get-token)))