diff --git a/3x5.js b/3x5.js index db59db9..7630677 100644 --- a/3x5.js +++ b/3x5.js @@ -24,12 +24,8 @@ * @returns {string} Markup to render / output */ function renderCard(state, code) { - /* Preprocess: fold line endings */ - code = code.replace(/(?<!\\)(\\\\)*\\q/g, "$1"); - /* Preprocess: escape HTML */ - code = escapeHtml(code); - - state.output = code; + const script = parseNotcl(code); + state.output = JSON.stringify(script, null, 2); return state.output; } @@ -59,6 +55,7 @@ let theCard = { } { Since we want escapes to work, these blocks [i will] be subject to substitutions. } + # A comment para { line endings escaped\ one slash diff --git a/index.html b/index.html index e9cad93..f9c3689 100644 --- a/index.html +++ b/index.html @@ -6,6 +6,7 @@ </head> <body> <script src="helpers.js"></script> + <script src="notcl.js"></script> <script src="3x5.js"></script> </body> </html> diff --git a/notcl.js b/notcl.js new file mode 100644 index 0000000..6068dbd --- /dev/null +++ b/notcl.js @@ -0,0 +1,73 @@ +/** + * @typedef {Command[]} Script + * @typedef {Word[]} Command + * @typedef {object} Word + * @property {string} text + */ + +/** + * Parse out a Notcl script into an easier-to-interpret representation. + * No script is actually executed yet. + * + * @param {string} code + * @returns Script + */ +function parseNotcl(code) { + /* Preprocess */ + // fold line endings + code = code.replace(/(?<!\\)(\\\\)*\\n/g, "$1"); + // escape HTML + code = escapeHtml(code); + + /* Parse */ + function nextWord(/* TODO: null/] terminator */) { + // Strip whitespace + code = code.replace(/^[^\S\n;]*/, ""); + // TODO: handle all kinds of brace/substitution stuff + const word = code.match(/^[^\s;]+/); + if (word) { + code = code.substring(word[0].length); + return { text: word[0] }; + } else { + return null; + } + } + + function nextCommand(/* TODO: null/] terminator */) { + const command = /** @type {Word[]} */ ([]); + while (true) { + // Strip whitespace + code = code.replace(/^\s*/, ""); + // Strip comments + if (code[0] == "#") { + code = code.replace(/^.*\n/, ""); + continue; + } + // Strip semicolons + if (code[0] == ";") { + code = code.substring(1); + continue; + } + break; + } + + while (true) { + const word = nextWord(); + if (word) { + command.push(word); + continue; + } + break; + } + + return command; + } + + /* Loop through commands, with safety check */ + const script = /** @type {Command[]} */ ([]); + for (let i = 0; i < 1000 && code != ""; i++) { + script.push(nextCommand()); + } + + return script; +}