1#lang scribble/doc 2@(require scribble/manual scribble/eval scribble/racket 3 "guide-utils.rkt" "modfile.rkt" 4 (for-syntax racket/base) 5 (for-label setup/dirs 6 syntax/strip-context 7 syntax-color/default-lexer)) 8 9@(define-syntax ! (make-element-id-transformer (lambda (v) #'@tt{|}))) 10@(define-syntax !- (make-element-id-transformer (lambda (v) #'@tt{|-}))) 11 12 13@title[#:tag "hash-languages" #:style 'toc]{Defining new @hash-lang[] Languages} 14 15When loading a module as a source program that starts 16 17@racketmod[ 18@#,racket[_language] 19] 20 21the @racket[_language] determines the way that the rest of the module 22is parsed at the @tech{reader} level. The @tech{reader}-level parse 23must produce a @racket[module] form as a @tech{syntax object}. As 24always, the second sub-form after @racket[module] specifies the 25@tech{module language} that controls the meaning of the module's body 26forms. Thus, a @racket[_language] specified after @hash-lang[] 27controls both the @tech{reader}-level and @tech{expander}-level 28parsing of a module. 29 30@local-table-of-contents[] 31 32@; ---------------------------------------- 33@section[#:tag "hash-lang syntax"]{Designating a @hash-lang[] Language} 34 35The syntax of a @racket[_language] intentionally overlaps with the 36syntax of a module path as used in @racket[require] or as a 37@tech{module language}, so that names like @racketmodname[racket], 38@racketmodname[racket/base], @racketmodname[slideshow], or 39@racketmodname[scribble/manual] can be used both as @hash-lang[] 40languages and as module paths. 41 42At the same time, the syntax of @racket[_language] is far more 43restricted than a module path, because only @litchar{a}-@litchar{z}, 44@litchar{A}-@litchar{Z}, @litchar{0}-@litchar{9}, 45@litchar{/} (not at the start or end), 46@litchar{_}, @litchar{-}, and @litchar{+} are allowed in a 47@racket[_language] name. These restrictions keep the syntax of 48@hash-lang[] as simple as possible. Keeping the syntax of @hash-lang[] 49simple, in turn, is important because the syntax is inherently 50inflexible and non-extensible; the @hash-lang[] protocol allows a 51@racket[_language] to refine and define syntax in a practically 52unconstrained way, but the @hash-lang[] protocol itself must remain 53fixed so that various different tools can ``boot'' into the extended 54world. 55 56Fortunately, the @hash-lang[] protocol provides a natural way to refer 57to languages in ways other than the rigid @racket[_language] syntax: 58by defining a @racket[_language] that implements its own nested 59protocol. We have already seen one example (in @secref["s-exp"]): the 60@racketmodname[s-exp] @racket[_language] allows a programmer to 61specify a @tech{module language} using the general @tech{module path} 62syntax. Meanwhile, @racketmodname[s-exp] takes care of the 63@tech{reader}-level responsibilities of a @hash-lang[] language. 64 65Unlike @racketmodname[racket], @racketmodname[s-exp] cannot be used as a 66module path with @racket[require]. Although the syntax of 67@racket[_language] for @hash-lang[] overlaps with the syntax of module 68paths, a @racket[_language] is not used directly as a module 69path. Instead, a @racket[_language] obtains a module path by trying two 70locations: first, it looks for a @racketidfont{reader} submodule of the 71main module for @racket[_language]. If this is not a valid module path, 72then @racket[_language] is suffixed with @racketidfont{/lang/reader}. 73(If neither is a valid module path, an error is raised.) The resulting 74module supplies @racketidfont{read} and @racketidfont{read-syntax} 75functions using a protocol that is similar to the one for 76@racketmetafont{#reader}. 77 78@guideother{@secref["hash-reader"] introduces @racketmetafont{#reader}.} 79 80A consequence of the way that a @hash-lang[] @racket[_language] is 81turned into a module path is that the language must be installed in a 82@tech{collection}, similar to the way that @filepath{racket} or 83@filepath{slideshow} are collections that are distributed with Racket. 84Again, however, there's an escape from this restriction: the 85@racketmodname[reader] language lets you specify a @tech{reader}-level 86implementation of a language using a general @tech{module path}. 87 88@; ---------------------------------------- 89@section[#:tag "hash-lang reader"]{Using @racket[@#,hash-lang[] @#,racketmodname[reader]]} 90 91The @racketmodname[reader] language for @hash-lang[] is similar to 92@racketmodname[s-exp], in that it acts as a kind of meta-language. 93Whereas @racketmodname[s-exp] lets a programmer specify a @tech{module 94language} at the @tech{expander} layer of parsing, 95@racketmodname[reader] lets a programmer specify a language at the 96@tech{reader} level. 97 98A @racket[@#,hash-lang[] @#,racketmodname[reader]] must be followed by 99a module path, and the specified module must provide two functions: 100@racketidfont{read} and @racketidfont{read-syntax}. The protocol is 101the same as for a @racketmetafont{#reader} implementation, but for 102@hash-lang[], the @racketidfont{read} and @racketidfont{read-syntax} 103functions must produce a @racket[module] form that is based on the 104rest of the input file for the module. 105 106The following @filepath{literal.rkt} module implements a language that 107treats its entire body as literal text and exports the text as a 108@racketidfont{data} string: 109 110@racketmodfile["literal.rkt"] 111 112The @filepath{literal.rkt} language uses @racket[strip-context] on the 113generated @racket[module] expression, because a 114@racketidfont{read-syntax} function should return a syntax object with 115no lexical context. Also, the @filepath{literal.rkt} language creates 116a module named @racketidfont{anything}, which is an arbitrary choice; 117the language is intended to be used in a file, and the longhand module 118name is ignored when it appears in a @racket[require]d file. 119 120The @filepath{literal.rkt} language can be used in a module 121@filepath{tuvalu.rkt}: 122 123@racketmodfile["tuvalu.rkt"] 124 125Importing @filepath{tuvalu.rkt} binds @racketidfont{data} to a 126string version of the module content: 127 128@interaction[ 129(require "tuvalu.rkt") 130data 131] 132 133@; ---------------------------------------- 134@section[#:tag "syntax/module-reader"]{Using @racket[@#,hash-lang[] @#,racketmodname[s-exp] @#,racketmodname[syntax/module-reader]]} 135 136Parsing a module body is usually not as trivial as in 137@filepath{literal.rkt}. A more typical module parser must iterate to 138parse multiple forms for a module body. A language is also more likely 139to extend Racket syntax---perhaps through a @tech{readtable}---instead 140of replacing Racket syntax completely. 141 142The @racketmodname[syntax/module-reader] @tech{module language} 143abstracts over common parts of a language implementation to simplify 144the creation of new languages. In its most basic form, a language 145implemented with @racketmodname[syntax/module-reader] simply specifies 146the @tech{module language} to be used for the language, in which case 147the @tech{reader} layer of the language is the same as Racket. For 148example, with 149 150@racketmod[ 151#:file "raquet-mlang.rkt" 152racket 153(provide (except-out (all-from-out racket) lambda) 154 (rename-out [lambda function])) 155] 156 157and 158 159@racketmod[ 160#:file "raquet.rkt" 161s-exp syntax/module-reader 162"raquet-mlang.rkt" 163] 164 165then 166 167@racketmod[ 168reader "raquet.rkt" 169(define identity (function (x) x)) 170(provide identity) 171] 172 173implements and exports the @racket[identity] function, since 174@filepath{raquet-mlang.rkt} exports @racket[lambda] as 175@racket[function]. 176 177The @racketmodname[syntax/module-reader] language accepts many optional 178specifications to adjust other features of the language. For example, 179an alternate @racketidfont{read} and @racketidfont{read-syntax} for 180parsing the language can be specified with @racket[#:read] and 181@racket[#:read-syntax], respectively. The following 182@filepath{dollar-racket.rkt} language uses @filepath{dollar.rkt} (see 183@secref["readtable"]) to build a language that is like 184@racketmodname[racket] but with a @litchar{$} escape to simple infix 185arithmetic: 186 187@racketmodfile["dollar-racket.rkt"] 188 189The @racket[require] form appears at the end of the module, 190because all of the keyword-tagged optional specifications for 191@racketmodname[syntax/module-reader] must appear before any helper 192imports or definitions. 193 194The following module uses @filepath{dollar-racket.rkt} to implement a 195@racket[cost] function using a @litchar{$} escape: 196 197@racketmodfile["store.rkt"] 198 199@; ---------------------------------------- 200@section[#:tag "language-collection"]{Installing a Language} 201 202So far, we have used the @racketmodname[reader] meta-language to 203access languages like @filepath{literal.rkt} and 204@filepath{dollar-racket.rkt}. If you want to use something like 205@racket[@#,hash-lang[] literal] directly, then you must move 206@filepath{literal.rkt} into a Racket @tech{collection} named 207@filepath{literal} (see also @secref["link-collection"]). 208Specifically, move @filepath{literal.rkt} to a @racketidfont{reader} 209submodule of @filepath{literal/main.rkt} for any directory name 210@filepath{literal}, like so: 211 212@racketmodfile["literal-main.rkt" "literal/main.rkt"] 213 214Then, install the @filepath{literal} 215directory as a package: 216 217@commandline{cd /path/to/literal ; raco pkg install} 218 219After moving the file and installing the package, you can use 220@racket[literal] directly after @hash-lang[]: 221 222@racketmod[ 223@#,racket[literal] 224Technology! 225System! 226Perfect! 227] 228 229@margin-note{See @other-manual['(lib "scribblings/raco/raco.scrbl")] 230for more information on using @exec{raco}.} 231 232You can also make your language available for others to install by 233using the Racket package manager (see @other-doc['(lib 234"pkg/scribblings/pkg.scrbl")]). After you create a @filepath{literal} 235package and register it with the Racket package catalog (see 236@secref["concept:catalog" #:doc '(lib "pkg/scribblings/pkg.scrbl")]), 237others can install it using @exec{raco pkg}: 238 239@commandline{raco pkg install literal} 240 241Once installed, others can invoke the language the same way: by using 242@racket[@#,hash-lang[] literal] at the top of a source file. 243 244If you use a public source repository (e.g., GitHub), you can link 245your package to the source. As you improve the package, others can 246update their version using @exec{raco pkg}: 247 248@commandline{raco pkg update literal} 249 250@margin-note{See @other-doc['(lib "pkg/scribblings/pkg.scrbl")] for more 251information about the Racket package manager.} 252 253@; ---------------------------------------- 254@section[#:tag "language-get-info"]{Source-Handling Configuration} 255 256The Racket distribution includes a Scribble language for writing prose 257documents, where Scribble extends the normal Racket to better support 258text. Here is an example Scribble document: 259 260@verbatim[#:indent 2]|{ 261#lang scribble/base 262 263@(define (get-name) "Self-Describing Document") 264 265@title[(get-name)] 266 267The title of this document is ``@(get-name).'' 268}| 269 270If you put that program in DrRacket's @tech{definitions area} and 271click @onscreen{Run}, then nothing much appears to happen. The 272@racketmodname[scribble/base] language just binds and exports 273@racketidfont{doc} as a description of a document, similar to the way 274that @filepath{literal.rkt} exports a string as @racketidfont{data}. 275 276Simply opening a module with the language 277@racketmodname[scribble/base] in DrRacket, however, causes a 278@onscreen{Scribble HTML} button to appear. Furthermore, DrRacket knows 279how to colorize Scribble syntax by coloring green those parts of the 280document that correspond to literal text. The language name 281@racketmodname[scribble/base] is not hard-wired into 282DrRacket. Instead, the implementation of the 283@racketmodname[scribble/base] language provides button and 284syntax-coloring information in response to a query from DrRacket. 285 286If you have installed the @racket[literal] language as described in 287@secref["language-collection"], then you can adjust 288@filepath{literal/main.rkt} so that DrRacket treats the content 289of a module in the @racket[literal] language as plain text instead of 290(erroneously) as Racket syntax: 291 292@racketmodfile["literal-main-get-info.rkt" "literal/main.rkt"] 293 294This revised @racket[literal] implementation provides a 295@racketidfont{get-info} function. The @racketidfont{get-info} function 296is called by @racket[read-language] (which DrRacket calls) with the 297source input stream and location information, 298in case query results should depend on the content of the module after 299the language name (which is not the case for @racket[literal]). The 300result of @racketidfont{get-info} is a function of two arguments. The 301first argument is always a symbol, indicating the kind of information 302that a tool requests from the language; the second argument is the 303default result to be returned if the language does not recognize the 304query or has no information for it. 305 306After DrRacket obtains the result of @racketidfont{get-info} for a 307language, it calls the function with a @racket['color-lexer] query; 308the result should be a function that implements syntax-coloring 309parsing on an input stream. For @racket[literal], the 310@racketmodname[syntax-color/default-lexer] module provides a 311@racket[default-lexer] syntax-coloring parser that is suitable for 312plain text, so @racket[literal] loads and returns that parser in 313response to a @racket['color-lexer] query. 314 315The set of symbols that a programming tool uses for queries 316is entirely between the tool and the languages that choose to 317cooperate with it. For example, in addition to @racket['color-lexer], 318DrRacket uses a @racket['drracket:toolbar-buttons] query to determine 319which buttons should be available in the toolbar to operate on modules 320using the language. 321 322The @racketmodname[syntax/module-reader] language lets you specify 323@racketidfont{get-info} handling through a @racket[#:info] optional 324specification. The protocol for an @racket[#:info] function is 325slightly different from the raw @racketidfont{get-info} protocol; the 326revised protocol allows @racketmodname[syntax/module-reader] the 327possibility of handling future language-information queries 328automatically. 329 330@; ---------------------------------------- 331@section[#:tag "module-runtime-config"]{Module-Handling Configuration} 332 333Suppose that the file @filepath{death-list-5.rkt} contains 334 335@racketmodfile["death-list-5.rkt"] 336 337If you @racket[require] @filepath{death-list-5.rkt} directly, then it 338prints the list in the usual Racket result format: 339 340@interaction[ 341(require "death-list-5.rkt") 342] 343 344However, if @filepath{death-list-5.rkt} is required by a 345@filepath{kiddo.rkt} that is implemented with @racketmodname[scheme] 346instead of @racketmodname[racket]: 347 348@racketmodfile["kiddo.rkt"] 349 350then, if you run @filepath{kiddo.rkt} file in DrRacket or if you run it 351directly with @exec{racket}, @filepath{kiddo.rkt} causes 352@filepath{death-list-5.rkt} to print its list in traditional Scheme 353format, without the leading quote: 354 355@racketblock[ 356@#,racketoutput{("O-Ren Ishii" "Vernita Green" "Budd" "Elle Driver" "Bill")} 357] 358 359The @filepath{kiddo.rkt} example illustrates how the format for 360printing a result value can depend on the main module of a program 361instead of the language that is used to implement it. 362 363More broadly, certain features of a language are only invoked when 364a module written in that language is run directly with @exec{racket} 365(as opposed to being imported into another module). One example is 366result-printing style (as shown above). Another example is REPL 367behavior. These features are part of what's called the 368@deftech{run-time configuration} of a language. 369 370Unlike the syntax-coloring property of a language (as described in 371@secref["language-get-info"]), the run-time configuration is a 372property of a @emph{module} per se as opposed to a property of 373the @emph{source text} representing the module. 374For that reason, the run-time configuration for a 375module needs to be available even if the module is compiled 376to bytecode form and the source is unavailable. Therefore, 377run-time configuration cannot be handled by the 378@racketidfont{get-info} function we're exporting from the language's 379parser module. 380 381Instead, it will be handled by a new 382@racket[configure-runtime] submodule that we'll add inside 383the parsed @racket[module] form. When a module is run directly 384with @exec{racket}, @exec{racket} looks for a 385@racket[configure-runtime] submodule. If it exists, @exec{racket} 386runs it. But if the module is imported into another module, 387the @racket['configure-runtime] submodule is ignored. (And if the 388@racket[configure-runtime] submodule doesn't exist, @exec{racket} 389just evaluates the module as usual.) That means that the 390@racket[configure-runtime] submodule can be used for any special 391setup tasks that need to happen when the module is run directly. 392 393Going back to the @racket[literal] language (see 394@secref["language-get-info"]), we can adjust the language so that 395directly running a @racket[literal] module causes it to print out its 396string, while using a @racket[literal] module in a larger program 397simply provides @racketidfont{data} without printing. To make this 398work, we will need an extra module. (For clarity here, we will implement 399this module as a separate file. But it could equally well be 400a submodule of an existing file.) 401 402@racketblock[ 403.... @#,elem{(the main installation or the user's space)} 404!- @#,filepath{literal} 405 !- @#,filepath{main.rkt} @#,elem{(with reader submodule)} 406 !- @#,filepath{show.rkt} @#,elem{(new)} 407] 408 409@itemlist[ 410 411 @item{The @filepath{literal/show.rkt} module will provide a 412 @racketidfont{show} function to be applied to the string 413 content of a @racket[literal] module, and also provide a 414 @racketidfont{show-enabled} parameter that controls whether 415 @racketidfont{show} actually prints the result.} 416 417 @item{The new @racket[configure-runtime] submodule in 418 @filepath{literal/main.rkt} will set the 419 @racketidfont{show-enabled} parameter to @racket[#t]. The 420 net effect is that @racketidfont{show} will print the strings 421 that it's given, but only when a module using the @racket[literal] 422 language is run directly (because only then will the 423 @racket[configure-runtime] submodule be invoked).} 424 425] 426 427 428These changes are implemented in the following revised 429@filepath{literal/main.rkt}: 430 431@racketmodfile["literal-main-language-info.rkt" "literal/main.rkt"] 432 433Then the @filepath{literal/show.rkt} module must provide 434the @racketidfont{show-enabled} parameter and @racketidfont{show} 435function: 436 437@racketmod[ 438#:file "literal/show.rkt" 439racket 440 441(provide show show-enabled) 442 443(define show-enabled (make-parameter #f)) 444 445(define (show v) 446 (when (show-enabled) 447 (display v))) 448] 449 450With all of the pieces for @racket[literal] in place, try running the 451following variant of @filepath{tuvalu.rkt} directly and through a 452@racket[require] from another module: 453 454@racketmod[ 455#:file "tuvalu.rkt" 456@#,racket[literal] 457Technology! 458System! 459Perfect! 460] 461 462When run directly, we'll see the result printed like so, because 463our @racket[configure-runtime] submodule will have set the 464@racketidfont{show-enabled} parameter to @racket[#t]: 465 466@racketblock[ 467@#,racketoutput{Technology! 468@(linebreak)System! 469@(linebreak)Perfect!} 470] 471 472But when imported into another module, printing will be suppressed, 473because the @racket[configure-runtime] submodule will not be invoked, 474and therefore the @racketidfont{show-enabled} parameter will remain 475at its default value of @racket[#f]. 476