Usage

Lilt is on nimble. A simple nimble refresh will download or update the package. Then, in your Nim code, just import lilt.

We’ll start with the bread and butter parser type:

Parser* = proc(text: string): LiltValue

A parser accepts some text and returns a parsed value. Alternatively, it may throw a RuleError, which just says that the text didn’t match the parser.

The returned value may be text, a node, or a list of nodes. This is encoded in the next three types:

LiltType* = enum
    ltText
    ltNode
    ltList

LiltValue* = object
    case kind*: LiltType
    of ltText:
        text*: string
    of ltNode:
        node*: Node
    of ltList:
        list*: seq[Node]

Node* = object
    kind*: string  # name of the rule that this node was parsed by
    properties*: TableRef[string, LiltValue]  # properties of the node

Instead of writing node.properties[key], one can just write node[key] via the following proc:

proc `[]`(node: Node, key: string): LiltValue =
  return node.properties[key]

In order to create parsers, one should use the included makeParsers proc, which looks like:

proc makeParsers*(code: string): Table[string, Parser]

It accepts a Lilt specification (code), and returns all of the defined rules in that specification as a table mapping :code:`string`s to :code:`Parser`s.

For your convenience, three LiltValue initializers have also been included:

proc initLiltValue*(text: string): LiltValue =
    return LiltValue(kind: ltText, text: text)

proc initLiltValue*(node: Node): LiltValue =
    return LiltValue(kind: ltNode, node: node)

proc initLiltValue*(list: seq[Node]): LiltValue =
    return LiltValue(kind: ltList, list: list)

Example

We’ll use the JSON parser example from the tutorial:

import lilt
import tables

# Create our Lilt specification
# Could also be, for instance, read from a file
const spec = """
value: _ #[string | number | object | array | trueLiteral | falseLiteral | nullLiteral] _
trueLiteral: _="" "true"
falseLiteral: _="" "false"
nullLiteral: _="" "null"

string: '"' value=*stringChar '"'
stringChar: [!<"\\> any] | "\\" [</\\bfnrt> | "u" hexDig hexDig hexDig hexDig]
hexDig: <1234567890ABCDEFabcdef>

number: ?negative="-" wholes=["0" | +digit] ?["." decimals=*digit] ?exponent=numberExp
numberExp: <eE> sign=<+-> digits=+digit

object: "{" _ pairs=?{&pair *["," &pair]} _ "}"
pair: _ key=string _ ":" _ value=value _

array: "[" _ items=?{&value *["," &value]} _ "]"
"""

# Is a Table[string, Parser]
let parsers = makeParsers(spec)

# Let's say we want to parse a number
# Get that parser by the name of the rule: "number"
let numberParser = parsers["number"]

# ...and use it!
let parsedNumber = numberParser("3.0e+10")

echo parsedNumber.node["wholes"].text  # "3"
echo parsedNumber.node["decimals"].text  # "0"
echo parsedNumber.node["exponent"].node["sign"].text  # "+"
echo parsedNumber.node["exponent"].node["digits"].text  # "10"


# Let's try it with some simple JSON
let jsonParser = parsers["value"]

echo jsonParser("30").node  # {"wholes": "30"}
echo jsonParser("\"string\"").node  # {"value": "string"}
echo jsonParser("""
{
  "name": "marbles",
  "color": "red",
  "count": 100
}
""").node
#[ becomes
{
  "pairs": [
    {
      "key": {"value": "name"},
      "value": {"value": "marbles"}
    },
    {
      "key": {"value": "color"},
      "value": {"value": "red"}
    },
    {
      "key": {"value": "count"},
      "value": {"wholes": 100},
    }
  ]
}
]#

Sublime Text 3 Integration

st3/Lilt.sublime-syntax contains a syntax definition for Lilt specifications usable with Sublime Text 3. Unfortuantely, there is no package on Package Control (yet).

To install, just drop Lilt.sublime-text into ~/.config/sublime-text-3/Packages/User. Then, in ST3, select view > syntax > Lilt. However, this should not be needed for .lilt files.