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() const scope = scopes[level] || [] scopes.length = level + 1 let entry = [doc.line()] Object.keys(schema.root).forEach(key => { if (entry[0] === key || entry[0].startsWith(`${key} `)) { entry = schema.root[key]({ entry, macros }) } }) if (!scopes[level]) { scopes[level] = scope scopes[level - 1].at(-1)[1] = scopes[level] } scope.push(entry) if (lastLevel == level) { console.log('DECREASE: ', doc.line(), scope) } lastLevel = level } return scopes[0] }