2 Adding Languages to DrScheme
2.1 Adding Module-based Languages to DrScheme
If a language can be implemented as a module (see module for details) and the standard language settings are sufficient, simply create an info.ss file in the collection where the module is saved. Include these definitions:
drscheme-language-modules: This must be bound to a list of collection path specifications or strings, one for each language in the collection. Each collection path specification is the quoted form of what might appear as an argument to require, using the lib argument (but without the lib). The strings represent relative paths starting at the directory containing the info.ss file. They are interpreted like string arguments to require.
drscheme-language-positions: This must be bound to a list of language positions. Each language position corresponds to the position of the language in language dialog. Each language position is a list of strings whose length must be at least two.
drscheme-language-numbers: This is optional. If present, it must be a list of a list of numbers. Each list corresponds to a single language from this collection. Each number indicates a sorting order in the language dialog for the corresponding string in drscheme-language-positions. If absent, it defaults to a list of zeros that has the same length as drscheme-language-positions. This will rarely be correct.
drscheme-language-one-line-summaries: This is optional. If present, it must be a list of strings. Each string is displayed at the bottom of the language dialog when the corresponding language is selected.
drscheme-language-urls: This is optional. If present, it must be a list whose elements are either strings or "#f". Clicking the corresponding language’s name in the interactions window opens a web browser to the url.
drscheme-language-readers: This is optional. If present, it must be bound to a quoted list of module specifications (that is, a quoted version of the argument to require). Each specification must be a module that exports a function named read-syntax. Each of these read-syntax functions must match MzScheme’s read-syntax primitive’s contract, but may read different concrete syntax.
If the module specification is a plain string, it represents a relative path starting at the directory containing the info.ss file. It is interpreted like the string arguments to require.
The lists must have the same length.
As an example, the Essentials of Programming Languages language specification’s info.ss looks like this:
(require string-constants) |
(define name "EoPL Support") |
(define drscheme-language-modules |
(list "eopl-lang.ss")) |
(define drscheme-language-positions |
"Essentials of Programming Languages"))) |
This info.ss file indicates that there is a single language in this collection. The module that implements the language is the eopl-lang.ss file in the same directory as the info.ss file. Additionally, the language dialog will contain Essentials of Programming Languages as a potential language. The use of the string constant teaching-languages ensures that EoPL’s language is placed properly in foreign language versions of DrScheme.
For collections that define multiple (related) languages, if the language-positions contain multiple strings, the languages whose leading strings match are grouped together. That is, if two languages have strings:
'("My Text" "First Language")
and
'("My Text" "Second Language")
the two languages will be grouped together in the language dialog.
2.2 Adding Arbitrary Languages to DrScheme
With some additional work, any language that can be compiled to PLT Scheme is supported by the tools interface, not just those that use standard configurations and module.
Each language is a class that implement the drscheme:language:language<%> interface. DrScheme also provides two simpler interfaces: drscheme:language:module-based-language<%> and drscheme:language:simple-module-based-language<%>, and mixins drscheme:language:simple-module-based-language->module-based-language-mixin and drscheme:language:module-based-language->language-mixin that build implementations of language^s from these simpler interfaces.
Once you have an implementation of the drscheme:language:language^ interface, call drscheme:language-configuration:add-language to add the language to DrScheme.
Each language comes with its own type, called settings. This can be any type the language designer chooses, but to aid documentation, we call it settings here. The settings type is expected to contain parameters of the language, such as case sensitivity, etc. The implementor of the language provides a GUI so the user can configure the settings and all of the language’s operations accept a setting. DrScheme maintains the current settings for each language.
2.3 Language Extensions
Some tools may require additional functionality from the drscheme:language:language interface. The drscheme:language:extend-language-interface function and the drscheme:language:get-default-mixin mixin make this possible.
For example, the MrFlow tool expands a program, analyzes it and then displays sets of values for each program point. These sets of values should be rendered in the syntax of the language that MrFlow analyzes. Since MrFlow doesn’t know which languages are available, it can call drscheme:language:extend-language-interface to extend the drscheme:language:language<%> interface with a method for rendering sets of values and provide a default implementation of that method. Tools that know about MrFlow can then override the value rendering method to provide a language-specific implementation of value rendering. Additionally, since the drscheme:language:get-default-mixin adds the default implementation for the value-set rendering method, all languages at least have some form of value-set rendering.
In some cases, it is important for one tool to avoid depending on another in the manner above. For example, if a tool that provides a new language provides an implementation for the MrFlow-specific method, that tool may fail to load if MrFlow is not present (Indeed, with the tool manager, this can happen to any tool that depends on another in this manner.)
To avoid this problem, consider writing your tool to first check to see if the base method is available before extending it. For example, if the MrFlow tool provides the render-value<%> interface, then a tool that overrides that method can first test to see if the superclass implements that method before overriding it:
(define (my-language-mixin %) |
(if (implementation? % mrflow:render-value<%>) |
(class % |
(define/override ...) |
(super-new)) |
%)) |
To help test your tool, use the PLTONLYTOOL environment variable to load it in isolation.