├── .gitignore ├── README.md ├── arithmetic ├── L1 │ └── semantics.rkt ├── L2 │ └── semantics.rkt ├── L3 │ └── semantics.rkt ├── lang │ └── reader.rkt └── semantics.rkt ├── common.rkt ├── conditionals ├── L1 │ └── semantics.rkt ├── L2 │ └── semantics.rkt ├── L3 │ └── semantics.rkt ├── lang │ └── reader.rkt └── semantics.rkt ├── documentation-tests ├── arithmetic.rkt ├── conditionals.rkt ├── fields.rkt ├── fun-calls.rkt ├── mut-structs.rkt └── mut-vars.rkt ├── eval-order ├── L1 │ └── semantics.rkt ├── L2 │ └── semantics.rkt ├── lang │ └── reader.rkt └── semantics.rkt ├── fields ├── L1 │ └── semantics.rkt ├── L2 │ └── semantics.rkt ├── L3 │ └── semantics.rkt ├── lang │ └── reader.rkt └── semantics.rkt ├── fun-calls ├── L1 │ └── semantics.rkt ├── L2 │ └── semantics.rkt ├── L3 │ └── semantics.rkt ├── lang │ └── reader.rkt └── semantics.rkt ├── info.rkt ├── make-semantics.rkt ├── mut-structs ├── L1 │ └── semantics.rkt ├── L2 │ └── semantics.rkt ├── L3 │ └── semantics.rkt ├── lang │ └── reader.rkt └── semantics.rkt ├── mut-vars ├── L1 │ └── semantics.rkt ├── L2 │ └── semantics.rkt ├── L3 │ └── semantics.rkt ├── lang │ └── reader.rkt └── semantics.rkt ├── scope ├── lang │ └── reader.rkt └── semantics.rkt ├── strings ├── L1 │ └── semantics.rkt ├── L2 │ └── semantics.rkt ├── L3 │ └── semantics.rkt ├── lang │ └── reader.rkt └── semantics.rkt └── utils.rkt /.gitignore: -------------------------------------------------------------------------------- 1 | compiled 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is the repository for Mystery Languages. Mystery languages are based on the paper 2 | [Teaching Programming Languages by Experimental and Adversarial Thinking](https://cs.brown.edu/~sk/Publications/Papers/Published/pkf-teach-pl-exp-adv-think/). 3 | 4 | # Setup 5 | 6 | ## Installation 7 | 8 | Install this package using the Racket package manager: 9 | 10 | * **Option 1:** from DrRacket, go to File | Install Package, and enter the URL 11 | (If DrRacket says `missing dependencies`, click Show Details | 12 | Dependencies Mode | Auto) 13 | 14 | `https://github.com/shriram/mystery-languages.git` 15 | 16 | * **Option 2:** at the command line (your OS terminal, _not_ in DrRacket), run 17 | 18 | `raco pkg install https://github.com/shriram/mystery-languages.git` 19 | 20 | Make sure your paths are set correctly so that you're installing the 21 | package for the right version! 22 | 23 | ## Checking 24 | 25 | To make sure your install succeeded, in DrRacket (or the command line, 26 | if you know what you're doing), run the following: 27 | 28 | ``` 29 | #lang mystery-languages/strings 30 | 31 | 3 32 | ``` 33 | 34 | You should see output like 35 | ``` 36 | 3 37 | L1: 3 38 | L2: 3 39 | L3: 3 40 | ``` 41 | This means everything is alright! 42 | 43 | ## Learn More 44 | 45 | You should probably watch 46 | [this video](https://youtu.be/EogblZ1Rdpo) 47 | before you continue; everything below will make much more sense. 48 | 49 | ----- 50 | 51 | # Documentation 52 | 53 | There are two parts: testing, and the languages. 54 | 55 | This documentation can be a little overwhelming initially. That's 56 | because it documents an entire *family* of languages. As you get 57 | closer to the end, you'll probably be grateful to have all the 58 | documentation on one page…but it does mean it can be a little 59 | intimidating at first. Don't worry! 60 | 61 | ## Testing 62 | 63 | In all of these languages, you can just write and run expressions as 64 | usual, or you can write tests to either express what you expect or 65 | record what you saw. Testing is a little funny because all these 66 | languages produce many values, not one! Therefore, the mystery 67 | language package provides a new testing form, `TEST`: 68 | 69 | (TEST …) 70 | 71 | Thus you might write 72 | 73 | (TEST (+ 4 5) 9 9 9) 74 | 75 | (assuming there were three language variants). This means you expect 76 | each of the three languages to produce `9`. 77 | 78 | One subtlety. If instead of the above you write 79 | 80 | (TEST (+ 4 5) 9 9 (+ 5 4)) 81 | 82 | that means you don't expect the third language to produce `9`, but 83 | rather the symbolic expression `(+ 5 4)`. That's what it means for 84 | each of the expected answers to be a *constant*. 85 | 86 | > In case you're wondering why… Imagine that you write an 87 | > expression. This expression needs to be evaluated. In which language 88 | > would it be evaluated? The whole point is that the languages might 89 | > differ, so there could be multiple outcomes. To avoid confusion, 90 | > this package assumes you will do all your *computation* inside the 91 | > expression, and check only for constants in testing. 92 | 93 | Sometimes, a test intentionally ends in an error (as a way of showing 94 | that one language errors while another does not). Instead of forcing 95 | you to write a complex error condition, you can just write `failure` 96 | in that position. Similarly, sometimes it's useful to say that a value 97 | is *not* some other value, again to emphasize difference. You can then 98 | say `(not )`. For instance: 99 | 100 | (TEST (/ 1 0) failure failure failure) 101 | 102 | says that `(/ 1 0)` will lead to an error in all the languages; 103 | 104 | (TEST (+ 1 2) 3 3 (not 2)) 105 | 106 | says that `(+ 1 2)` does *not* evaluate to `2` in the third 107 | language. 108 | 109 | > This is a rather unsurprising and perhaps odd use of `not`, but 110 | > there are times when writing the exact answer is hard, and all we 111 | > want to emphasize is that it is not some *other* exact, 112 | > easy-to-write answer. 113 | 114 | ## The Languages 115 | 116 | Below is the documentation of all the mystery languages. Most 117 | languages build on top of other languages; the notation 118 | `[arithmetic +]` means “all the features of `arithmetic`; in 119 | addition…”. `strings` is provided only for demonstration purposes. 120 | 121 | All languages have basic constants: numbers (like `0`, `1.3`), strings 122 | (like `""`, `"hi"`), booleans (`#t` or `#true`, and `#f` or 123 | `#false`). 124 | 125 | *All* languages use prefix-parenthetical syntax. Thus we add `1` and 126 | `2` as follows: 127 | 128 | (+ 1 2) ;; produces 3 129 | 130 | Because the parentheses disambiguate, most operations can take any 131 | number of parameters, such as: 132 | 133 | (+ 1 2 3) ;; produces 6 134 | (+ 1) ;; produces 1 135 | (+) ;; produces 0 136 | 137 | Because this is common to all languages, we do not explicate this 138 | syntax below. Because there are no infix operators, there are no other 139 | rules for function operations. We only introduce syntax when it is not 140 | an expression. 141 | 142 | ### `strings` 143 | 144 | ++ string=? string-ref 145 | 146 | `++` appends strings. `string=?` compares them for equality. `string-ref` refers to part of a string. 147 | 148 | ### `arithmetic` 149 | 150 | + - * / 151 | < <= > >= 152 | = <> 153 | defvar 154 | 155 | Most of these operations are self-explanatory. `<>` is 156 | not-equal. `defvar` defines variables: 157 | 158 | (defvar ) 159 | 160 | For instance: 161 | 162 | (defvar x 3) 163 | (TEST x 3 3 3) 164 | 165 | ### `conditionals` 166 | 167 | [arithmetic +] 168 | if and or not 169 | 170 | The `if` takes three parts: 171 | 172 | (if ) 173 | 174 | For instance: 175 | 176 | (TEST (if #t 1 2) 1 1 1) 177 | 178 | ### `fun-calls` 179 | 180 | [conditionals +] 181 | deffun 182 | 183 | `deffun` defines functions: 184 | 185 | (deffun ( …) ) 186 | 187 | The notation `…` above means “zero or more of”. Thus the following are 188 | all legal function definitions: 189 | 190 | (deffun (f) 3) 191 | (deffun (g x) (+ x x)) 192 | (deffun (h x y z) (++ x y z)) 193 | 194 | (TEST (f) 3 3 3) 195 | (TEST (g 5) 10 10 10) 196 | (TEST (h "a" "b" "c") "abc" "abc" "abc") 197 | 198 | 199 | ### `scope` 200 | 201 | [fun-calls +] 202 | lambda λ let 203 | empty list cons 204 | map filter 205 | 206 | These extra constructs have the same meaning as in Racket. Links to Racket's document: [`lambda` and `λ`](https://docs.racket-lang.org/guide/lambda.html), [`let`](https://docs.racket-lang.org/guide/let.html), [`empty`](https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Flist..rkt%29._empty%29%29), [`list`](https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._list%29%29), [`cons`](https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cons%29%29), [`map`](https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Fmap..rkt%29._map%29%29), and [`filter`](https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._filter%29%29). 207 | 208 | ### `fields` 209 | 210 | [fun-calls +] 211 | object oget 212 | 213 | `object` defines objects, and `oget` accesses their fields. Their 214 | syntaxes are as follows: 215 | 216 | (oget ) 217 | (object [ ] ...) 218 | 219 | where `name` can be either a variable-name or an expression. For 220 | instance, 221 | 222 | (defvar o (object [a 43] [b "hello"])) 223 | (TEST (oget o a) 43 43 43) 224 | 225 | ### `mut-vars` 226 | 227 | [fun-calls +] 228 | begin 229 | set! 230 | 231 | `begin` allows a sequence of expressions: 232 | 233 | (begin …) 234 | 235 | `set!` changes the value of a variable: 236 | 237 | (defvar v 3) 238 | (set! v 4) 239 | (TEST v 4 4 4) 240 | 241 | ### `mut-structs` 242 | 243 | [fields +] 244 | oset 245 | 246 | `oset` changes the value of a field. Its syntax is: 247 | 248 | (oset ) 249 | 250 | For instance: 251 | 252 | (defvar o (object [a 43] [b "hello"])) 253 | (oset o a 17) 254 | (TEST (oget o a) 17 17 17) 255 | 256 | ### `eval-order` 257 | 258 | [mut-vars +] 259 | 260 | No new constructs! Just new behavior… 261 | 262 | -------------------------------------------------------------------------------- /arithmetic/L1/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | ;; We don't use `inexact->exact` because, for example, 7 | ;; `(inexact->exact 0.1)` is not `1/10` but `3602879701896397/36028797018963968`. 8 | 9 | (define (my-inexact->exact n) 10 | (or (string->number 11 | (number->string n) 12 | ;; radix (default): 10-based numeral 13 | 10 14 | ;; convert-mode (default): #f if the string is not a valid number representation 15 | 'number-or-false 16 | ;; decimal-mode: required that all decimals are read as exact numbers 17 | 'decimal-as-exact) 18 | ;; If the conversion fails, returns the number as it is. 19 | ;; This may happen when `n` is, for example, `+inf.0` 20 | n)) 21 | 22 | (define (exact-value d) 23 | (if (number? d) 24 | (my-inexact->exact d) 25 | d)) 26 | 27 | (define-syntax-rule (my-#%app fun arg ...) 28 | (#%app (#%app exact-value fun) (#%app exact-value arg) ...)) 29 | 30 | (provide + - * / 31 | < <= > >= 32 | = <> 33 | ++ 34 | defvar 35 | #%module-begin 36 | #%top-interaction 37 | #%top 38 | (rename-out [my-#%app #%app]) 39 | #%datum) 40 | -------------------------------------------------------------------------------- /arithmetic/L2/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (define (inexact-value d) 7 | (if (number? d) 8 | (exact->inexact d) 9 | d)) 10 | 11 | (define (make-my +) 12 | (lambda args 13 | (if (andmap exact-integer? args) 14 | (apply + args) 15 | (apply + (map inexact-value args))))) 16 | (define my+ (make-my +)) 17 | (define my- (make-my -)) 18 | (define my* (make-my *)) 19 | 20 | ;; division is always in float point 21 | (define (my/ . args) 22 | (apply / (map inexact-value args))) 23 | 24 | (provide (rename-out [my+ +]) 25 | (rename-out [my- -]) 26 | (rename-out [my* *]) 27 | (rename-out [my/ /]) 28 | < <= > >= 29 | = <> 30 | ++ 31 | defvar 32 | #%module-begin 33 | #%top-interaction 34 | #%top 35 | #%app 36 | #%datum) 37 | -------------------------------------------------------------------------------- /arithmetic/L3/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (define (process-numbers d) 7 | (if (number? d) 8 | (if (exact-integer? d) 9 | d 10 | (exact->inexact d)) 11 | d)) 12 | 13 | (define-syntax-rule (my-#%app fun arg ...) 14 | (#%app (#%app process-numbers fun) (#%app process-numbers arg) ...)) 15 | 16 | (define (quotient-or-/ . ns) 17 | (if (and (pair? ns) (andmap exact-integer? ns)) 18 | (foldl (lambda (n so-far) 19 | (quotient so-far n)) 20 | (first ns) 21 | (rest ns)) 22 | (apply / ns))) 23 | 24 | (provide + - * (rename-out [quotient-or-/ /]) 25 | < <= > >= 26 | = <> 27 | ++ 28 | defvar 29 | #%module-begin 30 | #%top-interaction 31 | #%top 32 | (rename-out [my-#%app #%app]) 33 | #%datum) 34 | -------------------------------------------------------------------------------- /arithmetic/lang/reader.rkt: -------------------------------------------------------------------------------- 1 | #lang s-exp syntax/module-reader 2 | 3 | mystery-languages/arithmetic/semantics 4 | -------------------------------------------------------------------------------- /arithmetic/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require mystery-languages/make-semantics) 4 | 5 | (provide (rename-out [mod-begin #%module-begin] 6 | [ti #%top-interaction])) 7 | 8 | (define-values (namespaces lang-print-names) 9 | (make-namespaces-and-lang-print-names (list 'mystery-languages/arithmetic/L1/semantics 10 | 'mystery-languages/arithmetic/L2/semantics 11 | 'mystery-languages/arithmetic/L3/semantics))) 12 | 13 | (define-syntax (multi-runner stx) 14 | (syntax-case stx (TEST) 15 | [(_ (TEST e r ...)) 16 | #`(test-output 'e (list #'r ...) namespaces)] 17 | [(_ e) 18 | #`(show-output 'e namespaces lang-print-names)])) 19 | 20 | (define-syntax mod-begin 21 | (λ (stx) 22 | (syntax-case stx () 23 | [(_ b ...) 24 | #'(#%printing-module-begin (multi-runner b) ...)]))) 25 | 26 | (define-syntax ti 27 | (λ (stx) 28 | (syntax-case stx () 29 | ([_ . e] 30 | #'(#%top-interaction . (multi-runner e)))))) 31 | -------------------------------------------------------------------------------- /common.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils) 4 | (require [for-syntax racket]) 5 | 6 | (provide <> ++ begin defvar deffun) 7 | 8 | (provide object oget oset an-object? an-object an-object-ht) 9 | 10 | (provide set!) 11 | 12 | ;; ---------- basic 13 | 14 | (define (<> a b) (not (= a b))) 15 | 16 | (define ++ string-append) 17 | 18 | (define-syntax begin 19 | (syntax-rules () 20 | [(_) (void)] 21 | [(_ prepare ... result) 22 | (let* ([_ prepare] ...) 23 | result)])) 24 | 25 | (define-syntax (defvar stx) 26 | (syntax-parse stx 27 | [(_ var:id rhs:expr) 28 | #'(define var rhs)])) 29 | 30 | (define-syntax (deffun stx) 31 | (syntax-parse stx 32 | [(_ (fname:id arg:id ...) body:expr ...+) 33 | #'(define (fname arg ...) body ...)])) 34 | 35 | ;; ---------- objects 36 | 37 | (struct an-object (ht)) 38 | 39 | (define-syntax (object stx) 40 | (syntax-parse stx 41 | [(_ (fn:id rhs:expr) ...) 42 | #'(an-object (make-hasheq (list (cons 'fn rhs) ...)))])) 43 | 44 | (define-syntax (oget stx) 45 | (syntax-parse stx 46 | [(_ o:expr fn:id) 47 | #'(hash-ref (an-object-ht o) 48 | 'fn 49 | (λ () 50 | (error 'oget "field ~a not found" 'fn)))])) 51 | 52 | (define-syntax (oset stx) 53 | (syntax-parse stx 54 | [(_ o:expr fn:id v:expr) 55 | #'(hash-set! (an-object-ht o) 56 | 'fn 57 | v)])) 58 | -------------------------------------------------------------------------------- /conditionals/L1/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar) 13 | 14 | (provide [rename-out (strict-if if) (strict-and and) (strict-or or) (strict-not not)]) 15 | 16 | (define-syntax strict-if 17 | (syntax-rules () 18 | [(_ C T E) 19 | (let ([C-val C]) 20 | (if (boolean? C-val) 21 | (if C-val T E) 22 | (error 'if "condition must be a boolean: ~a" C-val)))])) 23 | 24 | (define-syntax strict-and 25 | (syntax-rules () 26 | [(_) #true] 27 | [(_ e0 e1 ...) 28 | (let ([e0-val e0]) 29 | (if (boolean? e0-val) 30 | (if e0-val 31 | (strict-and e1 ...) 32 | #false) 33 | (error 'and "condition must be a boolean: ~a" e0-val)))])) 34 | 35 | (define-syntax strict-or 36 | (syntax-rules () 37 | [(_) #false] 38 | [(_ e0 e1 ...) 39 | (let ([e0-val e0]) 40 | (if (boolean? e0-val) 41 | (if e0-val 42 | #true 43 | (strict-or e1 ...)) 44 | (error 'or "condition must be a boolean: ~a" e0-val)))])) 45 | 46 | (define (strict-not v) 47 | (if (boolean? v) 48 | (not v) 49 | (error 'not "argument must be a boolean: ~a" v))) 50 | -------------------------------------------------------------------------------- /conditionals/L2/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar) 13 | 14 | (provide and or not) 15 | 16 | (provide [rename-out (lispy-if if)]) 17 | 18 | (define-syntax lispy-if 19 | (syntax-rules () 20 | [(_ C T E) 21 | (if C T E)])) 22 | -------------------------------------------------------------------------------- /conditionals/L3/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar) 13 | 14 | (provide [rename-out (tf-if if) (tf-and and) (tf-or or) (tf-not not)]) 15 | 16 | (define (truthy? V) (not (falsy? V))) 17 | (define (falsy? V) (member V (list #false 0 "" "0"))) 18 | 19 | (define-syntax tf-if 20 | (syntax-rules () 21 | [(_ C T E) 22 | (if (truthy? C) T E)])) 23 | 24 | (define-syntax tf-and 25 | (syntax-rules () 26 | [(_) #true] 27 | [(_ e0) (truthy? e0)] 28 | [(_ e0 e1 ...) 29 | (if (truthy? e0) 30 | (tf-and e1 ...) 31 | #false)])) 32 | 33 | (define-syntax tf-or 34 | (syntax-rules () 35 | [(_) #false] 36 | [(_ e0 e1 ...) 37 | (if (truthy? e0) 38 | #true 39 | (tf-or e1 ...))])) 40 | 41 | (define (tf-not v) 42 | (if (truthy? v) #false #true)) 43 | -------------------------------------------------------------------------------- /conditionals/lang/reader.rkt: -------------------------------------------------------------------------------- 1 | #lang s-exp syntax/module-reader 2 | 3 | mystery-languages/conditionals/semantics 4 | -------------------------------------------------------------------------------- /conditionals/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require mystery-languages/make-semantics) 4 | 5 | (provide (rename-out [mod-begin #%module-begin] 6 | [ti #%top-interaction])) 7 | 8 | (define-values (namespaces lang-print-names) 9 | (make-namespaces-and-lang-print-names (list 'mystery-languages/conditionals/L1/semantics 10 | 'mystery-languages/conditionals/L2/semantics 11 | 'mystery-languages/conditionals/L3/semantics))) 12 | 13 | (define-syntax (multi-runner stx) 14 | (syntax-case stx (TEST) 15 | [(_ (TEST e r ...)) 16 | #`(test-output 'e (list #'r ...) namespaces)] 17 | [(_ e) 18 | #`(show-output 'e namespaces lang-print-names)])) 19 | 20 | (define-syntax mod-begin 21 | (λ (stx) 22 | (syntax-case stx () 23 | [(_ b ...) 24 | #'(#%printing-module-begin (multi-runner b) ...)]))) 25 | 26 | (define-syntax ti 27 | (λ (stx) 28 | (syntax-case stx () 29 | ([_ . e] 30 | #'(#%top-interaction . (multi-runner e)))))) 31 | -------------------------------------------------------------------------------- /documentation-tests/arithmetic.rkt: -------------------------------------------------------------------------------- 1 | #lang mystery-languages/arithmetic 2 | 3 | (defvar x 3) 4 | (TEST x 3 3 3) 5 | -------------------------------------------------------------------------------- /documentation-tests/conditionals.rkt: -------------------------------------------------------------------------------- 1 | #lang mystery-languages/conditionals 2 | 3 | (TEST (if #t 1 2) 1 1 1) 4 | -------------------------------------------------------------------------------- /documentation-tests/fields.rkt: -------------------------------------------------------------------------------- 1 | #lang mystery-languages/fields 2 | 3 | (defvar o (object [a 43] [b "hello"])) 4 | (TEST (oget o a) 43 43 43) 5 | -------------------------------------------------------------------------------- /documentation-tests/fun-calls.rkt: -------------------------------------------------------------------------------- 1 | #lang mystery-languages/fun-calls 2 | 3 | (deffun (f) 3) 4 | (deffun (g x) (+ x x)) 5 | (deffun (h x y z) (++ x y z)) 6 | 7 | (TEST (f) 3 3 3) 8 | (TEST (g 5) 10 10 10) 9 | (TEST (h "a" "b" "c") "abc" "abc" "abc") 10 | -------------------------------------------------------------------------------- /documentation-tests/mut-structs.rkt: -------------------------------------------------------------------------------- 1 | #lang mystery-languages/mut-structs 2 | 3 | (defvar o (object [a 43] [b "hello"])) 4 | (oset o a 17) 5 | (TEST (oget o a) 17 17 17) 6 | -------------------------------------------------------------------------------- /documentation-tests/mut-vars.rkt: -------------------------------------------------------------------------------- 1 | #lang mystery-languages/mut-vars 2 | 3 | (defvar v 3) 4 | (set! v 4) 5 | (TEST v 4 4 4) 6 | -------------------------------------------------------------------------------- /eval-order/L1/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar 13 | ++ 14 | if and or not 15 | deffun) 16 | 17 | (provide begin set!) 18 | -------------------------------------------------------------------------------- /eval-order/L2/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (require [prefix-in lazy: lazy]) 7 | 8 | (provide [rename-out (lazy:#%module-begin #%module-begin) (lazy:#%top-interaction #%top-interaction) 9 | (lazy:#%datum #%datum) (lazy:#%top #%top) (lazy:#%app #%app) 10 | 11 | (lazy:+ +) (lazy:- -) (lazy:* *) (lazy:/ /) 12 | (lazy:< <) (lazy:<= <=) (lazy:> >) (lazy:>= >=) 13 | (lazy:= =); 14 | (lazy:string-append ++) 15 | (lazy:if if) (lazy:and and) (lazy:or or) (lazy:not not)]) 16 | 17 | (provide <> defvar deffun) 18 | 19 | (provide [rename-out (lazy:begin begin)]) 20 | (provide set!) 21 | 22 | (lazy:define (<> a b) 23 | (lazy:not (lazy:= a b))) 24 | 25 | (define-syntax (deffun stx) 26 | (syntax-parse stx 27 | [(_ (fname:id arg:id ...) body:expr ...+) 28 | #'(lazy:define (fname arg ...) body ...)])) 29 | 30 | (define-syntax (defvar stx) 31 | (syntax-parse stx 32 | [(_ var:id rhs:expr) 33 | #'(lazy:define var rhs)])) 34 | 35 | (define-syntax (set! stx) 36 | (syntax-parse stx 37 | [(_ var:id val:expr) 38 | #'(lazy:set! var val)])) 39 | -------------------------------------------------------------------------------- /eval-order/lang/reader.rkt: -------------------------------------------------------------------------------- 1 | #lang s-exp syntax/module-reader 2 | 3 | mystery-languages/eval-order/semantics 4 | -------------------------------------------------------------------------------- /eval-order/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require mystery-languages/make-semantics) 4 | 5 | (provide (rename-out [mod-begin #%module-begin] 6 | [ti #%top-interaction])) 7 | 8 | (define-values (namespaces lang-print-names) 9 | (make-namespaces-and-lang-print-names (list 'mystery-languages/eval-order/L1/semantics 10 | 'mystery-languages/eval-order/L2/semantics))) 11 | 12 | (define-syntax (multi-runner stx) 13 | (syntax-case stx (TEST) 14 | [(_ (TEST e r ...)) 15 | #`(test-output 'e (list #'r ...) namespaces)] 16 | [(_ e) 17 | #`(show-output 'e namespaces lang-print-names)])) 18 | 19 | (define-syntax mod-begin 20 | (λ (stx) 21 | (syntax-case stx () 22 | [(_ b ...) 23 | #'(#%printing-module-begin (multi-runner b) ...)]))) 24 | 25 | (define-syntax ti 26 | (λ (stx) 27 | (syntax-case stx () 28 | ([_ . e] 29 | #'(#%top-interaction . (multi-runner e)))))) 30 | -------------------------------------------------------------------------------- /fields/L1/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar 13 | ++ 14 | if and or not 15 | deffun) 16 | 17 | (provide object oget) 18 | 19 | -------------------------------------------------------------------------------- /fields/L2/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar 13 | ++ 14 | if and or not 15 | deffun) 16 | 17 | (provide object oget) 18 | 19 | (define-syntax (wrap-fn-term stx) 20 | (syntax-parse stx 21 | [(_ fn:id) 22 | #`'fn] 23 | [(_ fn:expr) 24 | #`(let ([fn-v fn]) 25 | (if (string? fn-v) 26 | fn-v 27 | (error 'field-name "~a must be a name or string" 'fn)))])) 28 | 29 | (define-syntax (object stx) 30 | (syntax-parse stx 31 | [(_ (fn:expr rhs:expr) ...) 32 | #`(an-object 33 | (make-hash 34 | (list 35 | (cons (wrap-fn-term fn) rhs) 36 | ...)))])) 37 | 38 | (define-syntax (oget stx) 39 | (syntax-parse stx 40 | [(_ o:expr fn:expr) 41 | #`(hash-ref (an-object-ht o) 42 | (wrap-fn-term fn) 43 | (λ () 44 | (error 'oget "field ~a not found" fn-wrapped)))])) 45 | -------------------------------------------------------------------------------- /fields/L3/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar 13 | ++ 14 | if and or not 15 | deffun) 16 | 17 | (provide object oget) 18 | 19 | (define-syntax (wrap-fn-term stx) 20 | (syntax-parse stx 21 | [(_ fn:id) 22 | #`'fn] 23 | [(_ fn:expr) 24 | #`fn])) 25 | 26 | (define-syntax (object stx) 27 | (syntax-parse stx 28 | [(_ (fn:expr rhs:expr) ...) 29 | #`(an-object 30 | (make-hash 31 | (list 32 | (cons (wrap-fn-term fn) rhs) 33 | ...)))])) 34 | 35 | (define-syntax (oget stx) 36 | (syntax-parse stx 37 | [(_ o:expr fn:expr) 38 | #`(hash-ref (an-object-ht o) 39 | (wrap-fn-term fn) 40 | (λ () 41 | (error 'oget "field ~a not found" fn-wrapped)))])) 42 | -------------------------------------------------------------------------------- /fields/lang/reader.rkt: -------------------------------------------------------------------------------- 1 | #lang s-exp syntax/module-reader 2 | 3 | mystery-languages/fields/semantics 4 | -------------------------------------------------------------------------------- /fields/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require mystery-languages/make-semantics) 4 | 5 | (provide (rename-out [mod-begin #%module-begin] 6 | [ti #%top-interaction])) 7 | 8 | (define-values (namespaces lang-print-names) 9 | (make-namespaces-and-lang-print-names (list 'mystery-languages/fields/L1/semantics 10 | 'mystery-languages/fields/L2/semantics 11 | 'mystery-languages/fields/L3/semantics))) 12 | 13 | (define-syntax (multi-runner stx) 14 | (syntax-case stx (TEST) 15 | [(_ (TEST e r ...)) 16 | #`(test-output 'e (list #'r ...) namespaces)] 17 | [(_ e) 18 | #`(show-output 'e namespaces lang-print-names)])) 19 | 20 | (define-syntax mod-begin 21 | (λ (stx) 22 | (syntax-case stx () 23 | [(_ b ...) 24 | #'(#%printing-module-begin (multi-runner b) ...)]))) 25 | 26 | (define-syntax ti 27 | (λ (stx) 28 | (syntax-case stx () 29 | ([_ . e] 30 | #'(#%top-interaction . (multi-runner e)))))) 31 | -------------------------------------------------------------------------------- /fun-calls/L1/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar 13 | ++ 14 | if and or not) 15 | 16 | (provide deffun) 17 | 18 | (provide #%app) 19 | 20 | (define-syntax (deffun stx) 21 | (syntax-parse stx 22 | [(_ (fname:id arg:id ...) body:expr) 23 | #'(define (fname arg ...) body)])) 24 | -------------------------------------------------------------------------------- /fun-calls/L2/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar 13 | ++ 14 | if and or not) 15 | 16 | (provide deffun) 17 | 18 | (provide [rename-out (goto-app #%app)]) 19 | 20 | (define-syntax (goto-app e) 21 | (syntax-case e () 22 | [(_ f a ...) 23 | #'(if (unbox top-level-continuation) 24 | (#%app f a ...) 25 | (let/cc k 26 | (dynamic-wind 27 | (lambda () (set-box! top-level-continuation k)) 28 | (lambda () (#%app f a ...)) 29 | (lambda () (set-box! top-level-continuation #f)))))])) 30 | 31 | (define-syntax (deffun stx) 32 | (syntax-parse stx 33 | [(_ (fname:id arg:id ...) body:expr) 34 | #'(define (fname arg ...) 35 | ((unbox top-level-continuation) 36 | body))])) 37 | 38 | (define top-level-continuation (box #f)) 39 | 40 | (define-for-syntax locally-defined-functions (box '())) 41 | -------------------------------------------------------------------------------- /fun-calls/L3/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common racket/control) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%datum #%top) 7 | 8 | (provide defvar 9 | if and or not) 10 | 11 | (provide deffun) 12 | 13 | (provide [rename-out [lazy-app #%app]]) 14 | (provide 15 | [rename-out 16 | [lazy-+ +] 17 | [lazy-- -] 18 | [lazy-* *] 19 | [lazy-/ /] 20 | [lazy-< <] 21 | [lazy-<= <=] 22 | [lazy-> >] 23 | [lazy->= >=] 24 | [lazy-= =] 25 | [lazy-<> <>] 26 | [lazy-++ ++] 27 | ]) 28 | 29 | (define (make-lazy op) 30 | (lambda args 31 | (apply op (map (lambda (thunk) (thunk)) args)))) 32 | 33 | (define lazy-+ (make-lazy +)) 34 | (define lazy-- (make-lazy -)) 35 | (define lazy-* (make-lazy *)) 36 | (define lazy-/ (make-lazy /)) 37 | (define lazy-< (make-lazy <)) 38 | (define lazy-<= (make-lazy <=)) 39 | (define lazy-> (make-lazy >)) 40 | (define lazy->= (make-lazy >=)) 41 | (define lazy-= (make-lazy =)) 42 | (define lazy-<> (make-lazy <>)) 43 | (define lazy-++ (make-lazy ++)) 44 | 45 | (define-syntax-rule (lazy-app f a ...) 46 | (f (lambda () a) ...)) 47 | 48 | (define-syntax (deffun stx) 49 | (syntax-parse stx 50 | [(_ (f:id a:id ...) body:expr) 51 | #'(define f 52 | (let ([return-k #f]) 53 | (lambda (a ...) 54 | (define (run) 55 | (let ([a (a)] ...) 56 | body)) 57 | (cond 58 | [return-k 59 | (return-k (run))] 60 | [else 61 | (let/cc k 62 | (dynamic-wind 63 | (lambda () (set! return-k k)) 64 | (lambda () (run)) 65 | (lambda () (set! return-k #f))))]))))])) 66 | -------------------------------------------------------------------------------- /fun-calls/lang/reader.rkt: -------------------------------------------------------------------------------- 1 | #lang s-exp syntax/module-reader 2 | 3 | mystery-languages/fun-calls/semantics 4 | -------------------------------------------------------------------------------- /fun-calls/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require mystery-languages/make-semantics) 4 | 5 | (provide (rename-out [mod-begin #%module-begin] 6 | [ti #%top-interaction])) 7 | 8 | (define-values (namespaces lang-print-names) 9 | (make-namespaces-and-lang-print-names (list 'mystery-languages/fun-calls/L1/semantics 10 | 'mystery-languages/fun-calls/L2/semantics 11 | 'mystery-languages/fun-calls/L3/semantics))) 12 | 13 | (define-syntax (multi-runner stx) 14 | (syntax-case stx (TEST) 15 | [(_ (TEST e r ...)) 16 | #`(test-output 'e (list #'r ...) namespaces)] 17 | [(_ e) 18 | #`(show-output 'e namespaces lang-print-names)])) 19 | 20 | (define-syntax mod-begin 21 | (λ (stx) 22 | (syntax-case stx () 23 | [(_ b ...) 24 | #'(#%printing-module-begin (multi-runner b) ...)]))) 25 | 26 | (define-syntax ti 27 | (λ (stx) 28 | (syntax-case stx () 29 | ([_ . e] 30 | #'(#%top-interaction . (multi-runner e)))))) 31 | -------------------------------------------------------------------------------- /info.rkt: -------------------------------------------------------------------------------- 1 | #lang info 2 | (define collection "mystery-languages") 3 | (define version "2020.2") 4 | (define deps (list "lazy" "exact-decimal-lang" "https://github.com/shriram/smol.git")) 5 | -------------------------------------------------------------------------------- /make-semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | (require (only-in racket/struct make-constructor-style-printer)) 3 | (require (only-in mystery-languages/utils observe)) 4 | (require mystery-languages/common) 5 | (provide ML-error? ML-error-ex ML-okay? ML-okay-val) 6 | 7 | (struct ML-error (ex) #:transparent 8 | #:property prop:custom-print-quotable 'never 9 | #:methods gen:custom-write 10 | [(define write-proc 11 | (make-constructor-style-printer 12 | (lambda (obj) 'ML-error) 13 | (lambda (obj) (list (exn-message (ML-error-ex obj))))))]) 14 | (struct ML-okay (val) #:transparent) 15 | 16 | (require racket/pretty) 17 | (pretty-print-size-hook 18 | (lambda (v display? the-port) 19 | (if (procedure? v) 20 | (string-length "#") 21 | #f))) 22 | (pretty-print-print-hook 23 | (lambda (v display? the-port) 24 | (display "#" the-port))) 25 | 26 | (port-write-handler (current-output-port) (lambda (v port) (pretty-write v port #:newline? #f))) 27 | (port-display-handler (current-output-port) (lambda (v port) (pretty-display v port #:newline? #f))) 28 | (port-print-handler (current-output-port) (lambda (v port) (pretty-print v port #:newline? #f))) 29 | 30 | (require rackunit) 31 | 32 | (provide make-namespaces-and-lang-print-names show-output test-output) 33 | 34 | (define (make-namespaces-and-lang-print-names language-specs) 35 | 36 | (define lpns 37 | (foldr (λ (e past) 38 | (cons (string-append "L" (number->string e) ": ") 39 | past)) 40 | empty 41 | (range 1 (add1 (length language-specs))))) 42 | 43 | (define nss (map (λ (_) (make-base-empty-namespace)) language-specs)) 44 | 45 | (for-each (λ (ls ns) 46 | (parameterize ([current-namespace ns]) 47 | (namespace-require ls))) 48 | language-specs nss) 49 | 50 | (values nss lpns)) 51 | 52 | (define (run/okay-or-error expr n) 53 | (with-handlers ([exn? (λ (ex) (ML-error ex))]) 54 | (ML-okay (observe (eval expr n))))) 55 | 56 | (define (run-multiple e ns) 57 | (map (λ (n) (run/okay-or-error e n)) ns)) 58 | 59 | (define (test-multiple e ns cs) 60 | (map (λ (n c) 61 | (c (thunk (observe (eval e n))))) 62 | ns cs)) 63 | 64 | (define (show-output e namespaces lang-print-names) 65 | (writeln e) 66 | (let ([results (run-multiple e namespaces)]) 67 | (unless (andmap (λ (r) 68 | (and (ML-okay? r) (void? (ML-okay-val r)))) 69 | results) 70 | (for-each (λ (r lpn) 71 | (display lpn) 72 | (flush-output) 73 | (cond 74 | [(ML-okay? r) (writeln (ML-okay-val r))] 75 | [(ML-error? r) 76 | (let ([the-exn (ML-error-ex r)]) 77 | ((error-display-handler) (exn-message the-exn) #f))] 78 | [else (error 'multi-runner "shouldn't have gotten here: ~a" r)])) 79 | results lang-print-names))) 80 | (newline) 81 | (flush-output)) 82 | 83 | (define (test-output e expecteds namespaces) 84 | (display "••••• TESTING ") (write e) (displayln " (blank if all tests pass)") 85 | (flush-output) 86 | (unless (= (length namespaces) (length expecteds)) 87 | (error 'TEST "number of results ~a does not match number of result terms ~a" 88 | (length namespaces) 89 | (length expecteds))) 90 | (test-multiple e namespaces (map checker-of-expected expecteds)) 91 | (newline)) 92 | 93 | (define ((checker-of-expected expected) do) 94 | (define (make-checker neg? expected) 95 | (match expected 96 | [`(not ,expected) 97 | (make-checker (not neg?) expected)] 98 | [(or 'failure 'error) 99 | (if neg? 100 | (check-not-exn do) 101 | (check-exn any/c do))] 102 | [(or 'void 'void?) 103 | (if neg? 104 | (check-not-equal? (do) (void)) 105 | (check-equal? (do) (void)))] 106 | [(or 'procedure 'procedure?) 107 | (if neg? 108 | (check-pred (not/c procedure?) (do) "expecting a non-procedure") 109 | (check-pred procedure? (do) "expecting a procedure"))] 110 | [(or 'number 'number?) 111 | (if neg? 112 | (check-pred (not/c number?) (do) "expecting a non-number") 113 | (check-pred number? (do) "expecting a number"))] 114 | [(or 'boolean 'boolean?) 115 | (if neg? 116 | (check-pred (not/c boolean?) (do) "expecting a non-boolean") 117 | (check-pred boolean? (do) "expecting a boolean"))] 118 | [(or 'string 'string?) 119 | (if neg? 120 | (check-pred (not/c string?) (do) "expecting a non-string") 121 | (check-pred string? (do) "expecting a string"))] 122 | [(or 'object 'object?) 123 | (if neg? 124 | (check-pred (not/c an-object?) (do) "expecting a non-object") 125 | (check-pred an-object? (do) "expecting an object"))] 126 | [val 127 | #:when ((or/c number? string? boolean? char?) val) 128 | (if neg? 129 | (check-not-equal? (do) val) 130 | (check-equal? (do) val))] 131 | [other 132 | (fail (format "~a is not a valid way to specify the result. Please check the documentation" other))])) 133 | (with-check-info* 134 | (list 135 | (make-check-location 136 | (list 137 | (syntax-source expected) 138 | (syntax-line expected) 139 | (syntax-column expected) 140 | (syntax-position expected) 141 | (syntax-span expected)))) 142 | (thunk 143 | (make-checker #f (syntax->datum expected))))) 144 | -------------------------------------------------------------------------------- /mut-structs/L1/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar 13 | ++ 14 | if and or not 15 | deffun) 16 | 17 | (provide object oget oset) 18 | -------------------------------------------------------------------------------- /mut-structs/L2/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar 13 | ++ 14 | if and or not 15 | deffun) 16 | 17 | (provide object oget oset) 18 | 19 | (provide [rename-out (shallow-copy-app #%app)]) 20 | 21 | (define-syntax (shallow-copy-app e) 22 | (syntax-case e () 23 | [(_ f a ...) 24 | #'(f (if (an-object? a) 25 | (an-object (hash-copy (an-object-ht a))) 26 | a) 27 | ...)])) 28 | -------------------------------------------------------------------------------- /mut-structs/L3/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar 13 | ++ 14 | if and or not 15 | deffun) 16 | 17 | (provide object oget oset) 18 | 19 | (provide [rename-out (deep-copy-app #%app)]) 20 | 21 | (define (deep-copy-obj o) 22 | (if (an-object? o) 23 | (an-object (make-hasheq 24 | (hash-map (an-object-ht o) 25 | (λ (k v) 26 | (cons k (deep-copy-obj v)))))) 27 | o)) 28 | 29 | (define-syntax (deep-copy-app e) 30 | (syntax-case e () 31 | [(_ f a ...) 32 | #'(f (deep-copy-obj a) ...)])) 33 | -------------------------------------------------------------------------------- /mut-structs/lang/reader.rkt: -------------------------------------------------------------------------------- 1 | #lang s-exp syntax/module-reader 2 | 3 | mystery-languages/mut-structs/semantics 4 | -------------------------------------------------------------------------------- /mut-structs/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require mystery-languages/make-semantics) 4 | 5 | (provide (rename-out [mod-begin #%module-begin] 6 | [ti #%top-interaction])) 7 | 8 | (define-values (namespaces lang-print-names) 9 | (make-namespaces-and-lang-print-names (list 'mystery-languages/mut-structs/L1/semantics 10 | 'mystery-languages/mut-structs/L2/semantics 11 | 'mystery-languages/mut-structs/L3/semantics))) 12 | 13 | (define-syntax (multi-runner stx) 14 | (syntax-case stx (TEST) 15 | [(_ (TEST e r ...)) 16 | #`(test-output 'e (list #'r ...) namespaces)] 17 | [(_ e) 18 | #`(show-output 'e namespaces lang-print-names)])) 19 | 20 | (define-syntax mod-begin 21 | (λ (stx) 22 | (syntax-case stx () 23 | [(_ b ...) 24 | #'(#%printing-module-begin (multi-runner b) ...)]))) 25 | 26 | (define-syntax ti 27 | (λ (stx) 28 | (syntax-case stx () 29 | ([_ . e] 30 | #'(#%top-interaction . (multi-runner e)))))) 31 | -------------------------------------------------------------------------------- /mut-vars/L1/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide + - * / 10 | < <= > >= 11 | = <> 12 | defvar 13 | ++ 14 | if and or not 15 | deffun) 16 | 17 | (provide begin set!) 18 | -------------------------------------------------------------------------------- /mut-vars/L2/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction) 7 | 8 | (provide #%datum #%top 9 | + - * / 10 | < <= > >= 11 | = <> 12 | ++ 13 | not) 14 | (provide (rename-out 15 | [my-begin begin] 16 | [my-if if] 17 | [my-and and] 18 | [my-or or] 19 | [my-app #%app] 20 | [my-set! set!])) 21 | (provide defvar 22 | deffun) 23 | 24 | (define-syntax-rule (my-begin any ...) (begin (observe any) ...)) 25 | (define-syntax-rule (my-if any ...) (if (observe any) ...)) 26 | (define-syntax-rule (my-and any ...) (and (observe any) ...)) 27 | (define-syntax-rule (my-or any ...) (or (observe any) ...)) 28 | 29 | (define-syntax-rule (my-app fun arg ...) 30 | (let ([f (observe fun)]) 31 | (if (ud-proc? f) 32 | (f (as-box arg) ...) 33 | (f (observe arg) ...)))) 34 | 35 | (define-syntax (as-box stx) 36 | (syntax-parse stx 37 | [(_ x:id) 38 | #'x] 39 | [(_ e) 40 | #'(box e)])) 41 | 42 | (define-syntax (my-set! stx) 43 | (syntax-parse stx 44 | [(_ var:id rhs:expr) 45 | #'(set-box! var (observe rhs))])) 46 | 47 | (define-syntax (defvar stx) 48 | (syntax-parse stx 49 | [(_ var:id rhs:expr) 50 | #'(define var (box (observe rhs)))])) 51 | 52 | (define-syntax (deffun stx) 53 | (syntax-parse stx 54 | [(_ (fun:id arg:id ...) . body) 55 | #'(defvar fun 56 | (ud-proc 57 | (lambda (arg ...) 58 | (observe (let () . body)))))])) 59 | -------------------------------------------------------------------------------- /mut-vars/L3/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction) 7 | 8 | (provide #%datum #%top 9 | + - * / 10 | < <= > >= 11 | = <> 12 | ++ 13 | not) 14 | (provide (rename-out 15 | [my-begin begin] 16 | [my-if if] 17 | [my-and and] 18 | [my-or or] 19 | [my-app #%app] 20 | [my-set! set!])) 21 | (provide defvar 22 | deffun) 23 | 24 | (define-syntax-rule (my-begin any ...) (begin (observe any) ...)) 25 | (define-syntax-rule (my-if any ...) (if (observe any) ...)) 26 | (define-syntax-rule (my-and any ...) (and (observe any) ...)) 27 | (define-syntax-rule (my-or any ...) (or (observe any) ...)) 28 | 29 | (define-syntax-rule (my-app fun arg ...) 30 | (let ([f (observe fun)]) 31 | (if (ud-proc? f) 32 | (f (as-box arg) ...) 33 | (f (observe arg) ...)))) 34 | 35 | (define-syntax (as-box stx) 36 | (syntax-parse stx 37 | [(_ x:id) 38 | #'x] 39 | [(_ e) 40 | #'(box e)])) 41 | 42 | (define-syntax (my-set! stx) 43 | (syntax-parse stx 44 | [(_ var:id rhs:expr) 45 | #'(set-box! var (observe rhs))])) 46 | 47 | (define-syntax (defvar stx) 48 | (syntax-parse stx 49 | [(_ var:id rhs:expr) 50 | #'(define var (box (observe rhs)))])) 51 | #; 52 | (define-syntax (deffun stx) 53 | (syntax-parse stx 54 | [(_ (fun:id arg:id ...) . body) 55 | #'(defvar fun 56 | (ud-proc 57 | (lambda (arg ...) 58 | (observe (let () . body)))))])) 59 | 60 | (define-syntax (deffun stx) 61 | (syntax-parse stx 62 | [(_ (fun:id arg:id ...) . body) 63 | #'(defvar fun 64 | (ud-proc 65 | (lambda (arg ...) 66 | (let* ([arg0* (list arg ...)] 67 | [arg1* (map box-unbox arg0*)]) 68 | (begin0 69 | (observe (apply (lambda (arg ...) . body) arg1*)) 70 | (for-each set-box! arg0* (map unbox arg1*)))))))])) 71 | -------------------------------------------------------------------------------- /mut-vars/lang/reader.rkt: -------------------------------------------------------------------------------- 1 | #lang s-exp syntax/module-reader 2 | 3 | mystery-languages/mut-vars/semantics 4 | -------------------------------------------------------------------------------- /mut-vars/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require mystery-languages/make-semantics) 4 | 5 | (provide (rename-out [mod-begin #%module-begin] 6 | [ti #%top-interaction])) 7 | 8 | (define-values (namespaces lang-print-names) 9 | (make-namespaces-and-lang-print-names (list 'mystery-languages/mut-vars/L1/semantics 10 | 'mystery-languages/mut-vars/L2/semantics 11 | 'mystery-languages/mut-vars/L3/semantics))) 12 | 13 | (define-syntax (multi-runner stx) 14 | (syntax-case stx (TEST) 15 | [(_ (TEST e r ...)) 16 | #`(test-output 'e (list #'r ...) namespaces)] 17 | [(_ e) 18 | #`(show-output 'e namespaces lang-print-names)])) 19 | 20 | (define-syntax mod-begin 21 | (λ (stx) 22 | (syntax-case stx () 23 | [(_ b ...) 24 | #'(#%printing-module-begin (multi-runner b) ...)]))) 25 | 26 | (define-syntax ti 27 | (λ (stx) 28 | (syntax-case stx () 29 | ([_ . e] 30 | #'(#%top-interaction . (multi-runner e)))))) 31 | -------------------------------------------------------------------------------- /scope/lang/reader.rkt: -------------------------------------------------------------------------------- 1 | #lang s-exp syntax/module-reader 2 | mystery-languages/scope/semantics 3 | -------------------------------------------------------------------------------- /scope/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require mystery-languages/make-semantics) 4 | 5 | (provide (rename-out [mod-begin #%module-begin] 6 | [ti #%top-interaction])) 7 | 8 | (define-values (namespaces lang-print-names) 9 | (make-namespaces-and-lang-print-names (list 'smol/hof/semantics 10 | 'smol/dyn-scope-is-bad/semantics))) 11 | 12 | (define-syntax (multi-runner stx) 13 | (syntax-case stx (TEST) 14 | [(_ (TEST e r ...)) 15 | #`(test-output 'e (list #'r ...) namespaces)] 16 | [(_ e) 17 | #`(show-output 'e namespaces lang-print-names)])) 18 | 19 | (define-syntax mod-begin 20 | (λ (stx) 21 | (syntax-case stx () 22 | [(_ b ...) 23 | #'(#%printing-module-begin (multi-runner b) ...)]))) 24 | 25 | (define-syntax ti 26 | (λ (stx) 27 | (syntax-case stx () 28 | ([_ . e] 29 | #'(#%top-interaction . (multi-runner e)))))) 30 | -------------------------------------------------------------------------------- /strings/L1/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide ++ string=? string-ref) 10 | -------------------------------------------------------------------------------- /strings/L2/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide ++ string=? [rename-out (permissive-string-ref string-ref)]) 10 | 11 | (define string=? string-ci=?) 12 | 13 | (define (permissive-string-ref s n) 14 | (cond 15 | [(string=? s "") ""] 16 | [(> n (string-length s)) (string-ref s (sub1 (string-length s)) )] 17 | [else (string-ref s n)])) 18 | -------------------------------------------------------------------------------- /strings/L3/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require [for-syntax syntax/parse] mystery-languages/utils mystery-languages/common) 4 | (require [for-syntax racket]) 5 | 6 | (provide #%module-begin #%top-interaction 7 | #%datum #%top #%app) 8 | 9 | (provide ++ string=? [rename-out (permissive-string-ref string-ref)]) 10 | 11 | (define (++ . ws) 12 | (if (empty? ws) 13 | "" 14 | (if (empty? (rest ws)) 15 | (first ws) 16 | (string-append (first ws) 17 | " " 18 | (apply ++ (rest ws)))))) 19 | 20 | (define (permissive-string-ref s n) 21 | (cond 22 | [(string=? s "") ""] 23 | [(> n (string-length s)) ""] 24 | [else (string-ref s n)])) 25 | -------------------------------------------------------------------------------- /strings/lang/reader.rkt: -------------------------------------------------------------------------------- 1 | #lang s-exp syntax/module-reader 2 | 3 | mystery-languages/strings/semantics 4 | -------------------------------------------------------------------------------- /strings/semantics.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require mystery-languages/make-semantics) 4 | 5 | (provide (rename-out [mod-begin #%module-begin] 6 | [ti #%top-interaction])) 7 | 8 | (define-values (namespaces lang-print-names) 9 | (make-namespaces-and-lang-print-names (list 'mystery-languages/strings/L1/semantics 10 | 'mystery-languages/strings/L2/semantics 11 | 'mystery-languages/strings/L3/semantics))) 12 | 13 | (define-syntax (multi-runner stx) 14 | (syntax-case stx (TEST) 15 | [(_ (TEST e r ...)) 16 | #`(test-output 'e (list #'r ...) namespaces)] 17 | [(_ e) 18 | #`(show-output 'e namespaces lang-print-names)])) 19 | 20 | (define-syntax mod-begin 21 | (λ (stx) 22 | (syntax-case stx () 23 | [(_ b ...) 24 | #'(#%printing-module-begin (multi-runner b) ...)]))) 25 | 26 | (define-syntax ti 27 | (λ (stx) 28 | (syntax-case stx () 29 | ([_ . e] 30 | #'(#%top-interaction . (multi-runner e)))))) 31 | -------------------------------------------------------------------------------- /utils.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (provide show) 4 | 5 | (define (show V . m) 6 | (unless (empty? m) 7 | (display m) 8 | (newline)) 9 | (display V) 10 | (newline) 11 | V) 12 | 13 | ;; ---------- 14 | 15 | (provide box-unbox) 16 | 17 | (define (box-unbox e) 18 | (box (unbox e))) 19 | 20 | ;; ---------- observable 21 | 22 | (provide observe gen:observable) 23 | (require racket/generic) 24 | 25 | (define-generics observable 26 | (observe observable) 27 | #:defaults ([promise? 28 | (define (observe p) 29 | (force p))] 30 | [box? 31 | (define (observe b) 32 | (unbox b))] 33 | [any/c 34 | (define (observe v) v)])) 35 | 36 | ;; ---------- user-defined-function 37 | 38 | (provide ud-proc ud-proc?) 39 | 40 | (struct ud-proc (base) 41 | #:property prop:procedure 42 | (struct-field-index base)) 43 | --------------------------------------------------------------------------------