parser.scm 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. ;;; parser.scm -- parse tokens for Joy.
  2. ;;; Copyright © 2016 Eric Bavier <bavier@member.fsf.org>
  3. ;;;
  4. ;;; Joy is free software; you can redistribute it and/or modify it under
  5. ;;; the terms of the GNU General Public License as published by the Free
  6. ;;; Software Foundation; either version 3 of the License, or (at your
  7. ;;; option) any later version.
  8. ;;;
  9. ;;; Joy is distributed in the hope that it will be useful, but WITHOUT
  10. ;;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. ;;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  12. ;;; License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU General Public License
  15. ;;; along with Joy. If not, see <http://www.gnu.org/licenses/>.
  16. (define-module (language joy parser)
  17. #:use-module (language joy lexer)
  18. #:use-module (ice-9 format)
  19. #:use-module (ice-9 match)
  20. #:export (parse-joy parse-joy*))
  21. (define* (parse-error token msg . args)
  22. (apply error
  23. (format #f "~@[~a:~]~d:~d: ~a"
  24. (source-property token 'filename)
  25. (source-property token 'line)
  26. (source-property token 'column)
  27. msg)
  28. args))
  29. (define (return result token)
  30. (if (pair? result)
  31. (set-source-properties!
  32. result
  33. (source-properties token)))
  34. result)
  35. (define (lex-buffer lexer)
  36. "Given a lexer LEXER that returns tokens when invoked, return a new
  37. lexer. This lexer also returns tokens when invoked with no arguments
  38. but can also \"unread\" tokens when invoked with arguments, saving
  39. those tokens for later retrieval.
  40. E.g.
  41. (define lex (lex-buffer (get-lexer)))
  42. (lex)
  43. -> 'foo
  44. (lex 'foo)
  45. (lex)
  46. -> 'foo
  47. (lex)
  48. -> 'bar
  49. "
  50. (let ((buffer '()))
  51. (lambda tokens
  52. (match tokens
  53. (() (match buffer
  54. (() (lexer))
  55. ((token rest ...)
  56. (set! buffer rest)
  57. token)))
  58. (tokens
  59. (set! buffer (append tokens buffer)))))))
  60. (define (get-quote lex)
  61. (let* ((token (lex))
  62. (type (car token)))
  63. (case type
  64. ((eof)
  65. (parse-error token "unexpected end of file in quote"))
  66. ((square-open)
  67. (let* ((term (get-term lex #t))
  68. (token (lex))
  69. (type (car token)))
  70. (case type
  71. ((square-close)
  72. term)
  73. (else
  74. (parse-error
  75. token "expecting closing ']' in quote, got" token))))))))
  76. (define* (get-definition-sequence lex #:optional (consume-newline? #f))
  77. "Parse a DEFINE block and return a sequence of '<name> <term> def'"
  78. (define (consume-newlines)
  79. (match (lex)
  80. (('newline . _) (consume-newlines))
  81. (other (lex other))))
  82. (define (get-definition)
  83. (match (lex)
  84. ((and token' ('symbol . name))
  85. (consume-newlines)
  86. (match (lex)
  87. (('== . _)
  88. (consume-newlines)
  89. (let ((term (get-term lex)))
  90. (match (lex)
  91. (('semicolon . _)
  92. (values (list name) term))
  93. (token
  94. (parse-error token
  95. "expecting ';' at end of definition, got" token)))))
  96. (token
  97. (lex token' token)
  98. (values #f #f))))
  99. (token'
  100. (lex token')
  101. (values #f #f))))
  102. (match (lex)
  103. ((and token ((or 'define 'public 'private) . _))
  104. (consume-newlines)
  105. (let iterate ((definitions '()))
  106. (when consume-newline?
  107. (consume-newlines))
  108. (call-with-values (lambda () (get-definition))
  109. (lambda (name term)
  110. (if (and name term)
  111. (iterate (cons* 'def term name definitions))
  112. (begin
  113. (match (lex)
  114. (('end . _) #t) ;consume trailing 'END'
  115. (other (lex other)))
  116. (return (reverse definitions) token)))))))
  117. (token
  118. (parse-error token "expecting definition block, got" token))))
  119. (define* (get-term lex #:optional (consume-newline? #t))
  120. (let iterate ((items '()))
  121. (let* ((token (lex))
  122. (type (car token)))
  123. (case type
  124. ((eof semicolon end square-close define public private)
  125. (lex token) ;do not consume
  126. (return (reverse items) token))
  127. ((==)
  128. (parse-error token "'==' outside definition"))
  129. ((square-open)
  130. (lex token)
  131. (iterate (cons (get-quote lex) items)))
  132. ((newline)
  133. (if consume-newline?
  134. (iterate items) ;ignore newline
  135. (begin
  136. (lex token) ;replace newline
  137. (return (reverse items) token))))
  138. (else
  139. (iterate (cons (cdr token) items)))))))
  140. (define* (get-expression lex #:optional (consume-newline? #t))
  141. (let iterate ((items '()))
  142. (let* ((token (lex))
  143. (type (car token)))
  144. (case type
  145. ((eof)
  146. (match items
  147. (() (cdr token))
  148. (else (apply append (reverse items)))))
  149. ((== end)
  150. (parse-error token (string-append "'" (cdr token)
  151. "' outside definition")))
  152. ((paren-open bracket-open)
  153. (parse-error token "joy sets not implemented"))
  154. ((paren-close brack-blose square-close semicolon)
  155. (parse-error token "unexpected" (cdr token)))
  156. ((public private define)
  157. (lex token)
  158. (let ((defs (get-definition-sequence lex consume-newline?)))
  159. (iterate (cons defs items))))
  160. ((newline)
  161. (if consume-newline?
  162. (iterate items)
  163. (apply append (reverse items))))
  164. (else
  165. (lex token) ;put token back
  166. (iterate (cons (get-term lex consume-newline?)
  167. items)))))))
  168. (define* (parse-joy* port #:optional (consume-newline? #t))
  169. (let ((lexer (lex-buffer (get-lexer port))))
  170. (get-expression lexer consume-newline?)))
  171. (define (parse-joy port)
  172. (parse-joy* port))