#lang hypothetical-lanugage
(hypothetical-code)
--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/179b48af-cfe1-4d6a-8c11-6f27584a4129%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
The functionality you describe—in particular, setting up clean evaluation contexts—sounds a lot like what the "Run" button already does. Unless you have some other notion of "running" in mind for programs in your DSL, I think what you describe could be accomplished nicely with a "main" submodule, which (as you may know) is run only when its enclosing module is invoked as a main program, not when it is required as a library. One benefit is that this would make this functionality independent of DrRacket.
This sounds very similar to pict3d, particularly if you adopt the approach suggested by Phillip of using a main submodule to render things instead of a drracket plugin. Is pict3d close to what you're trying to do? Not saying you should use pict3d or do things a similar way—I'm just curious about your use case.
1. The language is a language for describing parametric 3D models, not for rendering, and the final result of being evaluated by Racket is a module containing a provided result value, which is a pointer to a C++ object which represents some a low level program evaluated by our C++ runtime to produce a triangle mesh.
2. Our C++ applications obtain the result value from a DSL program by calling scheme_dynamic_require in the inner loop of a Racket interpreter we've stuffed into a coroutine.
3. When the toolbar button is pushed in DrRacket we want to evaluate the program in a fresh namespace, (dynamic-require ''module-name 'result), and then pass that result value into a C++ FFI function that will handle the C++ side of evaluation and doing the actual OpenGL calls to visualize it in the editor. This should have similar behavior to the run button from an evaluation standpoint, but after evaluating the program, enter a render loop until, e.g. the button is pushed again to stop rendering. Here, the DrRacket plugin is responsible for creating the OpenGL context, which could be in a separate window, but as Kshitij said it would be ideal if we could figure out how to add a pane below the REPL.
If you're sure you want to get the raw program source and deal with it manually, you can use the method `get-definitions-text` on the DrRacket frame given as an argument to your button's callback function. This will give you the editor object for the definitions window. You can then use a method like `get-flattened-text` to get the source as a sting or (probably better) the function `open-input-test-editor` to get an input port directly.
Again, this part works just fine. In particular, because of the way Racket's submodules work, the code in the "main" submodule does not run when you instantiate the parent module, whether via `scheme_dynamic_require`, `dynamic-require`, `require`, or some other way: the compiled form of the submodule need not even be loaded into memory. So you can use rendering code in the main submodule without creating a dependency for your main application.
It could certainly open a new GUI window, and it could also return a value that renders as an embedded widget (snip) in the interactions pane. (See the plot library for an example.)
I haven't looked at the DrRacket extension APIs enough to be sure whether you could open a new pane in the DrRacket window, but it certainly seems possible.
May I ask why you need to have the C++ code embed Racket instead of
the other way around (ie using the FFI)?
Generally speaking, DrRacket (and other Racket tools) are going to work better if they get to
"drive", I expect.
On Fri, Jun 28, 2019 at 5:50 PM Philip McGrath <phi...@philipmcgrath.com> wrote:Again, this part works just fine. In particular, because of the way Racket's submodules work, the code in the "main" submodule does not run when you instantiate the parent module, whether via `scheme_dynamic_require`, `dynamic-require`, `require`, or some other way: the compiled form of the submodule need not even be loaded into memory. So you can use rendering code in the main submodule without creating a dependency for your main application.Specifically, this means we can avoid byte-compiling and loading any graphics modules the main submodule depends on, yes?
It could certainly open a new GUI window, and it could also return a value that renders as an embedded widget (snip) in the interactions pane. (See the plot library for an example.)Snips seem nice, but even browsing through the source for the 3d renderers for plot, I don't see any way to get an OpenGL context for a snip, since they appear to work on predefined DCs, rather than allowing you to construct a canvas.
I haven't looked at the DrRacket extension APIs enough to be sure whether you could open a new pane in the DrRacket window, but it certainly seems possible.Are you aware of any projects that usefully manipulate the interactions pane that I could turn to for example code? It looks like it's possible to extend that class.
I believe the main submodule will still be compiled the enclosing module is loaded from source, but that should be trivial: it really only needs a `require` and a function call. If the file has already been compiled to bytecode, the bytecode for the main submodule won't be loaded, nor for any of its transitive dependencies.Depending on how you are distributing your code, you may or may not want to add an indirection via `dynamic-require` to prevent the distribution building tools from shipping graphics libraries that you only need for the main submodule. (Basically this would be the reverse of what `racket/runtime-path` does.) I haven't done much with the tools for distributing built artifacts beyond toy experiments, but I think some of them may be able to do that stripping automatically or with e.g. a command-line flag, without needing a `dynamic-require`. At the maximum, you could put the graphics modules in their own package, analogous to the `foo`+`foo-lib`+`foo-doc`+`foo-test` convention: in that case, the support library for your main submodule (what I called `hypothetical-lanugage/private/render`) would just be a stub to `dynamic-require` the `render` function or do something useful if the graphics package isn't installed, like print a message to standard error.
I haven't used OpenGL, from Racket or otherwise, but it might be possible to use a bitmap from `make-gl-bitmap` as a buffer for your OpenGL drawing and copy it to the canvas via `draw-bitmap`. If you have an existing foreign library that does the actual drawing, you can get a platform-specific pointer via `gl-context<%>`.
I suspect, though, that a solution would involve your support library cooperating with an extension set up by your #lang.
On the whole, though, either returning a snip or creating a new `frame%` would probably be easier. Using a new `frame%` would also be entirely independent of DrRacket: I expect it would work with racket-mode for Emacs, for example.
I think I'm missing a bit more context so I'll continue this line ofDrRacket, and it seems unlikely to me that it is the most productive
questions. The path that you seem to be heading down seems to be one
where you'll duplicate a lot of work that's already gone into
Can you say a little more about what you want to do with DrRacket?
Do you expect to be able to run these programs? If so, does it
make sense to run them when you aren't in the
embedded-in-the-huge-C++-code-base mode? How about compilation of the
programs (i.e. macro expansion)?
Sorry for letting this thread lapse. Wrt to your third option
mentioned below, would it work to make that option accessible via the
FFI? If so, then maybe you could make the "essentially phase shifted
everything" into "actually phase shifted everything" and then when you
get the result program have your #%module-begin call into the FFI to
actually run the program. Does that seem like a viable option?
Yes - the architecture we eventually settled on is a main submodule that does roughly this to get a black-box value which we can pass back to a rendering function to produce a gl-bitmap, and stick it in a snip.