Best way to "inject" a type system in a small expression language that lacks its own type definition mechanisms? #2002
-
I'm working on a formula language that supports simple expressions that can be compared to how one might write a Java Streams or a C# LINQ expression. Here's a flavor for (roughly) how the language looks like:
The language does not have any mechanisms to define the types of the objects like Now I wonder what the architecturally most sound implementation approach could be for the following use case: I would like to provide a powerful VS Code extension for my language while making use of Langium's existing features as much as sensibly possible for this to keep implementation effort low and maintainability high. As a minimum, I would like the extension auto-complete:
I considered these options so far: 1) Treat this as a case of Multiple dependent languages While this might work, it feels like trying to jump through too many hoops: When we read the custom data format, we basically already have the types & global scope items available in a parsed data format. So having to convert them first and then parse them again feels like too much work. Also, I fear that this might not be well-maintainable in the long run. 2) Hook into the
b) Override the As a downside, it however looks like as if the result would be really hacky because the So in case this actually turns out to be a "suitable" option, I would love to get some guidance on how to populate my 3) Hook into the Pretty much the same "hackiness" as before might bite me here: Both interfaces require me to return a 4) "Give up" on cross-references completely and work only with the LSP capabilities
And I would need to live with the fact that all of Langium's nice scoping/linking/etc. capabilities would not support me anymore. Instead, I would need to override many of the existing default implementations for the LSP services, especially the I'm not really happy with either of these options so far. So I would really love to get some guidance, both on further options that I haven't considered yet, and on aspects that I should watch out for when going for any of the given options. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Hey @haukepribnow, these are some good ideas. I would personally go with (1) usually, since it has the added benefit of being able to provide users with the actual type definitions, so they have a way of looking up what the types are that they're working with. See also this guide on builtin libraries. (2) and (3) are mostly the same, in the sense that they simply enrich the scope with purely virtual objects that don't actually exist in documents. You would still need to declare interfaces for these types though in the Langium grammar, even if they don't have an implementing parser rule. See our documentation on declared types. You can then create instances of these interfaces in memory based on your custom data format. You then create a virtual document for these instances using It's rather clear that all three of these approaches are essentially the same:
I wouldn't recommend (4), you basically lose 80% of Langium's features that way. |
Beta Was this translation helpful? Give feedback.
Hey @haukepribnow,
these are some good ideas. I would personally go with (1) usually, since it has the added benefit of being able to provide users with the actual type definitions, so they have a way of looking up what the types are that they're working with. See also this guide on builtin libraries.
(2) and (3) are mostly the same, in the sense that they simply enrich the scope with purely virtual objects that don't actually exist in documents. You would still need to declare interfaces for these types though in the Langium grammar, even if they don't have an implementing parser rule. See our documentation on declared types. You can then create instances of these interfaces in memory ba…