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
```
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
elements together, while the interpreter would have to decide on a joining
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
OATS is a very simple format without many restrictions.
@ -45,4 +70,8 @@ generally ignore 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

View file

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

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

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

View file

@ -21,24 +21,31 @@ describe "OATS", ->
bob = {name: "person", {name: "name", "Bob"}, {name: "age", "20"}}
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", ->
rose = {name: "person", {name: "name", "Rose"}, {name: "age", "22"}}
assert.same {rose}, oats.decodefile("spec/fixtures/files/rose.oats")
pending "parses inline nodes", ->
it "parses inline nodes", ->
document = {
name: "document"
{name: "title", "Document"}
"Paragraph"
"Multiline Paragraph"
"Text with a"
{name: "nested", "nested"}
"node"
"Text with an"
{name: "nested"}
"empty nested node"
{
name: "section"
"Text with a "
{name: "inline", "inline"}
" node"
"Text with an "
{name: "inline"}
" 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", ->
assert.same {{name: "tester"}}, oats.decode("[tester]")

View file

@ -30,6 +30,36 @@ local function handledepth(callback, last, current, number)
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 line string
--- @param number number Line number currently being processed
@ -47,7 +77,7 @@ local function parseline(callback, line, lastdepth, number)
if depth then
handledepth(callback, lastdepth, depth, number)
callback("open", name)
callback("text", text)
parsetext(callback, text, number)
callback("close")
return depth-1 -- Minus one because the tag is already closed
end
@ -59,7 +89,7 @@ local function parseline(callback, line, lastdepth, number)
depth, text = line:match("^\t*()(.*)$")
if depth then
handledepth(callback, lastdepth, depth, number)
callback("text", text)
parsetext(callback, text, number)
return depth-1 -- Minus one because text doesn't get closed
end
end