# this is a copy paste implementation of github.com/krux02/ast_pattern_matching # Please provide bugfixes upstream first before adding them here. import macros, strutils, tables export macros when isMainModule: template debug(args: varargs[untyped]): untyped = echo args else: template debug(args: varargs[untyped]): untyped = discard const nnkIntLiterals* = nnkCharLit..nnkUInt64Lit nnkStringLiterals* = nnkStrLit..nnkTripleStrLit nnkFloatLiterals* = nnkFloatLit..nnkFloat64Lit proc newLit[T: enum](arg: T): NimNode = newIdentNode($arg) proc newLit[T](arg: set[T]): NimNode = ## does not work for the empty sets result = nnkCurly.newTree for x in arg: result.add newLit(x) type SomeFloat = float | float32 | float64 proc len[T](arg: set[T]): int = card(arg) type MatchingErrorKind* = enum NoError WrongKindLength WrongKindValue WrongIdent WrongCustomCondition MatchingError = object node*: NimNode expectedKind*: set[NimNodeKind] case kind*: MatchingErrorKind of NoError: discard of WrongKindLength: expectedLength*: int of WrongKindValue: expectedValue*: NimNode of WrongIdent, WrongCustomCondition: strVal*: string proc `$`*(arg: MatchingError): string = let n = arg.node case arg.kind of NoError: "no error" of WrongKindLength: let k = arg.expectedKind let l = arg.expectedLength var msg = "expected " if k.len == 0: msg.add "any node" elif k.len == 1: for el in k: # only one element but there is no index op for sets msg.add $el else: msg.add "a node in" & $k if l >= 0: msg.add " with " & $l & " child(ren)" msg.add ", but got " & $n.kind if l >= 0: msg.add " with " & $n.len & " child(ren)" msg of WrongKindValue: let k = $arg.expectedKind let v = arg.expectedValue.repr var msg = "expected " & k & " with value " & v & " but got " & n.lispRepr if n.kind in {nnkOpenSymChoice, nnkClosedSymChoice}: msg = msg & " (a sym-choice does not have a strVal member, maybe you should match with `ident`)" msg of WrongIdent: let prefix = "expected ident `" & arg.strVal & "` but got " if n.kind in {nnkIdent, nnkSym, nnkOpenSymChoice, nnkClosedSymChoice}: prefix & "`" & n.strVal & "`" else: prefix & $n.kind & " with " & $n.len & " child(ren)" of WrongCustomCondition: "custom condition check failed: " & arg.strVal proc failWithMatchingError*(arg: MatchingError): void {.compileTime, noReturn.} = error($arg, arg.node) proc expectValue(arg: NimNode; value: SomeInteger): void {.compileTime.} = arg.expectKind nnkLiterals if arg.intVal != int(value): error("expected value " & $value & " but got " & arg.repr, arg) proc expectValue(arg: NimNode; value: SomeFloat): void {.compileTime.} = arg.expectKind nnkLiterals if arg.floatVal != float(value): error("expected value " & $value & " but got " & arg.repr, arg) proc expectValue(arg: NimNode; value: string): void {.compileTime.} = arg.expectKind nnkLiterals if arg.strVal != value: error("expected value " & value & " but got " & arg.repr, arg) proc expectValue[T](arg: NimNode; value: pointer): void {.compileTime.} = arg.expectKind nnkLiterals if value != nil: error("Expect Value for pointers works only on `nil` when the argument is a pointer.") arg.expectKind nnkNilLit proc expectIdent(arg: NimNode; strVal: string): void {.compileTime.} = if not arg.eqIdent(strVal): error("Expect ident `" & strVal & "` but got " & arg.repr) proc matchLengthKind*(arg: NimNode; kind: set[NimNodeKind]; length: int): MatchingError {.compileTime.} = let kindFail = not(kind.card == 0 or arg.kind in kind) let lengthFail = not(length < 0 or length == arg.len) if kindFail or lengthFail: result.node = arg result.kind = WrongKindLength result.expectedLength = length result.expectedKind = kind proc matchLengthKind*(arg: NimNode; kind
# Compatible with ranger 1.4.2 through 1.6.*
#
# Automatically change the directory in bash after closing ranger
#
# This is a bash function for .bashrc to automatically change the directory to
# the last visited one after ranger quits.
# To undo the effect of this function, you can type "cd -" to return to the
# original directory.
function ranger-cd {
tempfile='/tmp/chosendir'
/usr/bin/ranger --choosedir="$tempfile" "${@:-$(pwd)}"
test -f "$tempfile" &&
if [ "$(cat -- "$tempfile")" != "$(echo -n `pwd`)" ]; then
cd -- "$(cat "$tempfile")"
fi
rm -f -- "$tempfile"
}
# This binds Ctrl-O to ranger-cd:
bind '"\C-o":"ranger-cd\C-m"'