Working on simpler array-based implementation.

This commit is contained in:
Joshua Bemenderfer 2022-11-15 22:07:24 -05:00
parent 296056ce16
commit 5dcf6598ba
2 changed files with 260 additions and 0 deletions

View File

@ -0,0 +1,121 @@
import { createLineData, useDocument } from '@terrace/core'
import { createStringReader } from '@terrace/core/readers/js-string'
export const SYMBOLS = {
TAIL: Symbol('TAIL'),
UNMATCHED: Symbol('UNMATCHED')
}
export const BASE_MACROS = {
// string ({ line }) {
// return tail(line).toString()
// },
// number ({ line }) {
// const num = +tail(line)
// if (isNaN(num) || line === '') return
// return num
// },
// primitive (args) {
// const num = macros.number(args)
// return num !== undefined ? num : macros.string(args)
// },
// any (args) {
// const macro = args.macros[args.head]
// if (macro) return macro(args)
// const numResult = args.macros.number(args)
// if (numResult !== undefined) return numResult
// args.tail = args.line
// return args.macros.string(args)
// },
// scope ({ addScope, head, tail, line }, definition) {
// return addScope({ definition, head, tail, line })
// }
}
export function getTail(key, macro) {
return args => {
const scope = args.scope
const result = macro(args)
if (result === undefined) return
if (!scope[key]) scope[key] = []
scope[key].push(result)
}
}
export function getText(key, macro) {
return (args) => {
const scope = args.scope
const result = macro({...args, tail: args.line })
if (result === undefined) return
if (!scope[key]) scope[key] = []
scope[key].push(result)
}
}
export function getUnmatched(macro) {
return (args) => {
const key = args.head
const scope = args.scope
const result = macro(args)
if (result === undefined) return
if (!scope[key]) scope[key] = []
scope[key].push(result)
}
}
export function isMacro (macro) {
return (args) => args.macros[macro](args)
}
export function isCollection (macro) {
return (args) => ({ [args.head]: macro(args) })
}
export function isScope (definition) {
return (args) => args.macros.scope(args, definition)
}
export async function parse(lines, schema) {
const doc = useDocument(createStringReader(lines))
const macros = schema.macros
const scopes = [[]]
function addScope() {
const scope = []
scopes[scopes.length] = scope
return scope
}
let ended = false
let lastLevel = 0
while (!ended) {
ended = await doc.next()
if (ended) break;
const level = doc.level()
scopes.length = level + 1
if (lastLevel == level) {
console.log('||DECREASE: ', doc.line())
}
lastLevel = level
let entry = [doc.line()]
Object.keys(schema.root).forEach(key => {
if (entry[0] === key || entry[0].startsWith(`${key} `)) {
entry = schema.root[key]({ entry, macros })
}
})
const scope = scopes[level] || []
if (!scopes[level]) {
scopes[level] = scope
scopes[level - 1].at(-1)[1] = scopes[level]
}
scope.push(entry)
}
return scopes[0]
}

View File

@ -0,0 +1,139 @@
import { SYMBOLS, parse, isScope, isMacro, getTail, getText, getUnmatched, isCollection } from './core.js'
const schemaTCE = `
macros
primitive match number string
section
pos number tail
content string unmatched
position number
options
parameter1 number
parameter2 string
literal unmatched string
unmatched primitive
root
title string
options options collection
subsection section
list
- string array
collection
section collection
collection2
unmatched collection
`
function head(line) {
return line.split(' ')[0]
}
function tail(line) {
return line.split(' ').slice(1).join(' ')
}
function chain(...macroNames) {
return (args) => {
for (const macroName of macroNames) {
if (args.macros[macroName]) args.entry = args.macros[macroName](args)
}
return args.entry
}
}
const schema = {
macros: {
tail({ entry }) {
return [head(entry[0]), tail(entry[0])]
},
string({ entry }) {
return [entry[0], entry[1].toString()]
},
number({ entry }) {
const num = +entry[1]
if (isNaN(num) || entry[1] === '') return entry
return [entry[0], num]
},
primitive(args) {
const num = macros.number(args)
return num !== undefined ? num : macros.string(args)
},
scope({ addScope, head, tail, entry }, definition) {
return addScope({ definition, head, tail, entry })
},
section: isScope({
[SYMBOLS.TAIL]: getTail('pos', isMacro('number')),
[SYMBOLS.UNMATCHED]: getText('content', isMacro('string')),
position: isMacro('number')
}),
options: isScope({
parameter1: isMacro('number'),
parameter2: isMacro('string'),
unmatched: isMacro('string'),
[SYMBOLS.UNMATCHED]: getUnmatched(isMacro('any')),
}),
any(args) {
const macro = args.macros[args.head]
if (macro) return macro(args)
const numResult = args.macros.number(args)
if (numResult !== undefined) return numResult
args.tail = args.entry
return args.macros.string(args)
},
},
root: {
// Move tail into value position and cast it to string.
title: chain('tail', 'string'),
// options: isMacro('options'),
// subsection: isMacro('section'),
// list: isScope({
// '-': isMacro('string')
// }),
// collection: isScope({
// section: isCollection(isMacro('section'))
// }),
// collection2: isScope({
// [SYMBOLS.UNMATCHED]: getUnmatched(isMacro('any'))
// })
}
}
const lines = [
`title Example`,
`options`,
` parameter1 30`,
` parameter2 Enim eu id anim minim reprehenderit nostrud eu amet deserunt ea ut do cupidatat ea.`,
`options`,
` parameter1 0`,
` parameter2 Esse incididunt et est adipisicing eiusmod aliqua enim ea aliqua id enim.`,
`subsection`,
` position 1`,
` Ea dolore in aliquip fugiat anim adipisicing amet aute tempor et deserunt est duis sint.`,
`subsection 2`,
` position 2`,
` Aute deserunt incididunt ad in sint adipisicing est officia velit pariatur ipsum deserunt quis nulla.`,
` Ea dolore in aliquip fugiat anim adipisicing amet aute tempor et deserunt est duis sint.`,
`list`,
` - item 1`,
` - item 2`,
`collection`,
` section`,
` lorem ipsum 1`,
` section`,
` lorem ipsum 2`,
`collection2`,
` section`,
` position 3`,
` Laborum aute anim occaecat occaecat pariatur tempor proident magna sit magna non non.`,
` list`,
` 1`,
` 2`
]
async function main() {
console.dir(await parse(lines, schema), { depth: null })
}
main()