~ehmry/dhall-nim

3cf4f2b91592e92c1a88cc62344406c169e76e12 — Emery Hemingway 1 year, 2 months ago b839efa
Dhall AST rendering
1 files changed, 178 insertions(+), 0 deletions(-)

A src/dhall/render.nim
A src/dhall/render.nim => src/dhall/render.nim +178 -0
@@ 0,0 1,178 @@
import ./term

import bigints

import std/options, std/strutils, std/tables

func `$`*(t: Term): string =
  if t.isNil: return "null"
  case t.kind:
  of tUniverse:
    result = $t.universe
  of tBuiltin:
    result = $t.builtin
  of tBoolLiteral:
    result = if t.bool: "True" else: "False"
  of tVar:
    if t.varIndex > 0:
      result = t.varName & "@" & $t.varIndex
    else:
      result = t.varName
  of tLambda:
    result = "(λ(" & t.lambdaLabel & " : " & $t.lambdaType & ") → " &
        $t.lambdaBody & ")"
  of tPi:
    if t.piLabel == "_":
      result = $t.piType & " → " & $t.piBody
    else:
      result = "∀(" & t.piLabel & " : " & $t.piType & ") → " & $t.piBody
  of tApp:
    result = "(" & $t.appFun
    for arg in t.appArgs:
      result.add(" ")
      result.add($arg)
    result.add(" )")
  of tOp:
    result = "(" & $t.opL & " " & $t.op & " " & $t.opR & ")"
  of tLet:
    result = ""
    for b in t.letBinds:
      result.add("let ")
      result.add(b.key)
      if not b.ann.isNil:
        result.add(": ")
        result.add($b.ann)
      result.add(" = ")
      result.add($b.val)
    result.add(" in ")
    result.add($t.letBody)
  of tAnnotation:
    result = $t.annExpr & " : " & $t.annAnn
  of tNaturalLiteral:
    result = $t.natural
  of tList:
    if t.list.len == 0:
      result = "[] : " & $t.listType
    else:
      result = "[ " & join(t.list, ", ") & " ]"
  of tTextLiteral:
    var hasNewline = t.textSuffix.contains({'\n'})
    for tc in t.textChunks:
      if hasNewline: break
      hasNewLine = tc.textPrefix.contains({'\n'})
    if hasNewline:
      result = "''\n"
      for tc in t.textChunks:
        result.add $tc
      result.add t.textSuffix
      result.add "''"
    else:
      result = "\""
      for tc in t.textChunks:
        result.add $tc
      result.add t.textSuffix
      result.add "\""
  of tAssert:
    result = "assert : " & $t.assertAnn
  of tImport:
    result = "import "
    result.add case t.importKind
      of iCode: ""
      of iText: "as Text "
      of iLocation: "as Location "
    result.add case t.importScheme
      of 0: "http://"
      of 1: "https://"
      of 2: "/"
      of 3: "./"
      of 4: "../"
      of 5: "~/"
      of 6: "env:"
      of 7: "missing"
      else: raiseAssert("unhandled import scheme " & $t.importScheme)
    result.add(join(t.importElements, "/"))
    if t.importQuery.isSome:
      result.add("?")
      result.add(t.importQuery.get)
    if not t.importCheck.len == 0:
      result.add " sha256:"
      for i in 2..31:
        result.add t.importCheck[i].toHex
  of tIf:
    result = "if " & $t.ifCond & " then " & $t.ifTrue & " else " & $t.ifFalse
  of tDoubleLiteral:
    result = $t.double
  of tIntegerLiteral:
    result = if t.integer > 0:
        "+" & $t.integer
      else: $t.integer
  of tSome:
    result = "Some " & $t.someVal
  of tRecordType:
    if t.recordType.len == 0:
      result = "{}"
    else:
      result = "{ "
      for key, val in t.recordType.pairs:
        if key == "" or key.startsWith(' ') or key.endsWith(' '):
          # TODO: builtin labels
          result.add "`"
          result.add(key)
          result.add "`"
        else:
          result.add(key)
        result.add(" : ")
        result.add($val)
        result.add(", ")
      result[^2] = ' '
      result[^1] = '}'
  of tRecordLiteral:
    if t.recordLiteral.len == 0:
      result = "{=}"
    else:
      result = "{ "
      for key, val in t.recordLiteral.pairs:
        result.add(key)
        result.add(" = ")
        result.add($val)
        result.add(", ")
      result[^2] = ' '
      result[^1] = '}'
  of tToMap:
    if t.toMapAnn.isNil:
      result = "toMap " & $t.toMapBody
    else:
      result = "toMap " & $t.toMapBody & " : " & $t.toMapAnn
  of tEmptyList:
    result = "[] : " & $t.emptyListType
  of tField:
    result = "(" & $t.fieldRecord & ")." & t.fieldName
  of tProject:
    result = $t.projectRecord & ".{" & join(t.projectNames, ", ") & "}"
  of tProjectType:
    result = $t.projectTypeRecord & ".(" & $t.projectTypeSelector & ")"
  of tUnionType:
    if t.union.len == 0:
      result = "<>"
    else:
      result = "< "
      for key, val in t.union.pairs:
        result.add(key)
        if not val.isNil:
          result.add(" : ")
          result.add($val)
        result.add(" | ")
      result[^2] = ' '
      result[^1] = '>'
  of tMerge:
    if t.mergeAnn.isNil:
      result = "merge (" & $t.mergeHandler & ") (" & $t.mergeUnion & ")"
    else:
      result = "merge (" & $t.mergeHandler & ") (" & $t.mergeUnion &
          ") : " & $t.mergeAnn
  of tEntry:
    result = "« " & $t.entryKey & " = " & $t.entryVal & " »"
  of tTextChunk:
    result = t.textPrefix & "${" & $t.textExpr & "}"
  of tBinding:
    result = "« " & $t.key & " = " & $t.val & " »"