From 4a09246307bdf0a2d745efba75049d3af424c457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Tue, 25 Apr 2017 16:39:36 +0200 Subject: [PATCH] Initial commit --- .gitignore | 6 +++ .travis.yml | 37 ++++++++++++++ LICENSE.txt | 11 +++++ README.md | 3 ++ info.rkt | 11 +++++ main.rkt | 29 +++++++++++ scribblings/chain-module-begin.scrbl | 73 ++++++++++++++++++++++++++++ 7 files changed, 170 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 info.rkt create mode 100644 main.rkt create mode 100644 scribblings/chain-module-begin.scrbl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1a59348 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*~ +\#* +.\#* +.DS_Store +compiled/ +/doc/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6a43ba2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,37 @@ +language: c +sudo: false + +env: + global: + # RACKET_DIR is an argument to install-racket.sh + - RACKET_DIR=~/racket + - PATH="$RACKET_DIR/bin:$PATH" + matrix: + # RACKET_VERSION is an argument to install-racket.sh + - RACKET_VERSION=6.0 COV=false + - RACKET_VERSION=6.1 COV=false + - RACKET_VERSION=6.1.1 COV=false + - RACKET_VERSION=6.2 COV=false + - RACKET_VERSION=6.3 COV=true + - RACKET_VERSION=6.4 COV=true + - RACKET_VERSION=6.5 COV=true + - RACKET_VERSION=6.6 COV=true + - RACKET_VERSION=6.7 COV=true + - RACKET_VERSION=6.8 COV=true + - RACKET_VERSION=RELEASE COV=true + - RACKET_VERSION=HEAD COV=true + +before_install: +- curl -L https://raw.githubusercontent.com/greghendershott/travis-racket/master/install-racket.sh | bash +- if $COV; then raco pkg install --deps search-auto doc-coverage cover cover-codecov; fi # or cover-coveralls + +install: +- raco pkg install --deps search-auto -j 2 + +script: +- raco test -x -p "$(basename "$TRAVIS_BUILD_DIR")" +- if $COV; then raco setup --check-pkg-deps --no-zo --no-launcher --no-install --no-post-install --no-docs --pkgs "$(basename "$TRAVIS_BUILD_DIR")"; fi +- if $COV; then raco doc-coverage "$(basename "$TRAVIS_BUILD_DIR")"; fi +- if $COV; then raco cover -s main -s test -s doc -f codecov -f html -d ~/coverage . || true; fi +# TODO: add an option to cover to run the "outer" module too, not just the submodules. +# TODO: deploy the coverage info. \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..5240c99 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,11 @@ +chain-module-begin +Copyright (c) 2017 georges + +This package is distributed under the GNU Lesser General Public +License (LGPL). This means that you can link chain-module-begin into proprietary +applications, provided you follow the rules stated in the LGPL. You +can also modify this package; if you distribute a modified version, +you must distribute it under the terms of the LGPL, which in +particular means that you must release the source code for the +modified software. See http://www.gnu.org/copyleft/lesser.html +for more information. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c3e3f7b --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +chain-module-begin +================== +README text here. diff --git a/info.rkt b/info.rkt new file mode 100644 index 0000000..65aedda --- /dev/null +++ b/info.rkt @@ -0,0 +1,11 @@ +#lang info +(define collection "chain-module-begin") +(define deps '("base" + "rackunit-lib" + "debug-scopes")) +(define build-deps '("scribble-lib" + "racket-doc")) +(define scribblings '(("scribblings/chain-module-begin.scrbl" ()))) +(define pkg-desc "Use this to build meta-languages, where a #%module-begin expands to the #%module-begin of another user-specified language.") +(define version "0.1") +(define pkg-authors '("Georges Dupéron")) diff --git a/main.rkt b/main.rkt new file mode 100644 index 0000000..406fa2c --- /dev/null +++ b/main.rkt @@ -0,0 +1,29 @@ +#lang racket/base + +(provide chain-module-begin) + +(require (for-syntax racket/base + syntax/parse + debug-scopes/named-scopes/exptime)) + +(define-syntax continue + (syntax-parser + [(_ whole-ctx lang lang-modbeg . body) + #:with ({~literal #%plain-module-begin} . expanded-body) + (local-expand (datum->syntax #'whole-ctx + `(,#'lang-modbeg . ,#'body) + #'whole-ctx) + 'module-begin + '()) + (define new-scope (make-module-like-named-scope + (format "nested-lang-~a" (syntax-e #'lang)))) + (new-scope #`(begin . expanded-body))])) + +(define-syntax chain-module-begin + (syntax-parser + [{~and whole (_ lang . body)} + #:with lang-modbeg (datum->syntax #'lang '#%module-begin #'lang) + #:with whole-ctx (datum->syntax #'whole 'ctx #'whole) + #'(#%plain-module-begin + (require lang) + (continue whole-ctx lang lang-modbeg . body))])) \ No newline at end of file diff --git a/scribblings/chain-module-begin.scrbl b/scribblings/chain-module-begin.scrbl new file mode 100644 index 0000000..b62c0da --- /dev/null +++ b/scribblings/chain-module-begin.scrbl @@ -0,0 +1,73 @@ +#lang scribble/manual +@require[@for-label[chain-module-begin + racket/base]] + +@title{Chaining module languages} +@author[@author+email["Georges Dupéron" "georges.duperon@gmail.com"]] + +@defmodule[chain-module-begin] + +This package is experimental. Later versions may break backward-compatibility. + +@defform[(chain-module-begin lang . body)]{ + This macro is intended to be used as the result of a @racket[#%module-begin] + macro. It chain-calls the @racket[#%module-begin] of @racket[lang]. This makes + it possible for a @racket[#%module-begin] to perform some changes on its body, + and then chain-call the @racket[#%module-begin] of a user-specified language. + + As an example here is the definition for a no-op language, which simply takes a + (possibly improper) list of languages to chain, and calls the next one: + + @racketblock[ + (module the-meta-lang racket/base + (provide (rename-out [new-#%module-begin #%module-begin])) + + (require chain-module-begin + (for-syntax racket/base + syntax/parse)) + + (define-syntax (new-#%module-begin stx) + (syntax-parse stx + [(_ {~or next-lang:id (next-lang:id . chain₊)} . body) + (define maybe-chain₊ (if (attribute chain₊) + `(,#'chain₊) + '())) + (define new-form `(,#'chain-module-begin ,#'next-lang ,@maybe-chain₊ + . ,(transform-body #'body))) + (datum->syntax stx new-form stx stx)])) + + (define-for-syntax (transform-body body) + (code:comment "identity transformation:") + body))] + + This language could then be used as follows: + + @racketblock[ + (module b the-meta-lang typed/racket + (define x : Number 123))] + + Given two other meta-language built in the same way and provided by + @racketid[meta-two] and @racketid[meta-three], it would be possible + to chain the three languages as follows: + + @racketblock[ + (module b the-lang (meta-two meta-three . typed/racket) + (define x : Number 123))] + + The @racket[chain-module-begin] macro produces the following syntax: + + @racketblock[(#%plain-module-begin + (require lang) + (continue . internal-args))] + + where @racket[(continue . _internal-args)] fully expands + @racket[(#%module-begin . body)], where @racket[#%module-begin] is the one + provided by @racket[lang], and produces the following syntax: + + @racketblock[(begin . _expanded-body)] + + An extra scope is added to the whole @racket[(begin . _expanded-body)] form, + so that a @racket[#%require] form within the @racket[_expanded-body] may + shadow bindings provided by @racket[lang], just as @racket[require] forms + normally have the possibility to shadow bindings provided by the @(hash-lang) + language.} \ No newline at end of file