shrimp/src/utils/tree.ts
2025-11-14 15:11:04 -08:00

72 lines
2.0 KiB
TypeScript

import { Tree, TreeCursor } from '@lezer/common'
import { type Value, fromValue } from 'reefvm'
import { SyntaxNode } from '#parser/node'
const nodeToString = (node: SyntaxNode, input: string, depth = 0): string => {
const indent = ' '.repeat(depth)
const text = input.slice(node.from, node.to)
const nodeName = node.name
if (node.firstChild) {
return `${indent}${nodeName}`
} else {
// Only strip quotes from whole String nodes (legacy DoubleQuote), not StringFragment/EscapeSeq/CurlyString
const cleanText = nodeName === 'String' ? text.slice(1, -1) : text
return `${indent}${nodeName} ${cleanText}`
}
}
export const treeToString2 = (tree: SyntaxNode, input: string, depth = 0): string => {
let lines = []
let node: SyntaxNode | null = tree
if (node.name === 'Program') node = node.firstChild
while (node) {
lines.push(nodeToString(node, input, depth))
if (node.firstChild)
lines.push(treeToString2(node.firstChild, input, depth + 1))
node = node.nextSibling
}
return lines.join('\n')
}
export const treeToString = (tree: Tree, input: string): string => {
const lines: string[] = []
const addNode = (cursor: TreeCursor, depth: number) => {
if (!cursor.name) return
const indent = ' '.repeat(depth)
const text = input.slice(cursor.from, cursor.to)
const nodeName = cursor.name // Save the node name before moving cursor
if (cursor.firstChild()) {
lines.push(`${indent}${nodeName}`)
do {
addNode(cursor, depth + 1)
} while (cursor.nextSibling())
cursor.parent()
} else {
const cleanText = nodeName === 'String' ? text.slice(1, -1) : text
lines.push(`${indent}${nodeName} ${cleanText}`)
}
}
const cursor = tree.cursor()
if (cursor.firstChild()) {
do {
addNode(cursor, 0)
} while (cursor.nextSibling())
}
return lines.join('\n')
}
export const VMResultToValue = (result: Value): unknown => {
return result.type === 'function' ? Function : fromValue(result)
}