(defun parse (str)
  "Parse STR as a Javascript script, returning a list of statements.
   Semicolon insertion is performed according to the ECMA-262 standard."
  (let ((lexer (make-instance 'javascript-lexer :text str)))
    (labels ((resignal (err)
               (let ((pos (token-start (yacc:yacc-parse-error-value err))))
                 (destructuring-bind (row . col) (position-to-line/column
                                                  str
                                                  pos)
                   (error (make-condition 'syntax-error
                                          :token (yacc:yacc-parse-error-value err)
                                          :expected-terminals (yacc:yacc-parse-error-expected-terminals err)
                                          :pos pos :row row :column col)))))
             (handle-yacc-error (err)
               (cond

                 ;; Irritating regular-expression-literal vs. division ambiguity case.
                 ;; If we encounter an unexpected RE literal, try interpreting it as a
                 ;; division operator instead.  We do that by rewinding the lexer to
                 ;; just before the RE literal and instructing it to read the slash as
                 ;; just a slash.  We then instruct the parser to throw away the RE
                 ;; literal and continue parsing.
                 ((and (eq :re-literal (yacc:yacc-parse-error-terminal err))
                       (find :slash (yacc:yacc-parse-error-expected-terminals err)))
                  (set-cursor lexer (token-start (yacc:yacc-parse-error-value err)))
                  (coerce-token lexer :slash)
                  (invoke-restart 'yacc:skip-terminal))
                 
                 ;; Don't try to perform semicolon insertion unless inserted-semicolons are permitted
                 ((null (find :inserted-semicolon (yacc:yacc-parse-error-expected-terminals err)))
                  (resignal err))
                   
                 ;; Semicolon-insertion case
                 ((or (encountered-line-terminator lexer)
                      (eq :right-curly (yacc:yacc-parse-error-terminal err))
                      (eq 'yacc:yacc-eof-symbol (yacc:yacc-parse-error-terminal err)))
                  (invoke-restart 'yacc:insert-terminal :inserted-semicolon 
                                  #s(token :terminal :inserted-semicolon :value ";")))

                 ;; Resignal as a jwacs error if we don't handle the yacc error
                 (t (resignal err)))))
                    
      (handler-bind ((yacc:yacc-parse-error #'handle-yacc-error))
        (yacc:parse-with-lexer (make-lexer-function lexer) javascript-script)))))