Working on simpler array-based implementation.
This commit is contained in:
121
docs/experiments/parsers/v3/core.js
Normal file
121
docs/experiments/parsers/v3/core.js
Normal 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]
|
||||||
|
}
|
||||||
139
docs/experiments/parsers/v3/example.js
Normal file
139
docs/experiments/parsers/v3/example.js
Normal 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()
|
||||||
Reference in New Issue
Block a user