gecko-dev/js2/semantics/CalculusMarkup.lisp

999 строки
45 KiB
Common Lisp

;;; The contents of this file are subject to the Netscape Public License
;;; Version 1.0 (the "NPL"); you may not use this file except in
;;; compliance with the NPL. You may obtain a copy of the NPL at
;;; http://www.mozilla.org/NPL/
;;;
;;; Software distributed under the NPL is distributed on an "AS IS" basis,
;;; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
;;; for the specific language governing rights and limitations under the
;;; NPL.
;;;
;;; The Initial Developer of this code under the NPL is Netscape
;;; Communications Corporation. Portions created by Netscape are
;;; Copyright (C) 1998 Netscape Communications Corporation. All Rights
;;; Reserved.
;;;
;;; ECMAScript semantic calculus markup emitters
;;;
;;; Waldemar Horwat (waldemar@netscape.com)
;;;
;;; ------------------------------------------------------------------------------------------------------
;;; SEMANTIC DEPICTION UTILITIES
(defparameter *semantic-keywords*
'(not and or is type oneof tuple action lambda if then else in new case of end let letexc))
; Emit markup for one of the semantic keywords, as specified by keyword-symbol.
(defun depict-semantic-keyword (markup-stream keyword-symbol)
(assert-true (find keyword-symbol *semantic-keywords* :test #'eq))
(depict-char-style (markup-stream :semantic-keyword)
(depict markup-stream (string-downcase (symbol-name keyword-symbol)))))
; If test is true, depict an opening parenthesis, evaluate body, and depict a closing
; parentheses. Otherwise, just evaluate body.
; Return the result value of body.
(defmacro depict-optional-parentheses ((markup-stream test) &body body)
(let ((temp (gensym "PAREN")))
`(let ((,temp ,test))
(when ,temp
(depict ,markup-stream "("))
(prog1
(progn ,@body)
(when ,temp
(depict ,markup-stream ")"))))))
;;; ------------------------------------------------------------------------------------------------------
;;; DEPICT-ENV
; A depict-env holds state that helps in depicting a grammar or lexer.
(defstruct depict-env
(grammar-info nil :type (or null grammar-info)) ;The current grammar-info or nil if none
(seen-nonterminals nil :type (or null hash-table)) ;Hash table (nonterminal -> t) of nonterminals already depicted
(mode nil :type (member nil :syntax :semantics)) ;Current heading (:syntax or :semantics) or nil if none
(pending-actions-reverse nil :type list)) ;Reverse-order list of closures of actions pending for a %print-actions
(defun checked-depict-env-grammar-info (depict-env)
(or (depict-env-grammar-info depict-env)
(error "Grammar needed")))
(defvar *visible-modes* t)
; Set the mode to the given mode, emitting a heading if necessary.
(defun depict-mode (markup-stream depict-env mode)
(unless (eq mode (depict-env-mode depict-env))
(when *visible-modes*
(ecase mode
(:syntax (depict-paragraph (markup-stream ':grammar-header)
(depict markup-stream "Syntax")))
(:semantics (depict-paragraph (markup-stream ':grammar-header)
(depict markup-stream "Semantics")))
((nil))))
(setf (depict-env-mode depict-env) mode)))
; Emit markup paragraphs for a command.
(defun depict-command (markup-stream world depict-env command)
(handler-bind ((error #'(lambda (condition)
(declare (ignore condition))
(format *error-output* "~&While depicting: ~:W~%" command))))
(let ((depictor (and (consp command)
(identifier? (first command))
(get (world-intern world (first command)) :depict-command))))
(if depictor
(apply depictor markup-stream world depict-env (rest command))
(error "Bad command: ~S" command)))))
; Emit markup paragraphs for the world's commands.
(defun depict-world-commands (markup-stream world)
(let ((depict-env (make-depict-env)))
(dolist (command (world-commands-source world))
(depict-command markup-stream world depict-env command))
(depict-clear-grammar markup-stream world depict-env)))
;;; ------------------------------------------------------------------------------------------------------
;;; DEPICTING TYPES
(defconstant *type-level-min* 0)
(defconstant *type-level-suffix* 1)
(defconstant *type-level-function* 2)
(defconstant *type-level-max* 2)
;;;
;;; The level argument indicates what kinds of component types may be represented without being placed
;;; in parentheses.
;;; level kinds
;;; 0 id, oneof, tuple, (type)
;;; 1 id, oneof, tuple, (type), type[], type^
;;; 2 id, oneof, tuple, (type), type[], type^, type x type -> type
; Emit markup for the name of a type, which must be a symbol.
(defun depict-type-name (markup-stream type-name)
(depict-char-style (markup-stream :type-name)
(depict markup-stream (symbol-upper-mixed-case-name type-name))))
; Emit markup for the name of a tuple or oneof field, which must be a symbol.
(defun depict-field-name (markup-stream field-name)
(depict-char-style (markup-stream :field-name)
(depict markup-stream (symbol-lower-mixed-case-name field-name))))
; If level < threshold, depict an opening parenthesis, evaluate body, and depict a closing
; parentheses. Otherwise, just evaluate body.
; Return the result value of body.
(defmacro depict-type-parentheses ((markup-stream level threshold) &body body)
`(depict-optional-parentheses (,markup-stream (< ,level ,threshold))
,@body))
; Emit markup for the given type expression. level is non-nil if this is a recursive
; call to depict-type-expr for which the markup-stream's style is :type-expression.
; In this case level indicates the binding level imposed by the enclosing type expression.
(defun depict-type-expr (markup-stream world type-expr &optional level)
(cond
((identifier? type-expr)
(depict-type-name markup-stream type-expr))
((type? type-expr)
(let ((type-str (print-type-to-string type-expr)))
(warn "Depicting raw type ~A" type-str)
(depict markup-stream "<<<" type-str ">>>")))
(t (let ((depictor (get (world-intern world (first type-expr)) :depict-type-constructor)))
(if level
(apply depictor markup-stream world level (rest type-expr))
(depict-char-style (markup-stream :type-expression)
(apply depictor markup-stream world *type-level-max* (rest type-expr))))))))
; (-> (<arg-type1> ... <arg-typen>) <result-type>)
; Level 2
; "<arg-type1>@1 x ... x <arg-typen>@1 -> <result-type>@1"
(defun depict--> (markup-stream world level arg-type-exprs result-type-expr)
(depict-type-parentheses (markup-stream level *type-level-function*)
(depict-list markup-stream
#'(lambda (markup-stream arg-type-expr)
(depict-type-expr markup-stream world arg-type-expr *type-level-suffix*))
arg-type-exprs
:separator '(" " :cartesian-product-10 " ")
:empty "()")
(depict markup-stream " " :function-arrow-10 " ")
(depict-type-expr markup-stream world result-type-expr *type-level-suffix*)))
; (vector <element-type>)
; Level 1
; "<element-type>@1[]"
(defun depict-vector (markup-stream world level element-type-expr)
(depict-type-parentheses (markup-stream level *type-level-suffix*)
(depict-type-expr markup-stream world element-type-expr *type-level-suffix*)
(depict markup-stream "[]")))
; (address <element-type>)
; Level 1
; "<element-type>@1^"
(defun depict-address (markup-stream world level element-type-expr)
(depict-type-parentheses (markup-stream level *type-level-suffix*)
(depict-type-expr markup-stream world element-type-expr *type-level-suffix*)
(depict markup-stream :up-arrow-10)))
(defun depict-tuple-or-oneof (markup-stream world keyword-symbol tag-pairs)
(depict-semantic-keyword markup-stream keyword-symbol)
(depict-list
markup-stream
#'(lambda (markup-stream tag-pair)
(if (identifier? tag-pair)
(depict-field-name markup-stream tag-pair)
(progn
(depict-field-name markup-stream (first tag-pair))
(depict markup-stream ": ")
(depict-type-expr markup-stream world (second tag-pair) *type-level-function*))))
tag-pairs
:indent 6
:prefix " {"
:prefix-break 0
:suffix "}"
:separator ";"
:break 1
:empty nil))
; (oneof (<tag1> <type1>) ... (<tagn> <typen>))
; Level 0
; "ONEOF{<tag1>: <type1>@0; ...; <tagn>:<typen>@0}"
(defun depict-oneof (markup-stream world level &rest tags-and-types)
(declare (ignore level))
(depict-tuple-or-oneof markup-stream world 'oneof tags-and-types))
; (tuple (<tag1> <type1>) ... (<tagn> <typen>))
; Level 0
; "TUPLE{<tag1>: <type1>@0; ...; <tagn>:<typen>@0}"
(defun depict-tuple (markup-stream world level &rest tags-and-types)
(declare (ignore level))
(depict-tuple-or-oneof markup-stream world 'tuple tags-and-types))
;;; ------------------------------------------------------------------------------------------------------
;;; DEPICTING EXPRESSIONS
(defconstant *primitive-level-min* 0)
(defconstant *primitive-level-unary-suffix* 1)
(defconstant *primitive-level-unary-prefix* 2)
(defconstant *primitive-level-unary* 3)
(defconstant *primitive-level-multiplicative* 4)
(defconstant *primitive-level-additive* 5)
(defconstant *primitive-level-relational* 6)
(defconstant *primitive-level-logical* 7)
(defconstant *primitive-level-unparenthesized-new* 8)
(defconstant *primitive-level-expr* 9)
(defconstant *primitive-level-stmt* 10)
(defconstant *primitive-level-max* 10)
;;;
;;; The level argument indicates what kinds of subexpressions may be represented without being placed
;;; in parentheses (or on a separate line for the case of lambda and if/then/else).
;;; level kinds
;;; 0 id, constant, (e)
;;; 1 id, constant, (e), f(...), new(v), a[i]
;;; 2 id, constant, (e), -e, @
;;; 3 id, constant, (e), f(...), new(v), a[i], -e, @
;;; 4 id, constant, (e), f(...), new(v), a[i], -e, @, /, *
;;; 5 id, constant, (e), f(...), new(v), a[i], -e, @, /, *, +, -
;;; 6 id, constant, (e), f(...), new(v), a[i], -e, @, /, *, +, -, relationals
;;; 7 id, constant, (e), f(...), new(v), a[i], -e, @, /, *, +, -, relationals, logicals
;;; 8 id, constant, (e), f(...), new(v), a[i], -e, @, /, *, +, -, relationals, logicals, new v
;;; 9 id, constant, (e), f(...), new(v), a[i], -e, @, /, *, +, -, relationals, logicals, new v
;;; 10 id, constant, (e), f(...), new(v), a[i], -e, @, /, *, +, -, relationals, logicals, new v, :=, lambda, if/then/else
; Return true if primitive-level1 is a superset of primitive-level2
; in the partial order of primitive levels.
(defun primitive-level->= (primitive-level1 primitive-level2)
(and (>= primitive-level1 primitive-level2)
(or (/= primitive-level1 *primitive-level-unary-prefix*)
(/= primitive-level2 *primitive-level-unary-suffix*))))
; If primitive-level is not a superset of threshold, depict an opening parenthesis,
; evaluate body, and depict a closing parentheses. Otherwise, just evaluate body.
; Return the result value of body.
(defmacro depict-expr-parentheses ((markup-stream primitive-level threshold) &body body)
`(depict-optional-parentheses (,markup-stream (not (primitive-level->= ,primitive-level ,threshold)))
,@body))
; Emit markup for the name of a global variable, which must be a symbol.
(defun depict-global-variable (markup-stream name)
(depict-char-style (markup-stream :global-variable)
(depict markup-stream (symbol-lower-mixed-case-name name))))
; Emit markup for the name of a local variable, which must be a symbol.
(defun depict-local-variable (markup-stream name)
(depict-char-style (markup-stream :local-variable)
(depict markup-stream (symbol-lower-mixed-case-name name))))
; Emit markup for the name of an action, which must be a symbol.
(defun depict-action-name (markup-stream action-name)
(depict-char-style (markup-stream :action-name)
(depict markup-stream (symbol-upper-mixed-case-name action-name))))
; Emit markup for the value constant.
(defun depict-constant (markup-stream constant)
(cond
((integerp constant)
(depict-integer markup-stream constant))
((floatp constant)
(depict markup-stream (format nil (if (= constant (floor constant 1)) "~,1F" "~F") constant)))
((characterp constant)
(depict markup-stream ':left-single-quote)
(depict-char-style (markup-stream ':character-literal)
(depict-character markup-stream constant nil))
(depict markup-stream ':right-single-quote))
((stringp constant)
(depict-string markup-stream constant))
(t (error "Bad constant ~S" constant))))
; Emit markup for the primitive when it is not called in a function call.
(defun depict-primitive (markup-stream primitive)
(unless (eq (primitive-appearance primitive) ':global)
(error "Can't depict primitive ~S outside a call" primitive))
(depict-item-or-group-list markup-stream (primitive-markup1 primitive)))
; Emit markup for the parameters to a function call.
(defun depict-call-parameters (markup-stream world annotated-parameters)
(depict-list markup-stream
#'(lambda (markup-stream parameter)
(depict-annotated-value-expr markup-stream world parameter))
annotated-parameters
:indent 4
:prefix "("
:prefix-break 0
:suffix ")"
:separator ","
:break 1
:empty nil))
; Emit markup for the function or primitive call. level indicates the binding level imposed
; by the enclosing expression.
(defun depict-call (markup-stream world level annotated-function-expr &rest annotated-arg-exprs)
(if (eq (first annotated-function-expr) 'expr-annotation:primitive)
(let ((primitive (symbol-primitive (second annotated-function-expr))))
(depict-expr-parentheses (markup-stream level (primitive-level primitive))
(ecase (primitive-appearance primitive)
(:global
(depict-primitive markup-stream primitive)
(depict-call-parameters markup-stream world annotated-arg-exprs))
(:infix
(assert-true (= (length annotated-arg-exprs) 2))
(depict-logical-block (markup-stream 0)
(depict-annotated-value-expr markup-stream world (first annotated-arg-exprs) (primitive-level1 primitive))
(let ((spaces (primitive-markup2 primitive)))
(when spaces
(depict-space markup-stream))
(depict-item-or-group-list markup-stream (primitive-markup1 primitive))
(depict-break markup-stream (if spaces 1 0)))
(depict-annotated-value-expr markup-stream world (second annotated-arg-exprs) (primitive-level2 primitive))))
(:unary
(assert-true (= (length annotated-arg-exprs) 1))
(depict-item-or-group-list markup-stream (primitive-markup1 primitive))
(depict-annotated-value-expr markup-stream world (first annotated-arg-exprs) (primitive-level1 primitive))
(depict-item-or-group-list markup-stream (primitive-markup2 primitive)))
(:phantom
(assert-true (= (length annotated-arg-exprs) 1))
(depict-annotated-value-expr markup-stream world (first annotated-arg-exprs) level)))))
(depict-expr-parentheses (markup-stream level *primitive-level-unary-suffix*)
(depict-annotated-value-expr markup-stream world annotated-function-expr *primitive-level-unary-suffix*)
(depict-call-parameters markup-stream world annotated-arg-exprs))))
; Emit markup for the reference to the action on the given general grammar symbol.
(defun depict-action-reference (markup-stream action-name general-grammar-symbol &optional index)
(depict-action-name markup-stream action-name)
(depict markup-stream :action-begin)
(depict-general-grammar-symbol markup-stream general-grammar-symbol index)
(depict markup-stream :action-end))
; Emit markup for the given annotated value expression. level indicates the binding level imposed
; by the enclosing expression.
(defun depict-annotated-value-expr (markup-stream world annotated-expr &optional (level *primitive-level-expr*))
(let ((annotation (first annotated-expr))
(args (rest annotated-expr)))
(ecase annotation
(expr-annotation:constant (depict-constant markup-stream (first args)))
(expr-annotation:primitive (depict-primitive markup-stream (symbol-primitive (first args))))
(expr-annotation:local (depict-local-variable markup-stream (first args)))
(expr-annotation:global (depict-global-variable markup-stream (first args)))
(expr-annotation:call (apply #'depict-call markup-stream world level args))
(expr-annotation:action (apply #'depict-action-reference markup-stream args))
(expr-annotation:special-form
(apply (get (first args) :depict-special-form) markup-stream world level (rest args)))
(expr-annotation:macro
(let ((depictor (get (first args) :depict-macro)))
(if depictor
(apply depictor markup-stream world level (rest args))
(depict-annotated-value-expr markup-stream world (second args) level)))))))
;;; ------------------------------------------------------------------------------------------------------
;;; DEPICTING SPECIAL FORMS
(defmacro depict-statement ((markup-stream keyword &optional (space t)) &body body)
`(depict-logical-block (,markup-stream 0)
(when (< level *primitive-level-stmt*)
(depict-break ,markup-stream))
(depict-expr-parentheses (,markup-stream level *primitive-level-stmt*)
(depict-semantic-keyword ,markup-stream ,keyword)
,@(and space `((depict-space ,markup-stream)))
,@body)))
; (bottom <type>)
(defun depict-bottom (markup-stream world level type-expr)
(declare (ignore world level type-expr))
(depict markup-stream ':bottom-10))
(defun depict-lambda-bindings (markup-stream world arg-binding-exprs)
(depict-list markup-stream
#'(lambda (markup-stream arg-binding)
(depict-local-variable markup-stream (first arg-binding))
(depict markup-stream ": ")
(depict-type-expr markup-stream world (second arg-binding)))
arg-binding-exprs
:prefix "("
:suffix ")"
:separator ", "
:empty nil))
; (lambda ((<var1> <type1> [:unused]) ... (<varn> <typen> [:unused])) <body>)
(defun depict-lambda (markup-stream world level arg-binding-exprs body-annotated-expr)
(depict-statement (markup-stream 'lambda nil)
(depict-lambda-bindings markup-stream world arg-binding-exprs)
(depict-logical-block (markup-stream 4)
(depict-break markup-stream)
(depict-annotated-value-expr markup-stream world body-annotated-expr *primitive-level-stmt*))))
; (if <condition-expr> <true-expr> <false-expr>)
(defun depict-if (markup-stream world level condition-annotated-expr true-annotated-expr false-annotated-expr)
(depict-statement (markup-stream 'if)
(depict-logical-block (markup-stream 4)
(depict-annotated-value-expr markup-stream world condition-annotated-expr))
(depict-break markup-stream)
(depict-semantic-keyword markup-stream 'then)
(depict-space markup-stream)
(depict-logical-block (markup-stream 7)
(depict-annotated-value-expr markup-stream world true-annotated-expr *primitive-level-stmt*))
(depict-break markup-stream)
(depict-semantic-keyword markup-stream 'else)
(depict-space markup-stream)
(depict-logical-block (markup-stream (if (special-form-annotated-expr? 'if false-annotated-expr) nil 6))
(depict-annotated-value-expr markup-stream world false-annotated-expr *primitive-level-stmt*))))
;;; Vectors
; (vector <element-expr> <element-expr> ... <element-expr>)
(defun depict-vector-form (markup-stream world level &rest element-annotated-exprs)
(declare (ignore level))
(depict-list markup-stream
#'(lambda (markup-stream element-annotated-expr)
(depict-annotated-value-expr markup-stream world element-annotated-expr))
element-annotated-exprs
:indent 1
:prefix ':vector-begin
:suffix ':vector-end
:separator ","
:break 1))
(defun depict-subscript-type-expr (markup-stream world type-expr)
(depict-char-style (markup-stream 'sub)
(depict-type-expr markup-stream world type-expr)))
; (vector-of <element-type>)
(defun depict-vector-of (markup-stream world level element-type-expr)
(declare (ignore level))
(depict markup-stream ':empty-vector)
(depict-subscript-type-expr markup-stream world element-type-expr))
(defun depict-special-function (markup-stream world name-str &rest arg-annotated-exprs)
(depict-char-style (markup-stream :global-variable)
(depict markup-stream name-str))
(depict-call-parameters markup-stream world arg-annotated-exprs))
; (empty <vector-expr>)
(defun depict-empty (markup-stream world level vector-annotated-expr)
(declare (ignore level))
(depict-special-function markup-stream world "empty" vector-annotated-expr))
; (length <vector-expr>)
(defun depict-length (markup-stream world level vector-annotated-expr)
(declare (ignore level))
(depict-special-function markup-stream world "length" vector-annotated-expr))
; (first <vector-expr>)
(defun depict-first (markup-stream world level vector-annotated-expr)
(declare (ignore level))
(depict-special-function markup-stream world "first" vector-annotated-expr))
; (last <vector-expr>)
(defun depict-last (markup-stream world level vector-annotated-expr)
(declare (ignore level))
(depict-special-function markup-stream world "last" vector-annotated-expr))
; (rest <vector-expr>)
(defun depict-rest (markup-stream world level vector-annotated-expr)
(declare (ignore level))
(depict-special-function markup-stream world "rest" vector-annotated-expr))
; (butlast <vector-expr>)
(defun depict-butlast (markup-stream world level vector-annotated-expr)
(declare (ignore level))
(depict-special-function markup-stream world "butLast" vector-annotated-expr))
; (nth <vector-expr> <n-expr>)
(defun depict-nth (markup-stream world level vector-annotated-expr n-annotated-expr)
(depict-expr-parentheses (markup-stream level *primitive-level-unary-suffix*)
(depict-annotated-value-expr markup-stream world vector-annotated-expr *primitive-level-unary-suffix*)
(depict markup-stream "[")
(depict-annotated-value-expr markup-stream world n-annotated-expr)
(depict markup-stream "]")))
; (append <vector-expr> <vector-expr>)
(defun depict-append (markup-stream world level vector1-annotated-expr vector2-annotated-expr)
(depict-expr-parentheses (markup-stream level *primitive-level-additive*)
(depict-logical-block (markup-stream 0)
(depict-annotated-value-expr markup-stream world vector1-annotated-expr *primitive-level-additive*)
(depict markup-stream " " :vector-append)
(depict-break markup-stream 1)
(depict-annotated-value-expr markup-stream world vector2-annotated-expr *primitive-level-additive*))))
;;; Oneofs
; (oneof <oneof-type> <tag> <value-expr>)
(defun depict-oneof-form (markup-stream world level tag &optional value-annotated-expr)
(depict-expr-parentheses (markup-stream level *primitive-level-unary-prefix*)
(depict-field-name markup-stream tag)
(when value-annotated-expr
(depict-logical-block (markup-stream 4)
(depict-break markup-stream 1)
(depict-annotated-value-expr markup-stream world value-annotated-expr *primitive-level-unary*)))))
; (typed-oneof <type-expr> <tag> <value-expr>)
(defun depict-typed-oneof (markup-stream world level type-expr tag &optional value-annotated-expr)
(depict-expr-parentheses (markup-stream level *primitive-level-unary-prefix*)
(depict-field-name markup-stream tag)
(depict-subscript-type-expr markup-stream world type-expr)
(when value-annotated-expr
(depict-logical-block (markup-stream 4)
(depict-break markup-stream 1)
(depict-annotated-value-expr markup-stream world value-annotated-expr *primitive-level-unary*)))))
; (case <oneof-expr> (<tag-spec> <value-expr>) (<tag-spec> <value-expr>) ... (<tag-spec> <value-expr>))
; where each <tag-spec> is either ((<tag> <tag> ... <tag>) nil nil) or ((<tag>) <var> <type>)
(defun depict-case (markup-stream world level oneof-annotated-expr &rest annotated-cases)
(depict-statement (markup-stream 'case)
(depict-logical-block (markup-stream 6)
(depict-annotated-value-expr markup-stream world oneof-annotated-expr))
(depict-space markup-stream)
(depict-semantic-keyword markup-stream 'of)
(depict-logical-block (markup-stream 3)
(mapl #'(lambda (annotated-cases)
(let* ((annotated-case (first annotated-cases))
(tag-spec (first annotated-case))
(tags (first tag-spec))
(var (second tag-spec))
(value-annotated-expr (second annotated-case)))
(depict-break markup-stream)
(depict-logical-block (markup-stream 6)
(depict-list markup-stream
#'depict-field-name
tags
:indent 0
:separator ","
:break 1)
(when var
(depict markup-stream "(")
(depict-local-variable markup-stream var)
(depict markup-stream ": ")
(depict-type-expr markup-stream world (third tag-spec))
(depict markup-stream ")"))
(depict markup-stream ":")
(depict-break markup-stream 1)
(depict-annotated-value-expr markup-stream world value-annotated-expr *primitive-level-stmt*)
(when (cdr annotated-cases)
(depict markup-stream ";")))))
annotated-cases)
(depict-break markup-stream)
(depict-semantic-keyword markup-stream 'end))))
; (select <tag> <oneof-expr>)
; (& <tag> <tuple-expr>)
(defun depict-select-or-& (markup-stream world level tag annotated-expr)
(depict-expr-parentheses (markup-stream level *primitive-level-unary-suffix*)
(depict-annotated-value-expr markup-stream world annotated-expr *primitive-level-unary-suffix*)
(depict markup-stream ".")
(depict-field-name markup-stream tag)))
; (is <tag> <oneof-expr>)
(defun depict-is (markup-stream world level tag oneof-annotated-expr)
(depict-expr-parentheses (markup-stream level *primitive-level-relational*)
(depict-annotated-value-expr markup-stream world oneof-annotated-expr *primitive-level-unary-suffix*)
(depict-space markup-stream)
(depict-semantic-keyword markup-stream 'is)
(depict-space markup-stream)
(depict-field-name markup-stream tag)))
;;; Tuples
; (tuple <tuple-type> <field-expr1> ... <field-exprn>)
(defun depict-tuple-form (markup-stream world level type-expr &rest annotated-exprs)
(declare (ignore level))
(depict-list markup-stream
#'(lambda (markup-stream parameter)
(depict-annotated-value-expr markup-stream world parameter))
annotated-exprs
:indent 4
:prefix ':tuple-begin
:prefix-break 0
:suffix ':tuple-end
:separator ","
:break 1
:empty nil)
(depict-subscript-type-expr markup-stream world type-expr))
;;; Addresses
; (new <value-expr>)
(defun depict-new (markup-stream world level value-annotated-expr)
(depict-logical-block (markup-stream 5)
(depict-semantic-keyword markup-stream 'new)
(depict-space markup-stream)
(depict-expr-parentheses (markup-stream level *primitive-level-unparenthesized-new*)
(depict-annotated-value-expr markup-stream world value-annotated-expr
(if (< level *primitive-level-unparenthesized-new*)
*primitive-level-expr*
*primitive-level-unary-prefix*)))))
; (@ <address-expr>)
(defun depict-@ (markup-stream world level address-annotated-expr)
(depict-expr-parentheses (markup-stream level *primitive-level-unary-prefix*)
(depict-logical-block (markup-stream 2)
(depict markup-stream "@")
(depict-annotated-value-expr markup-stream world address-annotated-expr *primitive-level-unary-prefix*))))
; (@= <address-expr> <value-expr>)
(defun depict-@= (markup-stream world level address-annotated-expr value-annotated-expr)
(depict-expr-parentheses (markup-stream level *primitive-level-stmt*)
(depict-logical-block (markup-stream 0)
(depict markup-stream "@")
(depict-annotated-value-expr markup-stream world address-annotated-expr *primitive-level-unary-prefix*)
(depict markup-stream " :=")
(depict-logical-block (markup-stream 6)
(depict-break markup-stream 1)
(depict-annotated-value-expr markup-stream world value-annotated-expr *primitive-level-stmt*)))))
; (address-equal <address-expr1> <address-expr2>)
(defun depict-address-equal (markup-stream world level address1-annotated-expr address2-annotated-expr)
(depict-expr-parentheses (markup-stream level *primitive-level-relational*)
(depict-logical-block (markup-stream 0)
(depict-annotated-value-expr markup-stream world address1-annotated-expr *primitive-level-additive*)
(depict markup-stream " " :identical-10)
(depict-break markup-stream 1)
(depict-annotated-value-expr markup-stream world address2-annotated-expr *primitive-level-additive*))))
;;; Macros
(defun depict-let-binding (markup-stream world var type-expr value-annotated-expr)
(depict-logical-block (markup-stream 4)
(depict-local-variable markup-stream var)
(depict markup-stream ": ")
(depict-type-expr markup-stream world type-expr)
(depict-break markup-stream 1)
(depict-logical-block (markup-stream 3)
(depict markup-stream "= ")
(depict-annotated-value-expr markup-stream world value-annotated-expr *primitive-level-stmt*))))
(defun depict-let-body (markup-stream world body-annotated-expr)
(depict-break markup-stream)
(depict-semantic-keyword markup-stream 'in)
(depict-space markup-stream)
(depict-logical-block (markup-stream (if (or (macro-annotated-expr? 'let body-annotated-expr)
(macro-annotated-expr? 'letexc body-annotated-expr))
nil
4))
(depict-annotated-value-expr markup-stream world body-annotated-expr *primitive-level-stmt*)))
; (let ((<var1> <type1> <expr1> [:unused]) ... (<varn> <typen> <exprn> [:unused])) <body>) ==>
; ((lambda ((<var1> <type1> [:unused]) ... (<varn> <typen> [:unused])) <body>) <expr1> ... <exprn>)
(defun depict-let (markup-stream world level annotated-expansion)
(assert-true (eq (first annotated-expansion) 'expr-annotation:call))
(let ((lambda-annotated-expr (second annotated-expansion))
(arg-annotated-exprs (cddr annotated-expansion)))
(assert-true (special-form-annotated-expr? 'lambda lambda-annotated-expr))
(let ((arg-binding-exprs (third lambda-annotated-expr))
(body-annotated-expr (fourth lambda-annotated-expr)))
(depict-statement (markup-stream 'let)
(depict-list markup-stream
#'(lambda (markup-stream arg-binding)
(depict-let-binding markup-stream world (first arg-binding) (second arg-binding) (pop arg-annotated-exprs)))
arg-binding-exprs
:indent 4
:separator ";"
:break t
:empty nil)
(depict-let-body markup-stream world body-annotated-expr)))))
; (letexc (<var> <type> <expr> [:unused]) <body>) ==>
; (case <expr>
; ((abrupt x exception) (typed-oneof <body-type> abrupt x))
; ((normal <var> <type> [:unused]) <body>)))
(defun depict-letexc (markup-stream world level annotated-expansion)
(assert-true (special-form-annotated-expr? 'case annotated-expansion))
(let* ((expr-annotated-expr (third annotated-expansion))
(abrupt-binding (fourth annotated-expansion))
(abrupt-tag-spec (first abrupt-binding))
(normal-binding (fifth annotated-expansion))
(normal-tag-spec (first normal-binding)))
(assert-true (equal (first abrupt-tag-spec) '(abrupt)))
(assert-true (equal (first normal-tag-spec) '(normal)))
(let* ((var (second normal-tag-spec))
(type-expr (third normal-tag-spec))
(body-annotated-expr (second normal-binding)))
(depict-statement (markup-stream 'letexc)
(depict-logical-block (markup-stream 9)
(depict-let-binding markup-stream world var type-expr expr-annotated-expr))
(depict-let-body markup-stream world body-annotated-expr)))))
;;; ------------------------------------------------------------------------------------------------------
;;; DEPICTING COMMANDS
(defmacro depict-semantics ((markup-stream depict-env &optional (paragraph-style ':semantics)) &body body)
`(progn
(depict-mode ,markup-stream ,depict-env :semantics)
(depict-paragraph (,markup-stream ,paragraph-style)
,@body)))
; (%section "section-name")
(defun depict-%section (markup-stream world depict-env section-name)
(declare (ignore world))
(assert-type section-name string)
(depict-mode markup-stream depict-env nil)
(depict-paragraph (markup-stream :section-heading)
(depict markup-stream section-name)))
; (%subsection "subsection-name")
(defun depict-%subsection (markup-stream world depict-env section-name)
(declare (ignore world))
(assert-type section-name string)
(depict-mode markup-stream depict-env nil)
(depict-paragraph (markup-stream :subsection-heading)
(depict markup-stream section-name)))
; (grammar-argument <argument> <attribute> <attribute> ... <attribute>)
(defun depict-grammar-argument (markup-stream world depict-env argument &rest attributes)
(declare (ignore world))
(depict-mode markup-stream depict-env :syntax)
(depict-paragraph (markup-stream :grammar-argument)
(depict-nonterminal-argument markup-stream argument)
(depict markup-stream " " :member-10 " ")
(depict-list markup-stream
#'(lambda (markup-stream attribute)
(depict-nonterminal-attribute markup-stream attribute))
attributes
:prefix "{"
:suffix "}"
:separator ", ")))
; (%rule <general-nonterminal-source>)
(defun depict-%rule (markup-stream world depict-env general-nonterminal-source)
(declare (ignore world))
(let* ((grammar-info (checked-depict-env-grammar-info depict-env))
(grammar (grammar-info-grammar grammar-info))
(general-nonterminal (grammar-parametrization-intern grammar general-nonterminal-source))
(seen-nonterminals (depict-env-seen-nonterminals depict-env)))
(when (grammar-info-charclass grammar-info general-nonterminal)
(error "Shouldn't use %rule on a lexer charclass nonterminal ~S" general-nonterminal))
(labels
((seen-nonterminal? (nonterminal)
(gethash nonterminal seen-nonterminals)))
(unless (every #'seen-nonterminal? (general-grammar-symbol-instances grammar general-nonterminal))
(depict-mode markup-stream depict-env :syntax)
(dolist (general-rule (grammar-general-rules grammar general-nonterminal))
(let ((rule-lhs-nonterminals (general-grammar-symbol-instances grammar (general-rule-lhs general-rule))))
(unless (every #'seen-nonterminal? rule-lhs-nonterminals)
(when (some #'seen-nonterminal? rule-lhs-nonterminals)
(warn "General rule for ~S listed before specific ones; use %rule to disambiguate" general-nonterminal))
(depict-general-rule markup-stream general-rule)
(dolist (nonterminal rule-lhs-nonterminals)
(setf (gethash nonterminal seen-nonterminals) t)))))))))
;******** May still have a problem when a specific rule precedes a general one.
; (%charclass <nonterminal>)
(defun depict-%charclass (markup-stream world depict-env nonterminal)
(let* ((grammar-info (checked-depict-env-grammar-info depict-env))
(charclass (grammar-info-charclass grammar-info nonterminal)))
(unless charclass
(error "%charclass with a non-charclass ~S" nonterminal))
(if (gethash nonterminal (depict-env-seen-nonterminals depict-env))
(warn "Duplicate charclass ~S" nonterminal)
(progn
(depict-mode markup-stream depict-env :syntax)
(depict-charclass markup-stream charclass)
(dolist (action-cons (charclass-actions charclass))
(depict-charclass-action world depict-env (cdr action-cons) nonterminal))
(setf (gethash nonterminal (depict-env-seen-nonterminals depict-env)) t)))))
; (%print-actions)
(defun depict-%print-actions (markup-stream world depict-env)
(declare (ignore world))
(dolist (pending-action (nreverse (depict-env-pending-actions-reverse depict-env)))
(funcall pending-action markup-stream depict-env))
(setf (depict-env-pending-actions-reverse depict-env) nil))
; (deftype <name> <type>)
(defun depict-deftype (markup-stream world depict-env name type-expr)
(depict-semantics (markup-stream depict-env)
(depict-logical-block (markup-stream 2)
(depict-semantic-keyword markup-stream 'type)
(depict-space markup-stream)
(depict-type-name markup-stream name)
(depict-break markup-stream 1)
(depict-logical-block (markup-stream 3)
(depict markup-stream "= ")
(depict-type-expr markup-stream world type-expr)))))
; (define <name> <type> <value> <destructured>)
; <destructured> is a flag that is true if this define was originally in the form
; (define (<name> (<arg1> <type1>) ... (<argn> <typen>)) <result-type> <value>)
; and converted into
; (define <name> (-> (<type1> ... <typen>) <result-type>)
; (lambda ((<arg1> <type1>) ... (<argn> <typen>)) <value>)
; t)
(defun depict-define (markup-stream world depict-env name type-expr value-expr destructured)
(depict-semantics (markup-stream depict-env)
(depict-logical-block (markup-stream 2)
(depict-global-variable markup-stream name)
(flet
((depict-type-and-value (markup-stream type-expr annotated-value-expr)
(depict-logical-block (markup-stream 0)
(depict-break markup-stream 1)
(depict markup-stream ": ")
(depict-type-expr markup-stream world type-expr))
(depict-break markup-stream 1)
(depict-logical-block (markup-stream 3)
(depict markup-stream "= ")
(depict-annotated-value-expr markup-stream world annotated-value-expr *primitive-level-max*))))
(let ((annotated-value-expr (nth-value 2 (scan-value world *null-type-env* value-expr))))
(if destructured
(progn
(assert-true (eq (first type-expr) '->))
(assert-true (special-form-annotated-expr? 'lambda annotated-value-expr))
(depict-lambda-bindings markup-stream world (third annotated-value-expr))
(depict-type-and-value markup-stream (third type-expr) (fourth annotated-value-expr)))
(depict-type-and-value markup-stream type-expr annotated-value-expr)))))))
; (set-grammar <name>)
(defun depict-set-grammar (markup-stream world depict-env name)
(depict-clear-grammar markup-stream world depict-env)
(let ((grammar-info (world-grammar-info world name)))
(unless grammar-info
(error "Unknown grammar ~A" name))
(setf (depict-env-grammar-info depict-env) grammar-info)
(setf (depict-env-seen-nonterminals depict-env) (make-hash-table :test #'eq))))
; (clear-grammar)
(defun depict-clear-grammar (markup-stream world depict-env)
(depict-%print-actions markup-stream world depict-env)
(depict-mode markup-stream depict-env nil)
(let ((grammar-info (depict-env-grammar-info depict-env)))
(when grammar-info
(let ((seen-nonterminals (depict-env-seen-nonterminals depict-env))
(missed-nonterminals nil))
(dolist (nonterminal (grammar-nonterminals-list (grammar-info-grammar grammar-info)))
(unless (or (gethash nonterminal seen-nonterminals)
(eq nonterminal *start-nonterminal*))
(push nonterminal missed-nonterminals)))
(when missed-nonterminals
(warn "Nonterminals not printed: ~S" missed-nonterminals)))
(setf (depict-env-grammar-info depict-env) nil)
(setf (depict-env-seen-nonterminals depict-env) nil))))
(defmacro depict-delayed-action ((markup-stream depict-env) &body depictor)
`(push #'(lambda (,markup-stream ,depict-env) ,@depictor)
(depict-env-pending-actions-reverse ,depict-env)))
(defun depict-declare-action-contents (markup-stream world action-name general-grammar-symbol type-expr)
(depict-semantic-keyword markup-stream 'action)
(depict-space markup-stream)
(depict-action-name markup-stream action-name)
(depict markup-stream :action-begin)
(depict-general-grammar-symbol markup-stream general-grammar-symbol)
(depict markup-stream :action-end)
(depict-break markup-stream 1)
(depict-logical-block (markup-stream 2)
(depict markup-stream ": ")
(depict-type-expr markup-stream world type-expr)))
; (declare-action <action-name> <general-grammar-symbol> <type>)
(defun depict-declare-action (markup-stream world depict-env action-name general-grammar-symbol-source type-expr)
(declare (ignore markup-stream))
(let* ((grammar-info (checked-depict-env-grammar-info depict-env))
(general-grammar-symbol (grammar-parametrization-intern (grammar-info-grammar grammar-info) general-grammar-symbol-source)))
(unless (grammar-info-charclass-or-partition grammar-info general-grammar-symbol)
(depict-delayed-action (markup-stream depict-env)
(depict-semantics (markup-stream depict-env)
(depict-logical-block (markup-stream 4)
(depict-declare-action-contents markup-stream world action-name general-grammar-symbol type-expr)))))))
; Declare and define the lexer-action on the charclass given by nonterminal.
(defun depict-charclass-action (world depict-env lexer-action nonterminal)
(depict-delayed-action (markup-stream depict-env)
(depict-semantics (markup-stream depict-env)
(depict-logical-block (markup-stream 4)
(depict-declare-action-contents markup-stream world (lexer-action-name lexer-action)
nonterminal (lexer-action-type-expr lexer-action))
(depict-break markup-stream 1)
(depict-logical-block (markup-stream 3)
(depict markup-stream "= ")
(depict-lexer-action markup-stream lexer-action nonterminal))))))
; (action <action-name> <production-name> <body>)
; <destructured> is a flag that is true if this define was originally in the form
; (action (<action-name> (<arg1> <type1>) ... (<argn> <typen>)) <production-name> <body>)
; and converted into
; (action <action-name> <production-name> (lambda ((<arg1> <type1>) ... (<argn> <typen>)) <body>) t)
(defun depict-action (markup-stream world depict-env action-name production-name body-expr destructured)
(declare (ignore markup-stream))
(let* ((grammar-info (checked-depict-env-grammar-info depict-env))
(grammar (grammar-info-grammar grammar-info))
(general-production (grammar-general-production grammar production-name)))
(unless (grammar-info-charclass grammar-info (general-production-lhs general-production))
(depict-delayed-action (markup-stream depict-env)
(depict-semantics (markup-stream depict-env :semantics-next)
(depict-logical-block (markup-stream 2)
(let* ((initial-env (general-production-action-env grammar general-production))
(body-annotated-expr (nth-value 2 (scan-value world initial-env body-expr)))
(action-grammar-symbols (annotated-expr-grammar-symbols body-annotated-expr)))
(depict-action-name markup-stream action-name)
(depict markup-stream :action-begin)
(depict-general-production markup-stream general-production action-grammar-symbols)
(depict markup-stream :action-end)
(flet
((depict-body (markup-stream body-annotated-expr)
(depict-break markup-stream 1)
(depict-logical-block (markup-stream 3)
(depict markup-stream "= ")
(depict-annotated-value-expr markup-stream world body-annotated-expr *primitive-level-stmt*))))
(if destructured
(progn
(assert-true (special-form-annotated-expr? 'lambda body-annotated-expr))
(depict-logical-block (markup-stream 10)
(depict-break markup-stream 0)
(depict-lambda-bindings markup-stream world (third body-annotated-expr)))
(depict-body markup-stream (fourth body-annotated-expr)))
(depict-body markup-stream body-annotated-expr))))))))))
; (terminal-action <action-name> <terminal> <lisp-function-name>)
(defun depict-terminal-action (markup-stream world depict-env action-name terminal function-name)
(declare (ignore markup-stream world depict-env action-name terminal function-name)))