2022-11-20 08:53:09 -05:00

122 lines
2.8 KiB
JavaScript

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]
}