Last active
April 9, 2025 03:33
-
-
Save thevurv/ae6f6c0a80f30147d115d78753fc130f to your computer and use it in GitHub Desktop.
JS-style syntax for Lua.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---@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