import { identifier, literal, Symbol, ws } from './common.js' import { Node, Edge, KeyValuePair, Label, Name, Direction, DirectedEdge } from './types.js' import { curry, is } from '../fn.js' import { many, maybe, map, seq, skip, between, noCaseString, separated, list, any } from '../parser.js' const { Bracket, Colon, Comma, Hyphen } = Symbol const name = map( ([x]) => new Name(x), identifier ) const trim = curry((parser, state) => ( between(ws, parser, ws, state) )) const label = map(([x]) => new Label(x), seq(trim(skip(Colon)), identifier)) const bracketed = curry((value, { Left, Right }, state) => ( between(trim(Left), value, trim(Right), state) )) const kvp = map( ([k, v]) => new KeyValuePair(k, v), separated(name, trim(Colon), literal) ) export const kvps = list(trim(Comma), kvp) export const properties = bracketed(kvps, Bracket.Curly) const id = seq(maybe(name), label) const makeObj = Ctr => params => { const [name, label] = is(Name, params[0]) ? [params[0], params[1]] : [undefined, params[0]] const properties = !name ? params.slice(1) : params.slice(2) return new Ctr(name, label, properties) } export const node = map( makeObj(Node), bracketed(seq(id, maybe(properties)), Bracket.Round) ) export const edge = map( makeObj(Edge), bracketed(seq(id, maybe(properties)), Bracket.Square) ) const arrowRight = map(() => Direction.Right, seq(Hyphen, Bracket.Angle.Right)) const arrowLeft = map(() => Direction.Left, seq(Bracket.Angle.Left, Hyphen)) const relationshipRight = map(([edge, direction]) => DirectedEdge.fromEdge(edge, direction), seq(skip(Hyphen), edge, arrowRight) ) const relationshipLeft = map(([direction, edge]) => DirectedEdge.fromEdge(edge, direction), seq(arrowLeft, edge, skip(Hyphen)) ) const relationship = seq(any(relationshipRight, relationshipLeft), node) const keyword = noCaseString('match') const params = seq(node, many(relationship)) export const statement = seq(skip(keyword), ws, params)