Lua++ Making my own scripting language

:page_facing_up: In short, I’m making my own scripting language!

As a Roblox dev, I’m very used to Lua and it’s actually my favorite scripting language (yet). I am also a Minecraft dev, but the only language available is Java, and it’s not quite my type…
Well there is a plugin that makes you code more easily called Skript, but I don’t like it at all
Because of that, I decided to code my own language (that’s similar to Lua) in Java for a plugin that allows me to script the systems (instead of doing it in Java, like a normal plugin)
No, the name of the language is not Lua++, I haven’t decided yet

:moyai: Current status: Interpreted Scripting Language

:speech_balloon: Suggestions / Ideas are highly appreciated!

:gear: Here’s how it works (latest updates, this message will be edited)

// Comment
-> Comment
-- Comment

do -- you can have scope blocks like this if you want
    console("Epic World!")
end


-- VARIABLES
x -- global, nil by default
y = 5
local m1, m2, m3 = 1, 2 -- m3 is nil by default
local final f: nil, string -- nil by default
f = "final variable" -- if final variable is nil (has not been set yet) you can still set it later
local ternary = true and 5 or 3 -- gets 5
local anotherTernary = false or nil or 5 or 10 -- gets 5

x = y = 2 -- chain assignment, translated to x = (y = 5)
x++*/ -- chain operators, translated to x = ((x+1+1)^2)/2 so 8



-- FUNCTIONS
local function lol(arg1, arg2: number = 5) -- params can be separated by , or ; (new line)
    console(arg1, arg2)               -- default param is set by an =, and its set if its not sent
end
lol(2) -- arg2 will be 5 by default
lol(2, nil) -- arg2 will be nil

local final div = function(x: number; y: number = 2)
    return x / y                 -- separated by ; else it will take y as a type
end

local function print(final args...: string) -- variadic function
    for k, v in args do     -- its just like a normal parameter, only it has the ... suffix
        console("[" + k + "] = " + v)
    end
end



-- LOOPS + IF
if true then console(true) end
for i=1, 10 do console(i) end
for i=1, 10, 2 do console(i) end
while true do break end
do break while true



-- ASYNC
-- Runs in another thread
async for i=1, 10 do console(i) end
async lol()
async do console("async") end


-- TABLES
local tbl: {} = {
    3, 4, 5 -- by default it starts indexing at [1]
    msg = "hi" -- separate either by , or ; (which is a new line)
    local x: bool = true
    meh = function() console("meh") end
    epic = function() console(self) end
}
local strictTable: {number, {string}} = {1, 2, 3, {"lol"}}
console(tbl[2]) -- 4
console(tbl.msg) -- hi
console(#tbl) -- 7 (lengthOf can be applied to strings also)
tbl.meh() -- meh
tbl:meh() -- meh
tbl.epic() -- nil
tbl:epic() -- <tbl>
  -- so by calling a function using : it will automatically set self to be that table
for k, v in tbl do -- for-each loop, used for tables (the value is optional)
    console("[" + k + "] = " + v)
end
3 Likes

This doesn’t help us, so please move your topic over to #help-and-feedback:creations-feedback

I will make it free, so you can also develop on minecraft using this language if you want

1 Like

Is it a interpreted language or compiled?

Right now it’s interpreted. After I finish the interpreter fully, then I’ll work on compiler (for efficiency)

This just seems like an overly complicated solution to a problem which is easily solved by just learning Java.

Also, how does your idea compare to something like this?

1 Like

I wont use mods on the server (Paper Server), and it’s just fun to make my own language also I guess

1 Like

In what language is it written?

I hope not assembly :pray::sob:

Java, since atm you can only make plugins writtien in Java, so I’m making a plugin that is basically this language

1 Like

technically java is interpreted,

.java files are translated into .class files by the java compiler, which is bytecode. So I guess lua++ being interpreted would mean it is read by a java lua++ parser?, while lua++ being compiled would mean it is read by the java virtual machine directly?

Yeah I’m not sure, I didn’t look into how it’s done yet. I’ll do it after I finish the interpreter

1 Like

Variadic Functions

  • This was a bit annoying to add, but we have it:
local function div(x: number; y: number; final args...: string) -- just like a normal param, only with ...
    for k, v in args do console("[" + k + "] = " + v) end
    return x / y
end
div(4, 2, "yey", "lol", "epic is hot")

Here some suggestions:

  • Manual garbage collection functions
  • :coefficients:

So self is defined by default no matter the context?

You did

{
  epic = function() print(self) end
}

In lua, the lack of self argument makes it so that self is not a locally defined variable in the context of the function. Is this voluntary?

self is automatically sent as the first argument in a function, so it exists no matter what.

local function lol(x: number)
    console(self, x)
end
-- translated as
local function lol(self, x: number)
    console(self, x)
end

lol(5)
-- translated to
lol(nil, 5)

Well, this works as well

local function test()
  print(x)
end

test()

This has to do with how globals are referenced & interpreted if non existent in environment.

This is an example:

self = 2

local function test()
	print(self) --outputs 2
end

local function test2(self)
    print(self) --outputs nil
end

test()
test2()

Self in function context doesn’t mean anything. If you define a function like so, part of a table:

local t = {}

function t.test()
    print(self) --outputs variable value of upper scope // global scope

   local self = 2 --You can redefine self yourself
end

This writing is the same as

local t = {
  test = function() ... end
}

However when you write

local t = {}

function t:test()
  print(self) --ouputs parameter self, which is here inferred

  local self = 2 --Cannot redefine as self exists as 1st param
end

Equivalent to

local t = {
  test = function(self) ... end
}

I didn’t think about defining scope outside, I’ll handle that also…

It’s mostly because the example you provided demonstrates that self is nil, it’s mostly because it’s undefined in global scope, not because it is defined as 1st silent param. I just tested that out on luau-lang to be sure about that

Another example being

function k(x)
  print(x)
end

local t = {
  k = k
}

t.k(1) --outputs 1
t:k(1) --outputs table0x<@>

Param shifting only occurs whenever you use : on a table to get a function address, and then run the function. All params will be shifted to the right & the table address passed as 1st one
So actually, self is just a fancy keyword, you can see that x became self in my upper example

Right now I’m working on tables, and they will be a bit different from the normal Lua tables, and then I’ll improve the self keyword also, maybe I’ll find more usages for it

1 Like

I may have missed this information, but out of curiosity, which tools are you using to syntaxic analysis? And yes ! It’s a great thing to make your own project & establish a language :slight_smile:

I actually had to do it this year as a project, we used LR analysis with Lex&Yacc, only for the syntaxic part though, not for stack & memory management