Skip to content

xieyuheng/x-data.js

Repository files navigation

x-data.js

An extension to S-expression to support list with attributes.

For example, we can represent the following JSON:

{ "oranges": 2, "apples": 6, "pears": 5 }

as:

[:oranges 2 :apples 6 :pears 5]

Quoted list:

'(lambda (x) x)

evaluates to:

['lambda ['x] 'x]

This is useful for writing interpreter in lisp with good support for error report.

For example:

(lambda (x) x)

can be parsed to:

['lambda ['x] 'x :row 0 :colum 0]

Install

npm install @xieyuheng/x-data.js

Examples

src/examples/lambda.test.ts:

import assert from "node:assert"
import { test } from "node:test"
import * as X from "../index.ts"

type Exp = Var | Lambda | Apply | Let
type Var = { kind: "Var"; name: string }
type Lambda = { kind: "Lambda"; name: string; ret: Exp }
type Apply = { kind: "Apply"; target: Exp; arg: Exp }
type Let = { kind: "Let"; name: string; rhs: Exp; body: Exp }

function Var(name: string): Var {
  return { kind: "Var", name }
}

function Lambda(name: string, ret: Exp): Lambda {
  return { kind: "Lambda", name, ret }
}

function Apply(target: Exp, arg: Exp): Apply {
  return { kind: "Apply", target, arg }
}

function Let(name: string, rhs: Exp, body: Exp): Let {
  return { kind: "Let", name, rhs, body }
}

function matchExp(data: X.Data): Exp {
  return X.match(expMatcher, data)
}

const expMatcher: X.Matcher<Exp> = X.matcherChoice<Exp>([
  X.matcher("`(lambda (,name) ,ret)", ({ name, ret }) =>
    Lambda(X.symbolToString(name), X.match(expMatcher, ret)),
  ),

  X.matcher("`(let ((,name ,rhs)) ,body)", ({ name, rhs, body }) =>
    Let(
      X.symbolToString(name),
      X.match(expMatcher, rhs),
      X.match(expMatcher, body),
    ),
  ),

  X.matcher("`(,target ,arg)", ({ target, arg }) =>
    Apply(X.match(expMatcher, target), X.match(expMatcher, arg)),
  ),

  X.matcher("name", ({ name }) => Var(X.symbolToString(name))),
])

function assertParse(text: string, exp: Exp): void {
  assert.deepStrictEqual(matchExp(X.parseData(text)), exp)
}

test("lambda example", () => {
  assertParse("x", Var("x"))

  assertParse("(f x)", Apply(Var("f"), Var("x")))

  assertParse("(lambda (x) x)", Lambda("x", Var("x")))

  assertParse(
    "((lambda (x) x) (lambda (x) x))",
    Apply(Lambda("x", Var("x")), Lambda("x", Var("x"))),
  )

  assertParse(
    "(let ((id (lambda (x) x))) (id id))",
    Let("id", Lambda("x", Var("x")), Apply(Var("id"), Var("id"))),
  )
})

Development

npm install     # Install dependencies
npm run build   # Compile `src/` to `lib/`
npm run test    # Run test

References

License

GPLv3

About

An extension to S-expression to support list with attributes.

Resources

License

Stars

Watchers

Forks