Skip to content

Commit

Permalink
Merge pull request #91 from triskaj/macrolet-statement
Browse files Browse the repository at this point in the history
Macrolet statement
  • Loading branch information
takagi authored Dec 5, 2017
2 parents 7b4d9a2 + 5435006 commit 6f328d1
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 0 deletions.
20 changes: 20 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,26 @@ Compiled:
return 1.0;
}

### MACROLET statement

MACROLET ({(name lambda-list local-form*)}*) statement*

`macrolet` establishes local macro definitions, using the same format as `defkernelmacro`, and executes a series of `statement`s with these definition bindings.

Example:

(macrolet ((square (a)
(if (numberp a)
(* a a)
`(* ,a ,a))))
(return (square 2)))

Compiled:

{
return 4;
}

### DO statement

DO ({(var init-form step-form)}*) (test-form) statement*
Expand Down
29 changes: 29 additions & 0 deletions src/lang/compiler/compile-statement.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
((if-p form) (compile-if form var-env func-env))
((let-p form) (compile-let form var-env func-env))
((symbol-macrolet-p form) (compile-symbol-macrolet form var-env func-env))
((macrolet-p form) (compile-macrolet form var-env func-env))
((do-p form) (compile-do form var-env func-env))
((with-shared-memory-p form)
(compile-with-shared-memory form var-env func-env))
Expand Down Expand Up @@ -142,6 +143,34 @@
(format nil "{~%~A}~%" statements2))))))


;;;
;;; Symbol-macrolet statement
;;;

(defun func-env-add-macrolet-bindings (func-env bindings)
(flet ((aux (func-env0 binding)
(let ((symbol (macrolet-binding-symbol binding))
(arguments (macrolet-binding-arguments binding))
(body (macrolet-binding-body binding)))
(function-environment-add-macro symbol arguments body
func-env0))))
(reduce #'aux bindings :initial-value func-env)))

(defun compile-macrolet-statements (statements var-env func-env)
(compile-statement `(progn ,@statements) var-env func-env))

(defun compile-macrolet (form var-env func-env)
(let ((bindings (macrolet-bindings form))
(statements (macrolet-statements form)))
(let ((func-env1 (func-env-add-macrolet-bindings func-env
bindings)))
(let ((statements1 (compile-macrolet-statements statements
var-env
func-env1)))
(let ((statements2 (indent 2 statements1)))
(format nil "{~%~A}~%" statements2))))))


;;;
;;; Do statement
;;;
Expand Down
62 changes: 62 additions & 0 deletions src/lang/syntax.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@
:symbol-macrolet-binding-p
:symbol-macrolet-binding-symbol
:symbol-macrolet-binding-expansion
;; Macrolet statement
:macrolet-p
:macrolet-bindings
:macrolet-statements
;; Macrolet statement - binding
:macrolet-binding-p
:macrolet-binding-symbol
:macrolet-binding-arguments
:macrolet-binding-body
;; Do statement
:do-p
:do-bindings
Expand Down Expand Up @@ -468,6 +477,59 @@
(let-binding-expr binding))


;;;
;;; Macrolet statement
;;;

(defun macrolet-p (form)
(cl-pattern:match form
(('macrolet . _) t)
(_ nil)))

(defun macrolet-bindings (form)
(cl-pattern:match form
(('macrolet bindings . _)
(if (every #'macrolet-binding-p bindings)
bindings
(error "The statement ~S is malformed." form)))
(('macrolet . _) (error "The statement ~S is malformed." form))
(_ (error "The value ~S is an invalid statement." form))))

(defun macrolet-statements (form)
(cl-pattern:match form
(('macrolet _ . statements) statements)
(('macrolet . _) (error "The statement ~S is malformed." form))
(_ (error "The value ~S is an invalid statement." form))))


;;;
;;; Macrolet statement - binding
;;;

(defun macrolet-binding-p (object)
(cl-pattern:match object
((name bindings . _)
(and (cl-cuda-symbol-p name)
(alexandria:proper-list-p bindings)
(mapcar #'cl-cuda-symbol-p bindings)))
(_ nil)))

(defun macrolet-binding-symbol (binding)
(unless (macrolet-binding-p binding)
(error "The value ~S is an invalid binding." binding))
(car binding))

(defun macrolet-binding-arguments (binding)
(unless (macrolet-binding-p binding)
(error "The value ~S is an invalid binding." binding))
(cadr binding))

(defun macrolet-binding-body (binding)
(unless (macrolet-binding-p binding)
(error "The value ~S is an invalid binding." binding))
(cddr binding))


;;;
;;; Do statement
;;;
Expand Down
24 changes: 24 additions & 0 deletions t/lang/compiler/compile-statement.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
:compile-if
:compile-let
:compile-symbol-macrolet
:compile-macrolet
:compile-do
:compile-with-shared-memory
:compile-set
Expand Down Expand Up @@ -115,6 +116,29 @@
"basic case 1")))


;;;
;;; test COMPILE-MACROLET function
;;;

(diag "COMPILE-MACROLET")

(let ((var-env (empty-variable-environment))
(func-env (empty-function-environment)))
(let ((lisp-code '(macrolet ((square (x) `(* ,x ,x)))
(return (square 2))))
(c-code (unlines "{"
" return (2 * 2);"
"}")))
(is (compile-macrolet lisp-code var-env func-env) c-code
"basic case 1"))
(let ((lisp-code '(macrolet ((optimized-square (x) (* x x)))
(return (optimized-square 2))))
(c-code (unlines "{"
" return 4;"
"}")))
(is (compile-macrolet lisp-code var-env func-env) c-code
"basic case 2")))


;;;
;;; test COMPILE-DO function
Expand Down
17 changes: 17 additions & 0 deletions t/lang/syntax.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,23 @@
"basic case 3")


;;;
;;; test Macrolet statement
;;;

(diag "Macrolet statement")

(ok (macrolet-p '(macrolet ((x () 'expanded-x))
(return)))
"basic case 1")
(ok (macrolet-p '(macrolet ((x () 'expanded-x))
(do-something)
(return)))
"basic case 2")
(ok (macrolet-p '(macrolet ((x () 'expanded-x))))
"basic case 3")


;;;
;;; test Do statement
;;;
Expand Down

0 comments on commit 6f328d1

Please sign in to comment.