mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-28 09:09:31 +00:00
Add text buffer syntax
This commit is contained in:
parent
ccaa40a99d
commit
e9606cdee0
13 changed files with 345 additions and 145 deletions
10
LANGUAGE.md
10
LANGUAGE.md
|
|
@ -635,6 +635,8 @@ Default types are:
|
||||||
|
|
||||||
* `object`: an object/record. Mutable. Can be created by calling a class function.
|
* `object`: an object/record. Mutable. Can be created by calling a class function.
|
||||||
|
|
||||||
|
* `event buffer`: an [event buffer](#event-buffer). Can be created using `%[text]`, where text is interpreted the same way as a text line (so you can perform interpolation, subtexts, add tags, etc.). Note that this only allows for text and flush events; if the text emit choices and custom events an error will be raised.
|
||||||
|
|
||||||
Every type is immutable, except `list`, `map` and `object`.
|
Every type is immutable, except `list`, `map` and `object`.
|
||||||
|
|
||||||
How conversions are handled from Anselme to Lua:
|
How conversions are handled from Anselme to Lua:
|
||||||
|
|
@ -645,11 +647,17 @@ How conversions are handled from Anselme to Lua:
|
||||||
|
|
||||||
* `string` -> `string`
|
* `string` -> `string`
|
||||||
|
|
||||||
|
* `pair` -> `table`, with a single key-value pair.
|
||||||
|
|
||||||
|
* `annotated` -> the annotated value (the annotation is stripped)
|
||||||
|
|
||||||
* `list` -> `table` (purely sequential table).
|
* `list` -> `table` (purely sequential table).
|
||||||
|
|
||||||
* `map` -> `table` (will map each key to a key in the Lua table).
|
* `map` -> `table` (will map each key to a key in the Lua table).
|
||||||
|
|
||||||
* `pair` -> `table`, with a single key-value pair.
|
* `object` -> `table` (containing each object and class property and its value)
|
||||||
|
|
||||||
|
* `event buffer` -> `table` (a list of events where each event is a list of two elements (event type and its eventual data), like `{ { "text", text = { { tags = {...}, text = "hello" } } }, { "flush" }, ... }`)
|
||||||
|
|
||||||
How conservions are handled from Lua to Anselme:
|
How conservions are handled from Lua to Anselme:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -250,7 +250,7 @@ local interpreter_methods = {
|
||||||
if re then coroutine.yield("error", re) end
|
if re then coroutine.yield("error", re) end
|
||||||
if rf then r = rf end
|
if rf then r = rf end
|
||||||
end
|
end
|
||||||
return to_lua(r)
|
return to_lua(r, self.state)
|
||||||
end,
|
end,
|
||||||
--- Evaluate an expression (string) or block, optionally in a specific namespace (string, will use root namespace if not specified).
|
--- Evaluate an expression (string) or block, optionally in a specific namespace (string, will use root namespace if not specified).
|
||||||
-- The expression can't yield events.
|
-- The expression can't yield events.
|
||||||
|
|
@ -292,7 +292,7 @@ local interpreter_methods = {
|
||||||
elseif event ~= "return" then
|
elseif event ~= "return" then
|
||||||
return nil, ("evaluated expression generated an %q event; at %s"):format(event, self.state.interpreter.running_line.source)
|
return nil, ("evaluated expression generated an %q event; at %s"):format(event, self.state.interpreter.running_line.source)
|
||||||
else
|
else
|
||||||
return to_lua(data)
|
return to_lua(data, self.state)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
@ -730,7 +730,7 @@ local vm_mt = {
|
||||||
if not interpreter then return interpreter, err end
|
if not interpreter then return interpreter, err end
|
||||||
local r, e = interpreter:eval(expr, namespace)
|
local r, e = interpreter:eval(expr, namespace)
|
||||||
if e then return r, e end
|
if e then return r, e end
|
||||||
assert(interpreter:step() == "return") -- trigger merge / end-of-script things
|
assert(interpreter:step() == "return", "evaluated expression can not emit events") -- trigger merge / end-of-script things
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,49 +5,6 @@ local common
|
||||||
local identifier_pattern
|
local identifier_pattern
|
||||||
local copy
|
local copy
|
||||||
|
|
||||||
--- copy some text & process it to be suited to be sent to Lua in an event
|
|
||||||
local function post_process_text(state, text)
|
|
||||||
local r = {}
|
|
||||||
-- copy into r & convert tags to lua
|
|
||||||
for _, t in ipairs(text) do
|
|
||||||
local tags = common.to_lua(t.tags)
|
|
||||||
if state.interpreter.base_lua_tags then
|
|
||||||
for k, v in pairs(state.interpreter.base_lua_tags) do
|
|
||||||
if tags[k] == nil then tags[k] = v end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.insert(r, {
|
|
||||||
text = t.text,
|
|
||||||
tags = tags
|
|
||||||
})
|
|
||||||
end
|
|
||||||
-- remove trailing spaces
|
|
||||||
if state.feature_flags["strip trailing spaces"] then
|
|
||||||
local final = r[#r]
|
|
||||||
if final then
|
|
||||||
final.text = final.text:match("^(.-) *$")
|
|
||||||
if final.text == "" then
|
|
||||||
table.remove(r)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- remove duplicate spaces
|
|
||||||
if state.feature_flags["strip duplicate spaces"] then
|
|
||||||
for i=1, #r-1 do
|
|
||||||
local a, b = r[i], r[i+1]
|
|
||||||
local na = #a.text:match(" *$")
|
|
||||||
local nb = #b.text:match("^ *")
|
|
||||||
if na > 0 and nb > 0 then -- remove duplicated spaces from second element first
|
|
||||||
b.text = b.text:match("^ *(.-)$")
|
|
||||||
end
|
|
||||||
if na > 1 then
|
|
||||||
a.text = a.text:match("^(.- ) *$")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return r
|
|
||||||
end
|
|
||||||
|
|
||||||
local function random_identifier()
|
local function random_identifier()
|
||||||
local r = ""
|
local r = ""
|
||||||
for _=1, 16 do -- that's live 10^31 possibilities, ought to be enough for anyone
|
for _=1, 16 do -- that's live 10^31 possibilities, ought to be enough for anyone
|
||||||
|
|
@ -383,9 +340,9 @@ common = {
|
||||||
--- convert anselme value to lua
|
--- convert anselme value to lua
|
||||||
-- lua value: if success (may be nil!)
|
-- lua value: if success (may be nil!)
|
||||||
-- nil, err: if error
|
-- nil, err: if error
|
||||||
to_lua = function(val)
|
to_lua = function(val, state)
|
||||||
if atypes[val.type] and atypes[val.type].to_lua then
|
if atypes[val.type] and atypes[val.type].to_lua then
|
||||||
return atypes[val.type].to_lua(val.value)
|
return atypes[val.type].to_lua(val.value, state)
|
||||||
else
|
else
|
||||||
return nil, ("no Lua exporter for type %q"):format(val.type)
|
return nil, ("no Lua exporter for type %q"):format(val.type)
|
||||||
end
|
end
|
||||||
|
|
@ -598,14 +555,14 @@ common = {
|
||||||
local choices
|
local choices
|
||||||
-- copy & process text buffer
|
-- copy & process text buffer
|
||||||
if type == "text" then
|
if type == "text" then
|
||||||
buffer = post_process_text(state, event.value)
|
buffer = common.post_process_text(state, event.value)
|
||||||
-- copy & process choice buffer
|
-- copy & process choice buffer
|
||||||
elseif type == "choice" then
|
elseif type == "choice" then
|
||||||
-- copy & process choice text content into buffer, and needed private state into choices for each choice
|
-- copy & process choice text content into buffer, and needed private state into choices for each choice
|
||||||
buffer = {}
|
buffer = {}
|
||||||
choices = {}
|
choices = {}
|
||||||
for _, c in ipairs(event.value) do
|
for _, c in ipairs(event.value) do
|
||||||
table.insert(buffer, post_process_text(state, c))
|
table.insert(buffer, common.post_process_text(state, c))
|
||||||
table.insert(choices, c._state)
|
table.insert(choices, c._state)
|
||||||
end
|
end
|
||||||
-- discard empty choices
|
-- discard empty choices
|
||||||
|
|
@ -647,7 +604,49 @@ common = {
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
}
|
},
|
||||||
|
--- copy some text & process it to be suited to be sent to Lua in an event
|
||||||
|
post_process_text = function(state, text)
|
||||||
|
local r = {}
|
||||||
|
-- copy into r & convert tags to lua
|
||||||
|
for _, t in ipairs(text) do
|
||||||
|
local tags = common.to_lua(t.tags, state)
|
||||||
|
if state.interpreter.base_lua_tags then
|
||||||
|
for k, v in pairs(state.interpreter.base_lua_tags) do
|
||||||
|
if tags[k] == nil then tags[k] = v end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(r, {
|
||||||
|
text = t.text,
|
||||||
|
tags = tags
|
||||||
|
})
|
||||||
|
end
|
||||||
|
-- remove trailing spaces
|
||||||
|
if state.feature_flags["strip trailing spaces"] then
|
||||||
|
local final = r[#r]
|
||||||
|
if final then
|
||||||
|
final.text = final.text:match("^(.-) *$")
|
||||||
|
if final.text == "" then
|
||||||
|
table.remove(r)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- remove duplicate spaces
|
||||||
|
if state.feature_flags["strip duplicate spaces"] then
|
||||||
|
for i=1, #r-1 do
|
||||||
|
local a, b = r[i], r[i+1]
|
||||||
|
local na = #a.text:match(" *$")
|
||||||
|
local nb = #b.text:match("^ *")
|
||||||
|
if na > 0 and nb > 0 then -- remove duplicated spaces from second element first
|
||||||
|
b.text = b.text:match("^ *(.-)$")
|
||||||
|
end
|
||||||
|
if na > 1 then
|
||||||
|
a.text = a.text:match("^(.- ) *$")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
package.loaded[...] = common
|
package.loaded[...] = common
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,33 @@ local function eval(state, exp)
|
||||||
type = "string",
|
type = "string",
|
||||||
value = t
|
value = t
|
||||||
}
|
}
|
||||||
|
-- text buffer
|
||||||
|
elseif exp.type == "text buffer" then
|
||||||
|
-- eval text expression
|
||||||
|
local v, e = eval(state, exp.text)
|
||||||
|
if not v then return v, e end
|
||||||
|
local l = v.type == "list" and v.value or { v }
|
||||||
|
-- write resulting buffers (plural if loop in text expression) into a single result buffer
|
||||||
|
local buffer = {}
|
||||||
|
for _, item in ipairs(l) do
|
||||||
|
if item.type == "event buffer" then
|
||||||
|
for _, event in ipairs(item.value) do
|
||||||
|
if event.type ~= "text" and event.type ~= "flush" then
|
||||||
|
return nil, ("event %q can't be captured in a text buffer"):format(event.type)
|
||||||
|
end
|
||||||
|
table.insert(buffer, event)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
type = "event buffer",
|
||||||
|
value = buffer
|
||||||
|
}
|
||||||
-- parentheses
|
-- parentheses
|
||||||
elseif exp.type == "parentheses" then
|
elseif exp.type == "parentheses" then
|
||||||
return eval(state, exp.expression)
|
return eval(state, exp.expression)
|
||||||
-- list defined in brackets
|
-- list defined in brackets
|
||||||
elseif exp.type == "list_brackets" then
|
elseif exp.type == "list brackets" then
|
||||||
if exp.expression then
|
if exp.expression then
|
||||||
local v, e = eval(state, exp.expression)
|
local v, e = eval(state, exp.expression)
|
||||||
if not v then return nil, e end
|
if not v then return nil, e end
|
||||||
|
|
@ -53,9 +75,9 @@ local function eval(state, exp)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
-- map defined in brackets
|
-- map defined in brackets
|
||||||
elseif exp.type == "map_brackets" then
|
elseif exp.type == "map brackets" then
|
||||||
-- get constructing list
|
-- get constructing list
|
||||||
local list, e = eval(state, { type = "list_brackets", expression = exp.expression })
|
local list, e = eval(state, { type = "list brackets", expression = exp.expression })
|
||||||
if not list then return nil, e end
|
if not list then return nil, e end
|
||||||
-- make map
|
-- make map
|
||||||
local map = {}
|
local map = {}
|
||||||
|
|
@ -166,7 +188,7 @@ local function eval(state, exp)
|
||||||
}
|
}
|
||||||
-- tag
|
-- tag
|
||||||
elseif exp.type == "#" then
|
elseif exp.type == "#" then
|
||||||
local right, righte = eval(state, { type = "map_brackets", expression = exp.right })
|
local right, righte = eval(state, { type = "map brackets", expression = exp.right })
|
||||||
if not right then return nil, righte end
|
if not right then return nil, righte end
|
||||||
tags:push(state, right)
|
tags:push(state, right)
|
||||||
local left, lefte = eval(state, exp.left)
|
local left, lefte = eval(state, exp.left)
|
||||||
|
|
@ -202,7 +224,7 @@ local function eval(state, exp)
|
||||||
end
|
end
|
||||||
-- function
|
-- function
|
||||||
elseif exp.type == "function call" then
|
elseif exp.type == "function call" then
|
||||||
-- eval args: map_brackets
|
-- eval args: map brackets
|
||||||
local args = {}
|
local args = {}
|
||||||
local last_contiguous_positional = 0
|
local last_contiguous_positional = 0
|
||||||
if exp.argument then
|
if exp.argument then
|
||||||
|
|
@ -444,7 +466,7 @@ local function eval(state, exp)
|
||||||
elseif lua_fn.mode == nil then
|
elseif lua_fn.mode == nil then
|
||||||
local l_lua = {}
|
local l_lua = {}
|
||||||
for _, v in ipairs(final_args) do
|
for _, v in ipairs(final_args) do
|
||||||
local lv, e = to_lua(v)
|
local lv, e = to_lua(v, state)
|
||||||
if e then return nil, e end
|
if e then return nil, e end
|
||||||
table.insert(l_lua, lv)
|
table.insert(l_lua, lv)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,7 @@ common = {
|
||||||
implicit_call = implicit_call, -- was call implicitely (no ! or parentheses)?
|
implicit_call = implicit_call, -- was call implicitely (no ! or parentheses)?
|
||||||
variants = variants, -- list of potential variants
|
variants = variants, -- list of potential variants
|
||||||
argument = { -- wrap everything in a list literal to simplify later things (otherwise may be nil, single value, list constructor)
|
argument = { -- wrap everything in a list literal to simplify later things (otherwise may be nil, single value, list constructor)
|
||||||
type = "map_brackets",
|
type = "map brackets",
|
||||||
expression = arg
|
expression = arg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,15 @@ local function expression(s, state, namespace, current_priority, operating_on)
|
||||||
local l, e = parse_text(d, state, namespace, "string") -- parse interpolated expressions
|
local l, e = parse_text(d, state, namespace, "string") -- parse interpolated expressions
|
||||||
if not l then return l, e end
|
if not l then return l, e end
|
||||||
return expression(r, state, namespace, current_priority, l)
|
return expression(r, state, namespace, current_priority, l)
|
||||||
|
-- text buffer
|
||||||
|
elseif s:match("^%%%[") then
|
||||||
|
local text = s:match("^%%(.*)$")
|
||||||
|
local v, r = parse_text(text, state, namespace, "text", "#~", true)
|
||||||
|
if not v then return nil, r end
|
||||||
|
return expression(r, state, namespace, current_priority, {
|
||||||
|
type = "text buffer",
|
||||||
|
text = v
|
||||||
|
})
|
||||||
-- paranthesis
|
-- paranthesis
|
||||||
elseif s:match("^%b()") then
|
elseif s:match("^%b()") then
|
||||||
local content, r = s:match("^(%b())(.*)$")
|
local content, r = s:match("^(%b())(.*)$")
|
||||||
|
|
@ -134,7 +143,7 @@ local function expression(s, state, namespace, current_priority, operating_on)
|
||||||
if r_paren:match("[^%s]") then return nil, ("unexpected %q at end of list parenthesis expression"):format(r_paren) end
|
if r_paren:match("[^%s]") then return nil, ("unexpected %q at end of list parenthesis expression"):format(r_paren) end
|
||||||
end
|
end
|
||||||
return expression(r, state, namespace, current_priority, {
|
return expression(r, state, namespace, current_priority, {
|
||||||
type = "list_brackets",
|
type = "list brackets",
|
||||||
expression = exp
|
expression = exp
|
||||||
})
|
})
|
||||||
-- map parenthesis
|
-- map parenthesis
|
||||||
|
|
@ -149,7 +158,7 @@ local function expression(s, state, namespace, current_priority, operating_on)
|
||||||
if r_paren:match("[^%s]") then return nil, ("unexpected %q at end of map parenthesis expression"):format(r_paren) end
|
if r_paren:match("[^%s]") then return nil, ("unexpected %q at end of map parenthesis expression"):format(r_paren) end
|
||||||
end
|
end
|
||||||
return expression(r, state, namespace, current_priority, {
|
return expression(r, state, namespace, current_priority, {
|
||||||
type = "map_brackets",
|
type = "map brackets",
|
||||||
expression = exp
|
expression = exp
|
||||||
})
|
})
|
||||||
-- identifier
|
-- identifier
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,16 @@ local function parse(state)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- get list of properties
|
||||||
|
-- (unlike scoped, does not includes subnamespaces)
|
||||||
|
if line.properties then
|
||||||
|
line.properties = {}
|
||||||
|
for name in pairs(state.variables) do
|
||||||
|
if name:sub(1, #namespace) == namespace and not name:sub(#namespace+1):match("%.") then
|
||||||
|
table.insert(line.properties, name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
-- expressions
|
-- expressions
|
||||||
if line.expression then
|
if line.expression then
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,7 @@ local function parse_line(line, state, namespace, parent_function)
|
||||||
elseif lr:match("^%%") then
|
elseif lr:match("^%%") then
|
||||||
r.subtype = "class"
|
r.subtype = "class"
|
||||||
r.resume_boundary = true
|
r.resume_boundary = true
|
||||||
|
r.properties = true
|
||||||
allow_params = false
|
allow_params = false
|
||||||
allow_assign = false
|
allow_assign = false
|
||||||
elseif lr:match("^%!") then
|
elseif lr:match("^%!") then
|
||||||
|
|
|
||||||
228
stdlib/types.lua
228
stdlib/types.lua
|
|
@ -1,4 +1,4 @@
|
||||||
local format, to_lua, from_lua, events, anselme, escape, hash, mark_constant, update_hashes
|
local format, to_lua, from_lua, events, anselme, escape, hash, mark_constant, update_hashes, get_variable, find_function_variant_from_fqm, post_process_text
|
||||||
|
|
||||||
local types = {}
|
local types = {}
|
||||||
types.lua = {
|
types.lua = {
|
||||||
|
|
@ -114,6 +114,58 @@ types.anselme = {
|
||||||
end,
|
end,
|
||||||
mark_constant = function() end,
|
mark_constant = function() end,
|
||||||
},
|
},
|
||||||
|
pair = {
|
||||||
|
format = function(val)
|
||||||
|
local k, ke = format(val[1])
|
||||||
|
if not k then return k, ke end
|
||||||
|
local v, ve = format(val[2])
|
||||||
|
if not v then return v, ve end
|
||||||
|
return ("%s=%s"):format(k, v)
|
||||||
|
end,
|
||||||
|
to_lua = function(val, state)
|
||||||
|
local k, ke = to_lua(val[1], state)
|
||||||
|
if ke then return nil, ke end
|
||||||
|
local v, ve = to_lua(val[2], state)
|
||||||
|
if ve then return nil, ve end
|
||||||
|
return { [k] = v }
|
||||||
|
end,
|
||||||
|
hash = function(val)
|
||||||
|
local k, ke = hash(val[1])
|
||||||
|
if not k then return k, ke end
|
||||||
|
local v, ve = hash(val[2])
|
||||||
|
if not v then return v, ve end
|
||||||
|
return ("p(%s=%s)"):format(k, v)
|
||||||
|
end,
|
||||||
|
mark_constant = function(v)
|
||||||
|
mark_constant(v.value[1])
|
||||||
|
mark_constant(v.value[2])
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
annotated = {
|
||||||
|
format = function(val)
|
||||||
|
local k, ke = format(val[1])
|
||||||
|
if not k then return k, ke end
|
||||||
|
local v, ve = format(val[2])
|
||||||
|
if not v then return v, ve end
|
||||||
|
return ("%s::%s"):format(k, v)
|
||||||
|
end,
|
||||||
|
to_lua = function(val, state)
|
||||||
|
local k, ke = to_lua(val[1], state)
|
||||||
|
if ke then return nil, ke end
|
||||||
|
return k
|
||||||
|
end,
|
||||||
|
hash = function(val)
|
||||||
|
local k, ke = hash(val[1])
|
||||||
|
if not k then return k, ke end
|
||||||
|
local v, ve = hash(val[2])
|
||||||
|
if not v then return v, ve end
|
||||||
|
return ("a(%s::%s)"):format(k, v)
|
||||||
|
end,
|
||||||
|
mark_constant = function(v)
|
||||||
|
mark_constant(v.value[1])
|
||||||
|
mark_constant(v.value[2])
|
||||||
|
end,
|
||||||
|
},
|
||||||
list = {
|
list = {
|
||||||
mutable = true,
|
mutable = true,
|
||||||
format = function(val)
|
format = function(val)
|
||||||
|
|
@ -125,11 +177,11 @@ types.anselme = {
|
||||||
end
|
end
|
||||||
return ("[%s]"):format(table.concat(l, ", "))
|
return ("[%s]"):format(table.concat(l, ", "))
|
||||||
end,
|
end,
|
||||||
to_lua = function(val)
|
to_lua = function(val, state)
|
||||||
local l = {}
|
local l = {}
|
||||||
for _, v in ipairs(val) do
|
for _, v in ipairs(val) do
|
||||||
local s, e = to_lua(v)
|
local s, e = to_lua(v, state)
|
||||||
if not s and e then return s, e end
|
if e then return nil, e end
|
||||||
table.insert(l, s)
|
table.insert(l, s)
|
||||||
end
|
end
|
||||||
return l
|
return l
|
||||||
|
|
@ -164,13 +216,13 @@ types.anselme = {
|
||||||
table.sort(l)
|
table.sort(l)
|
||||||
return ("{%s}"):format(table.concat(l, ", "))
|
return ("{%s}"):format(table.concat(l, ", "))
|
||||||
end,
|
end,
|
||||||
to_lua = function(val)
|
to_lua = function(val, state)
|
||||||
local l = {}
|
local l = {}
|
||||||
for _, v in pairs(val) do
|
for _, v in pairs(val) do
|
||||||
local kl, ke = to_lua(v[1])
|
local kl, ke = to_lua(v[1], state)
|
||||||
if not kl and ke then return kl, ke end
|
if ke then return nil, ke end
|
||||||
local xl, xe = to_lua(v[2])
|
local xl, xe = to_lua(v[2], state)
|
||||||
if not xl and xe then return xl, xe end
|
if xe then return nil, xe end
|
||||||
l[kl] = xl
|
l[kl] = xl
|
||||||
end
|
end
|
||||||
return l
|
return l
|
||||||
|
|
@ -196,56 +248,56 @@ types.anselme = {
|
||||||
update_hashes(v)
|
update_hashes(v)
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
pair = {
|
object = {
|
||||||
|
mutable = true,
|
||||||
format = function(val)
|
format = function(val)
|
||||||
local k, ke = format(val[1])
|
local attributes = {}
|
||||||
if not k then return k, ke end
|
for name, v in pairs(val.attributes) do
|
||||||
local v, ve = format(val[2])
|
table.insert(attributes, ("%s=%s"):format(name:gsub("^"..escape(val.class)..".", ""), format(v)))
|
||||||
if not v then return v, ve end
|
end
|
||||||
return ("%s=%s"):format(k, v)
|
if #attributes > 0 then
|
||||||
|
table.sort(attributes)
|
||||||
|
return ("%%%s(%s)"):format(val.class, table.concat(attributes, ", "))
|
||||||
|
else
|
||||||
|
return ("%%%s"):format(val.class)
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
to_lua = function(val)
|
to_lua = function(val, state)
|
||||||
local k, ke = to_lua(val[1])
|
local r = {}
|
||||||
if not k and ke then return k, ke end
|
local namespacePattern = "^"..escape(val.class).."%."
|
||||||
local v, ve = to_lua(val[2])
|
-- set object properties
|
||||||
if not v and ve then return v, ve end
|
for name, v in pairs(val.attributes) do
|
||||||
return { [k] = v }
|
local var, err = to_lua(v, state)
|
||||||
|
if err then return nil, err end
|
||||||
|
r[name:gsub(namespacePattern, "")] = var
|
||||||
|
end
|
||||||
|
-- set class properties
|
||||||
|
local class, err = find_function_variant_from_fqm(val.class, state, nil)
|
||||||
|
if not class then return nil, err end
|
||||||
|
assert(#class == 1 and class[1].subtype == "class")
|
||||||
|
class = class[1]
|
||||||
|
for _, prop in ipairs(class.properties) do
|
||||||
|
if not val.attributes[prop] then
|
||||||
|
local var
|
||||||
|
var, err = get_variable(state, prop)
|
||||||
|
if not var then return nil, err end
|
||||||
|
var, err = to_lua(var, state)
|
||||||
|
if err then return nil, err end
|
||||||
|
r[prop:gsub(namespacePattern, "")] = var
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return r
|
||||||
end,
|
end,
|
||||||
hash = function(val)
|
hash = function(val)
|
||||||
local k, ke = hash(val[1])
|
local attributes = {}
|
||||||
if not k then return k, ke end
|
for name, v in pairs(val.attributes) do
|
||||||
local v, ve = hash(val[2])
|
table.insert(attributes, ("%s=%s"):format(name:gsub("^"..escape(val.class)..".", ""), format(v)))
|
||||||
if not v then return v, ve end
|
end
|
||||||
return ("p(%s=%s)"):format(k, v)
|
table.sort(attributes)
|
||||||
|
return ("%%(%s;%s)"):format(val.class, table.concat(attributes, ","))
|
||||||
end,
|
end,
|
||||||
mark_constant = function(v)
|
mark_constant = function(v)
|
||||||
mark_constant(v.value[1])
|
v.constant = true
|
||||||
mark_constant(v.value[2])
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
annotated = {
|
|
||||||
format = function(val)
|
|
||||||
local k, ke = format(val[1])
|
|
||||||
if not k then return k, ke end
|
|
||||||
local v, ve = format(val[2])
|
|
||||||
if not v then return v, ve end
|
|
||||||
return ("%s::%s"):format(k, v)
|
|
||||||
end,
|
|
||||||
to_lua = function(val)
|
|
||||||
local k, ke = to_lua(val[1])
|
|
||||||
if not k and ke then return k, ke end
|
|
||||||
return k
|
|
||||||
end,
|
|
||||||
hash = function(val)
|
|
||||||
local k, ke = hash(val[1])
|
|
||||||
if not k then return k, ke end
|
|
||||||
local v, ve = hash(val[2])
|
|
||||||
if not v then return v, ve end
|
|
||||||
return ("a(%s::%s)"):format(k, v)
|
|
||||||
end,
|
|
||||||
mark_constant = function(v)
|
|
||||||
mark_constant(v.value[1])
|
|
||||||
mark_constant(v.value[2])
|
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
["function reference"] = {
|
["function reference"] = {
|
||||||
|
|
@ -273,47 +325,55 @@ types.anselme = {
|
||||||
end,
|
end,
|
||||||
mark_constant = function() end,
|
mark_constant = function() end,
|
||||||
},
|
},
|
||||||
object = {
|
-- event buffer: can only be used outside of Anselme internal for text & flush events (through text buffers)
|
||||||
mutable = true,
|
|
||||||
format = function(val)
|
|
||||||
local attributes = {}
|
|
||||||
for name, v in pairs(val.attributes) do
|
|
||||||
table.insert(attributes, ("%s=%s"):format(name:gsub("^"..escape(val.class)..".", ""), format(v)))
|
|
||||||
end
|
|
||||||
if #attributes > 0 then
|
|
||||||
table.sort(attributes)
|
|
||||||
return ("%%%s(%s)"):format(val.class, table.concat(attributes, ", "))
|
|
||||||
else
|
|
||||||
return ("%%%s"):format(val.class)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
to_lua = nil,
|
|
||||||
hash = function(val)
|
|
||||||
local attributes = {}
|
|
||||||
for name, v in pairs(val.attributes) do
|
|
||||||
table.insert(attributes, ("%s=%s"):format(name:gsub("^"..escape(val.class)..".", ""), format(v)))
|
|
||||||
end
|
|
||||||
table.sort(attributes)
|
|
||||||
return ("%%(%s;%s)"):format(val.class, table.concat(attributes, ","))
|
|
||||||
end,
|
|
||||||
mark_constant = function(v)
|
|
||||||
v.constant = true
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
-- internal types
|
|
||||||
["event buffer"] = {
|
["event buffer"] = {
|
||||||
format = function(val) -- triggered from subtexts
|
format = function(val) -- triggered from subtexts
|
||||||
local v, e = events:write_buffer(anselme.running.state, val)
|
local v, e = events:write_buffer(anselme.running.state, val)
|
||||||
if not v then return v, e end
|
if not v then return v, e end
|
||||||
return ""
|
return ""
|
||||||
end
|
end,
|
||||||
|
to_lua = function(val, state)
|
||||||
|
local r = {}
|
||||||
|
for _, event in ipairs(val) do
|
||||||
|
if event.type == "text" then
|
||||||
|
table.insert(r, { "text", post_process_text(state, event.value) })
|
||||||
|
elseif event.type == "flush" then
|
||||||
|
table.insert(r, { "flush" })
|
||||||
|
else
|
||||||
|
return nil, ("event %q in event buffer can't be converted to a Lua value"):format(event.type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end,
|
||||||
|
hash = function(val)
|
||||||
|
local l = {}
|
||||||
|
for _, event in ipairs(val) do
|
||||||
|
if event.type == "text" then
|
||||||
|
local text = {}
|
||||||
|
for _, t in ipairs(event.value) do
|
||||||
|
local str = ("s(%s)"):format(t.text)
|
||||||
|
local tags, e = hash(t.tags)
|
||||||
|
if not tags then return nil, e end
|
||||||
|
table.insert(text, ("%s#%s"):format(str, tags))
|
||||||
|
end
|
||||||
|
table.insert(l, ("text(%s)"):format(table.concat(text, ",")))
|
||||||
|
elseif event.type == "flush" then
|
||||||
|
table.insert(l, "flush")
|
||||||
|
else
|
||||||
|
return nil, ("event %q in event buffer cannot be hashed"):format(event.type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ("eb(%s)"):format(table.concat(l, ","))
|
||||||
|
end,
|
||||||
|
mark_constant = function() end,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
package.loaded[...] = types
|
package.loaded[...] = types
|
||||||
local common = require((...):gsub("stdlib%.types$", "interpreter.common"))
|
local common = require((...):gsub("stdlib%.types$", "interpreter.common"))
|
||||||
format, to_lua, from_lua, events, hash, mark_constant, update_hashes = common.format, common.to_lua, common.from_lua, common.events, common.hash, common.mark_constant, common.update_hashes
|
format, to_lua, from_lua, events, hash, mark_constant, update_hashes, get_variable, post_process_text = common.format, common.to_lua, common.from_lua, common.events, common.hash, common.mark_constant, common.update_hashes, common.get_variable, common.post_process_text
|
||||||
anselme = require((...):gsub("stdlib%.types$", "anselme"))
|
anselme = require((...):gsub("stdlib%.types$", "anselme"))
|
||||||
escape = require((...):gsub("stdlib%.types$", "parser.common")).escape
|
local pcommon = require((...):gsub("stdlib%.types$", "parser.common"))
|
||||||
|
escape, find_function_variant_from_fqm = pcommon.escape, pcommon.find_function_variant_from_fqm
|
||||||
|
|
||||||
return types
|
return types
|
||||||
|
|
|
||||||
8
test/tests/text buffer with tags.ans
Normal file
8
test/tests/text buffer with tags.ans
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
:$ f
|
||||||
|
lol # 1
|
||||||
|
|
||||||
|
d
|
||||||
|
|
||||||
|
:a = %[a {f} [t # 2] b]
|
||||||
|
|
||||||
|
@a
|
||||||
41
test/tests/text buffer with tags.lua
Normal file
41
test/tests/text buffer with tags.lua
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
local _={}
|
||||||
|
_[21]={}
|
||||||
|
_[20]={2}
|
||||||
|
_[19]={}
|
||||||
|
_[18]={1}
|
||||||
|
_[17]={}
|
||||||
|
_[16]={text="b",tags=_[21]}
|
||||||
|
_[15]={text="t ",tags=_[20]}
|
||||||
|
_[14]={text="d",tags=_[19]}
|
||||||
|
_[13]={text="lol",tags=_[18]}
|
||||||
|
_[12]={text="a",tags=_[17]}
|
||||||
|
_[11]={_[15],_[16]}
|
||||||
|
_[10]={_[14]}
|
||||||
|
_[9]={_[13]}
|
||||||
|
_[8]={_[12]}
|
||||||
|
_[7]={"text",_[11]}
|
||||||
|
_[6]={"text",_[10]}
|
||||||
|
_[5]={"flush"}
|
||||||
|
_[4]={"text",_[9]}
|
||||||
|
_[3]={"text",_[8]}
|
||||||
|
_[2]={_[3],_[4],_[5],_[6],_[7]}
|
||||||
|
_[1]={"return",_[2]}
|
||||||
|
return {_[1]}
|
||||||
|
--[[
|
||||||
|
{ "return", { { "text", { {
|
||||||
|
tags = {},
|
||||||
|
text = "a"
|
||||||
|
} } }, { "text", { {
|
||||||
|
tags = { 1 },
|
||||||
|
text = "lol"
|
||||||
|
} } }, { "flush" }, { "text", { {
|
||||||
|
tags = {},
|
||||||
|
text = "d"
|
||||||
|
} } }, { "text", { {
|
||||||
|
tags = { 2 },
|
||||||
|
text = "t "
|
||||||
|
}, {
|
||||||
|
tags = {},
|
||||||
|
text = "b"
|
||||||
|
} } } } }
|
||||||
|
]]--
|
||||||
8
test/tests/text buffer.ans
Normal file
8
test/tests/text buffer.ans
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
:$ f
|
||||||
|
lol
|
||||||
|
|
||||||
|
d
|
||||||
|
|
||||||
|
:a = %[a {f} b]
|
||||||
|
|
||||||
|
@a
|
||||||
34
test/tests/text buffer.lua
Normal file
34
test/tests/text buffer.lua
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
local _={}
|
||||||
|
_[17]={}
|
||||||
|
_[16]={}
|
||||||
|
_[15]={}
|
||||||
|
_[14]={}
|
||||||
|
_[13]={tags=_[17],text=" b"}
|
||||||
|
_[12]={tags=_[16],text="d"}
|
||||||
|
_[11]={tags=_[15],text="lol"}
|
||||||
|
_[10]={tags=_[14],text="a"}
|
||||||
|
_[9]={_[12],_[13]}
|
||||||
|
_[8]={_[11]}
|
||||||
|
_[7]={_[10]}
|
||||||
|
_[6]={"text",_[9]}
|
||||||
|
_[5]={"flush"}
|
||||||
|
_[4]={"text",_[8]}
|
||||||
|
_[3]={"text",_[7]}
|
||||||
|
_[2]={_[3],_[4],_[5],_[6]}
|
||||||
|
_[1]={"return",_[2]}
|
||||||
|
return {_[1]}
|
||||||
|
--[[
|
||||||
|
{ "return", { { "text", { {
|
||||||
|
tags = {},
|
||||||
|
text = "a"
|
||||||
|
} } }, { "text", { {
|
||||||
|
tags = {},
|
||||||
|
text = "lol"
|
||||||
|
} } }, { "flush" }, { "text", { {
|
||||||
|
tags = {},
|
||||||
|
text = "d"
|
||||||
|
}, {
|
||||||
|
tags = {},
|
||||||
|
text = " b"
|
||||||
|
} } } } }
|
||||||
|
]]--
|
||||||
Loading…
Add table
Add a link
Reference in a new issue