Finish implementing OATS
This commit is contained in:
parent
1be4d8db49
commit
4ffe1f0ad9
5 changed files with 89 additions and 26 deletions
35
readme.md
35
readme.md
|
@ -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
|
||||||
|
|
13
spec/fixtures/files/document.oats
vendored
13
spec/fixtures/files/document.oats
vendored
|
@ -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
4
spec/fixtures/files/multi.oats
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
multi
|
||||||
|
line
|
||||||
|
|
||||||
|
strings
|
|
@ -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]")
|
||||||
|
|
34
src/oats.lua
34
src/oats.lua
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue