-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started
In order to run NGN, all that is needed is an environment capable of running Lua code. The main engine is written in standard Lua, with no external libraries necessary, but it can be run in any standard or non-standard Lua environment, provided the core functionality is unchanged.
NGN programs are, by default, structured similarly to Lua programs. This can be changed via modification or extension, but the standard setup is fairly simple.
NGN is not actually a full programming language - rather, it is an engine that can be used as the core for a programming language, with a sample set of rules, or framework, built around it. The stock framework is easy to learn and fairly multipurpose, but NGN's true strength is malleability; odds are, at some point, you will want to modify its behavior to suit your needs. The engine itself is under 100 lines long, and looks like this:
function ngn.tokenize(str)
str = str:gsub("%[#.-#%]", ""):gsub("##.-\n", "")
local t, r = "", ""
while #str > 0 do
for _, ct in ipairs(ngn.tokens) do
local s, e = str:find(ct[1])
if s == 1 then
t = t .. str:sub(s, e):gsub(ct[1], ct[2])
r = r .. ct[2]:gsub("%S?%%%d", "")
str = str:sub(e, -1)
break break
end
end
str = str:sub(2,-1)
end
return t, r
end
function ngn.compile(t, lvars)
local cs = ""
lvars = lvars or {}
while #t > 0 do
for _, r in ipairs(ngn.rules) do
local s, e = t:find(r[1])
if s == 1 then
local d = {t:match(r[1])}
cs = cs .. "{<" .. _ .. ">:"
for i, v in ipairs(d) do
cs = cs .. "["
if v:match("%b{}") == v then
local comp = ngn.compile(v:sub(2,-2), lvars)
comp = comp
:gsub("%b[]",function(r)return "@OBR;"..r:sub(2,-2).."@CBR;" end)
:gsub("%b{}",function(r)return "@OCB;"..r:sub(2,-2).."@CCB;" end)
or comp
cs = cs .. comp
else
cs = cs .. v
end
cs = cs .. "];"
end
cs = cs .. "};"
t = t:sub(e, -1)
break break
end
end
t = t:sub(2,-1)
end
return cs
end
function ngn.interpret(t, lvars)
lvars = lvars or {}
lvars.INTERP = true
while #t > 0 do
for _, r in ipairs(ngn.rules) do
local s, e = t:find(r[1])
if s == 1 then
r[2](lvars, t:match(r[1]))
t = t:sub(e, -1)
break break
end
end
t = t:sub(2,-1)
end
end
function ngn.run(t, lvars)
lvars = lvars or {}
for b in t:gmatch("%b{};") do
for r, a in b:gmatch("{(%b<>):(.-)};") do
local arg = {}
for ca in a:gmatch("(%b[]);") do
table.insert(arg, ca:sub(2,-2))
end
ngn.rules[tonumber(r:sub(2,-2))][2](lvars, table.unpack(arg))
end
end
end
It relies on various other items in the ngn table to dictate its top-level behavior - to modify the language syntax and rules, modify or add rules to ngn.rules and, if necessary, ngn.tokens. To modify the internal behavior of the language, you can modify the engine itself. The language is similar to a car - like most languages, it looks simple from the outside but the engine itself seems extremely complicated to a novice programmer. However, also like a car engine, the code at the core of NGN is fairly simply designed, and can be easily modified by a reasonably experienced coder.