Skip to content

Instantly share code, notes, and snippets.

@fowlmouth
Last active August 29, 2015 14:21
Show Gist options
  • Save fowlmouth/23416b8607337623a330 to your computer and use it in GitHub Desktop.
Save fowlmouth/23416b8607337623a330 to your computer and use it in GitHub Desktop.
import macros
macro echoCode (x:varargs[untyped]): stmt =
var call = newCall("echo")
let high = len(x)-1
for i in 0 .. high:
let item = x[i]
let code = repr(item)
call.add(
quote do: `code`,
newLit(": "),
quote do: `item`
)
if i < high:
call.add newLit ", "
if len(call) > 1:
return call
type MatchLocation* = object
line*, col*: int
index*: int
proc binarySearch [T] (a: openArray[T], key: T): int =
## binary search for `key` in `a`. Returns insertion index.
## adapted from nim stdlib algorithm module
var b = len(a)
while result < b:
var mid = (result + b) div 2
if a[mid] < key: result = mid + 1
else: b = mid
if result >= len(a): result = -1
proc findLineCol (input:InputState; index:int): MatchLocation =
result.index = index
if input.newlines.len == 0:
# no newlines edgecase
result.line = 0
result.col = index
return
var line = input.newlines.binarySearch(index)
echoCode index, line, input.newlines
if line == -1: line = <len(input.newlines)
let line_index =
if line == 0: 0
else: input.newlines[<line]
#let line_index = input.newlines[line] # index of the newline
stdout.write " "
echoCode line_index
result.line = line
result.col = index - line_index
proc loc* (input:var InputState; index:int): MatchLocation =
if input.newlines.isNil:
input.newlines = newseq[int]()
var i = 0
while i < len(input.str):
if input.str[i] == '\L':
input.newlines.add i
elif input.str[i] == '\r' and input.str[i+1] == '\L':
input.newlines.add i
inc i, 1
inc i,1
result = input.findLineCol index
import glossolalia
type Node = object
s: string
locA,locB: MatchLocation
grammar(Node):
proc dbgNode [N] (r:Rule[N]): Rule[N] =
Rule[N](
m: proc(input:var InputState): Match[N] =
result = r.m(input)
if result.kind == mNodes:
for n in result.nodes:
echo n
echo "____________"
)
proc saveNode (match:string; locA,locB:MatchLocation): Node =
Node(s: match, locA: locA, locB: locB)
whitespace :=
+(str("\r\L") or chr({'\L',' ','\t'}))
test_rule :=
?whitespace and
chr('A').repeat(0,3).save(saveNode).dbgNode and
?whitespace and
chr('B').repeat(0,3).save(saveNode).dbgNode and
?whitespace and
chr('C').repeat(0,3).save(saveNode).dbgNode and
?whitespace
let tests = [
"AAABBBCCC",
"AAA\LBBB\LCCC",
"\LAAA\LBBB\LCCC\L"
]
for t in tests:
let m = test_rule.match(t)
if m:
for x in m.nodes:
echo x
else:
echo "failed to match ", t
echo "#######################################"
(s: AAA, locA: (line: 0, col: 0, index: 0), locB: (line: 0, col: 3, index: 3))
____________
(s: BBB, locA: (line: 0, col: 3, index: 3), locB: (line: 0, col: 6, index: 6))
____________
(s: CCC, locA: (line: 0, col: 6, index: 6), locB: (line: 0, col: 9, index: 9))
____________
(s: AAA, locA: (line: 0, col: 0, index: 0), locB: (line: 0, col: 3, index: 3))
(s: BBB, locA: (line: 0, col: 3, index: 3), locB: (line: 0, col: 6, index: 6))
(s: CCC, locA: (line: 0, col: 6, index: 6), locB: (line: 0, col: 9, index: 9))
#######################################
index: 0, line: 0, input.newlines: @[3, 7]
line_index: 0
index: 3, line: 0, input.newlines: @[3, 7]
line_index: 0
(s: AAA, locA: (line: 0, col: 0, index: 0), locB: (line: 0, col: 3, index: 3))
____________
index: 4, line: 1, input.newlines: @[3, 7]
line_index: 3
index: 7, line: 1, input.newlines: @[3, 7]
line_index: 3
(s: BBB, locA: (line: 1, col: 1, index: 4), locB: (line: 1, col: 4, index: 7))
____________
index: 8, line: -1, input.newlines: @[3, 7]
line_index: 3
index: 11, line: -1, input.newlines: @[3, 7]
line_index: 3
(s: CCC, locA: (line: 1, col: 5, index: 8), locB: (line: 1, col: 8, index: 11))
____________
(s: AAA, locA: (line: 0, col: 0, index: 0), locB: (line: 0, col: 3, index: 3))
(s: BBB, locA: (line: 1, col: 1, index: 4), locB: (line: 1, col: 4, index: 7))
(s: CCC, locA: (line: 1, col: 5, index: 8), locB: (line: 1, col: 8, index: 11))
#######################################
index: 1, line: 1, input.newlines: @[0, 4, 8, 12]
line_index: 0
index: 4, line: 1, input.newlines: @[0, 4, 8, 12]
line_index: 0
(s: AAA, locA: (line: 1, col: 1, index: 1), locB: (line: 1, col: 4, index: 4))
____________
index: 5, line: 2, input.newlines: @[0, 4, 8, 12]
line_index: 4
index: 8, line: 2, input.newlines: @[0, 4, 8, 12]
line_index: 4
(s: BBB, locA: (line: 2, col: 1, index: 5), locB: (line: 2, col: 4, index: 8))
____________
index: 9, line: 3, input.newlines: @[0, 4, 8, 12]
line_index: 8
index: 12, line: 3, input.newlines: @[0, 4, 8, 12]
line_index: 8
(s: CCC, locA: (line: 3, col: 1, index: 9), locB: (line: 3, col: 4, index: 12))
____________
(s: AAA, locA: (line: 1, col: 1, index: 1), locB: (line: 1, col: 4, index: 4))
(s: BBB, locA: (line: 2, col: 1, index: 5), locB: (line: 2, col: 4, index: 8))
(s: CCC, locA: (line: 3, col: 1, index: 9), locB: (line: 3, col: 4, index: 12))
#######################################
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment