Work in progress, recovered from old crybaby.
[sod] / src / parse-module.lisp
diff --git a/src/parse-module.lisp b/src/parse-module.lisp
new file mode 100644 (file)
index 0000000..1989ebb
--- /dev/null
@@ -0,0 +1,169 @@
+;;; -*-lisp-*-
+;;;
+;;; Top-level parser for module syntax
+;;;
+;;; (c) 2010 Straylight/Edgeware
+;;;
+
+;;;----- Licensing notice ---------------------------------------------------
+;;;
+;;; This file is part of the Sensble Object Design, an object system for C.
+;;;
+;;; SOD is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; SOD is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with SOD; if not, write to the Free Software Foundation,
+;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+(in-package #:sod)
+
+;;;--------------------------------------------------------------------------
+;;; Toplevel syntax.
+
+(export 'module)
+
+;;; Type names.
+
+(define-pluggable-parser module typename (scanner)
+  ;; `typename' ID ( `,' ID )* `;'
+
+  (with-parser-context (token-scanner-context :scanner scanner)
+    (parse (and "typename"
+               (skip-many (:min 1)
+                 (seq ((id :id))
+                   (if (gethash id *module-type-map*)
+                       (cerror* "Type `~A' already defined" id)
+                       (add-to-module *module*
+                                      (make-instance 'type-item
+                                                     :name id))))
+                 #\,)
+               #\;))))
+
+;;; Fragments.
+
+(define-pluggable-parser module code (scanner)
+  ;; `code' ID `:' ID [ CONSTRAINTS ] `{' C-FRAGMENT `}'
+
+  (with-parser-context (token-scanner-context :scanner scanner)
+    (parse (seq ("code"
+                (reason :id)
+                #\:
+                (name :id)
+                (constraints (? (seq (#\[
+                                      (constraints (list (:min 1)
+                                                     (list (:min 1) :id)
+                                                     #\,))
+                                      #\])
+                                  constraints)))
+                (fragment (parse-delimited-fragment scanner #\{ #\})))
+            (add-to-module *module* (make-instance 'code-fragment-item
+                                                   :fragment fragment
+                                                   :constraints constraints
+                                                   :reason reason
+                                                   :name name))))))
+
+;;; External files.
+
+(defun read-module (pathname &key (truename (truename pathname)) location)
+  "Parse the file at PATHNAME as a module, returning it.
+
+   This is the main entry point for parsing module files.  You may well know
+   the file's TRUENAME already (e.g., because `probe-file' dropped it into
+   your lap) so you can avoid repeating the search by providing it.
+
+   The LOCATION is the thing which wanted the module imported -- usually a
+   `file-location' object, though it might be anything other than `t' which
+   can be printed in the event of circular imports."
+
+  (define-module (pathname :location location :truename truename)
+    (with-open-file (f-stream pathname :direction :input)
+      (let* ((*readtable* (copy-readtable))
+            (char-scanner (make-instance 'charbuf-scanner
+                                         :stream f-stream))
+            (scanner (make-instance 'sod-token-scanner
+                                    :char-scanner char-scanner)))
+       (with-default-error-location (scanner)
+         (with-parser-context (token-scanner-context :scanner scanner)
+           (parse (skip-many () (plug module scanner)))))))))
+
+(define-pluggable-parser module test (scanner)
+  ;; `demo' STRING `;'
+
+  (with-parser-context (token-scanner-context :scanner scanner)
+    (parse (seq ("demo" (string :string) #\;)
+            (format t ";; DEMO ~S~%" string)))))
+
+(define-pluggable-parser module file (scanner)
+  ;; `import' STRING `;'
+  ;; `load' STRING `;'
+
+  (flet ((common (name type what thunk)
+          (find-file scanner
+                     (merge-pathnames name
+                                      (make-pathname :type type
+                                                     :case :common))
+                     what
+                     thunk)))
+    (with-parser-context (token-scanner-context :scanner scanner)
+      (parse (or (seq ("import" (name :string) #\;)
+                  (common name "SOD" "module"
+                          (lambda (path true)
+                            (handler-case
+                                (let ((module (read-module path
+                                                           :truename true)))
+                                  (when module
+                                    (module-import module)
+                                    (pushnew module
+                                             (module-dependencies
+                                              *module*))))
+                              (file-error (error)
+                                (cerror* "Error reading module ~S: ~A"
+                                         path error))))))
+                (seq ("load" (name :string) #\;)
+                  (common name "LISP" "Lisp file"
+                          (lambda (path true)
+                            (handler-case
+                                (load true :verbose nil :print nil)
+                              (error (error)
+                                (cerror* "Error loading Lisp file ~S: ~A"
+                                         path error)))))))))))
+
+;;; Lisp escape.
+
+(define-pluggable-parser module lisp (scanner)
+  ;; `lisp' s-expression `;'
+
+  (with-parser-context (token-scanner-context :scanner scanner)
+    (parse (seq ((sexp (if (and (eql (token-type scanner) :id)
+                               (string= (token-value scanner) "lisp"))
+                          (let* ((stream (make-scanner-stream scanner))
+                                 (sexp (read stream t)))
+                            (scanner-step scanner)
+                            (values sexp t t))
+                          (values '((:id "lisp")) nil nil)))
+                #\;)
+            (eval sexp)))))
+
+;;;--------------------------------------------------------------------------
+;;; Class declarations.
+
+(define-pluggable-parser module class (scanner)
+  ;; `class' id [`:' id-list] `{' class-item* `}'
+
+  (with-parser-context (token-scanner-context :scanner scanner)
+    (parse (seq ("class"
+                (name :id)
+                (supers (? (seq (#\: (supers (list (:min 1) :id #\,)))
+                                supers)))
+                #\{
+                
+
+;;;----- That's all, folks --------------------------------------------------