JMPL Devlog #4
Building a Better Tomorrow
July 20th 2025
Tags:
C
JMPL
Programming Language
Welcome to this week's JMPL update. This week I've been working on features for v0.2.1 including a defining feature for JMPL.
What's changed?
The main addition to JMPL this week is... drumroll please... set-builder notation! This feature took me a long time to plan and build, but in the end it was all worth it. Its very powerful and has quickly become my favourite feature in JMPL so far. Set-builder notation (SBN) was one of the ideas I've had for JMPL since the very beginning. Short tangent - I first had the idea for a mathematics-inspired set-based programming language in a maths classroom in 2022 and began work on designing it during lectures in 2024. SBN was in my notes right from the start and when I found out Haskell had a very similar feature I was committed on adding it.
// JMPL presents: Set-builder notation
out {x^2 | x ∈ {1 ... 5}} // {1, 4, 9, 16, 25}
Set-builder notation creates a set by specifying a predicate that filters over members of another set. The main design goal for SBN was to make it identical to how you'd write it in a mathematical context. This is possible using the generator system I developed for for loops. The syntax takes the form:
{expression | qualifier 1, ..., qualifier n}
With a 'qualifier' being a generator in the form x ∈/in S or a predicate filter and 'expression' being any expression (including a generator). Qualifiers are delimited by commas and there must be at least one generator and an expression for the statement to be valid. Only one generator can be on the left side of the pipe but there can be unlimited generators and filters overall. Here are some examples:
// No filter
out {x | x ∈ {1 ... 5}} // {1, 2, 3, 4, 5}
// Filter
out {x | x ∈ {1 ... 10}, x mod 2 == 0} // {2, 4, 6, 8, 10}
// Multiple filters
out {x | x ∈ {1 ... 10}, x mod 2 == 0, x > 5} // {6, 8, 10}
// Multiple generators
out {x + y | x ∈ {1 ... 3}, y ∈ {1 ... 3}} // {2, 3, 4, 5, 6}
// Generator on the left side of the pipe
out {x ∈ {1 ... 5} | x mod 2 == 0} // {2, 4}
// ASCII notation
out {x | x in {1 ... 5}} // {1, 2, 3, 4, 5}
As generators use the same syntax as the set membership operation, once a generator has been defined, subsequent uses of that generator with ∈ or in will create a set membership predicate.
// Set of numbers between 1 and 5 that are also between 4 and 7
out {x | x ∈ {1 ... 5}, x ∈ {4 ... 7}} // {4, 5}
Generators are parsed left-to-right so a generator left of the pipe will take precedence over a right side one. For a little debugging tip, set-builders are wrapped in their own implicit function by the compiler so runtime errors will add a '@setb' function to the call stack. This new syntax makes writing sets a lot easier and I look forward to seeing it used in the future.
Now time for a quick fire of the other minor features and fixes that I worked on this week.
Bug fixes and optimisations:
- Interpreter no longer crashes when freeing upvalues and objects at the end of the program
- Interpreter no longer crashes when an invalid infix operation is found (e.g. g{1})
- Fixed implicit return leaving values on the stack and producing the wrong return value
- Optimised set storage and operations
Additions:
- round(x) native - returns the closest integer of an number number
- Made strings indexable using subscript
- Made tuples be able to be concatenated
- 'put' keyword - outputs text to the console without adding a newline
- Simple implicit multiplication when a number preceeds a numerical variable (e.g. let x = 3, 2x = 6)
And that's it for this week!
What's next?
As I mentioned last week, I'm still working on nondeterminate set member access, and quantification, but with how long set-builder notation took to design and implement, they've been postponed. I also have a few things in the works such as characters, refactoring strings, index slicing, and map notation, so stick around!