~ehmry/dhall-nim

88637947bfa6dd6b90063519e4089ffa86b90bba — Emery Hemingway 10 months ago 3b8e458
Add xml_to_dhall utility
3 files changed, 105 insertions(+), 1 deletions(-)

M dhall.nimble
A src/dhall/xml.nim
A src/xml_to_dhall.nim
M dhall.nimble => dhall.nimble +1 -1
@@ 6,7 6,7 @@ description   = "Dhall language evaluator"
license       = "GPL-3.0"
srcDir        = "src"
installExt    = @["nim"]

bin           = @["xml_to_dhall"]


# Dependencies

A src/dhall/xml.nim => src/dhall/xml.nim +59 -0
@@ 0,0 1,59 @@
import ./terms

import std/options, std/strtabs, std/xmltree

proc toDhall*(xml: XmlNode): Term =
  ## Convert an XML node to a Dhall Term according to ``Prelude.XML``.
  ## https://github.com/dhall-lang/dhall-lang/blob/v19.0.0/Prelude/XML/Type.dhall
  proc toApp(xml: XmlNode): Term =
    case xml.kind
    of xnText:
      result = newApp(newField(newVar"xml", "text"), xml.text.newTerm)
    of xnElement:
      var attrs = Term(kind: tList, list: newSeqOfCap[Term](xml.attrsLen))
      if xml.attrsLen == 0:
        attrs.listType = some newRecordType(
            [("mapKey", bText.newTerm), ("mapValue", bText.newTerm)])
      else:
        for key, val in xml.attrs.pairs:
          attrs.list.add newRecordLiteral(
            [("mapKey", key.newTerm), ("mapValue", val.newTerm)])
      var content = Term(kind: tList, list: newSeqOfCap[Term](xml.len))
      if xml.len == 0:
        content.listType = some newVar"XML"
      else:
        for subNode in xml.items:
          case subNode.kind
          of xnText, xnElement:
            content.list.add subNode.toApp
          else: discard
      result = newApp(newField(newVar"xml", "element"), newRecordLiteral([ (
          "attributes", attrs), ("content", content), ("name",
          xml.tag.newTerm)]))
    else:
      raiseAssert("unrepresentable XML kind " & $xml.kind)
  var XMLVar = newVar"XML"
  var textPi = newPi(bText.newTerm, XMLVar)
  var elementPi = newPi(
    newRecordType([
      ("name", bText.newTerm),
      ("content", newListType(XMLVar)),
      ("attributes", newListType(
        newRecordType([
          ("mapKey", bText.newTerm), ("mapValue", bText.newTerm)
        ])
      )
    )]),
    XMLvar)
  result = Term(kind: tLambda,
    funcLabel: "XML",
    funcType: bType.newTerm,
    funcBody: Term(kind: tLambda,
        funcLabel: "xml",
        funcType: newRecordType([
          ("text", textPi),
          ("element", elementPi)]),
          funcBody: xml.toApp))

proc toXml*(expr: Value): XmlNode =
  raiseAssert "not implemented"

A src/xml_to_dhall.nim => src/xml_to_dhall.nim +45 -0
@@ 0,0 1,45 @@
import dhall/binary, dhall/render, dhall/xml
import std/parseopt, std/xmlparser

proc usage() =
  stderr.write "xml_to_dhall [--binary|-b] < input.xml > output.dhall"
  quit 1

proc main() =
  type Format = enum unicode, binary, error
  var format: Format
  for kind, key, _ in getopt():
    if format != error:
      case kind:
      of cmdLongOption:
        case key
        of "binary", "cbor", "encode":
          format = binary
        of "help":
          usage()
        else:
          format = error
      of cmdShortOption:
        case key
        of "b", "c", "e":
          format = binary
        of "h":
          usage()
        else:
          format = error
      else:
        format = error

  if format == error:
    echo "unhandled command flags"
    quit -1

  let buf = stdin.readAll
  if buf != "":
    let expr = buf.parseXml.toDhall
    if format == binary:
      stdout.write expr.encode
    else:
      stdout.write $expr

main()