Re: Fwd: [racket-users] Writing a "command-line front-end" for a language

2022-09-03 Thread Philip McGrath
On Sat, Sep 3, 2022, at 2:09 PM, Shu-Hung You wrote:
> -- Forwarded message -
> From: Shu-Hung You 
> Date: Sat, Sep 3, 2022 at 1:03 PM
> Subject: Re: [racket-users] Writing a "command-line front-end" for a language
> To: Reuben Thomas 
>
>
> Running `racket foo.asm` will produce the desired output, so a shell
> script that directly passes the arguments to Racket could work.
> Otherwise, just use (dynamic-require filename #f) in main.rkt.
>
> At the technical level, foo.asm is in fact an ordinary Racket module,
> just like any other .rkt file. Therefore it can be run in the same way
> using APIs that require and instantiate modules.
>
> ---
>
> On a side note, the forum has mostly moved to Discourse
> (https://racket.discourse.group/).
>

This is all correct, and you can also make just `./foo.asm` work: 
https://docs.racket-lang.org/guide/scripts.html

However, in some cases you might really want a program other than `racket` as 
the entry point for your language: for instance, maybe you want to have flags 
for controlling where the output goes. One example of such a program is the 
`scribble` executable included in the main Racket distribution. The 
implementation is in 
, 
and the associated "info.rkt" file 
()
 arranges for `raco setup` to create a `scribble` to run it. (This example uses 
the old mzscheme-launcher-names/mzscheme-launcher-libraries instead of the 
newer racket-launcher-names/racket-launcher-libraries: see documentation at 
.)

A couple additional details:

> On Sat, Sep 3, 2022 at 6:01 AM 'Reuben Thomas' via Racket Users
>  wrote:
>>
>> I have a partial implementation up and running using #lang lines. I would 
>> like to add a more traditional command-line interface, so I can (eventually) 
>> say:
>>
>> hackasm foo.asm
>>
>> on a file without a #lang line.
>>
>> My code is available at https://github.com/rrthomas/hackasm
>>
>> [...]
>>
>> So far, all I've worked out how to do is run the language's read-syntax 
>> function (imported from parser.rkt), and thereby return the parsed syntax 
>> object as the result.
>>
>> What I'd like to do is call the evaluator on the parse tree, but after a lot 
>> of scratching my head over the Racket documentation and search results, I 
>> cannot work out how to do that.

It is possible to use Racket to implement languages that don't use #lang, but 
you would loose many advantages like IDE support and well-defined separate 
compilation, and you would need to use some fairly low-level mechanisms. Unless 
there is a hard requirement, I'd recommend that you just use #lang in your 
programs. For example, the whole family of languages supported by the 
`scribble` command-line tool use #lang. (Indeed, #lang is how the tool can 
support a whole *family* of languages.)

> On Sat, Sep 3, 2022 at 6:01 AM 'Reuben Thomas' via Racket Users
>  wrote:
>>
>> I have implemented the language as a dialect, so that the "main.rkt" module 
>> is "free" to be used for the command-line interface. (Perhaps this can be 
>> fixed too, that would be nice!)
>>
>> [...]
>>
>> The contents of my main.rkt looks like this:
>>
>> #lang br/quicklang
>> (require "parser.rkt" "tokenizer.rkt" (submod "asm.rkt" reader))
>>
>> (module+ main
>>   (require racket/cmdline)
>>   (let ((filename
>>  (command-line
>>   #:program "hackasm" ;
>>   #:args (filename)
>>   filename)))
>> (read-syntax filename (open-input-file filename
>>

There are many possible ways to organize this: to some extent it's a matter of 
how you expect your language and cli to be used, and to some extent it's a 
matter of taste. I wouldn't consider your current organization "wrong", 
necessarily. But, if you'd like hackasm to be a multi-purpose entry point, one 
way to do that would be:

 1. Move "expander.rkt" to "main.rkt"

 2. Add a reader submodule like the one in "asm.rkt", but using just hackasm 
where you currently have hackasm/expander in the result of read-systax. 
Optionally, you might consider using syntax/module-reader (Guide: 
 Reference: 
)
 with the #:whole-body-readers? option for your reader submodule.

 3. Add a main submodule like the one in the current version of "main.rkt", but 
implemented more like scribble/run. You might want to write it as `(module* 
main racket/base ...)` unless you want to implement the command line tool in 
your hackasm language.

If you do that, `(require hackasm)`, `(module foo hackasm)` and `#lang hackasm` 
will all access your language, and running the file will run your 

Fwd: [racket-users] Writing a "command-line front-end" for a language

2022-09-03 Thread Shu-Hung You
-- Forwarded message -
From: Shu-Hung You 
Date: Sat, Sep 3, 2022 at 1:03 PM
Subject: Re: [racket-users] Writing a "command-line front-end" for a language
To: Reuben Thomas 


Running `racket foo.asm` will produce the desired output, so a shell
script that directly passes the arguments to Racket could work.
Otherwise, just use (dynamic-require filename #f) in main.rkt.

At the technical level, foo.asm is in fact an ordinary Racket module,
just like any other .rkt file. Therefore it can be run in the same way
using APIs that require and instantiate modules.

---

On a side note, the forum has mostly moved to Discourse
(https://racket.discourse.group/).

On Sat, Sep 3, 2022 at 6:01 AM 'Reuben Thomas' via Racket Users
 wrote:
>
> I'm a relative Racket newbie, and I've just enjoyed Beautiful Racket.
>
> I am working on a Racket implementation of a simple assembler (for the Hack 
> VM in the NAND2Tetris course).
>
> I have a partial implementation up and running using #lang lines. I would 
> like to add a more traditional command-line interface, so I can (eventually) 
> say:
>
> hackasm foo.asm
>
> on a file without a #lang line.
>
> My code is available at https://github.com/rrthomas/hackasm
>
> Here's the nub of the problem: I can't work out how to call the language 
> evaluator "manually". I have implemented the language as a dialect, so that 
> the "main.rkt" module is "free" to be used for the command-line interface. 
> (Perhaps this can be fixed too, that would be nice!)
>
> A typical assembler file might start like this:
>
> #lang hackasm/asm
> @2
> D=A
> @3
>
> When I run this file (e.g. in DrRacket), I get some output as expected:
>
> 0010
> 11101101
> 0011
>
> (The assembler outputs ASCII-encoded binary!)
>
> The contents of my main.rkt looks like this:
>
> #lang br/quicklang
> (require "parser.rkt" "tokenizer.rkt" (submod "asm.rkt" reader))
>
> (module+ main
>   (require racket/cmdline)
>   (let ((filename
>  (command-line
>   #:program "hackasm" ;
>   #:args (filename)
>   filename)))
> (read-syntax filename (open-input-file filename
>
> So far, all I've worked out how to do is run the language's read-syntax 
> function (imported from parser.rkt), and thereby return the parsed syntax 
> object as the result.
>
> What I'd like to do is call the evaluator on the parse tree, but after a lot 
> of scratching my head over the Racket documentation and search results, I 
> cannot work out how to do that. I presume the code should look something like:
>
> (eval (??? (read-syntax filename (open-input-file filename
>
> where in the end I'm eval-ing a form, and where ??? represents something that 
> turns the syntax object into a runnable module.
>
> Apologies for the length of this post (I was unsure how I could make it 
> shorter), and thanks in advance for any help!
>
> --
> https://rrt.sc3d.org
>
> --
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/racket-users/CAOnWdohy31fHyvUd9rbY8tZFLJKUpevgnZ8jPH2-5_QtSFm%2BhA%40mail.gmail.com.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAMTzy%2BYSy2DH3zzdpzujRuiu37zMzKYZvu0p%2Bfk1RsNqeuJRDQ%40mail.gmail.com.


[racket-users] Writing a "command-line front-end" for a language

2022-09-03 Thread 'Reuben Thomas' via Racket Users
I'm a relative Racket newbie, and I've just enjoyed *Beautiful Racket*.

I am working on a Racket implementation of a simple assembler (for the Hack
VM in the NAND2Tetris course).

I have a partial implementation up and running using #lang lines. I would
like to add a more traditional command-line interface, so I can
(eventually) say:

hackasm foo.asm

on a file without a #lang line.

My code is available at https://github.com/rrthomas/hackasm

Here's the nub of the problem: I can't work out how to call the language
evaluator "manually". I have implemented the language as a dialect, so that
the "main.rkt" module is "free" to be used for the command-line interface.
(Perhaps this can be fixed too, that would be nice!)

A typical assembler file might start like this:

#lang hackasm/asm
@2
D=A
@3

When I run this file (e.g. in DrRacket), I get some output as expected:

0010
11101101
0011

(The assembler outputs ASCII-encoded binary!)

The contents of my main.rkt looks like this:

#lang br/quicklang
(require "parser.rkt" "tokenizer.rkt" (submod "asm.rkt" reader))

(module+ main
  (require racket/cmdline)
  (let ((filename
 (command-line
  #:program "hackasm" ;
  #:args (filename)
  filename)))
(read-syntax filename (open-input-file filename

So far, all I've worked out how to do is run the language's read-syntax
function (imported from parser.rkt), and thereby return the parsed syntax
object as the result.

What I'd like to do is call the evaluator on the parse tree, but after a
lot of scratching my head over the Racket documentation and search results,
I cannot work out how to do that. I presume the code should look something
like:

(eval (??? (read-syntax filename (open-input-file filename

where in the end I'm eval-ing a form, and where ??? represents something
that turns the syntax object into a runnable module.

Apologies for the length of this post (I was unsure how I could make it
shorter), and thanks in advance for any help!

-- 
https://rrt.sc3d.org

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAOnWdohy31fHyvUd9rbY8tZFLJKUpevgnZ8jPH2-5_QtSFm%2BhA%40mail.gmail.com.