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
srcs
list is a single course - each entry in the
libs
list, be it a jar file or not, is searched for anindex.value
file to augment the current index.
- each entry in the
- Concept hierarchy - each folder
/X
has its own index file, called eitherX/X.md
orX/index.md
. Nested folders equal nested concepts. - Indexing - to help in easy cross-linking between concepts:
- Each concept of course
A
stored inX/Y/Z/Z.md
may be linked viaZ
,Y-Z
,X-Y-Z
,A:Z
,A:Y-Z
,A:X-Y-Z
- Each Rascal module of course
A
nameda::b::C
may 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
A
nameda::b
may 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/Z
may be linked as though it were a concept file. - The index is a
rel[str,str]
from the above described links to theindex.md
files in the generated hierarchy. - The compiler reports missing links and ambiguous links as errors.
- A single
index.value
file 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-shell
are 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. TheContent
module that serves HTML or any other file is also inlined in the output Markdown file. - Code blocks marked
rascal-shell,continue
are executed in the previously constructed environment (from top to bottom in the Markdown file) and behave the same otherwise. - Code blocks marked
rascal-prepare
with or withoutcontinue
behave 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
,examples
etc. tags - (overloaded) function declarations with their
doc
,synopsis
,examples
etc. tags - alias declarations with their
doc
,synopsis
,examples
etc. 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::Indexer
implements indexing and lookuplang::rascal::tutor::Compiler
implements linking, code execution, toc, and the generation of index files.lang::rascal::tutor::apidoc::ExtractInfo
parses Rascal code and generates an intermediate overviewlang::rascal::tutor::apidoc::GenerateMarkdown
generates a single Markdown file for each Rascal module, and also reusesCompiler
to process embedded markdown with code examples, links, etc.lang::rascal::tutor::repl::TutorCommandExecutor
encapsulates 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.