Skip to content

Instantly share code, notes, and snippets.

@soasme
Created October 18, 2018 09:02
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save soasme/1a5271090250baed7936b5ac451e50c2 to your computer and use it in GitHub Desktop.
Save soasme/1a5271090250baed7936b5ac451e50c2 to your computer and use it in GitHub Desktop.
import re, strutils, strformat, tables, sequtils, math
type
Header* = object
doc: string
level: int
MarkdownTokenType* {.pure.} = enum
Header
MarkdownTokenRef* = ref object
case type*: MarkdownTokenType
of MarkdownTokenType.Header: headerVal*: Header
MarkdownError* = object of Exception
let blockRules = {
MarkdownTokenType.Header: re"^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)",
}.toTable
proc findToken(doc: string, start: var int, ruleType: MarkdownTokenType): MarkdownTokenRef =
let regex = blockRules[ruleType]
var matches: array[5, string]
let size = doc[start .. doc.len - 1].matchLen(regex, matches=matches)
if size == -1:
return nil
case ruleType
of MarkdownTokenType.Header:
let val = Header(level: matches[0].len, doc: matches[1])
result = MarkdownTokenRef(type: MarkdownTokenType.Header, headerVal: val)
start += size
iterator parseTokens(doc: string): MarkdownTokenRef =
var n = 0
while n < len(doc):
var token: MarkdownTokenRef = nil
for type in [
MarkdownTokenType.Header,
]:
token = findToken(doc, n, type)
if token != nil:
yield token
break
if token == nil:
raise newException(MarkdownError, fmt"unknown block rule at position {n}.")
proc renderToken(token: MarkdownTokenRef): string =
case token.type
of MarkdownTokenType.Header:
let header = token.headerVal
result = fmt"<h{header.level}>{header.doc}</h{header.level}>"
proc markdown*(doc: string): string =
for token in parseTokens(doc):
result &= renderToken(token)
when isMainModule:
stdout.write(markdown(stdin.readAll))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment