This commit is contained in:
2026-03-29 11:46:50 +01:00
parent e6f3b5c77f
commit 7aa282b405
8 changed files with 175 additions and 102 deletions

View File

@@ -66,6 +66,12 @@ function indices(t)
return indices
end
function map(t,func)
for index,item in pairs(t) do
t[index] = func(index,item)
end
end
-- Ensures a table has a metatable
function ensure_metatable(t)
local meta = getmetatable(t)

View File

@@ -1,3 +1,8 @@
out "huh?";
// proto:
(FUCK!)
// single line comment
log "a";
/*
multi
line
comment
*/
log "b";

View File

@@ -1,15 +1,15 @@
local path = ...
require("nellie.proto")
function Run(args)
function Run(...)
-- Take arguments as neli files to read and interpret
local root = Chain(
string.format(
"in cmd 'nelli {%s}'",
table.concat(args,";")
table.concat({...},";")
)
)
for _,parameter in pairs(args) do
for _,parameter in pairs({...}) do
local chain = Chain(
string.format("in 'call: root' @'%s'",parameter)
):from(root)

View File

@@ -339,9 +339,6 @@ function Scope:run(expression,chain,original)
)
,2)
else
for index,item in pairs(binds) do
print("index:",index,"item:",item)
end
if not binding then error("No binding") end -- todo: improve error
return binding:call(
original,

View File

@@ -72,6 +72,7 @@ end
-- From a table of actions of patterns,
-- consume the earliest pattern (index)
-- and call the value
local NONE = {}
function Consumer:consumePatterns(patterns,state)
-- t: {string = function...}
assert_type("table")(patterns,"Arg 't' #1: %s")
@@ -84,31 +85,37 @@ function Consumer:consumePatterns(patterns,state)
end
local origin = self.range.first or 1
-- Get the next earliest match
local findex,ffinal,fpattern,ffunc,fexcess -- TODO: make this not be a bunch of locals. New class?
local callback = nil
local earliest = {}
--local findex,ffinal,fpattern,ffunc,fexcess -- TODO: make this not be a bunch of locals. New class?
for pattern,new_func in pairs(patterns) do
local new_index,new_final = self.range:find(pattern)
if new_index and
((not findex) or (findex > new_index))
((not earliest.index) or (earliest.index > new_index))
then
if not new_index then return end
findex = new_index
ffinal = new_final
fpattern = pattern
ffunc = new_func
fexcess = self.range.reader:get(
if not new_index then return end -- (later:) what why?
earliest.index = new_index
earliest.final = new_final
earliest.pattern = pattern
callback = new_func
earliest.excess = self.range.reader:get(
self.range.first or 1,
new_final - 1
earliest.index - 1
)
end
end
-- Pass into the func
if not ffunc then
if not callback then
if patterns[NONE] then
return patterns[NONE]()
end
return nil
end
assert(findex) assert(ffinal)
self.range:move(ffinal+1) -- Move range to after the match
local fmatch = self.range.reader:match(fpattern,findex)
-- Pass back consumed result to
assert(earliest.index) assert(earliest.final)
self.range:move(earliest.final+1) -- Move range to after the match
local fmatch = self.range.reader:match(earliest.pattern,earliest.final)
-- This seems to be broken:
local sum = self.range.reader:get(origin+1,self.range.first)
:gsub("\r\n","\n")
:gsub("\r","\n")
@@ -120,7 +127,7 @@ function Consumer:consumePatterns(patterns,state)
self.col = self.col + 1
end
end
return ffunc(fexcess,fmatch,state)
return callback(earliest,state)
end
-- Interpret some text
@@ -164,37 +171,96 @@ function Parse(content,uri,chain)
patterns.uriClose = ">"
patterns.singleLineComment = "//"
patterns.multiLineCommentOpen = "/%*"
patterns.multiLineCommentOpen = "%*/"
patterns.multiLineCommentClose = "%*/"
patterns.colonSyntax = ":"
-- TODO: I don't like that this structure does: open(stuff;close) instead of open(stuff)close
-- TODO: current:insert() is repeated in EVERY meal. I wonder if this should be fixed -__-
local expressionMeals = {
[patterns.singleLineString] = function(words,_,current)
current:insert(words,consumer:consumePatterns({
-- Give me: {patterns that take (match,state)}, the state, and a handler for comments
-- I will give you a function that will return the result of consumePatterns(patterns)
-- With escapes handled.
local function makeConsumerEscaping(patterns,state,handler)
return function()
handler = handler or function() end
local escaped = true
local function escape() escaped = true end
while escaped do
escaped = false
consumer:consumePatterns(union({
[patterns.singleLineComment] = function(...)
handler(...)
consumer:consumePatterns({
[patterns.newLine] = escape
})
end,
[patterns.multiLineCommentOpen] = function(...)
handler(...)
consumer:consumePatterns({
[NONE] = error,
[patterns.multiLineCommentClose] = escape
})
end,
},patterns),state)
end
end
end
-- Give me {patterns that take (match,current)} and current (expression)
local function makeConsumerAppending(patterns,state)
local appendingPatterns = map(patterns,function(func)
return function(match,current)
current:insert(match.excess,func(match,current))
end
end)
makeConsumerEscaping(appendingPatterns,function(match,current)
current:insert(match.excess)
end)
end
local function makeConsumerExpressive()
local function consumeSingleLineString()
return
end
local function consumeNamed()
end
local function consumeMultiLineString()
end
local function consumeURI()
end
return makeConsumerAppending({
[patterns.singleLineString] = function(match,current)
return consumer:consumePatterns({
["[\n\r]"] = function()
error("Incomplete string literal")
end,
[patterns.singleLineString] = function(words,_)
return expression({"text",Expression({words})})
end
}))
})
end,
[patterns.named] = function(words,_,current)
current:insert(words,consumer:consumePatterns({
current:insert(words,consumePatternsEscaping({
[patterns.named] = function(words,_)
return expression({"the",Expression({words})})
end
}))
end,
[patterns.multiLineStringOpen] = function(words,_,current)
current:insert(words,consumer:consumePatterns({
["[\n\r]"] = function()
error("Incomplete string literal")
[patterns.multiLineStringOpen] = function(match,current)
return consumer:consumePatterns({
[patterns.multiLineStringClose] = function(words,_)
return expression({"text",Expression({words})})
end
})
end,
[patterns.multiLineStringOpen] = function(words,_,current)
current:insert(words,consumePatternsEscaping({
[patterns.multiLineStringClose] = function(words,_)
return expression({"text",Expression({words})})
end
}))
end,
[patterns.uriOpen] = function(words,_,current)
current:insert(words,consumer:consumePatterns({
current:insert()
current:insert(words,consumePatternsEscaping({
["[\n\r]"] = function()
current:error("Incomplete URI literal")
end,
@@ -203,28 +269,21 @@ function Parse(content,uri,chain)
end
}))
end,
[patterns.expressionOpen] = function(words,_,current)
current:insert(words,consumeExpression())
[patterns.expressionOpen] = function(match,current)
return consumeExpression()
end,
[patterns.colonSyntax] = function(match,current)
return consumeExpression()
end,
[patterns.blockOpen] = function(match,current)
return consumeBlock()
end,
[patterns.singleLineComment] = function(words,_,current)
--current:insert(words) -- Consume what was left
consumer:consumePatterns({
[patterns.newLine] = function() end
})
end,
[patterns.multiLineCommentOpen] = function(words,_,current)
current:insert(words)
consumer:consumePatterns({
[patterns.multiLineCommentClose] = function() end
})
end,
[patterns.colonSyntax] = function(words,_,current)
current:insert(words,consumeExpression())
end,
[patterns.blockOpen] = function(words,_,current)
current:insert(words,consumeBlock())
end,
}
end
local function consumePatternsExpressive(patterns,current)
return consumePatternsEscaping
end
-- Consume a {} block of code
function consumeBlock(closing_pattern)
closing_pattern = closing_pattern or patterns.blockClose
@@ -233,7 +292,7 @@ function Parse(content,uri,chain)
local loop = true
while loop do
local remaining = consumer:remaining()
local expr = consumer:consumePatterns(union(expressionMeals,{
local expr = consumePatternsEscaping(union(expressionMeals,{
[patterns.blockDelimiter] = function(words,_)
current:insert(words)
if current:empty() then
@@ -261,7 +320,7 @@ function Parse(content,uri,chain)
local loop = true
while loop do
local remaining = consumer:remaining()
local expr = consumer:consumePatterns(union(expressionMeals,{
local expr = consumePatternsEscaping(union(expressionMeals,{
[patterns.expressionClose] = function(words,_,_current)
current:insert(words)
loop = false

View File

@@ -2,7 +2,7 @@
require("nellie.parser")
function Bind(scope,abstract,callback)
for _,expression in pairs(Parse(abstract)) do
for _,expression in pairs(Parse(abstract).items) do
assert_meta(Expression)(expression)
scope:insert(Binding(
expression,
@@ -21,7 +21,7 @@ end
function Do(scope,expression,chain,name)
local latest
for index,item in pairs(expression.items) do
latest = Run(scope,item,chain,"do: "+tostring(index))
latest = Run(scope,item,chain,"do: "..tostring(index))
end
return latest
end
@@ -283,23 +283,24 @@ Bind(ns,"let ((named (name)) be (value))",function(s,e,c) end)
Bind(ns,"new table",function(s,e,c) return {} end)
]]
Bind(ns,"(closed)",function(s,e,c) return Run(s,e.closed,c,"(...)") end)
Bind(ns,"text (text)",function(s,e,c) return e.text:text() end)
Bind(ns,"(closed)",function(s,e,c) print(e.closed) return Run(s,e.closed,c,"(...)") end)
Bind(ns,"log (text)",function(s,e,c) log(Run(s,e.text,c,"print: text")) end)
Bind(ns,"this scope",function(s,e,c) return s end)
Bind(ns,"new scope",function(s,e,c) return Scope() end) -- TODO: chains?!!?
Bind(ns,"index (table) with (key)",function(s,e,c) return Run(s,e,c,"") end)
Bind(ns,[[
(input) means do (output);
(input) in (input_scope) means do (output);
(input) means (output);
(input) in (input_scope) means (output);
(input) means do (output) in (output_scope);
(input) in (input_scope) means do (output) in (output_scope)
]],function(s,e,c1) -- A substitution
local input_scope = s
if e.input_scope then input_scope = Run(s,e.input_scope,c1,"means: input scope") end
local output_scope = s
if e.output_scope then output_scope = Run(s,e.output_scope,c2,"means: output scope") end
Bind(e.input_scope,e.input,function(s,e,c2)
return Do(e.output_scope,e.output,c2) -- TODO: chains?!
(input) in (input_scope) means (output) in (output_scope)
]],function(s1,e1,c1) -- A substitution
local input_scope = s1
if e1.input_scope then input_scope = Run(s1,e1.input_scope,c1,"means: input scope") end
local output_scope = s1
if e1.output_scope then output_scope = Run(s1,e1.output_scope,c1,"means: output scope") end
Bind(input_scope,e1.input,function(s2,e2,c2)
return Do(output_scope,e1.output,c2) -- TODO: chains?!
end)
end)
Bind(ns,"do (stuff) in (scope); do (stuff)",function(s,e,c)
@@ -311,7 +312,8 @@ Bind(ns,"new table",function(s,e,c) return {} end)
local Hpath = "nellie/helper.nel"
local Hchain = Chain("in internal: "..Hpath)
local success,result = Hchain:call(function(chain)
Run(NelliScope,Parse(read(Hpath),Hpath,chain),chain)
print(Parse(read(Hpath),Hpath,chain))
Do(NelliScope,Parse(read(Hpath),Hpath,chain),chain)
end)
--[[ Documentation:

2
run.sh
View File

@@ -4,5 +4,5 @@ then
echo "lua could not be found"
exit 1
else
lua -i -v -W -l nellie -e Run "$@"
lua -l nellie -e "Run'$@'"
fi

View File

@@ -3,3 +3,7 @@ local function test(file,result)
end
test("print.nel",[[hello world!]])
do
end