Compare commits

...

77 Commits

Author SHA1 Message Date
Matthew Butterick 7d41a489c6 ensure prev-indent is an exact-nonnegative-integer 1 year ago
Matthew Butterick b0d133f4ba suppress testing of indenter due to CI issue 3 years ago
Matthew Butterick 07ef0ea181
badge harder 3 years ago
Matthew Butterick c71303e5f5
badge it 3 years ago
Matthew Butterick a2d7349459
Update README.md 3 years ago
Bogdan Popa 216536ef29
improve CI workflow (#23)
* ci: run a single Xvfb instance for all tests

* ci: add 8.0 and 8.1

* ci: skip failures on 6.7 BC, 7.{7,8,9} CS, currenct BC&CS
3 years ago
Matthew Butterick 7f1f62d714
Update README.md 3 years ago
Matthew Butterick d75a344bee
Update module.rkt 3 years ago
Matthew Butterick f0e2cb5b32 doc fix (closes #22) 4 years ago
Matthew Butterick 68bafddd61
Update ci.yml 4 years ago
Matthew Butterick bac21d8849 Revert "allow false"
This reverts commit dfef06c967.
4 years ago
Matthew Butterick 08698d0573
Update ci.yml 4 years ago
Matthew Butterick 9d86c43758 change CI action 4 years ago
Matthew Butterick bc67284dfc switch Travis for GH actions 4 years ago
Matthew Butterick dfef06c967 allow false 4 years ago
Matthew Butterick db99679d5e less def 4 years ago
Matthew Butterick bf374b1514 missing import 4 years ago
Matthew Butterick f86e14d579 update travis 4 years ago
Matthew Butterick 2aa3dbade1 move br/macro to separate package 4 years ago
Matthew Butterick 1f571fc8de unnecessary predicate 4 years ago
Matthew Butterick 6ec0d25f5d
Update LICENSE.md 4 years ago
Matthew Butterick 853e791e84 new xvfb notation for travis 5 years ago
Matthew Butterick f2eb41aab9 disable @ command char 5 years ago
Matthew Butterick e65ef99a06 touchup 5 years ago
Matthew Butterick 5fc143c123 fix negativity, more 5 years ago
Matthew Butterick 9c168fbd98 fix negativity 5 years ago
Ryan Davis 83206c4521 Extended report-datum to be friendly to eof.
read-syntax returns either a syntax or eof. This allows report-datum
to be used to debug read-syntax issues.
5 years ago
Ryan Davis d0f5fa76a9 strip trailing whitespace
separate from my content commit so you can skip this if you want
5 years ago
Matthew Butterick 0a625a17ee simplify 5 years ago
Matthew Butterick 310651e374 newline 5 years ago
Matthew Butterick 7547324037 omit srcloc 5 years ago
Matthew Butterick efa9ce3264 strip-bindings 5 years ago
Matthew Butterick 3999b3515b tacopocalypse sample 5 years ago
Matthew Butterick 1fe93f59a2 bump version to v1.6 5 years ago
Matthew Butterick 4f3db25a0b adjust numbers 5 years ago
Matthew Butterick 7ea139ac4f refinement 5 years ago
Matthew Butterick d649998e74 omit 5 years ago
Matthew Butterick a948725d58
Update .travis.yml 5 years ago
Matthew Butterick 8677730d47
Update .travis.yml 5 years ago
Matthew Butterick ad48faa13d demo details 5 years ago
Matthew Butterick e0944fea24 update scriptish 5 years ago
Matthew Butterick 944c543db7 refac scriptish 5 years ago
Matthew Butterick 37bc753b27 add `lexer-file-path` 5 years ago
Matthew Butterick 0a0d5831a7 refactor 5 years ago
Matthew Butterick ac5daac9ea more consistent 5 years ago
Matthew Butterick 06a0c155ab update algebra & precalc demos 5 years ago
Matthew Butterick 684abfc3e6 update algebra demo 5 years ago
Matthew Butterick 6d4f0a7b69 changes 5 years ago
Matthew Butterick 0fededb98a use lozenge 5 years ago
Matthew Butterick 5f98d03dab add mb 5 years ago
Matthew Butterick e88e9b164e refac solution 5 years ago
Matthew Butterick d116cfcb82 self-expanding 5 years ago
Matthew Butterick 02a4d9a50e touchup 5 years ago
Matthew Butterick 6024945967 touchup 5 years ago
Matthew Butterick b4c69df771 reversal 5 years ago
Matthew Butterick 5adc13ec08 touchup demos 5 years ago
Matthew Butterick 70acaa4394 omit 5 years ago
Matthew Butterick 081561e9cd add loc 5 years ago
Matthew Butterick 0b24352082 put on source locations 5 years ago
Matthew Butterick 177f0bbb09 scriptish demo 5 years ago
Matthew Butterick 5c40ca6279 loop touchup 5 years ago
Matthew Butterick 57522a1be9 read, expand, conjunction 5 years ago
Matthew Butterick 3c97c01b62 adjust txtadv 5 years ago
Matthew Butterick 67e0064c45 numberstring demo 5 years ago
Matthew Butterick 89c652afd6 mirror demo 5 years ago
Matthew Butterick e5523b2835 dyadic demo 5 years ago
Matthew Butterick c883cb05b2
Update README.md 5 years ago
Matthew Butterick 8744265a90 move it 5 years ago
Matthew Butterick cd68f12985 correct output contracts (fixes #19) 5 years ago
Matthew Butterick 52a91b7183 add dep 5 years ago
Matthew Butterick 1116d43e58 note 5 years ago
Matthew Butterick 15b00031e8 retry 5 years ago
Matthew Butterick 6b4743728b Revert "Update .travis.yml"
This reverts commit f138f7a22a.
5 years ago
Matthew Butterick 9e6349d602 also bump 5 years ago
Matthew Butterick f138f7a22a
Update .travis.yml 5 years ago
Matthew Butterick db0dedfbcf also bump 5 years ago
Matthew Butterick eec4502c4c bump to 1.5; min version 6.7 5 years ago

@ -0,0 +1,72 @@
name: CI
on: [push, pull_request]
jobs:
run:
name: "Build using Racket '${{ matrix.racket-version }}' (${{ matrix.racket-variant }})"
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.xfail == 'yes' }}
strategy:
fail-fast: false
matrix:
racket-version: ["6.7", "6.8", "6.9", "6.11", "6.12", "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8", "7.9", "8.0", "8.1", "current"]
racket-variant: ["BC", "CS"]
# CS builds are only provided for versions 7.4 and up so avoid
# running the job for prior versions.
exclude:
- {racket-version: "6.6", racket-variant: "CS"}
- {racket-version: "6.7", racket-variant: "CS"}
- {racket-version: "6.8", racket-variant: "CS"}
- {racket-version: "6.9", racket-variant: "CS"}
- {racket-version: "6.10.1", racket-variant: "CS"}
- {racket-version: "6.11", racket-variant: "CS"}
- {racket-version: "6.12", racket-variant: "CS"}
- {racket-version: "7.0", racket-variant: "CS"}
- {racket-version: "7.1", racket-variant: "CS"}
- {racket-version: "7.2", racket-variant: "CS"}
- {racket-version: "7.3", racket-variant: "CS"}
include:
- {racket-version: "6.7", racket-variant: "BC", xfail: "yes"}
- {racket-version: "7.7", racket-variant: "CS", xfail: "yes"}
- {racket-version: "7.8", racket-variant: "CS", xfail: "yes"}
- {racket-version: "7.9", racket-variant: "CS", xfail: "yes"}
- {racket-version: "current", racket-variant: "BC", xfail: "yes"}
- {racket-version: "current", racket-variant: "CS", xfail: "yes"}
env:
DISPLAY: :99
steps:
- name: Checkout
uses: actions/checkout@master
- uses: Bogdanp/setup-racket@v0.11
with:
distribution: 'full'
version: ${{ matrix.racket-version }}
variant: ${{ matrix.racket-variant }}
- name: Install package and its dependencies
run: raco pkg install --deps search-auto https://github.com/mbutterick/br-parser-tools.git?path=br-parser-tools-lib
- name: install brag
run: raco pkg install --deps search-auto https://github.com/mbutterick/brag.git?path=brag
- name: install br-macro
run: raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket-macro
- name: install br lib
run: raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket-lib
- name: install br demo
run: raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket-demo
- name: install br
run: raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket
- name: Start virtual framebuffer
run: Xvfb "$DISPLAY" -screen 0 1280x1024x24 &
- name: Run the brm tests
run: raco test -p beautiful-racket-macro
- name: Run the lib tests
run: raco test -p beautiful-racket-lib
- name: Run the demo tests
run: raco test -p beautiful-racket-demo
- name: Run the br tests
run: raco test -p beautiful-racket

@ -1,58 +0,0 @@
# adapted from
# https://github.com/greghendershott/travis-racket/blob/master/.travis.yml
# Thanks Greg!
language: c
sudo: false
env:
global:
- RACKET_DIR=~/racket
matrix:
# - RACKET_VERSION=6.0
# - RACKET_VERSION=6.1
# - RACKET_VERSION=6.2
- RACKET_VERSION=6.3
# - RACKET_VERSION=6.4
# - RACKET_VERSION=6.5
- RACKET_VERSION=6.6
# - RACKET_VERSION=6.7
# - RACKET_VERSION=6.8
- RACKET_VERSION=6.9
# - RACKET_VERSION=6.10
# - RACKET_VERSION=6.11
- RACKET_VERSION=6.12
- RACKET_VERSION=7.0
- RACKET_VERSION=7.1
- RACKET_VERSION=HEAD
- RACKET_VERSION=HEADCS
# You may want to test against certain versions of Racket, without
# having them count against the overall success/failure.
matrix:
allow_failures:
#- env: RACKET_VERSION=HEAD
- env: RACKET_VERSION=HEADCS
# Fast finish: Overall build result is determined as soon as any of
# its rows have failed, or, all of its rows that aren't allowed to
# fail have succeeded.
fast_finish: true
before_install:
- "export DISPLAY=:99.0" # needed for testing with `racket/gui`
- "sh -e /etc/init.d/xvfb start" # needed for testing with `racket/gui`
- git clone https://github.com/mbutterick/travis-racket.git
- cat travis-racket/install-racket.sh | bash # pipe to bash not sh!
- export PATH="${RACKET_DIR}/bin:${PATH}" #install-racket.sh can't set for us
script:
- cd .. # Travis did a cd into the dir. Back up, for the next:
# don't rely on package server
- travis_retry raco pkg install --deps search-auto https://github.com/mbutterick/br-parser-tools.git?path=br-parser-tools-lib
- travis_retry raco pkg install --deps search-auto https://github.com/mbutterick/brag.git?path=brag
- travis_retry raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket-lib
- raco test -p beautiful-racket-lib
- travis_retry raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket-demo
- raco test -p beautiful-racket-demo
- travis_retry raco pkg install --deps search-auto https://github.com/mbutterick/beautiful-racket.git?path=beautiful-racket
- raco test -p beautiful-racket

@ -0,0 +1,9 @@
MIT License for `beautiful-racket`
© 2016-2019 Matthew Butterick
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -1,5 +1,5 @@
beautiful-racket [![Build Status](https://travis-ci.org/mbutterick/beautiful-racket.svg?branch=master)](https://travis-ci.org/mbutterick/beautiful-racket)
-
## beautiful-racket [![Build Status](https://github.com/mbutterick/beautiful-racket/workflows/CI/badge.svg)](https://github.com/mbutterick/beautiful-racket/actions)
Resources for the “Beautiful Racket” book, including:
@ -10,28 +10,25 @@ Resources for the “Beautiful Racket” book, including:
* sample languages
Installation
-
## Installation
`raco pkg install beautiful-racket`
Update
-
## Update
`raco pkg update --update-deps beautiful-racket`
Documentation
-
## Documentation
http://docs.racket-lang.org/br
MIT license
-
`beautiful-racket` © 2016-2019 Matthew Butterick
## License
MIT
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
## Project status
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Complete. I will maintain the code but no major updates are planned.

@ -1,9 +1,6 @@
#lang brag
top : (func-def | func-app)*
func-def : /"fun" var /"(" vars /")" /"=" expr
/vars : var [/"," var]
expr : var "+" var | value
@value : var | INT | func-app
func-app : var /"(" value [/"," value] /")"
@var : ID
top : (fun | app)*
fun : /"fun" ID /"(" ID [/"," ID] /")" /"=" expr
expr : ID /"+" ID | app
app : ID /"(" (ID | INT) [/"," ID] /")"

@ -1,6 +1,6 @@
#lang br/quicklang
(require brag/support "grammar.rkt")
(provide (all-defined-out) #%module-begin)
(provide top fun expr app)
(module+ reader
(provide read-syntax))
@ -8,27 +8,29 @@
(define-lex-abbrev reserved-toks
(:or "fun" "(" ")" "=" "+" ","))
(define tokenize
(define tokenize-1
(lexer
[whitespace (tokenize input-port)]
[whitespace (token lexeme #:skip? #t)]
[(from/stop-before "#" "\n") (token 'COMMENT #:skip? #t)]
[reserved-toks lexeme]
[alphabetic (token 'ID (string->symbol lexeme))]
[(:+ alphabetic) (token 'ID (string->symbol lexeme))]
[(:+ (char-set "0123456789")) (token 'INT (string->number lexeme))]))
(define-macro top #'begin)
(define-macro top #'#%module-begin)
(define-macro (func-def VAR VARS EXPR)
#'(define (VAR . VARS) EXPR))
(define-macro-cases fun
[(_ VAR ARG0 EXPR) #'(define (VAR ARG0) EXPR)]
[(_ VAR ARG0 ARG1 EXPR) #'(define (VAR ARG0 ARG1) EXPR)])
(define-macro-cases expr
[(_ LEFT "+" RIGHT) #'(+ LEFT RIGHT)]
[(_ LEFT RIGHT) #'(+ LEFT RIGHT)]
[(_ OTHER) #'OTHER])
(define-macro func-app #'#%app)
(define-macro app #'#%app)
(define (read-syntax src ip)
(define parse-tree (parse (λ () (tokenize ip))))
(strip-context
(define parse-tree (parse src (λ () (tokenize-1 ip))))
(strip-bindings
(with-syntax ([PT parse-tree])
#'(module mod-name algebra-demo
#'(module algebra-mod algebra-demo
PT))))

@ -1,4 +1,6 @@
#lang algebra-demo
fun f(x,y) = x + y
fun g(z) = f(z,z)
g(10)
fun f(x,y) = x + y
# fun f(x,y) = x * y
fun g(zz) = f(zz,zz)
g(10)
g(23)

@ -1,4 +1,4 @@
#lang racket
#lang br
(provide #%top-interaction #%module-begin
(rename-out [my-datum #%datum]
[my-datum #%top]

@ -3,7 +3,7 @@
(define-lex-abbrev digits (:+ (char-set "0123456789")))
(define-lex-abbrev reserved-terms (:or "print" "goto" "end" "+" ":" ";" "let" "=" "input" "-" "*" "/" "^" "mod" "(" ")" "def" "if" "then" "else" "<" ">" "<>" "and" "or" "not" "gosub" "return" "for" "to" "step" "next"))
(define-lex-abbrev reserved-terms (:or "print" "goto" "end" "+" ":" ";" "let" "=" "input" "-" "*" "/" "^" "mod" "(" ")" "if" "then" "else" "<" ">" "<>" "and" "or" "not" "gosub" "return" "for" "to" "step" "next"))
(define basic-lexer
(lexer-srcloc

@ -3,7 +3,7 @@
(define-lex-abbrev digits (:+ (char-set "0123456789")))
(define-lex-abbrev reserved-terms (:or "print" "goto" "end" "+" ":" ";" "let" "=" "input" "-" "*" "/" "^" "mod" "(" ")" "def" "if" "then" "else" "<" ">" "<>" "and" "or" "not" "gosub" "return" "for" "to" "step" "next" "def" "," "import" "export"))
(define-lex-abbrev reserved-terms (:or "print" "goto" "end" "+" ":" ";" "let" "=" "input" "-" "*" "/" "^" "mod" "(" ")" "if" "then" "else" "<" ">" "<>" "and" "or" "not" "gosub" "return" "for" "to" "step" "next" "def" "," "import" "export"))
(define-lex-abbrev racket-id-kapu
(:or whitespace (char-set "()[]{}\",'`;#|\\")))

@ -0,0 +1,26 @@
#lang br/quicklang
(module reader br
(provide read-syntax)
(define (read-syntax name port)
(define s-exprs (let loop ([toks null])
(define tok (read port))
(if (eof-object? tok)
(reverse toks)
(loop (cons tok toks)))))
(strip-bindings
(with-syntax ([(EXPR ...) s-exprs])
#'(module read-only-mod conjunction-demo
EXPR ...)))))
(define (convert-expr x)
(cond
[(list? x) (map convert-expr x)]
[(number? x) 42]
[(string? x) "whee"]
[else 'kaboom]))
(define-macro (my-module-begin EXPR ...)
#'(#%module-begin
(convert-expr 'EXPR) ...))
(provide (rename-out [my-module-begin #%module-begin]))

@ -0,0 +1,4 @@
#lang conjunction-demo
"hello world"
(+ 1 (* 2 (- x)))

@ -0,0 +1,40 @@
#lang br
(require racket/file)
#|
(define src (file->string "source.txt"))
(define strs (string-split src))
(define toks (map (λ (str) (or (string->number str) (string->symbol str))) strs))
(define expr (list (second toks) (first toks) (third toks)))
(eval expr (make-base-namespace))
|#
#|
(eval
(match (for/list ([str (in-list (string-split (file->string "source.txt")))])
(or (string->number str) (string->symbol str)))
[(list num1 op num2) (list op num1 num2)])
(make-base-namespace))
|#
(define (eval-src src)
(eval
(match (for/list ([str (in-list (string-split src))])
(or (string->number str) (string->symbol str)))
[(list num1 op num2) (list op num1 num2)]) (make-base-namespace)))
(module reader br
(provide read-syntax)
(define (read-syntax name ip)
`(module mod "main.rkt"
,(port->string ip))))
(provide #%datum #%top-interaction (rename-out [mb #%module-begin]))
(define-macro (mb SRC)
#'(#%module-begin
(eval-src SRC)))

@ -0,0 +1,2 @@
#lang dyadic-demo
12 + 34

@ -0,0 +1,13 @@
#lang br
(define (convert-expr x)
(cond
[(list? x) (map convert-expr x)]
[(number? x) 42]
[(string? x) "whee"]
[else 'kaboom]))
(define-macro (my-module-begin EXPR ...)
#'(#%module-begin
(convert-expr 'EXPR) ...))
(provide (rename-out [my-module-begin #%module-begin]))

@ -0,0 +1,4 @@
#lang s-exp expand-only-demo
"hello world"
(+ 1 (* 2 (- x)))

@ -5,9 +5,11 @@
(define collection 'multi)
(define version "1.4")
(define version "1.6")
(define deps '(["base" #:version "6.3"]
;; base v6.7 dependency needs to be called 6.6.0.900
;; due to strange little bug in `raco pkg install`
(define deps '(["base" #:version "6.6.0.900"]
"sugar"
"beautiful-racket-lib"
"rackunit-lib"
@ -17,3 +19,5 @@
"syntax-color-lib"
"gui-lib"
"math-lib"))
(define build-deps '("at-exp-lib"))

@ -0,0 +1,18 @@
#lang br
(provide #%top-interaction #%module-begin
(rename-out [my-datum #%datum]
[my-datum #%top]
[my-app #%app]))
(define-macro (my-datum . THING)
(define datum (syntax->datum #'THING))
(cond
[(string? datum) #'"whee"]
[(number? datum) #'42]
[else #''kaboom]))
(define-macro (my-app FUNC . ARGS)
#'(list FUNC . ARGS))
(module reader syntax/module-reader
injunction-demo)

@ -0,0 +1,4 @@
#lang injunction-demo
"hello world"
(+ 1 (* 2 (- x)))

@ -11,7 +11,7 @@
(cond
[(not prev-line) 0]
[else
(define prev-indent (line-indent tbox prev-line))
(define prev-indent (or (line-indent tbox prev-line) 0))
(cond
[(left-bracket?
(line-first-visible-char tbox prev-line))

@ -5,11 +5,10 @@
(require rackunit))
(define (jsonic-token? x)
(or (eof-object? x) (string? x) (token-struct? x)))
(or (eof-object? x) (token-struct? x)))
(module+ test
(check-true (jsonic-token? eof))
(check-true (jsonic-token? "a string"))
(check-true (jsonic-token? (token 'A-TOKEN-STRUCT "hi")))
(check-false (jsonic-token? 42)))

@ -5,11 +5,10 @@
(require rackunit))
(define (token? x)
(or (eof-object? x) (string? x) (token-struct? x)))
(or (eof-object? x) (token-struct? x)))
(module+ test
(check-true (token? eof))
(check-true (token? "a string"))
(check-true (token? (token 'A-TOKEN-STRUCT "hi")))
(check-false (token? 42)))

@ -0,0 +1,18 @@
#lang br/quicklang
(module reader br
(provide (rename-out [rs read-syntax]))
(define (rs src ip)
(define toks (for/list ([tok (in-port (λ (p) (read-syntax src ip)) ip)])
tok))
(strip-context
(with-syntax ([(PT ...) toks])
#'(module _ mirror-demo
PT ...)))))
(provide (except-out (all-from-out br/quicklang) #%module-begin)
(rename-out [mb #%module-begin]))
(define-macro (mb PT ...)
#'(#%module-begin
PT ...))

@ -0,0 +1,4 @@
#lang mirror-demo
"hello world"
(+ 1 (* 2 (- 3)))

@ -0,0 +1,54 @@
#lang br
(require racket/sequence)
(module reader br
(provide read-syntax)
(define (read-syntax path ip)
(strip-context
#`(module mod numberstring-demo
#,@(map string->number (regexp-match* #rx"." (string-trim (port->string ip))))))))
(define (ones->word num)
(case num
[(1) "one"][(2) "two"][(3) "three"][(4) "four"][(5) "five"]
[(6) "six"][(7) "seven"][(8) "eight"][(9) "nine"]))
(define (tens->word num)
(case num
[(2) "twenty"][(3) "thirty"][(4) "forty"][(5) "fifty"]
[(6) "sixty"][(7) "seventy"][(8) "eighty"][(9) "ninety"]
[else (number->string num)]))
(define (two-digit->word num)
(case num
[(10) "ten"][(11) "eleven"][(12) "twelve"][(13) "thirteen"][(14) "fourteen"]
[(15) "fifteen"][(16) "sixteen"][(17) "seventeen"][(18) "eighteen"][(19) "nineteen"]
[else (string-join (cons (tens->word (quotient num 10))
(if (positive? (modulo num 10))
(list (ones->word (modulo num 10)))
null)) "-")]))
(define (triple->string triple)
(match-define (list h t o) triple)
(string-join
(append
(if (positive? h)
(list (ones->word h) "hundred")
null)
(if (positive? t)
(list (two-digit->word (+ (* 10 t) o)))
(list (ones->word o)))) " "))
(define (ones triple) (format "~a" (triple->string triple)))
(define (thousands triple) (format "~a thousand" (triple->string triple)))
(define (millions triple) (format "~a million" (triple->string triple)))
(provide #%datum #%top-interaction (rename-out [mb #%module-begin]))
(define-macro (mb . DIGITS)
#'(#%module-begin
(define digits (list . DIGITS))
(define padded-digits (append (make-list (- 9 (length digits)) 0) digits))
(display (string-join (reverse (for/list ([triple (in-slice 3 (reverse padded-digits))]
[quantifier (list ones thousands millions)]
#:unless (equal? triple '(0 0 0)))
(quantifier (reverse triple)))) ", "))))

@ -0,0 +1,2 @@
#lang numberstring-demo
56833458

@ -1,11 +1,12 @@
#lang brag
top : (func-def | func-app)*
func-def : /"fun" var /"(" vars /")" /"=" expr
/vars : [var (/"," var)*]
@expr : sum
sum : [sum ("+" | "-")] product
product : [product ("*" | "/")] value
@value : var | INT | func-app | /"(" expr /")"
func-app : var /"(" [expr (/"," expr)*] /")"
top : (fun | app)*
fun : /"fun" var /"(" argvars /")" /"=" expr
/argvars : [var (/"," var)*]
@expr : add-or-sub
add-or-sub : [add-or-sub ("+" | "-")] mult-or-div
mult-or-div : [mult-or-div ("*" | "/")] value
@value : var | int | app | /"(" expr /")"
int : ["-"] INT
app : var /"(" [expr (/"," expr)*] /")"
@var : ID

@ -1,6 +1,6 @@
#lang br/quicklang
(require brag/support "grammar.rkt")
(provide (all-defined-out) #%module-begin)
(provide top fun app add-or-sub mult-or-div int)
(module+ reader
(provide read-syntax))
@ -8,35 +8,41 @@
(define-lex-abbrev reserved-toks
(:or "fun" "(" ")" "=" "+" "*" "/" "-" ","))
(define tokenize
(define-lex-abbrev digit (char-set "0123456789"))
(define tokenize-1
(lexer
[(:or (from/to "//" "\n") (from/to "/*" "*/")) (token 'COMMENT #:skip? #t)]
[whitespace (tokenize input-port)]
[whitespace (token lexeme #:skip? #t)]
[(:or (from/stop-before "#" "\n")
(from/to "/*" "*/")) (token 'COMMENT #:skip? #t)]
[reserved-toks lexeme]
[alphabetic (token 'ID (string->symbol lexeme))]
[(:+ (char-set "0123456789")) (token 'INT (string->number lexeme))]))
[(:+ digit) (token 'INT (string->number lexeme))]
[(:+ alphabetic) (token 'ID (string->symbol lexeme))]))
(define-macro top #'begin)
(define-macro top #'#%module-begin)
(define-macro (func-def VAR VARS EXPR)
#'(define (VAR . VARS) EXPR))
(define-macro (fun VAR (ARGVAR ...) EXPR)
#'(define (VAR ARGVAR ...) EXPR))
(define-macro-cases sum
(define-macro-cases add-or-sub
[(_ LEFT "+" RIGHT) #'(+ LEFT RIGHT)]
[(_ LEFT "-" RIGHT) #'(- LEFT RIGHT)]
[(_ OTHER) #'OTHER])
(define-macro-cases product
[(_ LEFT OP-STR RIGHT)
(with-syntax ([OP (string->symbol (syntax->datum #'OP-STR))])
#'(OP LEFT RIGHT))]
(define-macro-cases mult-or-div
[(_ LEFT "*" RIGHT) #'(* LEFT RIGHT)]
[(_ LEFT "/" RIGHT) #'(/ LEFT RIGHT)]
[(_ OTHER) #'OTHER])
(define-macro func-app #'#%app)
(define-macro-cases int
[(_ VAL) #'VAL]
[(_ "-" VAL) #'(- VAL)])
(define-macro app #'#%app)
(define (read-syntax src ip)
(define parse-tree (parse (λ () (tokenize ip))))
(strip-context
(define parse-tree (parse src (λ () (tokenize-1 ip))))
(strip-bindings
(with-syntax ([PT parse-tree])
#'(module mod-name precalc-demo
#'(module precalc-mod precalc-demo
PT))))

@ -1,15 +1,15 @@
#lang precalc-demo
fun f(x, y, z) = x + x + x * (y + y) + y * z - z - z
fun g(z) = f(z, z, z) // line comment
g(10) // 300
fun g(z) = f(z, z, z) # line comment
g(-10) # = 300
fun h() = g(10)
h() // also 300
h() # = 300
fun k(x) = x / 10 / 10 / (x / x)
k(h()) // 3
k(10 * (15 + 3 * 5)) // 3
k(h()) # = 3
k(-10 * (15 + 3 * 5)) # = -3
/*
multiline comment

@ -0,0 +1,13 @@
#lang br
(module reader br
(provide read-syntax)
(define (read-syntax name port)
(define s-exprs (let loop ([toks null])
(define tok (read port))
(if (eof-object? tok)
(reverse toks)
(loop (cons tok toks)))))
(strip-bindings
(with-syntax ([(EXPR ...) s-exprs])
#'(module read-only-mod br
EXPR ...)))))

@ -0,0 +1,4 @@
#lang read-only-demo
"hello world"
(+ 1 (* 2 (- 3)))

@ -0,0 +1,138 @@
#lang br
(require racket/stxparam)
(provide (all-defined-out)
#%app #%top #%datum #%top-interaction)
(define-macro top #'#%module-begin)
(define-macro-cases ternary
[(_ EXPR) #'EXPR]
[(_ COND TRUE-EXPR FALSE-EXPR) #'(if COND TRUE-EXPR FALSE-EXPR)])
(define-macro-cases logical-or
[(_ VAL) #'VAL]
[(_ L "||" R) #'(or L R)])
(define-macro-cases logical-and
[(_ VAL) #'VAL]
[(_ L "&&" R) #'(and L R)])
(define-macro (my-app ID ARG ...)
#'(error 'boom))
(define-macro-cases var
[(_ ID VAL) #'(define ID VAL)]
[(_ ID ... VAL) #'(begin (define ID VAL) ...)])
(define (add/concat . xs)
(cond
[(andmap number? xs) (let ([sum (apply + xs)])
(if (and (integer? sum) (inexact? sum))
(inexact->exact sum)
sum))]
[(ormap string? xs) (string-join (map ~a xs) "")]))
(define-macro-cases add-or-sub
[(_ LEFT "+" RIGHT) #'(add/concat LEFT RIGHT)]
[(_ LEFT "-" RIGHT) #'(- LEFT RIGHT)]
[(_ OTHER) #'OTHER])
(define-macro-cases mult-or-div
[(_ LEFT "*" RIGHT) #'(* LEFT RIGHT)]
[(_ LEFT "/" RIGHT) #'(/ LEFT RIGHT)]
[(_ OTHER) #'OTHER])
(define-macro (object (K V) ...)
#'(make-hash (list (cons K V) ...)))
(define-syntax-parameter return
(λ (stx) (error 'not-parameterized)))
(define-macro (fun (ARG ...) STMT ...)
(syntax/loc caller-stx
(λ (ARG ...)
(let/cc return-cc
(syntax-parameterize ([return (make-rename-transformer #'return-cc)])
(void) STMT ...)))))
(define-macro (defun ID (ARG ...) STMT ...)
#'(define ID (fun (ARG ...) STMT ...)))
(define (resolve-deref base . keys)
(for/fold ([val base])
([key (in-list keys)])
(cond
[(and
(hash? val)
(cond
[(hash-ref val key #f)]
[(hash-ref val (symbol->string key) #f)]
[else #f]))]
[else (error 'deref-failure)])))
(define-macro (deref (BASE KEY ...))
#'(resolve-deref BASE 'KEY ...))
(define-macro app #'#%app)
(define-macro-cases if-else
[(_ COND TSTMT ... "else" FSTMT ...) #'(cond
[COND TSTMT ...]
[else FSTMT ...])]
[(_ COND STMT ...) #'(when COND STMT ...)])
(define-macro-cases equal-or-not
[(_ VAL) #'VAL]
[(_ L "==" R) #'(equal? L R)]
[(_ L "!=" R) #'(not (equal? L R))])
(define-macro-cases gt-or-lt
[(_ VAL) #'VAL]
[(_ L "<" R) #'(< L R)]
[(_ L "<=" R) #'(<= L R)]
[(_ L ">" R) #'(> L R)]
[(_ L ">=" R) #'(>= L R)])
(define-macro (while COND STMT ...)
#'(let loop ()
(when COND
STMT ...
(loop))))
(define (alert x) (displayln (format "ALERT! ~a" x)))
#;(require racket/gui)
#;(define (alert text)
(define dialog (instantiate dialog% ("Alert")))
(new message% [parent dialog] [label text])
(define panel (new horizontal-panel% [parent dialog]
[alignment '(center center)]))
(new button% [parent panel] [label "Ok"]
[callback (lambda (button event)
(send dialog show #f))])
(send dialog show #t))
(define-macro-cases increment
[(_ ID) #'ID]
[(_ "++" ID) #'(let ()
(set! ID (add1 ID))
ID)]
[(_ "--" ID) #'(let ()
(set! ID (sub1 ID))
ID)]
[(_ ID "++") #'(begin0
ID
(set! ID (add1 ID)))]
[(_ ID "--") #'(begin0
ID
(set! ID (sub1 ID)))])
(define-macro-cases reassignment
[(_ ID) #'ID]
[(_ ID "+=" EXPR) #'(let ()
(set! ID (+ ID EXPR))
ID)]
[(_ ID "-=" EXPR) #'(let ()
(set! ID (- ID EXPR))
ID)])

@ -0,0 +1,31 @@
#lang brag
top : @statement*
statement : (var | expr | return | defun) /";" | if-else | while
var : /"var" (varname /"=")+ expr
@expr : reassignment
reassignment : ID [("+=" | "-=") expr] | ternary
ternary : expr /"?" expr /":" expr | logical-or
logical-or : [logical-or "||"] logical-and
logical-and : [logical-and "&&"] equal-or-not
equal-or-not : [equal-or-not ("!=" | "==")] gt-or-lt
gt-or-lt : [gt-or-lt ("<" | "<=" | ">" | ">=")] add-or-sub
add-or-sub : [add-or-sub ("+" | "-")] mult-or-div
mult-or-div : [mult-or-div ("*" | "/")] value
@value : NUMBER | STRING | object
| fun | app | increment | varname | /"(" expr /")"
increment : ("++" | "--") varname | varname ("++" | "--")
object : /"{" @kvs /"}"
kvs : [kv (/"," kv)*]
/kv : expr /":" expr
defun : /"function" ID /"(" varnames /")" @block
fun : /"function" /"(" varnames /")" @block
/varnames : [varname (/"," varname)*]
@varname : ID | deref
deref : DEREF
block : /"{" @statement* /"}"
return : /"return" expr
app : varname /"(" @exprs /")"
exprs : [expr (/"," expr)*]
if-else : /"if" /"(" expr /")" @block ["else" @block]
while : /"while" /"(" expr /")" @block

@ -0,0 +1,4 @@
#lang info
(define compile-omit-paths '("less-rackety.rkt" "test.rkt"))
(define test-omit-paths '("less-rackety.rkt" "test.rkt"))

@ -0,0 +1,43 @@
#lang br/quicklang
(require "grammar.rkt" brag/support)
(module+ reader
(provide read-syntax))
(define-lex-abbrev reserved-toks
(:or "var" "=" ";" "{" "}" "//" "/*" "*/"
"+" "*" "/" "-"
"'" "\""
":" "," "(" ")"
"if" "else" "while" "?"
"==" "!=" "<=" "<" ">=" ">" "&&" "||"
"function"
"return" "++" "--" "+=" "-="))
(define-lex-abbrev digits (:+ (char-set "0123456789")))
(define tokenize-1
(lexer-srcloc
[(:or (from/stop-before "//" "\n")
(from/to "/*" "*/")) (token 'COMMENT #:skip? #t)]
[reserved-toks lexeme]
[(:seq (:? "-") (:or (:seq (:? digits) "." digits)
(:seq digits (:? "."))))
(token 'NUMBER (string->number lexeme))]
[(:seq (:+ (:- (:or alphabetic punctuation digits) reserved-toks)))
(if (string-contains? lexeme ".")
(token 'DEREF (map string->symbol (string-split lexeme ".")))
(token 'ID (string->symbol lexeme)))]
[(:or (from/to "\"" "\"") (from/to "'" "'"))
(token 'STRING (string-trim lexeme (substring lexeme 0 1)))]
[whitespace (token 'WHITE #:skip? #t)]
[any-char lexeme]))
(define (read-syntax src ip)
(port-count-lines! ip)
(lexer-file-path ip)
(define parse-tree (parse src (λ () (tokenize-1 ip))))
(strip-bindings
(with-syntax ([PT parse-tree])
#'(module scriptish-mod scriptish-demo/expander
PT))))

@ -0,0 +1,21 @@
#lang scriptish-demo
-1; // line comment
10 ;
/* multi
// line
comment */
2;
var al = -.123;
var bo = "foo";
var cy = 1.;
var da = 'bar';
al;bo;cy;da;
cy + cy + cy;
al+cy*al-cy/100;
cy++;
cy + cy + bo + da;
bo+cy+cy+da;

@ -0,0 +1,34 @@
#lang scriptish-demo
var x = 42;
var s = "string";
x + x; // prints 84
s + x; // prints "string42"
var thing = {
"foo" : 42,
'bar' : function(x) {
return x + 15;
}
};
thing.foo; // prints 42
thing.bar; // prints #<procedure:...test.rkt:11:12>
thing.bar(3); // prints 18
if ( thing.foo == 42 ) {
// prints "The correct answer is 42"
alert("The correct answer is " + thing.foo);
} else {
alert("Nope");
}
var idx = 0;
while ( idx != 50 ) {
if ( thing.bar(idx) == 35 ) {
// prints "Calamity at 20!"
alert("Calamity at " + idx + "!");
}
idx++;
}

@ -7,7 +7,7 @@
(for/list ([tok (in-port read-char ip)])
tok))
(define (parse toks)
(define (parse src toks)
(for/list ([tok (in-list toks)])
(define int (char->integer tok))
(for/list ([bit (in-range 7)])
@ -17,8 +17,13 @@
(define (read-syntax src ip)
(define toks (tokenize ip))
(define parse-tree (parse toks))
(strip-context
(define parse-tree (parse src toks))
(strip-bindings
(with-syntax ([PT parse-tree])
#'(module tacofied racket
(for-each displayln 'PT)))))
#'(module tacofied taco-compiler-demo
PT))))
(define-macro (mb PT)
#'(#%module-begin
(for-each displayln 'PT)))
(provide (rename-out [mb #%module-begin]))

@ -7,7 +7,7 @@
(for/list ([tok (in-port read ip)])
tok))
(define (parse toks)
(define (parse src toks)
(for/list ([tok (in-list toks)])
(integer->char
(for/sum ([val (in-list tok)]
@ -17,8 +17,13 @@
(define (read-syntax src ip)
(define toks (tokenize ip))
(define parse-tree (parse toks))
(define parse-tree (parse src toks))
(strip-context
(with-syntax ([PT parse-tree])
#'(module untaco racket
(display (list->string 'PT))))))
#'(module untaco taco-decompiler-demo
PT))))
(define-macro (mb PT)
#'(#%module-begin
(display (list->string 'PT))))
(provide (rename-out [mb #%module-begin]))

@ -7,7 +7,7 @@
(for/list ([tok (in-port read ip)])
tok))
(define (parse toks)
(define (parse src toks)
(for/list ([tok (in-list toks)])
(integer->char
(for/sum ([val (in-list tok)]
@ -17,7 +17,7 @@
(define (read-syntax src ip)
(define toks (tokenize ip))
(define parse-tree (parse toks))
(define parse-tree (parse src toks))
(define src-string (list->string parse-tree))
(define racket-toks
(for/list ([tok (in-port read (open-input-string src-string))])

@ -1,11 +1,14 @@
#lang br/quicklang
(require brag/support "grammar.rkt")
(provide (all-from-out br/quicklang) (all-defined-out))
(provide taco-program taco-leaf
taco not-a-taco
show
#%module-begin)
(module+ reader
(provide read-syntax))
(define (tokenize ip)
(define (tokenize-1 ip)
(define lex
(lexer
["#$" lexeme]
@ -25,10 +28,13 @@
(define (not-a-taco) 0)
(define (show pt)
(display (apply string pt)))
(define (read-syntax src ip)
(define token-thunk (λ () (tokenize ip)))
(define parse-tree (parse token-thunk))
(define token-thunk (λ () (tokenize-1 ip)))
(define parse-tree (parse src token-thunk))
(strip-context
(with-syntax ([PT parse-tree])
#'(module winner taco-victory-demo
(display (apply string PT))))))
(show PT)))))

@ -8,7 +8,7 @@
(for/list ([tok (in-port read-char ip)])
tok))
(define (parse toks)
(define (parse src toks)
(define parse-tree-datum (parse-to-datum toks))
(for/list ([leaf (in-list (cdr parse-tree-datum))])
(integer->char
@ -17,11 +17,15 @@
#:when (equal? val '(taco)))
(expt 2 power)))))
(define (read-syntax src ip)
(define toks (tokenize ip))
(define parse-tree (parse toks))
(define parse-tree (parse src toks))
(strip-context
(with-syntax ([PT parse-tree])
#'(module untaco racket
(display (list->string 'PT))))))
#'(module tacogram-mod tacogram-demo
PT))))
(define-macro (mb PT)
#'(#%module-begin
(display (list->string 'PT))))
(provide (rename-out [mb #%module-begin]))

@ -1,5 +1,5 @@
#lang br/quicklang
(require brag/support racket/sequence)
(require brag/support)
(module+ reader
(provide read-syntax))
@ -11,24 +11,31 @@
[any-char (lex input-port)]))
(define (tokenize ip)
(define toklets
(for/list ([toklet (in-port lex ip)])
toklet))
(for/list ([tok (in-slice 7 toklets)])
(for/list ([tok (in-port lex ip)])
tok))
(define (parse toks)
(for/list ([tok (in-list toks)])
(define (parse src toks)
(define heptatoks
(let loop ([toks toks][acc null])
(if (empty? toks)
(reverse acc)
(loop (drop toks 7) (cons (take toks 7) acc)))))
(for/list ([heptatok (in-list heptatoks)])
(integer->char
(for/sum ([val (in-list tok)]
(for/sum ([val (in-list heptatok)]
[power (in-naturals)]
#:when (eq? val 'taco))
(expt 2 power)))))
(define (read-syntax src ip)
(define toks (tokenize ip))
(define parse-tree (parse toks))
(define parse-tree (parse src toks))
(strip-context
(with-syntax ([PT parse-tree])
#'(module untaco racket
(display (list->string 'PT))))))
#'(module taco-mod tacopocalypse-demo
PT))))
(define-macro (my-module-begin PT)
#'(#%module-begin
(display (list->string 'PT))))
(provide (rename-out [my-module-begin #%module-begin]))

@ -0,0 +1,38 @@
#lang txtadv-demo
===VERBS===
north, n
"go north"
south, s
"go south"
get _, grab _, take _
"take"
===THINGS===
---cactus---
get
"You win!"
===PLACES===
---meadow---
"Welcome to the Cactus Game! You're standing in a meadow. There is a desert to the south."
[]
south
desert
---desert---
"You're in a desert. There is nothing for miles around."
[cactus]
north
meadow
===START===
meadow

@ -0,0 +1,5 @@
#lang racket/base
(module reader racket/base
(require "reader.rkt")
(provide (all-from-out "reader.rkt")))

@ -1,6 +1,6 @@
#lang brag
txtadv-program : verb-section everywhere-section things-section places-section start-section
txtadv-program : [verb-section] [everywhere-section] [things-section] [places-section] start-section
verb-section : /"===VERBS===" verb-item+

@ -5,19 +5,21 @@
(define-macro-cases report
[(_ EXPR) #'(report EXPR EXPR)]
[(_ EXPR NAME)
#'(let ([expr-result EXPR])
#'(let ([expr-result EXPR])
(eprintf "~a = ~v\n" 'NAME expr-result)
expr-result)])
(define-macro-cases report-datum
[(_ STX-EXPR) #`(report-datum STX-EXPR #,(syntax->datum #'STX-EXPR))]
[(_ STX-EXPR NAME)
#'(let ()
(eprintf "~a = ~v\n" 'NAME (syntax->datum STX-EXPR))
STX-EXPR)])
#'(let ([stx STX-EXPR])
(eprintf "~a = ~v\n" 'NAME (if (eof-object? stx)
stx
(syntax->datum stx)))
stx)])
(define-macro (define-multi-version MULTI-NAME NAME)
#'(define-macro (MULTI-NAME X (... ...))
#'(begin (NAME X) (... ...))))
(define-multi-version report* report)
(define-multi-version report* report)

@ -1,19 +1,6 @@
#lang racket/base
(require racket/function
(for-syntax racket/base
syntax/parse
br/private/generate-literals
syntax/define))
(provide (all-defined-out)
(for-syntax with-shared-id))
(module+ test (require rackunit))
(begin-for-syntax
;; expose the caller context within br:define macros with syntax parameter
(require (for-syntax racket/base) racket/stxparam)
(provide caller-stx)
(define-syntax-parameter caller-stx (λ(stx) (error 'caller-stx-not-parameterized))))
(require racket/function (for-syntax racket/base syntax/parse) br/macro)
(provide (all-defined-out) (all-from-out br/macro))
(define-syntax (define-cases stx)
(syntax-parse stx
@ -29,217 +16,3 @@
'define-cases
"no matching case for calling pattern"
(syntax->datum stx))]))
(module+ test
(define-cases f
[(_ arg) (add1 arg)]
[(_ arg1 arg2) (+ arg1 arg2)]
[(_ . any) 'boing])
(check-equal? (f 42) 43)
(check-equal? (f 42 5) 47)
(check-equal? (f 42 5 'zonk) 'boing)
(define-cases f-one-arg
[(_ arg) (add1 arg)])
(check-exn exn:fail:contract:arity? (λ _ (f-one-arg 1 2 3))))
(define-syntax-rule (debug-define-macro (ID . PAT-ARGS) BODY)
(define-macro (ID . PAT-ARGS)
#`(begin
(for-each displayln
(list
(format "input pattern = #'~a" '#,'(ID . PAT-ARGS))
(format "output pattern = #'~a" (cadr '#,'BODY))
(format "invoked as = ~a" (syntax->datum #'(ID . PAT-ARGS)))
(format "expanded as = ~a" '#,(syntax->datum BODY))
(format "evaluated as = ~a" #,BODY)))
#,BODY)))
(module+ test
(require racket/port)
(parameterize ([current-output-port (open-output-nowhere)])
(check-equal? (let ()
(debug-define-macro (foo X Y Z)
#'(apply + (list X Y Z)))
(foo 1 2 3)) 6)
(check-equal? (let ()
(debug-define-macro (foo X ...) #'(apply * (list X ...)))
(foo 10 11 12)) 1320)))
(begin-for-syntax
(begin-for-syntax
(require (for-syntax racket/base))
(define-syntax-rule (make-shared-syntax-macro caller-stx)
#'(syntax-rules stx
[(_ form)
#'(datum->syntax caller-stx (if (syntax? form)
(syntax-e form)
form))]))))
(module+ test
(define-macro (dirty-maker ARG)
(with-syntax ([dirty-bar (datum->syntax caller-stx 'dirty-bar)])
#'(define dirty-bar (* ARG 2))))
(dirty-maker 42)
(check-equal? dirty-bar 84))
(begin-for-syntax
(define-syntax-rule (with-shared-id (id ...) . body)
(with-syntax ([id (datum->syntax caller-stx 'id)] ...)
. body)))
;; `syntax-parse` classes shared by `define-macro` and `define-macro-cases`
(begin-for-syntax
(require syntax/parse)
(define-syntax-class syntaxed-id
#:literals (syntax quasisyntax)
#:description "id in syntaxed form"
(pattern ([~or syntax quasisyntax] name:id)))
(define-syntax-class syntaxed-thing
#:literals (syntax quasisyntax)
#:description "some datum in syntaxed form"
(pattern ([~or syntax quasisyntax] thing:expr)))
(define-syntax-class else-clause
#:literals (else)
(pattern [else . body:expr]))
(define-syntax-class transformer-func
#:literals (lambda λ)
(pattern ([~or lambda λ] (arg:id) . body:expr))))
(define-syntax (define-macro stx)
(syntax-parse stx
[(_ id:id stxed-id:syntaxed-id)
#'(define-syntax id (make-rename-transformer stxed-id))]
[(_ id:id func:transformer-func)
#'(define-syntax id func)]
[(_ id:id func-id:id)
#'(define-syntax id func-id)]
[(_ id:id stxed-thing:syntaxed-thing)
#'(define-macro id (λ (stx) stxed-thing))]
[(_ (id:id . patargs:expr) . body:expr)
(with-syntax ([id (syntax-property #'id 'caller 'define-macro)])
#'(define-macro-cases id [(id . patargs) (begin . body)]))]
[else (raise-syntax-error
'define-macro
"no matching case for calling pattern"
(syntax->datum stx))]))
(define-syntax (define-macro-cases stx)
(define (error-source stx) (or (syntax-property stx 'caller) 'define-macro-cases))
(syntax-parse stx
[(_ id:id)
(raise-syntax-error (error-source #'id) "no cases given" (syntax->datum #'id))]
[(_ id:id leading-pat:expr ... else-pat:else-clause trailing-pat0:expr trailing-pat:expr ...)
(raise-syntax-error (error-source #'id) "`else` clause must be last" (syntax->datum #'id))]
[(_ id:id (pat:expr . result-exprs:expr) ... else-clause:else-clause)
(unless (ellipses-follow-wildcards-or-subpatterns? #'(pat ...))
(raise-syntax-error (error-source #'id) "ellipsis in pattern can only appear after wildcard or subpattern" (syntax->datum stx)))
(with-syntax ([(PAT ...) (map (λ (x) (literalize-pat x #'~literal)) (syntax->list #'(pat ...)))])
#'(define-macro id
(λ (stx)
(define result
(syntax-parameterize ([caller-stx (make-rename-transformer #'stx)])
(syntax-parse (syntax-case stx () [any #'any])
[PAT . result-exprs] ...
else-clause)))
(if (syntax? result)
result
(datum->syntax #'id result)))))]
[(_ id:id pat-clause:expr ...) ; macro without `else` clause will reach this branch
#'(define-macro-cases id
pat-clause ...
[else (raise-syntax-error
'id
"no matching case for calling pattern"
(syntax->datum caller-stx))])]
[else (raise-syntax-error
(error-source #'id)
"no matching case for calling pattern"
(syntax->datum stx))]))
(module+ test
(define-macro plus (λ (stx) #'+))
(check-equal? (plus 42) +)
(define-macro plusser #'plus)
(check-equal? (plusser 42) +)
(check-equal? plusser +)
(define-macro (times [nested ARG]) #`(* ARG ARG))
(check-equal? (times [nested 10]) 100)
(define-macro timeser #'times)
(check-equal? (timeser [nested 12]) 144)
(define-macro fortytwo #`42)
(check-equal? fortytwo 42)
(check-equal? (let ()
(define-macro (foo X)
(with-syntax ([zam #'+])
#'(zam X X))) (foo 42)) 84)
(begin
(define-macro (redefine ID) #'(define ID 42))
(redefine zoombar)
(check-equal? zoombar 42))
;; use caller-stx parameter to introduce identifier unhygienically
(define-macro (zam ARG1 ARG2 ARG3)
(with-syntax ([dz (datum->syntax caller-stx 'dirty-zam)])
#`(define dz 'got-dirty-zam)))
(zam 'this 'that 42)
(check-equal? dirty-zam 'got-dirty-zam)
(define-macro (add X) #'(+ X X))
(check-equal? (add 5) 10)
(define-macro (add-b 9X) #'(+ 9X 9X))
(check-equal? (add-b 5) 10)
(define-macro-cases add-again [(_ X) #'(+ X X)])
(check-equal? (add-again 5) 10)
(define-macro-cases add-3rd [(_ X) #'(+ X X)])
(check-equal? (add-3rd 5) 10)
(define-macro add-4th #'add-3rd)
(check-equal? (add-4th 5) 10)
(define foo-val 'got-foo-val)
(define (foo-func) 'got-foo-func)
(define-macro-cases op
[(_ "+") #''got-plus]
[(_ ARG) #''got-something-else]
[(_) #'(foo-func)]
[_ #'foo-val])
(check-equal? (op "+") 'got-plus)
(check-equal? (op 42) 'got-something-else)
(check-equal? (op) 'got-foo-func)
(check-equal? op 'got-foo-val)
(define-macro-cases elseop
[(_ ARG) #''got-arg]
[else #''got-else])
(check-equal? (elseop "+") 'got-arg)
(check-equal? (elseop "+" 42) 'got-else)
(check-exn exn:fail:syntax? (λ () (expand-once #'(define-macro-cases no-cases))))
(check-exn exn:fail:syntax? (λ () (expand-once #'(define-macro-cases badelseop
[else #''got-else]
[(_ _arg) #''got-arg]))))
(define-macro-cases no-else-macro
[(_ ARG) #''got-arg])
(check-exn exn:fail:syntax? (λ _ (expand-once #'(no-else-macro 'arg1 'arg2)))))
(define-macro (define-unhygienic-macro (ID PAT ...) BODY ... STX-OBJECT)
#'(define-macro (ID PAT ...)
BODY ...
(datum->syntax caller-stx (syntax->datum STX-OBJECT))))

@ -0,0 +1,9 @@
#lang info
;; for unknown reason "indent.rkt"
;; started causing CI failures
;; consistently on 6.7, 7.7CS, 7.8CS, 7.9CS
;; I assume it has something to do with the fact that
;; it imports `framework` and `racket/gui`,
;; OTOH why does it fail in these?
(define test-omit-paths '("indent.rkt"))

@ -23,16 +23,20 @@
(provide (rename-out
[br-read read]
[br-read-syntax read-syntax]
[at:get-info get-info]))
[brr-mod:get-info get-info]))
(module at-reader syntax/module-reader
(module br-reader syntax/module-reader
#:language 'br
#:info br-get-info
#:read at:read
#:read-syntax at:read-syntax
(require br/get-info (prefix-in at: scribble/reader)))
#:read my-read
#:read-syntax my-read-syntax
(require br/get-info (prefix-in at: scribble/reader))
(define (my-read ip) (syntax->datum (my-read-syntax ip)))
(define (my-read-syntax src ip)
(parameterize ([current-readtable (at:make-at-readtable #:command-char #\◊)])
(read-syntax src ip))))
(require debug/reader (prefix-in at: 'at-reader))
(require debug/reader (prefix-in brr-mod: 'br-reader))
#|
Use wrap-reader on the whole-module read function that would be exported
@ -40,5 +44,5 @@ by the reader module, not the single-expression read function like
at:read-syntax that you deal with within syntax/module-reader or normal use.
|#
(define br-read (wrap-reader at:read))
(define br-read-syntax (wrap-reader at:read-syntax)))
(define br-read (wrap-reader brr-mod:read))
(define br-read-syntax (wrap-reader brr-mod:read-syntax)))

@ -71,8 +71,8 @@
(define end (+ current-idx how-many))
(bytes-copy! bs 0 current-bs current-idx end)
(set! current-idx end)
(set! col (+ col how-many))
(set! pos (+ pos how-many))
(set! col (+ (or col 0) how-many))
(set! pos (+ (or pos 0) how-many))
(unless (< current-idx (bytes-length current-bs))
(consume-ss!))
how-many]

@ -2,9 +2,12 @@
(define collection 'multi)
(define version "1.4")
(define version "1.5")
(define deps '(["base" #:version "6.3"]
;; base v6.7 dependency needs to be called 6.6.0.900
;; due to strange little bug in `raco pkg install`
(define deps '(["base" #:version "6.6.0.900"]
"beautiful-racket-macro"
"at-exp-lib"
"sugar"
"debug"

@ -0,0 +1,245 @@
#lang racket/base
(require racket/function
(for-syntax racket/base
syntax/parse
"private/generate-literals.rkt"
syntax/define))
(provide (all-defined-out)
(for-syntax with-shared-id))
(module+ test (require rackunit))
(begin-for-syntax
;; expose the caller context within br:define macros with syntax parameter
(require (for-syntax racket/base) racket/stxparam)
(provide caller-stx)
(define-syntax-parameter caller-stx (λ(stx) (error 'caller-stx-not-parameterized))))
(define-syntax (define-cases stx)
(syntax-parse stx
#:literals (syntax)
[(_ id:id)
(raise-syntax-error 'define-cases "no cases given" (syntax->datum #'id))]
[(_ id:id [(_ . pat-args:expr) . body:expr] ...)
#'(define id
(case-lambda
[pat-args . body] ...
[rest-pat (apply raise-arity-error 'id (normalize-arity (map length '(pat-args ...))) rest-pat)]))]
[else (raise-syntax-error
'define-cases
"no matching case for calling pattern"
(syntax->datum stx))]))
(module+ test
(define-cases f
[(_ arg) (add1 arg)]
[(_ arg1 arg2) (+ arg1 arg2)]
[(_ . any) 'boing])
(check-equal? (f 42) 43)
(check-equal? (f 42 5) 47)
(check-equal? (f 42 5 'zonk) 'boing)
(define-cases f-one-arg
[(_ arg) (add1 arg)])
(check-exn exn:fail:contract:arity? (λ _ (f-one-arg 1 2 3))))
(define-syntax-rule (debug-define-macro (ID . PAT-ARGS) BODY)
(define-macro (ID . PAT-ARGS)
#`(begin
(for-each displayln
(list
(format "input pattern = #'~a" '#,'(ID . PAT-ARGS))
(format "output pattern = #'~a" (cadr '#,'BODY))
(format "invoked as = ~a" (syntax->datum #'(ID . PAT-ARGS)))
(format "expanded as = ~a" '#,(syntax->datum BODY))
(format "evaluated as = ~a" #,BODY)))
#,BODY)))
(module+ test
(require racket/port)
(parameterize ([current-output-port (open-output-nowhere)])
(check-equal? (let ()
(debug-define-macro (foo X Y Z)
#'(apply + (list X Y Z)))
(foo 1 2 3)) 6)
(check-equal? (let ()
(debug-define-macro (foo X ...) #'(apply * (list X ...)))
(foo 10 11 12)) 1320)))
(begin-for-syntax
(begin-for-syntax
(require (for-syntax racket/base))
(define-syntax-rule (make-shared-syntax-macro caller-stx)
#'(syntax-rules stx
[(_ form)
#'(datum->syntax caller-stx (if (syntax? form)
(syntax-e form)
form))]))))
(module+ test
(define-macro (dirty-maker ARG)
(with-syntax ([dirty-bar (datum->syntax caller-stx 'dirty-bar)])
#'(define dirty-bar (* ARG 2))))
(dirty-maker 42)
(check-equal? dirty-bar 84))
(begin-for-syntax
(define-syntax-rule (with-shared-id (id ...) . body)
(with-syntax ([id (datum->syntax caller-stx 'id)] ...)
. body)))
;; `syntax-parse` classes shared by `define-macro` and `define-macro-cases`
(begin-for-syntax
(require syntax/parse)
(define-syntax-class syntaxed-id
#:literals (syntax quasisyntax)
#:description "id in syntaxed form"
(pattern ([~or syntax quasisyntax] name:id)))
(define-syntax-class syntaxed-thing
#:literals (syntax quasisyntax)
#:description "some datum in syntaxed form"
(pattern ([~or syntax quasisyntax] thing:expr)))
(define-syntax-class else-clause
#:literals (else)
(pattern [else . body:expr]))
(define-syntax-class transformer-func
#:literals (lambda λ)
(pattern ([~or lambda λ] (arg:id) . body:expr))))
(define-syntax (define-macro stx)
(syntax-parse stx
[(_ id:id stxed-id:syntaxed-id)
#'(define-syntax id (make-rename-transformer stxed-id))]
[(_ id:id func:transformer-func)
#'(define-syntax id func)]
[(_ id:id func-id:id)
#'(define-syntax id func-id)]
[(_ id:id stxed-thing:syntaxed-thing)
#'(define-macro id (λ (stx) stxed-thing))]
[(_ (id:id . patargs:expr) . body:expr)
(with-syntax ([id (syntax-property #'id 'caller 'define-macro)])
#'(define-macro-cases id [(id . patargs) (begin . body)]))]
[else (raise-syntax-error
'define-macro
"no matching case for calling pattern"
(syntax->datum stx))]))
(define-syntax (define-macro-cases stx)
(define (error-source stx) (or (syntax-property stx 'caller) 'define-macro-cases))
(syntax-parse stx
[(_ id:id)
(raise-syntax-error (error-source #'id) "no cases given" (syntax->datum #'id))]
[(_ id:id leading-pat:expr ... else-pat:else-clause trailing-pat0:expr trailing-pat:expr ...)
(raise-syntax-error (error-source #'id) "`else` clause must be last" (syntax->datum #'id))]
[(_ id:id (pat:expr . result-exprs:expr) ... else-clause:else-clause)
(unless (ellipses-follow-wildcards-or-subpatterns? #'(pat ...))
(raise-syntax-error (error-source #'id) "ellipsis in pattern can only appear after wildcard or subpattern" (syntax->datum stx)))
(with-syntax ([(PAT ...) (map (λ (x) (literalize-pat x #'~literal)) (syntax->list #'(pat ...)))])
#'(define-macro id
(λ (stx)
(define result
(syntax-parameterize ([caller-stx (make-rename-transformer #'stx)])
(syntax-parse (syntax-case stx () [any #'any])
[PAT . result-exprs] ...
else-clause)))
(if (syntax? result)
result
(datum->syntax #'id result)))))]
[(_ id:id pat-clause:expr ...) ; macro without `else` clause will reach this branch
#'(define-macro-cases id
pat-clause ...
[else (raise-syntax-error
'id
"no matching case for calling pattern"
(syntax->datum caller-stx))])]
[else (raise-syntax-error
(error-source #'id)
"no matching case for calling pattern"
(syntax->datum stx))]))
(module+ test
(define-macro plus (λ (stx) #'+))
(check-equal? (plus 42) +)
(define-macro plusser #'plus)
(check-equal? (plusser 42) +)
(check-equal? plusser +)
(define-macro (times [nested ARG]) #`(* ARG ARG))
(check-equal? (times [nested 10]) 100)
(define-macro timeser #'times)
(check-equal? (timeser [nested 12]) 144)
(define-macro fortytwo #`42)
(check-equal? fortytwo 42)
(check-equal? (let ()
(define-macro (foo X)
(with-syntax ([zam #'+])
#'(zam X X))) (foo 42)) 84)
(begin
(define-macro (redefine ID) #'(define ID 42))
(redefine zoombar)
(check-equal? zoombar 42))
;; use caller-stx parameter to introduce identifier unhygienically
(define-macro (zam ARG1 ARG2 ARG3)
(with-syntax ([dz (datum->syntax caller-stx 'dirty-zam)])
#`(define dz 'got-dirty-zam)))
(zam 'this 'that 42)
(check-equal? dirty-zam 'got-dirty-zam)
(define-macro (add X) #'(+ X X))
(check-equal? (add 5) 10)
(define-macro (add-b 9X) #'(+ 9X 9X))
(check-equal? (add-b 5) 10)
(define-macro-cases add-again [(_ X) #'(+ X X)])
(check-equal? (add-again 5) 10)
(define-macro-cases add-3rd [(_ X) #'(+ X X)])
(check-equal? (add-3rd 5) 10)
(define-macro add-4th #'add-3rd)
(check-equal? (add-4th 5) 10)
(define foo-val 'got-foo-val)
(define (foo-func) 'got-foo-func)
(define-macro-cases op
[(_ "+") #''got-plus]
[(_ ARG) #''got-something-else]
[(_) #'(foo-func)]
[_ #'foo-val])
(check-equal? (op "+") 'got-plus)
(check-equal? (op 42) 'got-something-else)
(check-equal? (op) 'got-foo-func)
(check-equal? op 'got-foo-val)
(define-macro-cases elseop
[(_ ARG) #''got-arg]
[else #''got-else])
(check-equal? (elseop "+") 'got-arg)
(check-equal? (elseop "+" 42) 'got-else)
(check-exn exn:fail:syntax? (λ () (expand-once #'(define-macro-cases no-cases))))
(check-exn exn:fail:syntax? (λ () (expand-once #'(define-macro-cases badelseop
[else #''got-else]
[(_ _arg) #''got-arg]))))
(define-macro-cases no-else-macro
[(_ ARG) #''got-arg])
(check-exn exn:fail:syntax? (λ _ (expand-once #'(no-else-macro 'arg1 'arg2)))))
(define-macro (define-unhygienic-macro (ID PAT ...) BODY ... STX-OBJECT)
#'(define-macro (ID PAT ...)
BODY ...
(datum->syntax caller-stx (syntax->datum STX-OBJECT))))

@ -1,7 +1,7 @@
#lang racket/base
(require (for-syntax
racket/base
br/private/generate-literals)
"private/generate-literals.rkt")
racket/list
racket/match
racket/syntax
@ -9,8 +9,8 @@
syntax/stx
syntax/strip-context
syntax/parse
br/define
br/private/syntax-flatten)
"macro.rkt"
"private/syntax-flatten.rkt")
(provide (all-defined-out)
syntax-flatten
stx-map

@ -0,0 +1,11 @@
#lang info
(define collection 'multi)
(define version "1.5")
;; base v6.7 dependency needs to be called 6.6.0.900
;; due to strange little bug in `raco pkg install`
(define deps '(["base" #:version "6.6.0.900"]))
(define build-deps '("rackunit-lib"))

@ -19,6 +19,13 @@ This library provides the @tt{#lang br} teaching language used in the book, as w
This library is designed to smooth over some of the small idiosyncrasies and inconsistencies in Racket, so that those new to Racket are more likely to say ``ah, that makes sense'' rather than ``huh? what?''
@section{Installation}
If you want all the code & documentation, install the package @racket[beautiful-racket].
If you just want the code modules (for instance, for use as a dependency in another project) install the package @racket[beautiful-racket-lib].
If you just want the @racketmodname[br/macro] and @racketmodname[br/syntax] modules, install the package @racket[beautiful-racket-macro].
@section{Conditionals}
@ -155,7 +162,7 @@ But be careful — in the example below, the result of the @racket[if] expressi
(if (and (report (first-condition? x)) (second-condition? x))
(one-thing)
(other-thing))
(report x)]
(report x)]
@defform[(report* expr ...)]
@ -170,6 +177,8 @@ A variant of @racket[report] for use with @secref["stx-obj" #:doc '(lib "scribbl
@defmodule[br/define]
@margin-note{This module also exports the bindings from @racketmodname[br/macro].}
@defform[
(define-cases id
[pat body ...+] ...+)
@ -199,6 +208,12 @@ Define a function that behaves differently depending on how many arguments are s
]
@section{Macro}
@defmodule[br/macro #:packages ("beautiful-racket-lib" "beautiful-racket-macro")]
@defform*[
#:literals (syntax lambda stx)
[
@ -386,7 +401,7 @@ Like @racket[define-macro], but moves @racket[result-expr] into the lexical cont
@section{Syntax}
@defmodule[br/syntax]
@defmodule[br/syntax #:packages ("beautiful-racket-lib" "beautiful-racket-macro")]
@defform[(with-pattern ([pattern stx-expr] ...) body ...+)]{
Bind pattern variables within each @racket[pattern] by matching the pattern to its respective @racket[stx-expr]. These pattern variables can be used in later patternexpression clauses, or in @racket[body]. Uses the same pattern conventions as @racket[define-macro] (i.e., wildcard variables must be in @tt{CAPS}; everything else is treated as a literal).
@ -555,14 +570,14 @@ Get the line index in @racket[textbox] that contains @racket[position].
@defproc[(previous-line
[textbox (is-a?/c text%)]
[position (or/c exact-nonnegative-integer? #f)])
exact-nonnegative-integer?]{
(or/c exact-nonnegative-integer? #f)]{
Get the line index in @racket[textbox] of the line before the one that contains @racket[position].
}
@defproc[(next-line
[textbox (is-a?/c text%)]
[position (or/c exact-nonnegative-integer? #f)])
exact-nonnegative-integer?]{
(or/c exact-nonnegative-integer? #f)]{
Get the line index in @racket[textbox] of the line after the one that contains @racket[position].
}

@ -1,9 +1,11 @@
#lang info
(define collection 'multi)
(define version "1.4")
(define version "1.6")
(define deps '(["base" #:version "6.3"]
;; base v6.7 dependency needs to be called 6.6.0.900
;; due to strange little bug in `raco pkg install`
(define deps '(["base" #:version "6.6.0.900"]
"beautiful-racket-lib"
"beautiful-racket-demo"))

Loading…
Cancel
Save