summary refs log tree commit diff
path: root/src/guile/skribilo/evaluator.scm
diff options
context:
space:
mode:
Diffstat (limited to 'src/guile/skribilo/evaluator.scm')
-rw-r--r--src/guile/skribilo/evaluator.scm203
1 files changed, 203 insertions, 0 deletions
diff --git a/src/guile/skribilo/evaluator.scm b/src/guile/skribilo/evaluator.scm
new file mode 100644
index 0000000..8502d51
--- /dev/null
+++ b/src/guile/skribilo/evaluator.scm
@@ -0,0 +1,203 @@
+;;; eval.scm  --  Skribilo evaluator.
+;;;
+;;; Copyright 2003-2004  Erick Gallesio - I3S-CNRS/ESSI <eg@essi.fr>
+;;; Copyright 2005,2006  Ludovic Courtès  <ludovic.courtes@laas.fr>
+;;;
+;;;
+;;; This program 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.
+;;;
+;;; This program 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 this program; if not, write to the Free Software
+;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+;;; USA.
+
+
+(define-module (skribilo evaluator)
+  :export (evaluate-document evaluate-document-from-port
+	   load-document include-document *load-options*)
+  :autoload (skribilo parameters) (*verbose* *document-path*)
+  :autoload (skribilo location)   (<location>)
+  :autoload (skribilo ast)        (ast? markup?)
+  :autoload (skribilo engine)     (*current-engine*
+				   engine? find-engine engine-ident)
+  :autoload (skribilo reader)     (*document-reader*)
+
+  :autoload (skribilo verify)     (verify)
+  :autoload (skribilo resolve)    (resolve!)
+
+  :autoload (skribilo module)     (*skribilo-user-module*))
+
+
+(use-modules (skribilo utils syntax)
+	     (skribilo condition)
+	     (skribilo debug)
+	     (skribilo output)
+             (skribilo lib)
+
+	     (ice-9 optargs)
+	     (oop goops)
+	     (srfi srfi-1)
+	     (srfi srfi-13)
+	     (srfi srfi-34)
+	     (srfi srfi-35)
+	     (srfi srfi-39))
+
+
+(fluid-set! current-reader %skribilo-module-reader)
+
+
+;;;
+;;; %EVALUATE
+;;;
+(define (%evaluate expr)
+  ;; Evaluate EXPR, an arbitrary S-expression that may contain calls to the
+  ;; markup functions defined in a markup package such as
+  ;; `(skribilo package base)', e.g., `(bold "hello")'.
+  (let ((result (eval expr (*skribilo-user-module*))))
+
+    (if (ast? result)
+	(let ((file (source-property expr 'filename))
+	      (line (source-property expr 'line))
+	      (column (source-property expr 'column)))
+	  (slot-set! result 'loc
+		     (make <location>
+		       :file file :line line :pos column))))
+
+    result))
+
+
+
+;;;
+;;; EVALUATE-DOCUMENT
+;;;
+(define* (evaluate-document a e :key (env '()))
+  ;; Argument A must denote an AST of something like that, not just an
+  ;; S-exp.
+  (with-debug 2 'evaluate-document
+     (debug-item "a=" a " e=" (engine-ident e))
+     (let ((a2 (resolve! a e env)))
+       (debug-item "resolved a=" a)
+       (let ((a3 (verify a2 e)))
+	 (debug-item "verified a=" a3)
+	 (output a3 e)))))
+
+;;;
+;;; EVALUATE-DOCUMENT-FROM-PORT
+;;;
+(define* (evaluate-document-from-port port engine
+				      :key (env '())
+				           (reader (*document-reader*)))
+  (with-debug 2 'evaluate-document-from-port
+     (debug-item "engine=" engine)
+     (debug-item "reader=" reader)
+
+     (let ((e (if (symbol? engine) (find-engine engine) engine)))
+       (debug-item "e=" e)
+       (if (not (engine? e))
+	   (skribe-error 'evaluate-document-from-port "cannot find engine" engine)
+	   (let loop ((exp (reader port)))
+	     (with-debug 10 'evaluate-document-from-port
+		(debug-item "exp=" exp))
+	     (unless (eof-object? exp)
+	       (evaluate-document (%evaluate exp) e :env env)
+	       (loop (reader port))))))))
+
+
+;;;
+;;; LOAD-DOCUMENT
+;;;
+
+;; Options that may make sense to a specific back-end or package.
+(define-public *load-options* (make-parameter '()))
+
+;; List of the names of files already loaded.
+(define *loaded-files* (make-parameter '()))
+
+(define* (load-document file :key (engine #f) (path #f) :allow-other-keys
+			:rest opt)
+  (with-debug 4 'skribe-load
+     (debug-item "  engine=" engine)
+     (debug-item "  path=" path)
+     (debug-item "  opt=" opt)
+
+     (let* ((ei  (*current-engine*))
+	    (path (append (cond
+			   ((not path) (*document-path*))
+			   ((string? path) (list path))
+			   ((not (and (list? path) (every? string? path)))
+			    (raise (condition (&invalid-argument-error
+					       (proc-name 'load-document)
+					       (argument  path)))))
+			   (else path))
+			  %load-path))
+            (filep (or (search-path path file)
+		       (search-path (append path %load-path) file)
+		       (search-path (append path %load-path)
+				    (let ((dot (string-rindex file #\.)))
+				      (if dot
+					  (string-append
+					   (string-take file dot)
+					   ".scm")
+					  file))))))
+
+       (unless (and (string? filep) (file-exists? filep))
+	 (raise (condition (&file-search-error
+			    (file-name file)
+			    (path path)))))
+
+       ;; Pass the additional options to the back-end and/or packages being
+       ;; used.
+       (parameterize ((*load-options* opt))
+
+	 ;; Load this file if not already done
+	 ;; FIXME: Shouldn't we remove this logic?  -- Ludo'.
+	 (unless (member filep (*loaded-files*))
+	   (cond
+	    ((> (*verbose*) 1)
+	     (format (current-error-port) "  [loading file: ~S ~S]\n" filep opt))
+	    ((> (*verbose*) 0)
+	     (format (current-error-port) "  [loading file: ~S]\n" filep)))
+
+	   ;; Load it
+	   (with-input-from-file filep
+	     (lambda ()
+	       (evaluate-document-from-port (current-input-port) ei)))
+
+	   (*loaded-files* (cons filep (*loaded-files*))))))))
+
+;;;
+;;; INCLUDE-DOCUMENT
+;;;
+(define* (include-document file :key (path (*document-path*))
+			             (reader (*document-reader*)))
+  (unless (every string? path)
+    (raise (condition (&invalid-argument-error (proc-name 'include-document)
+					       (argument  path)))))
+
+  (let ((full-path (search-path path file)))
+    (unless (and (string? full-path) (file-exists? full-path))
+      (raise (condition (&file-search-error
+			 (file-name file)
+			 (path path)))))
+
+    (when (> (*verbose*) 0)
+      (format (current-error-port) "  [including file: ~S]\n" full-path))
+
+    (with-input-from-file full-path
+      (lambda ()
+	(let Loop ((exp (reader (current-input-port)))
+		   (res '()))
+	  (if (eof-object? exp)
+	      (if (and (pair? res) (null? (cdr res)))
+		    (car res)
+		    (reverse! res))
+	      (Loop (reader (current-input-port))
+		    (cons (%evaluate exp) res))))))))