Architecture
Synopsis
The global architecture of the Rascal Tutor
Description
The Rascal Tutor is a Markdown and Rascal source file pre-processor. As input it takes Docusaurus Markdown files organized in hierarchical folders, and Rascal modules organized in hierarchical packages. One root folder is called a "course". As output the pre-processor produces per course
a folder hierarchy again, where each folder has its own index.md file (generated or written). After the tutor
compiler has generated such a consistent folder of interconnected markdown files, other downstream processors can turn them into (static) html websites, pdf files or otherwise. The standard way of processing is to use the Docusaurus static website generator.
The important features of the pre-processor, "compiler", are:
- The compiler is configured via
util::Reflective::PathConfig, where:- each entry in the
srcslist is a single course - each entry in the
libslist, be it a jar file or not, is searched for anindex.valuefile to augment the current index.
- each entry in the
- Concept hierarchy - each folder
/Xhas its own index file, called eitherX/X.mdorX/index.md. Nested folders equal nested concepts. - Indexing - to help in easy cross-linking between concepts:
- Each concept of course
Astored inX/Y/Z/Z.mdmay be linked viaZ,Y-Z,X-Y-Z,A:Z,A:Y-Z,A:X-Y-Z - Each Rascal module of course
Anameda::b::Cmay be linked viaC,b-C,a::b::C,module:a::b::C,A:C,A:b-C,A:a::b::C,A:module:a::b::C - Each Rascal package of course
Anameda::bmay be linked viab,a::b,package:a::b,A:b,A:a::b,A:module:a::b - Each image
x.{png,svg,jpg,jpeg}stored inX/Y/Zmay be linked as though it were a concept file. - The index is a
rel[str,str]from the above described links to theindex.mdfiles in the generated hierarchy. - The compiler reports missing links and ambiguous links as errors.
- A single
index.valuefile is written in the output folder for future reference by depending projects.
- Each concept of course
- Code execution ensures lively demonstrations which are checked for correctness.
- Code blocks marked
rascal-shellare executed line-by-line on the REPL prompt. Each prompt starts with a fresh environment. All error and standard output is captured and printed back. TheContentmodule that serves HTML or any other file is also inlined in the output Markdown file. - Code blocks marked
rascal-shell,continueare executed in the previously constructed environment (from top to bottom in the Markdown file) and behave the same otherwise. - Code blocks marked
rascal-preparewith or withoutcontinuebehave the same as above, except that no output or input is printed back into the output file.
- Code blocks marked
- Links written between
((and))are resolved using the previously described index. - Table of contents are generated for the word TOC between three
(((brackets))); the content of each concept is the concept nested under it in the hierarchy. - Each Rascal file is indexed to list the declarations it contains and information is extracted:
- data declarations with their
doc,synopsis,examplesetc. tags - (overloaded) function declarations with their
doc,synopsis,examplesetc. tags - alias declarations with their
doc,synopsis,examplesetc. tags
- data declarations with their
- Screenshots of interactive ((Library:module:Content) visualizations can be made by configuring the compiler to use selenium and chrome.
Features on the TODO list are:
- Interactive Questions (have to be revived)
To implement these features the following components are relevant:
lang::rascal::tutor::Indexerimplements indexing and lookuplang::rascal::tutor::Compilerimplements linking, code execution, toc, and the generation of index files.lang::rascal::tutor::apidoc::ExtractInfoparses Rascal code and generates an intermediate overviewlang::rascal::tutor::apidoc::GenerateMarkdowngenerates a single Markdown file for each Rascal module, and also reusesCompilerto process embedded markdown with code examples, links, etc.lang::rascal::tutor::repl::TutorCommandExecutorencapsulates a Rascal REPL as a set of closures (eval,reset, andprompt)- for efficiency's sake a single executor is shared among all Markdown and Rascal files that are compiled in a single run. Between every file the executor is reset for a new environment, but previously loaded modules remain in the heap available for reuse.
Benefits
- Index creation is modular: an index is created per course and these indices are combined at runtime.
- Code execution is reasonably time efficient, although it may require quite some memory because eventually an entire course will be loaded.
Pitfalls
- Courses are compiled on a per-course basis. Support for incremental courses compilation is not yet available.
- Badly balanced code block quotes are not detected by this pre-processor but will fail HTML compilation downstream.
- Manual links are not checked at compile-time by this pre-processor but fill fail HTML compilation downstream.