(in-package #:user-side-compiler) (defun string-nth-line (string line) (assert (> line 0)) (let ((start (loop :repeat line :for start := 0 :then (1+ (position #\Newline string :start start)) :finally (return start)))) (subseq string start (if (< start (length string)) (position #\Newline string :start (1+ start)) nil)))) (defun point-out-source (source) (if (null source) "No source info." (destructuring-bind (text line . column) source (cond ((null text) (format nil "Line ~D, column ~D" line column)) ((stringp text) (with-output-to-string (output) (format output "~%Found on line ~D, column ~D:~%~A~%" line column (string-nth-line text line)) (loop :repeat column :do (write-char #\Space output)) (write-char #\^ output))))))) (define-condition usc-error (error) ((%source :accessor source :initarg :source :initform nil) (%format-control :accessor format-control :initarg :format-control) (%format-arguments :accessor format-arguments :initarg :format-arguments :initform '()) (%context-string :reader context-string :initform "User-side compiler error at unknown stage:")) (:report (lambda (c s) (format s "~A~%~A~%~A" (context-string c) (apply #'format nil (format-control c) (format-arguments c)) (point-out-source (source c)))))) (define-condition tokenizer-error (usc-error) ((%context-string :initform "Tokenizing error:"))) (define-condition missing-function-error (usc-error) ((%context-string :initform "Non-existent function (TODO nicer error for this):"))) (define-condition parser-error (usc-error) ((%context-string :initform "Syntax error:"))) (defun error-parser (source format-control &rest format-arguments) (error 'parser-error :source source :format-control format-control :format-arguments format-arguments))