Finish implementing OATS

This commit is contained in:
Talia 2024-12-20 23:21:46 +01:00
parent 1be4d8db49
commit 4ffe1f0ad9
Signed by: darkwiiplayer
GPG key ID: 7808674088232B3E
5 changed files with 89 additions and 26 deletions

View file

@ -25,15 +25,40 @@ Nested elements are indented
nested text nested text
``` ```
Multi-line text nodes are yet to be decided. As of now, the options are: Tags with only one text node can be shortened to one-line tags:
1. Consecutive non-empty lines of text are merged with a space ```
2. Any non-empty text line is always a single text element [tag-name] single text node
evaluates to the same as
[tag-name]
single text node
```
Text nodes mixed with one-line tags can further be shortened with inline tags:
```
Plain text with some
[bold] tagged
text
[emphasis] in between
evaluates to the same as
Plain text with some [bold tagged] text [emphasis in between]
```
**Note**: Consumers may have a better understanding of whether and how to join text **Note**: Consumers may have a better understanding of whether and how to join text
elements together, while the interpreter would have to decide on a joining elements together, while the interpreter would have to decide on a joining
strategy (most likely concatenation with a space character in between). strategy (most likely concatenation with a space character in between).
### Data Type
OATS makes no attempts to interpret text.
Everything is considered a string and it is left up to the consuming application
to decide how to interpret the textual representation.
### Conventions ### Conventions
OATS is a very simple format without many restrictions. OATS is a very simple format without many restrictions.
@ -45,4 +70,8 @@ generally ignore case.
Tag names should use lowercase kebab-case. Tag names should use lowercase kebab-case.
Applications that interpret parts of a tag name as a namespace should use a
single colon `:` as the namespace separator, with namespaces preceding the tag
name.
## Interface ## Interface

View file

@ -1,12 +1,5 @@
[document] [document]
[section] [section]
[title] Document Text with a [inline inline] node
Text with an [inline] empty nested node
Paragraph [one-line] with [inline] node
Multiline
Paragraph
Text with a [nested nested] node
Text with an [nested] empty nested node

4
spec/fixtures/files/multi.oats vendored Normal file
View file

@ -0,0 +1,4 @@
multi
line
strings

View file

@ -20,25 +20,32 @@ describe "OATS", ->
it "parses basic text nodes", -> it "parses basic text nodes", ->
bob = {name: "person", {name: "name", "Bob"}, {name: "age", "20"}} bob = {name: "person", {name: "name", "Bob"}, {name: "age", "20"}}
assert.same {bob}, oats.decodefile("spec/fixtures/files/bob.oats") assert.same {bob}, oats.decodefile("spec/fixtures/files/bob.oats")
it "parses multiple lines into separate nodes", ->
assert.same {"multi", "line", "strings"}, oats.decodefile("spec/fixtures/files/multi.oats")
it "parses one-line nodes", -> it "parses one-line nodes", ->
rose = {name: "person", {name: "name", "Rose"}, {name: "age", "22"}} rose = {name: "person", {name: "name", "Rose"}, {name: "age", "22"}}
assert.same {rose}, oats.decodefile("spec/fixtures/files/rose.oats") assert.same {rose}, oats.decodefile("spec/fixtures/files/rose.oats")
pending "parses inline nodes", -> it "parses inline nodes", ->
document = { document = {
name: "document" name: "document"
{name: "title", "Document"} {
"Paragraph" name: "section"
"Multiline Paragraph" "Text with a "
"Text with a" {name: "inline", "inline"}
{name: "nested", "nested"} " node"
"node" "Text with an "
"Text with an" {name: "inline"}
{name: "nested"} " empty nested node"
"empty nested node" {name: "one-line", "with ", {name: "inline"}, " node"}
}
} }
assert.same {document}, oats.decodefile("spec/fixtures/files/document.oats") assert.same document, oats.decodefile("spec/fixtures/files/document.oats")[1]
it "errors for endless inline nodes", ->
assert.has.error (-> oats.decode("line with [endless tag")), "Endless inline tag on 1:11"
it "parses strings files", -> it "parses strings files", ->
assert.same {{name: "tester"}}, oats.decode("[tester]") assert.same {{name: "tester"}}, oats.decode("[tester]")

View file

@ -30,6 +30,36 @@ local function handledepth(callback, last, current, number)
end end
end end
local function parsetext(callback, text, number)
local start = 1
local inline while true do
inline = text:find("[", start, true)
if inline then
callback("text", text:sub(start, inline - 1))
local close = text:find("]", inline, true)
if close then
local inline_content = text:sub(inline+1, close-1)
local inline_name, inline_text
inline_name, inline_text = inline_content:match("^([^%s]+)%s+(.+)$")
if not inline_name then
inline_name = inline_content
end
callback("open", inline_name)
if inline_text then
callback("text", inline_text)
end
callback("close")
start = close + 1
else
error(string.format("Endless inline tag on %i:%i", number, inline))
end
else
break
end
end
callback("text", text:sub(start))
end
--- @param callback callback --- @param callback callback
--- @param line string --- @param line string
--- @param number number Line number currently being processed --- @param number number Line number currently being processed
@ -47,7 +77,7 @@ local function parseline(callback, line, lastdepth, number)
if depth then if depth then
handledepth(callback, lastdepth, depth, number) handledepth(callback, lastdepth, depth, number)
callback("open", name) callback("open", name)
callback("text", text) parsetext(callback, text, number)
callback("close") callback("close")
return depth-1 -- Minus one because the tag is already closed return depth-1 -- Minus one because the tag is already closed
end end
@ -59,7 +89,7 @@ local function parseline(callback, line, lastdepth, number)
depth, text = line:match("^\t*()(.*)$") depth, text = line:match("^\t*()(.*)$")
if depth then if depth then
handledepth(callback, lastdepth, depth, number) handledepth(callback, lastdepth, depth, number)
callback("text", text) parsetext(callback, text, number)
return depth-1 -- Minus one because text doesn't get closed return depth-1 -- Minus one because text doesn't get closed
end end
end end