|
1 | 1 | (uiop:define-package :diff-backend/parser |
2 | 2 | (:nicknames :parser) |
3 | | - (:use :cl :diff-backend/lexer) |
| 3 | + (:use :cl :diff-backend/lexer |
| 4 | + :diff-backend/utils) |
4 | 5 | (:import-from :alexandria |
5 | | - :eswitch) |
| 6 | + :eswitch) |
6 | 7 | (:export #:parser)) |
7 | 8 |
|
8 | 9 | (in-package :diff-backend/parser) |
|
14 | 15 |
|
15 | 16 | (defvar *cur-lex* nil) |
16 | 17 |
|
| 18 | +(defclass* parser-error-info () |
| 19 | + ((error-text |
| 20 | + :accessor error-text |
| 21 | + :initarg :error-text) |
| 22 | + (error-lex-id |
| 23 | + :accessor error-lex-id |
| 24 | + :initarg :error-lex-id))) |
| 25 | + |
17 | 26 | (defun next-lexem () |
18 | 27 | (progn |
19 | 28 | (setf *cur-lex* (first *lexems-rest*)) |
20 | 29 | (setf *lexems-rest* (rest *lexems-rest*)) |
21 | 30 | *cur-lex*)) |
22 | 31 |
|
23 | | -(defun cur-lexem () |
24 | | - *cur-lex*) |
| 32 | +(defun throw-error (error-text error-lex) |
| 33 | + (throw 'parser-start |
| 34 | + (values nil |
| 35 | + (make-instance |
| 36 | + 'parser-error-info |
| 37 | + :error-text |
| 38 | + (format nil "At (~S:~S) ~A" |
| 39 | + (lexem-line error-lex) |
| 40 | + (lexem-column error-lex) |
| 41 | + error-text) |
| 42 | + :error-lex-id (id error-lex))))) |
25 | 43 |
|
26 | 44 | (defun parser (lexems) |
27 | 45 | (let ((*lexems-rest* lexems) |
28 | 46 | (s-expr-l)) |
29 | | - (loop :while *lexems-rest* |
30 | | - :do (push (s-expr-rule (next-lexem)) s-expr-l)) |
31 | | - `(:top () ,@(reverse s-expr-l)))) |
| 47 | + (catch 'parser-start |
| 48 | + (loop :while *lexems-rest* |
| 49 | + :do (push (s-expr-rule (next-lexem)) s-expr-l)) |
| 50 | + `(:top () ,@(reverse s-expr-l))))) |
32 | 51 |
|
33 | 52 | (defun s-expr-rule (lex) |
34 | 53 | (ecase (lexem-type lex) |
|
37 | 56 | ((:left-parent) |
38 | 57 | (list-rule lex)) |
39 | 58 | ((:quote) |
40 | | - `(:quote ((:coord ,(lexem-line lex) |
41 | | - ,(lexem-column lex))) |
42 | | - ,(s-expr-rule (next-lexem)))))) |
| 59 | + (let ((next-lex (next-lexem))) |
| 60 | + (when (or (null next-lex) |
| 61 | + (eq (lexem-type next-lex) :right-parent)) |
| 62 | + (throw-error "no s-expr after '" lex)) |
| 63 | + `(:quote |
| 64 | + ((:coord ,(lexem-line lex) |
| 65 | + ,(lexem-column lex))) |
| 66 | + ,(s-expr-rule next-lex)))) |
| 67 | + ((:right-parent) |
| 68 | + (throw-error "unmatched close parenthesis" lex)))) |
43 | 69 |
|
44 | 70 | (defun list-rule (left-parent-lexem) |
45 | 71 | (do ((s-expr-l nil) |
46 | 72 | (lex (next-lexem) (next-lexem))) |
47 | | - ((eq (lexem-type lex) :right-parent) |
| 73 | + ((when lex (eq (lexem-type lex) :right-parent)) |
48 | 74 | `(:list ((:lparen-coord ,(lexem-line left-parent-lexem) |
49 | 75 | ,(lexem-column left-parent-lexem)) |
50 | 76 | (:rparen-coord ,(lexem-line lex) |
51 | 77 | ,(lexem-column lex))) |
52 | 78 | ,@(reverse s-expr-l))) |
| 79 | + (unless lex |
| 80 | + (throw-error "unclosed parenthesis" left-parent-lexem)) |
53 | 81 | (push (s-expr-rule lex) s-expr-l))) |
0 commit comments