Compare commits

..

4 commits

Author SHA1 Message Date
Anish Lakhwara ab4c5b6f58 readme 2024-08-31 22:59:37 -07:00
Anish Lakhwara 9fe7d6820c add architecture diagram
touch README
2024-08-31 22:43:34 -07:00
Anish Lakhwara c6870aa4f0 add todo 2024-08-31 22:43:29 -07:00
Anish Lakhwara 636dc6d59d init: working task add parser 2024-08-31 21:46:09 -07:00
14 changed files with 18 additions and 1029 deletions

View file

@ -31,7 +31,3 @@ Next:
Completed: Completed:
- Syncing between JS & Go clients - Syncing between JS & Go clients
- Parsing `task add` grammar (For Go) - Parsing `task add` grammar (For Go)
## Architecture
![architecture diagram](./architecture.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 111 KiB

View file

@ -2,13 +2,8 @@ package mast
import ( import (
"database/sql" "database/sql"
"embed"
"log"
) )
//go:embed migrations/0001.sql
var migration0001 embed.FS
func RunMigrations(db *sql.DB) error { func RunMigrations(db *sql.DB) error {
// Load the cr-sqlite extension // Load the cr-sqlite extension
// _, err := db.Exec("SELECT load_extension('./crsqlite.so', 'sqlite3_crsqlite_init')") // _, err := db.Exec("SELECT load_extension('./crsqlite.so', 'sqlite3_crsqlite_init')")
@ -16,15 +11,11 @@ func RunMigrations(db *sql.DB) error {
// return fmt.Errorf("failed to load cr-sqlite extension: %w", err) // return fmt.Errorf("failed to load cr-sqlite extension: %w", err)
// } // }
// Read the embedded SQL file
sqlData, err := migration0001.ReadFile("migrations/0001.sql")
if err != nil {
log.Fatalf("Failed to read embedded SQL file: %v", err)
}
sqlQuery := string(sqlData)
// Create the todos table and initialize it as a CRDT // Create the todos table and initialize it as a CRDT
_, err = db.Exec(sqlQuery) _, err := db.Exec(`
CREATE TABLE IF NOT EXISTS todos (id blob PRIMARY KEY NOT NULL, content TEXT, completed INTEGER NOT NULL DEFAULT 0);
SELECT crsql_as_crr('todos');
`)
if err != nil { if err != nil {
return err return err
} }

View file

@ -1,13 +0,0 @@
CREATE TABLE IF NOT EXISTS todos
(
id blob PRIMARY KEY NOT NULL,
description text,
project text,
tags text,
due text,
wait text,
priority text,
urgency real,
completed integer NOT NULL DEFAULT 0
);
SELECT crsql_as_crr('todos');

1
envrc Normal file
View file

@ -0,0 +1 @@
use flake

View file

@ -1,23 +1,5 @@
{ {
"nodes": { "nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1708407374, "lastModified": 1708407374,
@ -36,24 +18,8 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
} }
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View file

@ -1,28 +1,11 @@
{ {
description = "A basic flake with a shell"; description = "A basic flake with a shell";
inputs = { inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { nixpkgs, flake-utils, ... }: outputs = { nixpkgs, ... }:
flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages."x86_64-linux";
let in {
pkgs = import nixpkgs { inherit system; }; devShells."x86_64-linux".default =
in pkgs.mkShell { packages = with pkgs; [ go sqlite nodejs pigeon ]; };
{
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
go
pigeon
nodejs
sqlite
];
shellHook = ''
echo "System: ${system}"
'';
}; };
} }
);
}

View file

@ -4,7 +4,6 @@
import wasmUrl from '@vlcn.io/crsqlite-wasm/crsqlite.wasm?url'; import wasmUrl from '@vlcn.io/crsqlite-wasm/crsqlite.wasm?url';
import { start } from "@vlcn.io/ws-client/worker.js"; import { start } from "@vlcn.io/ws-client/worker.js";
import { createDbProvider } from "@vlcn.io/ws-browserdb"; import { createDbProvider } from "@vlcn.io/ws-browserdb";
import * as addParser from '../../parser/add_parser.js';
let db; let db;
let ws; let ws;
@ -18,13 +17,7 @@
await db.exec(` await db.exec(`
CREATE TABLE IF NOT EXISTS todos ( CREATE TABLE IF NOT EXISTS todos (
id BLOB PRIMARY KEY NOT NULL, id BLOB PRIMARY KEY NOT NULL,
description TEXT, content TEXT,
project text,
tags text,
due text,
wait text,
priority text,
urgency real,
completed INTEGER NOT NULL DEFAULT 0 completed INTEGER NOT NULL DEFAULT 0
); );
SELECT crsql_as_crr('todos'); SELECT crsql_as_crr('todos');
@ -94,37 +87,12 @@
todos = result; todos = result;
} }
// TODO:
// This is fucking sucks
// make the stupid parser do this 😩
async function Marshall(parsed) {
let project = "";
const tags = [];
console.log(parsed);
for (const attr of parsed.attributes) {
console.log(attr);
switch (attr.type) {
case 'project':
console.log("project" + attr.value);
project = attr.value;
break;
case 'tag':
console.log("tag" + attr.value);
tags.push(attr.value);
break;
}
}
return {description: parsed.description, tags: tags, project: project};
}
async function addTodo() { async function addTodo() {
if (newTodo.trim()) { if (newTodo.trim()) {
const parsed = await Marshall(addParser.parse(newTodo));
console.log(parsed);
await db.exec(` await db.exec(`
INSERT INTO todos (id, description, tags, project, completed) INSERT INTO todos (id, content, completed)
VALUES (lower(hex(randomblob(16))), ?, ?, ?, 0) VALUES (lower(hex(randomblob(16))), ?, 0)
`, [parsed.description, JSON.stringify(parsed.tags), parsed.project]); `, [newTodo.trim()]);
newTodo = ''; newTodo = '';
loadTodos(); loadTodos();
} }
@ -141,7 +109,7 @@
</script> </script>
<main> <main>
<h1>Mast</h1> <h1>Svelte Todo with cr-sqlite</h1>
<input <input
bind:value={newTodo} bind:value={newTodo}
on:keypress={(e) => e.key === 'Enter' && addTodo()} on:keypress={(e) => e.key === 'Enter' && addTodo()}
@ -156,7 +124,7 @@
checked={todo.completed} checked={todo.completed}
on:change={() => toggleTodo(todo.id)} on:change={() => toggleTodo(todo.id)}
/> />
<span class:completed={todo.completed}>{todo.description} pro:{todo.project} {todo.tags}</span> <span class:completed={todo.completed}>{todo.content}</span>
</li> </li>
{/each} {/each}
</ul> </ul>

BIN
main Executable file

Binary file not shown.

85
package-lock.json generated
View file

@ -1,85 +0,0 @@
{
"name": "mast",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"peggy": "^4.0.3"
}
},
"node_modules/@peggyjs/from-mem": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@peggyjs/from-mem/-/from-mem-1.3.0.tgz",
"integrity": "sha512-kzGoIRJjkg3KuGI4bopz9UvF3KguzfxalHRDEIdqEZUe45xezsQ6cx30e0RKuxPUexojQRBfu89Okn7f4/QXsw==",
"dependencies": {
"semver": "7.6.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/commander": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
"integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
"engines": {
"node": ">=18"
}
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/peggy": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/peggy/-/peggy-4.0.3.tgz",
"integrity": "sha512-v7/Pt6kGYsfXsCrfb52q7/yg5jaAwiVaUMAPLPvy4DJJU6Wwr72t6nDIqIDkGfzd1B4zeVuTnQT0RGeOhe/uSA==",
"dependencies": {
"@peggyjs/from-mem": "1.3.0",
"commander": "^12.1.0",
"source-map-generator": "0.8.0"
},
"bin": {
"peggy": "bin/peggy.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/semver": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/source-map-generator": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/source-map-generator/-/source-map-generator-0.8.0.tgz",
"integrity": "sha512-psgxdGMwl5MZM9S3FWee4EgsEaIjahYV5AzGnwUvPhWeITz/j6rKpysQHlQ4USdxvINlb8lKfWGIXwfkrgtqkA==",
"engines": {
"node": ">= 10"
}
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
}

View file

@ -1,5 +0,0 @@
{
"dependencies": {
"peggy": "^4.0.3"
}
}

View file

@ -1,46 +0,0 @@
{
function MakeAdd(description, attributes) {
return {
description: description,
attributes: attributes || []
};
}
function MakeAttributes(attributes) {
return attributes.flatMap(attr => attr[1]);
}
}
Add = desc:Description attributes:Attributes? {
return MakeAdd(desc, attributes);
}
Description = chars:(!Attribute .)+ {
return chars.map(c => c[1]).join('');
}
Attributes = attributes:(_ Attribute)* {
return MakeAttributes(attributes);
}
Attribute = Project / Priority / Tag
Project = ("pro:" / "project:" / "+") value:Word {
return { type: "project", value: value };
}
Priority = "priority:" value:[HML] {
return { type: "priority", value: value };
}
Tag = "#" value:Word {
return { type: "tag", value: value };
}
Word = chars:[a-zA-Z0-9_-]+ {
return chars.join('');
}
_ = [ \\t]*
EOF = !.

View file

@ -1,767 +0,0 @@
// @generated by Peggy 4.1.1.
//
// https://peggyjs.org/
function peg$subclass(child, parent) {
function C() { this.constructor = child; }
C.prototype = parent.prototype;
child.prototype = new C();
}
function peg$SyntaxError(message, expected, found, location) {
var self = Error.call(this, message);
// istanbul ignore next Check is a necessary evil to support older environments
if (Object.setPrototypeOf) {
Object.setPrototypeOf(self, peg$SyntaxError.prototype);
}
self.expected = expected;
self.found = found;
self.location = location;
self.name = "SyntaxError";
return self;
}
peg$subclass(peg$SyntaxError, Error);
function peg$padEnd(str, targetLength, padString) {
padString = padString || " ";
if (str.length > targetLength) { return str; }
targetLength -= str.length;
padString += padString.repeat(targetLength);
return str + padString.slice(0, targetLength);
}
peg$SyntaxError.prototype.format = function(sources) {
var str = "Error: " + this.message;
if (this.location) {
var src = null;
var k;
for (k = 0; k < sources.length; k++) {
if (sources[k].source === this.location.source) {
src = sources[k].text.split(/\r\n|\n|\r/g);
break;
}
}
var s = this.location.start;
var offset_s = (this.location.source && (typeof this.location.source.offset === "function"))
? this.location.source.offset(s)
: s;
var loc = this.location.source + ":" + offset_s.line + ":" + offset_s.column;
if (src) {
var e = this.location.end;
var filler = peg$padEnd("", offset_s.line.toString().length, ' ');
var line = src[s.line - 1];
var last = s.line === e.line ? e.column : line.length + 1;
var hatLen = (last - s.column) || 1;
str += "\n --> " + loc + "\n"
+ filler + " |\n"
+ offset_s.line + " | " + line + "\n"
+ filler + " | " + peg$padEnd("", s.column - 1, ' ')
+ peg$padEnd("", hatLen, "^");
} else {
str += "\n at " + loc;
}
}
return str;
};
peg$SyntaxError.buildMessage = function(expected, found) {
var DESCRIBE_EXPECTATION_FNS = {
literal: function(expectation) {
return "\"" + literalEscape(expectation.text) + "\"";
},
class: function(expectation) {
var escapedParts = expectation.parts.map(function(part) {
return Array.isArray(part)
? classEscape(part[0]) + "-" + classEscape(part[1])
: classEscape(part);
});
return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]";
},
any: function() {
return "any character";
},
end: function() {
return "end of input";
},
other: function(expectation) {
return expectation.description;
}
};
function hex(ch) {
return ch.charCodeAt(0).toString(16).toUpperCase();
}
function literalEscape(s) {
return s
.replace(/\\/g, "\\\\")
.replace(/"/g, "\\\"")
.replace(/\0/g, "\\0")
.replace(/\t/g, "\\t")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
}
function classEscape(s) {
return s
.replace(/\\/g, "\\\\")
.replace(/\]/g, "\\]")
.replace(/\^/g, "\\^")
.replace(/-/g, "\\-")
.replace(/\0/g, "\\0")
.replace(/\t/g, "\\t")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
}
function describeExpectation(expectation) {
return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
}
function describeExpected(expected) {
var descriptions = expected.map(describeExpectation);
var i, j;
descriptions.sort();
if (descriptions.length > 0) {
for (i = 1, j = 1; i < descriptions.length; i++) {
if (descriptions[i - 1] !== descriptions[i]) {
descriptions[j] = descriptions[i];
j++;
}
}
descriptions.length = j;
}
switch (descriptions.length) {
case 1:
return descriptions[0];
case 2:
return descriptions[0] + " or " + descriptions[1];
default:
return descriptions.slice(0, -1).join(", ")
+ ", or "
+ descriptions[descriptions.length - 1];
}
}
function describeFound(found) {
return found ? "\"" + literalEscape(found) + "\"" : "end of input";
}
return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
};
function peg$parse(input, options) {
options = options !== undefined ? options : {};
var peg$FAILED = {};
var peg$source = options.grammarSource;
var peg$startRuleFunctions = { Add: peg$parseAdd };
var peg$startRuleFunction = peg$parseAdd;
var peg$c0 = "pro:";
var peg$c1 = "project:";
var peg$c2 = "+";
var peg$c3 = "priority:";
var peg$c4 = "#";
var peg$r0 = /^[HML]/;
var peg$r1 = /^[a-zA-Z0-9_\-]/;
var peg$r2 = /^[ \\t]/;
var peg$e0 = peg$anyExpectation();
var peg$e1 = peg$literalExpectation("pro:", false);
var peg$e2 = peg$literalExpectation("project:", false);
var peg$e3 = peg$literalExpectation("+", false);
var peg$e4 = peg$literalExpectation("priority:", false);
var peg$e5 = peg$classExpectation(["H", "M", "L"], false, false);
var peg$e6 = peg$literalExpectation("#", false);
var peg$e7 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "_", "-"], false, false);
var peg$e8 = peg$classExpectation([" ", "\\", "t"], false, false);
var peg$f0 = function(desc, attributes) {
return MakeAdd(desc, attributes);
};
var peg$f1 = function(chars) {
return chars.map(c => c[1]).join('');
};
var peg$f2 = function(attributes) {
return MakeAttributes(attributes);
};
var peg$f3 = function(value) {
return { type: "project", value: value };
};
var peg$f4 = function(value) {
return { type: "priority", value: value };
};
var peg$f5 = function(value) {
return { type: "tag", value: value };
};
var peg$f6 = function(chars) {
return chars.join('');
};
var peg$currPos = options.peg$currPos | 0;
var peg$savedPos = peg$currPos;
var peg$posDetailsCache = [{ line: 1, column: 1 }];
var peg$maxFailPos = peg$currPos;
var peg$maxFailExpected = options.peg$maxFailExpected || [];
var peg$silentFails = options.peg$silentFails | 0;
var peg$result;
if (options.startRule) {
if (!(options.startRule in peg$startRuleFunctions)) {
throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
}
peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
}
function text() {
return input.substring(peg$savedPos, peg$currPos);
}
function offset() {
return peg$savedPos;
}
function range() {
return {
source: peg$source,
start: peg$savedPos,
end: peg$currPos
};
}
function location() {
return peg$computeLocation(peg$savedPos, peg$currPos);
}
function expected(description, location) {
location = location !== undefined
? location
: peg$computeLocation(peg$savedPos, peg$currPos);
throw peg$buildStructuredError(
[peg$otherExpectation(description)],
input.substring(peg$savedPos, peg$currPos),
location
);
}
function error(message, location) {
location = location !== undefined
? location
: peg$computeLocation(peg$savedPos, peg$currPos);
throw peg$buildSimpleError(message, location);
}
function peg$literalExpectation(text, ignoreCase) {
return { type: "literal", text: text, ignoreCase: ignoreCase };
}
function peg$classExpectation(parts, inverted, ignoreCase) {
return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };
}
function peg$anyExpectation() {
return { type: "any" };
}
function peg$endExpectation() {
return { type: "end" };
}
function peg$otherExpectation(description) {
return { type: "other", description: description };
}
function peg$computePosDetails(pos) {
var details = peg$posDetailsCache[pos];
var p;
if (details) {
return details;
} else {
if (pos >= peg$posDetailsCache.length) {
p = peg$posDetailsCache.length - 1;
} else {
p = pos;
while (!peg$posDetailsCache[--p]) {}
}
details = peg$posDetailsCache[p];
details = {
line: details.line,
column: details.column
};
while (p < pos) {
if (input.charCodeAt(p) === 10) {
details.line++;
details.column = 1;
} else {
details.column++;
}
p++;
}
peg$posDetailsCache[pos] = details;
return details;
}
}
function peg$computeLocation(startPos, endPos, offset) {
var startPosDetails = peg$computePosDetails(startPos);
var endPosDetails = peg$computePosDetails(endPos);
var res = {
source: peg$source,
start: {
offset: startPos,
line: startPosDetails.line,
column: startPosDetails.column
},
end: {
offset: endPos,
line: endPosDetails.line,
column: endPosDetails.column
}
};
if (offset && peg$source && (typeof peg$source.offset === "function")) {
res.start = peg$source.offset(res.start);
res.end = peg$source.offset(res.end);
}
return res;
}
function peg$fail(expected) {
if (peg$currPos < peg$maxFailPos) { return; }
if (peg$currPos > peg$maxFailPos) {
peg$maxFailPos = peg$currPos;
peg$maxFailExpected = [];
}
peg$maxFailExpected.push(expected);
}
function peg$buildSimpleError(message, location) {
return new peg$SyntaxError(message, null, null, location);
}
function peg$buildStructuredError(expected, found, location) {
return new peg$SyntaxError(
peg$SyntaxError.buildMessage(expected, found),
expected,
found,
location
);
}
function peg$parseAdd() {
var s0, s1, s2;
s0 = peg$currPos;
s1 = peg$parseDescription();
if (s1 !== peg$FAILED) {
s2 = peg$parseAttributes();
peg$savedPos = s0;
s0 = peg$f0(s1, s2);
} else {
peg$currPos = s0;
s0 = peg$FAILED;
}
return s0;
}
function peg$parseDescription() {
var s0, s1, s2, s3, s4;
s0 = peg$currPos;
s1 = [];
s2 = peg$currPos;
s3 = peg$currPos;
peg$silentFails++;
s4 = peg$parseAttribute();
peg$silentFails--;
if (s4 === peg$FAILED) {
s3 = undefined;
} else {
peg$currPos = s3;
s3 = peg$FAILED;
}
if (s3 !== peg$FAILED) {
if (input.length > peg$currPos) {
s4 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s4 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e0); }
}
if (s4 !== peg$FAILED) {
s3 = [s3, s4];
s2 = s3;
} else {
peg$currPos = s2;
s2 = peg$FAILED;
}
} else {
peg$currPos = s2;
s2 = peg$FAILED;
}
if (s2 !== peg$FAILED) {
while (s2 !== peg$FAILED) {
s1.push(s2);
s2 = peg$currPos;
s3 = peg$currPos;
peg$silentFails++;
s4 = peg$parseAttribute();
peg$silentFails--;
if (s4 === peg$FAILED) {
s3 = undefined;
} else {
peg$currPos = s3;
s3 = peg$FAILED;
}
if (s3 !== peg$FAILED) {
if (input.length > peg$currPos) {
s4 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s4 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e0); }
}
if (s4 !== peg$FAILED) {
s3 = [s3, s4];
s2 = s3;
} else {
peg$currPos = s2;
s2 = peg$FAILED;
}
} else {
peg$currPos = s2;
s2 = peg$FAILED;
}
}
} else {
s1 = peg$FAILED;
}
if (s1 !== peg$FAILED) {
peg$savedPos = s0;
s1 = peg$f1(s1);
}
s0 = s1;
return s0;
}
function peg$parseAttributes() {
var s0, s1, s2, s3, s4;
s0 = peg$currPos;
s1 = [];
s2 = peg$currPos;
s3 = peg$parse_();
s4 = peg$parseAttribute();
if (s4 !== peg$FAILED) {
s3 = [s3, s4];
s2 = s3;
} else {
peg$currPos = s2;
s2 = peg$FAILED;
}
while (s2 !== peg$FAILED) {
s1.push(s2);
s2 = peg$currPos;
s3 = peg$parse_();
s4 = peg$parseAttribute();
if (s4 !== peg$FAILED) {
s3 = [s3, s4];
s2 = s3;
} else {
peg$currPos = s2;
s2 = peg$FAILED;
}
}
peg$savedPos = s0;
s1 = peg$f2(s1);
s0 = s1;
return s0;
}
function peg$parseAttribute() {
var s0;
s0 = peg$parseProject();
if (s0 === peg$FAILED) {
s0 = peg$parsePriority();
if (s0 === peg$FAILED) {
s0 = peg$parseTag();
}
}
return s0;
}
function peg$parseProject() {
var s0, s1, s2;
s0 = peg$currPos;
if (input.substr(peg$currPos, 4) === peg$c0) {
s1 = peg$c0;
peg$currPos += 4;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e1); }
}
if (s1 === peg$FAILED) {
if (input.substr(peg$currPos, 8) === peg$c1) {
s1 = peg$c1;
peg$currPos += 8;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e2); }
}
if (s1 === peg$FAILED) {
if (input.charCodeAt(peg$currPos) === 43) {
s1 = peg$c2;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e3); }
}
}
}
if (s1 !== peg$FAILED) {
s2 = peg$parseWord();
if (s2 !== peg$FAILED) {
peg$savedPos = s0;
s0 = peg$f3(s2);
} else {
peg$currPos = s0;
s0 = peg$FAILED;
}
} else {
peg$currPos = s0;
s0 = peg$FAILED;
}
return s0;
}
function peg$parsePriority() {
var s0, s1, s2;
s0 = peg$currPos;
if (input.substr(peg$currPos, 9) === peg$c3) {
s1 = peg$c3;
peg$currPos += 9;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e4); }
}
if (s1 !== peg$FAILED) {
s2 = input.charAt(peg$currPos);
if (peg$r0.test(s2)) {
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e5); }
}
if (s2 !== peg$FAILED) {
peg$savedPos = s0;
s0 = peg$f4(s2);
} else {
peg$currPos = s0;
s0 = peg$FAILED;
}
} else {
peg$currPos = s0;
s0 = peg$FAILED;
}
return s0;
}
function peg$parseTag() {
var s0, s1, s2;
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 35) {
s1 = peg$c4;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e6); }
}
if (s1 !== peg$FAILED) {
s2 = peg$parseWord();
if (s2 !== peg$FAILED) {
peg$savedPos = s0;
s0 = peg$f5(s2);
} else {
peg$currPos = s0;
s0 = peg$FAILED;
}
} else {
peg$currPos = s0;
s0 = peg$FAILED;
}
return s0;
}
function peg$parseWord() {
var s0, s1, s2;
s0 = peg$currPos;
s1 = [];
s2 = input.charAt(peg$currPos);
if (peg$r1.test(s2)) {
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e7); }
}
if (s2 !== peg$FAILED) {
while (s2 !== peg$FAILED) {
s1.push(s2);
s2 = input.charAt(peg$currPos);
if (peg$r1.test(s2)) {
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e7); }
}
}
} else {
s1 = peg$FAILED;
}
if (s1 !== peg$FAILED) {
peg$savedPos = s0;
s1 = peg$f6(s1);
}
s0 = s1;
return s0;
}
function peg$parse_() {
var s0, s1;
s0 = [];
s1 = input.charAt(peg$currPos);
if (peg$r2.test(s1)) {
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e8); }
}
while (s1 !== peg$FAILED) {
s0.push(s1);
s1 = input.charAt(peg$currPos);
if (peg$r2.test(s1)) {
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e8); }
}
}
return s0;
}
function peg$parseEOF() {
var s0, s1;
s0 = peg$currPos;
peg$silentFails++;
if (input.length > peg$currPos) {
s1 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e0); }
}
peg$silentFails--;
if (s1 === peg$FAILED) {
s0 = undefined;
} else {
peg$currPos = s0;
s0 = peg$FAILED;
}
return s0;
}
function MakeAdd(description, attributes) {
return {
description: description,
attributes: attributes || []
};
}
function MakeAttributes(attributes) {
return attributes.flatMap(attr => attr[1]);
}
peg$result = peg$startRuleFunction();
if (options.peg$library) {
return /** @type {any} */ ({
peg$result,
peg$currPos,
peg$FAILED,
peg$maxFailExpected,
peg$maxFailPos
});
}
if (peg$result !== peg$FAILED && peg$currPos === input.length) {
return peg$result;
} else {
if (peg$result !== peg$FAILED && peg$currPos < input.length) {
peg$fail(peg$endExpectation());
}
throw peg$buildStructuredError(
peg$maxFailExpected,
peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,
peg$maxFailPos < input.length
? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
: peg$computeLocation(peg$maxFailPos, peg$maxFailPos)
);
}
}
const peg$allowedStartRules = [
"Add"
];
export {
peg$allowedStartRules as StartRules,
peg$SyntaxError as SyntaxError,
peg$parse as parse
};