Lunar, a superset programming language of Lua 5.1

Thanks for asking! Yes, there are more reasons beyond syntactic sugar going for Lunar. One major point is to increase productivity, but we also want to add static typing and better language integration with editors through language server, including intellisense.

  1. Regarding lambda expressions, you’re right, it’s easy to create anonymous functions in Lua. However, one of the ideas floating in my head is the methods you see in functional programming such as map, filter, etc. For example, assume you want to kick players whose AccountAge is less than 7, you could very easily pass predicates around like so: Player:GetPlayers():filter(|p| p.AccountAge < 7):foreach(|p| p:Kick("not allowed yada yada"). This would get verbose fast using anonymous function, never mind annoying to write repetitively. This is just one use case though, but maybe it’s a dumb idea. ¯\_(ツ)_/¯

  2. As for static typing, that is actually in the pipeline! We technically support typed members right now, but obviously we do not perform type checking yet. I do agree with you there, dynamically typed languages do not scale well in a team setting, which is one of the goal Lunar aims to solve.

  3. We do break down classes into two separate tables, one that holds static members and another that holds instance members. Checking whether an instance is an instance of T is something I have been thinking about, but haven’t needed to tackle it… So I haven’t yet thought this through so I’m not sure about pros vs cons here… Ideally we do want to provide a method of asserting whether an instance is of type T at runtime, including polymorphism.

Keep in mind everything is not set in stone and my mind can be changed given constructive criticism. Hence I’m posting this despite it being very early, because I want Lunar to work with people, not against them.

1 Like

We’ve decided to keep a lot of the Lua syntax as-is since we want to allow people to be able to migrate their code at their own pace (such as moving their classes to our new class declaration), while still being able to run it all through Lunar. In Lunar, it is still easier to effectively do that than Lua itself through x += 1 compared to x = x + 1. Also, we cannot add an option to switch the syntax, here’s a few reasons why not:

  1. It’s hard work internally to make sure both options work at the same time. We already have a ton of tests for existing syntax, with more to come with new implementations.
  2. You’d lose the ability to properly use any tools we create for Lunar, such as language support for VSCode (soon™).
  3. This would harm the ability to run pure Lua, and we would like to avoid that to ensure Lunar stays as a superset.

We’ll try to add as much as we can that makes sense and helps people out that matches how Lua would maybe do things, but we also would like to implement things that make it easier to do something, even if to do so you have to use symbols (such as our lambdas).

As for types, one of the goal of Lunar is to add type inference, which means you don’t always need to declare it. There is however a few cases where you want types to be enforced at compile time, so that’s a pretty big necessity. Hopefully our implementation for types will actually help people who are unfamiliar with it, not run into much trouble with it, and maybe even be easier to work with!

1 Like

When you put it like that, lambda notation makes a bit more sense. Are there plans for having filtering tables and whatnot build in, or were those soley for example?

You might just be able to get away with something as simple as a IsA method or a ClassName property to check the type of created classes to be honest. Lua’s standard for OOP and Roblox’s especially essentially point to that solution.

@ChasingSpace You didn’t specifically address whether x++ or the sort would be added. Is that a no, then? I couldn’t tell if you were talking about changing the comment syntax or all of it.

I’ll see if I can convert a project over to Lunar and report back with how it performs. I’m personally excited for what the future may hold for it.

1 Like

Sorry, that response turned into multiple things. We won’t be implementing x++ or x-- because the latter interferes with the comment syntax, and we want to maintain the entire Lua 5.1 syntax, just with new additions on top of it. It wouldn’t make much sense (at least to me), to implement x++ but not x--

Lunar should support all Lua 5.1 syntax, so hopefully everything goes well with converting your project over!

2 Likes

Well, it’s just an idea at this stage. Like I mentioned earlier, we want to increase productivity, so it could make it’s way in. We would have to solve a few problems with it after the foundation is done. Conditional extension methods like this requires type information which we don’t yet do.

Yeah, it could be as simple as IsA until you realize that requires a base class to inherit from. It’s a problem to tackle on later.

This is very interesting… How can we make lunar code and then run it on Roblox? And does it actually compile everything to a new file or does it simply parse the contents of the file?

Currently, it compiles source files to a new file that can be specified with a compiler config file .lunarconfig
example:

include = { "lunar", "spec" }
out_dir = "dist"

The plan is to bundle a roblox compiler with lunar that works similar to roblox-ts, and can be synced to roblox using rojo or other syncing plugins we may support in the future.


In other news, I just released a new import and export syntax!
You can now use

export class A end
export function B() end
export C = "Hello"

which should compile to

local A = {}
A.__index = {}
function A.new()
  return A.constructor(setmetatable({}, A))
end
function A.constructor(self)
  return self
end
local function B()
end
local C = "Hello"
return {
  A,
  B,
  C,
}

Along with

from 'path.to.my_module' import A as MyClass, B, C, * as MyModule

which should compile to

local MyModule = require('path.to.my_module')
local B = MyModule.B
local MyClass = MyModule.A
local C = MyModule.C

Note that this is still experimental and subject to change
I would not recommend using lunar in any major projects until we have published our first release. We plan on bootstrapping lunar after the initial release.

5 Likes

Are you thinking of adding access modifiers to class attributes/methods (or wherever else it is applicable), like in java? It could be helpful on teams when, for example, you have to make sure a function is called or some restrictions are applied through a set method instead of directly assigning to the variable. It could be done with just the local keyword, and you could make up more specific keywords if you plan to add an inheritance feature.

We do want to add public, private, and protected access modifiers to class members! It feels wrong to not include these when one of the major feature of Lunar is the static typing. We will also add const and readonly, too!

We already support class inheritance! At the moment it’s written like so: class C << S, but we’re going to change this to class C extends S soon enough.

You can use this existing Lunar project I wrote. Clone this repository somewhere.
https://github.com/Apakovtac/commander

Basically the workflow looks like this for now.

  1. Start up rojo server
  2. Start rojo plugin in the client
  3. Run lunarc in this directory for each change you do. We’ll be adding --watch mode later to invoke this on each save.

The instructions for compiling Lunar are a tad vague. Specifically, it doesn’t list LuaFileSystem as a dependency but it appears to be one. That puts a damper on things as I’m not a big fan of LuaRocks.

You may want to update the instructions regardless; they’re not clear on what to do and it took a bit of looking around to figure out what the problem was. I actually had to modify lunarc to even see the error message saying I didn’t have LuaFileSystem available. It would be great if the instructions were more clear beyond “do this” then leaving people to their own devices.

1 Like

This was a huge oversight. We’re applying a fix to include a more clear message when you don’t have LuaFileSystem for now, and we’re going to work on having lunarc not require LuaFileSystem. Only the compiler uses LuaFileSystem, and the reason this wasn’t very clear to us is because we use busted for unit testing, which has LuaFileSystem as a dependency.

We’ll also be updating our installation steps to reflect LuaFileSystem being a dependency, as well as being more thorough about how to install and use Lunar. This should be very soon.

Sorry about that, and thanks for letting us know about it!


We’ve updated the README to be more thorough and include dependencies, as well as updating lunarc to show a more friendly error message for when you don’t have LuaFileSystem.

1 Like

We plan on using luastatic to bundle the actual release (so that most users won’t need to use luarocks modules if they don’t want to).

Currently we still do not have a stable release, nor have we bootstrapped, so for now lfs need to be installed.

I agree, luarocks is a really annoying package manager, but lfs is unfortunately necessary in order to make command line tools in lua. So it won’t be a requirement for the user upon release, but certain dependencies will be for contributors.

3 Likes

Lunar now has a language documentation for its syntax as well as semantics! You should be able to learn Lunar easily now that it’s explained to you instead of inferring what was possible or intended. We hope this would allow Lunar to be more widely adopted as we develop Lunar.

We also have bootstrapped the compiler, so now Lunar is written in Lunar! We’re eating our own dogfood now.


We want to know your experience with Lunar so far! So please give us feedback, whether that was porting over a project or creating a Hello World program, etc.

1 Like

Is there any reason why %= wasn’t added to Lunar, or is that just an oversight?

2 Likes

Whoops, yes it is an oversight. I have added it in in this commit c2c9d86! The docs are also updated too.

1 Like

If I were to use Lunar, how would I debug and fix runtime errors? Does the Lua output have the same line numbers as the Lunar source? Are the Lua errors easy to trace back to the Lunar code? Does Lunar provide an easy-to-use way to map a Lua error back to a Lunar file and line number?

2 Likes

The output of your code should look similar enough to what you initially wrote that you should be able to pinpoint where in your code something went wrong. Pure Lua code will always be mirrored. Parts of code using our syntax will look different, but still understandable.

An example would be x += 1 which turns into x = x + 1, which is still very understandable.

One of our primary focuses right now is to ensure you can still read and understand your code after it’s gone through Lunar.

Right now we don’t have any plans of having a way of mapping errors to Lunar itself, or having source mapping. We’re currently focusing on improving the user experience while editing Lunar code so you don’t have issues such as no syntax highlighting, improper indentation due to Lua not recognizing new things such as classes, and we are going to be working on implementing a Language Server for better integration with VSCode. Additionally, we’re going to be doing extra work on the compiler to enable some useful features such as watch mode, and a way to initialize projects without needing to create the files yourself.

We are also in the progress of making a thorough type system which will encompass everything Roblox and Pure Lua implements, such as Instances (Part, Script, etc.), and types (string, number, etc.)

We hope that eventually you’ll find yourself actually having difficulty running into those kinds of bugs by having VSCode tell you if something may be nil, and allow you to add appropriate checks to ensure everything goes right.

Being able to read and understand the code only helps so far if the line number is 100 lines off from the Lunar source. Are errors always within a couple of lines?

You should be able to combine any additional Lunar logic into one line so that Lua and Lunar line numbers match up perfectly! This would greatly ease fixing runtime errors, and could be implemented as an optional mode for when you don’t plan on looking at the Lua source. If I’m writing my game in Lunar, then I don’t plan on ever modifying the Lua output and I’d rather avoid reading it as much as I can. All the changes I need to make are in the Lunar source, so I just want to read where the error is then go check my code!

Runtime errors are unavoidable, especially in such a dynamic language. Fixing some errors at “transpile-time” is no substitute for being able to fix errors that occur at runtime. I love the idea of preventing certain classes of errors with type checking though!


Ultimately, Lunar adds a lot of stuff I like – I’ll probably use it eventually – but it’s still not clear to me what fixing a runtime error with Lunar looks like. Do I have to hunt and guess which Lunar line caused the error? Or does Lunar make sure to maintain the same line numbers? If not, are the line numbers really close together, or can they drift apart across a really long script that makes heavy use of Lunar’s additional syntax?

I’m guessing that the answers to those questions are, “Lunar does not maintain the same line numbers”, and “line numbers can drift apart across a really long script,” but I want to give you a chance to correct me and I want to provide feedback. I don’t think I’ll use Lunar until it’s easy to fix errors that occur during runtime.

Anyway, Lunar looks really cool so far! I’m excited to try it out someday!

For smaller scripts, usually yes. If your script gets lengthy and uses a lot of Lunar’s features, you’ll probably find yourself far off from the line where you declared something in Lunar.

Sadly, I’m not sure we’ll implement a way to congest Lunar’s additional features into one line. Currently, our configuration file is only applicable to the compiler itself, and doesn’t have any say in what to change while reading the Lunar code or what the Lua output is. We’re going to be improving this once we take a closer look at the compiler to add options such as initializing projects, and watch mode.

Absolutely. Right now, we’re focusing on people setting up their projects and actually writing code in Lunar, but we’ll definitely be looking into improving errors and general debugging.

When ran through Roblox, there are lines and stack traces usually, so if you look through what function or block of code an error is, you should be able to find where the error came from. It’s much easier if code is distributed through ModuleScripts, since they can sometimes be relatively small compared to much larger catch-all scripts.

Well, I have an example since we’ve bootstrapped Lunar entirely. Hopefully this can serve as an example of how it looks, and the similarities. Classes are a bit more extended out due to how it is writing them in Lua, sadly.

The lines of code are pretty similar despite a moderately lengthy script, but clearly it is lacking in style-awareness, generally because we ignore certain white-space characters such as new lines. This will be something that we will tackle once we’ve cleared up prioritized things.

Here's the Lexer written in Lunar

lunar/lunar/compiler/lexical/lexer.lunar at master · lunarlang/lunar · GitHub

And here's the Lexer when ran through Lunar

lunar/lib/lunar/compiler/lexical/lexer.lua at master · lunarlang/lunar · GitHub

1 Like