Skip to content

Instantly share code, notes, and snippets.

@thevurv
Last active April 9, 2025 03:33
Show Gist options
  • Save thevurv/ae6f6c0a80f30147d115d78753fc130f to your computer and use it in GitHub Desktop.
Save thevurv/ae6f6c0a80f30147d115d78753fc130f to your computer and use it in GitHub Desktop.
JS-style syntax for Lua.
---@class Class
---@overload fun(t: table): Class
---@field constructor function
---@field name string
---@field prototype table<string, any>
---@class StaticField
---@field name string
---@type table<string, Class>
local Classes = {}
---@type Class
local LastClassCreated
local DEFAULT_CONSTRUCTOR = function() end
local StaticMT = {}
---@class class
---@overload fun(name: string): Class
local class = setmetatable({}, {
__call = function(t, className)
local classToBuild = { constructor = DEFAULT_CONSTRUCTOR, name = className, prototype = {} }
getfenv(1)[className] = classToBuild
LastClassCreated = setmetatable(classToBuild, {
__call = function(t, classStructure)
for k, v in pairs(classStructure) do
if debug.getmetatable(k) == StaticMT then
classToBuild[k.name] = v
elseif k == "constructor" then
classToBuild[k] = v
else
classToBuild.prototype[k] = v
end
end
return classToBuild
end
})
Classes[className] = LastClassCreated
return LastClassCreated
end
})
---@class extends
---@overload fun(base: string): Class
local extends = setmetatable({}, {
__call = function(t, baseClassName)
local classToBuild = LastClassCreated
local baseClass = Classes[baseClassName]
if not baseClass then
error("Base class '" .. baseClassName .. "' not found.")
end
-- Set again, to allow extending even further.
LastClassCreated = setmetatable({}, {
__call = function(t, classStructure)
-- Inheritance
for k, v in pairs(baseClass.prototype) do
classToBuild.prototype[k] = v
end
for k, v in pairs(classStructure) do
if debug.getmetatable(k) == StaticMT then
classToBuild[k.name] = v
elseif k == "constructor" then
classToBuild[k] = setfenv(v, setmetatable({ super = baseClass.constructor }, { __index = _G, __newindex = _G }))
else
classToBuild.prototype[k] = v
end
end
return classToBuild
end
})
return LastClassCreated
end
})
---@class static
---@overload fun(name: string): StaticField
local static = setmetatable({}, {
__call = function(t, name)
return setmetatable({ field = true, name = name }, StaticMT)
end
})
---@class new
---@overload fun(name: string): table
local new = setmetatable({}, {
__call = function(t, name)
local class = Classes[name]
if not class then
error("Class '" .. name .. "' not found.")
end
local instance = setmetatable({}, { __index = class.prototype })
return function(...)
class.constructor(instance, ...)
return instance
end
end
})
--
local CurrentImport
---@param vars string[] | string
local function import(vars)
CurrentImport = vars
end
---@param moduleName string
local function from(moduleName)
if not CurrentImport then
error("import() must be called before from()")
end
local out = require(moduleName)
for _, v in ipairs(CurrentImport) do
getfenv(1)[v] = out[v]
end
CurrentImport = nil
end
local DeclaringConst = false
local ConstVariables = {}
local IsConstVariable = {}
local function const()
DeclaringConst = true
end
local ENV = {}
setmetatable(ENV, { __index = setmetatable(ConstVariables, { __index = _G }), __newindex = function(t, k, v)
if DeclaringConst then
IsConstVariable[k] = true
ConstVariables[k] = v
DeclaringConst = false
return
end
if IsConstVariable[k] then
error("Cannot reassign constant variable '" .. k .. "'", 2)
end
rawset(t, k, v)
end })
setfenv(1, ENV)
--
import { "foo", "bar", "baz" } from "imported";
const() x = 2;
x = 3;
class "Fruit" {
constructor = function(this)
print("Fruit constructor called")
end;
eat = function(this)
print("Eating fruit")
end;
}
class "Apple" extends "Fruit" {
[static "bar"] = function()
print("Static function here")
end;
baz = function(this)
print(this.a)
end;
constructor = function(this, a, b)
super(a, b)
this.a = a
this.b = b
end;
}
local myApple = new "Apple" (1, 2);
myApple:eat()
print(myApple:baz(), myApple.bar, Apple.bar)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment