This repository contains the Neverlang-based implementation of the Questionnaire Language (QL) for the paper "The State of the Art in Language Workbenches: 12 Years Later". Our implementation showcases the modular language components and supporting infrastructure in Neverlang.
To build and run the QL implementation:
-
Clone this repository
-
Run the execution script
./gradlew questionnaire-language-compose-adapter:run
- You can play with both the QL language and the styling language thereof by editing the
questionnaire-language/examples/example.qnandquestionnaire-language/examples/style.qlsfiles, respectively. - You can change the input files by editing the
questionnaire-language-compose-adapter/build.gradle.ktsfile (task args at lines 53-54).
- You can play with both the QL language and the styling language thereof by editing the
-
Generate the LSP client(s)
./gradlew questionnaire-language-client:generateLSPClient
This task generates the following three directories:
ql.questionnarielanguage-nvim-client-0.0.1,ql.questionnarielanguage-vscode-client-0.0.1, andql.questionnarielanguage-vim-client-0.0.1, which contain the LSP client implementations for Neovim, VS Code, and Vim, respectively. -
Copy the generated configuration to your editor of choice.
- Please refer to your editor's documentation for how to set up LSP clients. For Vim users, the client configuration requires the
coc.nvimplugin installed. For VSCode users, the client configuration can either be installed or ran in debug mode.
- Please refer to your editor's documentation for how to set up LSP clients. For Vim users, the client configuration requires the
Generating and running a debugger for QL requires several steps. Please refer to the DAP README file for detailed instructions.
- All major constructs from the original QL assignment are implemented.
- Modular structure with separation between syntax, semantics, typing rules, and UI components.
- UI components in Jetpack Compose Desktop.
- Off-the-shelf primitive types and expressions, including type resolution.
- Custom types such as
DateandMoneycompatible with the pre-existing type definitions.
We leveraged a family of DSLs called Typelang, specifically designed to describe and implement type systems for DSLs . Typelang is:
- a declarative language;
- integrated with our LSP implementations;
- executed at runtime via code generation.
In QL, questions and derived values are annotated using user-defined Typelang types. The Typelang engine performs type checking and type inference. Any generated errors are reported in the IDE according to the LSP standard.
The QL executable features:
- custom QL form with dynamic widgets;
- form export to Json files;
- interactive variables editing between application and DAP.
The QLS language allows users to define styles for QL forms. It is implemented as a DSL in Neverlang and supports theme switching and choice between switches and checkboxes for boolean variables. QL and QLS are fully independent.
- Test for cyclic dependencies.
- Test for determinism.
- QLS references (styling is global).
-
Total implementation time: ~17 person hours
- Language definition: 2h
- LSP + Typelang system: 6h
- DAP: 7h
- GUI: 2h
-
Lines of code (LoC):
- Neverlang modules (QL + QLS): 655 LoC (10 modules)
- Neverlang glue code (QL + QLS): 65 LoC (5 files)
- Java classes (including libraries, LSP, and DAP definitions): 1848 LoC (36 files)
- Kotlin files (Compose GUI): 1421 LoC (15 files)