diff options
author | bptato <nincsnevem662@gmail.com> | 2024-02-17 22:03:07 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-02-17 22:07:11 +0100 |
commit | 390772358cedc9ed541a27b3cac1f8d97beef0ef (patch) | |
tree | 621e56ad7b1b4957b1ba686a8902381ce270619c /src/js | |
parent | e98d0ad1dc51050eb17120f835847d55950c2a0b (diff) | |
download | chawan-390772358cedc9ed541a27b3cac1f8d97beef0ef.tar.gz |
regex: re-work compileSearchRegex
I've gotten tired of not being able to search for forward slashes. Now it works like in vim, and you can also set default ignore case in the config.
Diffstat (limited to 'src/js')
-rw-r--r-- | src/js/fromjs.nim | 23 | ||||
-rw-r--r-- | src/js/javascript.nim | 1 | ||||
-rw-r--r-- | src/js/opaque.nim | 8 | ||||
-rw-r--r-- | src/js/regex.nim | 84 | ||||
-rw-r--r-- | src/js/tojs.nim | 11 |
5 files changed, 62 insertions, 65 deletions
diff --git a/src/js/fromjs.nim b/src/js/fromjs.nim index 823a045e..f0ff8a91 100644 --- a/src/js/fromjs.nim +++ b/src/js/fromjs.nim @@ -10,6 +10,7 @@ import js/jstypes import js/opaque import js/tojs import types/opt +import utils/twtstr proc fromJS*[T](ctx: JSContext, val: JSValue): JSResult[T] @@ -230,7 +231,7 @@ proc fromJSSeq[T](ctx: JSContext, val: JSValue): JSResult[seq[T]] = s.add(genericRes.get) return ok(s) -proc fromJSSet[T](ctx: JSContext, val: JSValue): Opt[set[T]] = +proc fromJSSet[T](ctx: JSContext, val: JSValue): JSResult[set[T]] = let itprop = JS_GetProperty(ctx, val, ctx.getOpaque().sym_refs[ITERATOR]) if JS_IsException(itprop): return err() @@ -249,14 +250,14 @@ proc fromJSSet[T](ctx: JSContext, val: JSValue): Opt[set[T]] = if JS_IsException(next): return err() defer: JS_FreeValue(ctx, next) - let doneVal = JS_GetProperty(ctx, next, ctx.getOpaque().done) + let doneVal = JS_GetProperty(ctx, next, ctx.getOpaque().str_refs[DONE]) if JS_IsException(doneVal): return err() defer: JS_FreeValue(ctx, doneVal) let done = ?fromJS[bool](ctx, doneVal) if done: break - let valueVal = JS_GetProperty(ctx, next, ctx.getOpaque().value) + let valueVal = JS_GetProperty(ctx, next, ctx.getOpaque().str_refs[VALUE]) if JS_IsException(valueVal): return err() defer: JS_FreeValue(ctx, valueVal) @@ -377,19 +378,9 @@ proc fromJSEnum[T: enum](ctx: JSContext, val: JSValue): JSResult[T] = if JS_IsException(val): return err() let s = ?toString(ctx, val) - # cmp when len is small enough, otherwise hashmap - when {T.low..T.high}.len <= 4: - for e in T.low .. T.high: - if $e == s: - return ok(e) - else: - const tab = (func(): Table[string, T] = - result = initTable[string, T]() - for e in T.low .. T.high: - result[$e] = e - )() - if s in tab: - return ok(tab[s]) + let r = strictParseEnum[T](s) + if r.isSome: + return ok(r.get) return errTypeError("`" & s & "' is not a valid value for enumeration " & $T) proc fromJSPObj0(ctx: JSContext, val: JSValue, t: string): diff --git a/src/js/javascript.nim b/src/js/javascript.nim index 9e814386..d208ffad 100644 --- a/src/js/javascript.nim +++ b/src/js/javascript.nim @@ -170,6 +170,7 @@ proc free*(ctx: var JSContext) = JS_FreeValue(ctx, opaque.Array_prototype_values) JS_FreeValue(ctx, opaque.Object_prototype_valueOf) JS_FreeValue(ctx, opaque.Uint8Array_ctor) + JS_FreeValue(ctx, opaque.Set_ctor) for v in opaque.err_ctors: JS_FreeValue(ctx, v) GC_unref(opaque) diff --git a/src/js/opaque.nim b/src/js/opaque.nim index 135b6994..bae2bd5a 100644 --- a/src/js/opaque.nim +++ b/src/js/opaque.nim @@ -33,6 +33,7 @@ type Array_prototype_values*: JSValue Object_prototype_valueOf*: JSValue Uint8Array_ctor*: JSValue + Set_ctor*: JSValue err_ctors*: array[JSErrorEnum, JSValue] htmldda*: JSClassID # only one of these exists: document.all. @@ -71,8 +72,11 @@ func newJSContextOpaque*(ctx: JSContext): JSContextOpaque = opaque.Object_prototype_valueOf = JS_GetPropertyStr(ctx, objproto, "valueOf") JS_FreeValue(ctx, objproto) block: - let u8actor = JS_GetPropertyStr(ctx, global, "Uint8Array") - opaque.Uint8Array_ctor = u8actor + opaque.Set_ctor = JS_GetPropertyStr(ctx, global, "Set") + assert not JS_IsException(opaque.Set_ctor) + block: + opaque.Uint8Array_ctor = JS_GetPropertyStr(ctx, global, "Uint8Array") + assert not JS_IsException(opaque.Uint8Array_ctor) for e in JSErrorEnum: let s = $e let err = JS_GetPropertyStr(ctx, global, cstring(s)) diff --git a/src/js/regex.nim b/src/js/regex.nim index fdc9e8e0..1d78f806 100644 --- a/src/js/regex.nim +++ b/src/js/regex.nim @@ -6,13 +6,7 @@ import bindings/quickjs import types/opt import utils/twtstr -export - LRE_FLAG_GLOBAL, - LRE_FLAG_IGNORECASE, - LRE_FLAG_MULTILINE, - LRE_FLAG_DOTALL, - LRE_FLAG_UTF16, - LRE_FLAG_STICKY +export LREFlags type Regex* = object @@ -34,13 +28,13 @@ var dummyContext = JS_NewContextRaw(dummyRuntime) func `$`*(regex: Regex): string = regex.buf -proc compileRegex*(buf: string, flags: int): Result[Regex, string] = +proc compileRegex*(buf: string, flags: LREFlags = {}): Result[Regex, string] = var error_msg_size = 64 var error_msg = newString(error_msg_size) prepareMutation(error_msg) var plen: cint let bytecode = lre_compile(addr plen, cstring(error_msg), - cint(error_msg_size), cstring(buf), csize_t(buf.len), cint(flags), + cint(error_msg_size), cstring(buf), csize_t(buf.len), flags.toCInt, dummyContext) if bytecode == nil: return err(error_msg.until('\0')) # Failed to compile. @@ -68,16 +62,16 @@ func countBackslashes(buf: string, i: int): int = # mnop -> ^mnop$ proc compileMatchRegex*(buf: string): Result[Regex, string] = if buf.len == 0: - return compileRegex(buf, 0) + return compileRegex(buf) if buf[0] == '^': - return compileRegex(buf, 0) + return compileRegex(buf) if buf[^1] == '$': # Check whether the final dollar sign is escaped. if buf.len == 1 or buf[^2] != '\\': - return compileRegex(buf, 0) + return compileRegex(buf) let j = buf.countBackslashes(buf.high - 2) if j mod 2 == 1: # odd, because we do not count the last backslash - return compileRegex(buf, 0) + return compileRegex(buf) # escaped. proceed as if no dollar sign was at the end if buf[^1] == '\\': # Check if the regex contains an invalid trailing backslash. @@ -87,38 +81,34 @@ proc compileMatchRegex*(buf: string): Result[Regex, string] = var buf2 = "^" buf2 &= buf buf2 &= "$" - return compileRegex(buf2, 0) - -proc compileSearchRegex*(str: string): Result[Regex, string] = - # Parse any applicable flags in regex/<flags>. The last forward slash is - # dropped when <flags> is empty, and interpreted as a character when the - # flags are is invalid. - - var i = str.high - var flagsi = -1 - while i >= 0: - case str[i] - of '/': - flagsi = i - break - of 'i', 'm', 's', 'u': discard - else: break # invalid flag - dec i - - var flags = LRE_FLAG_GLOBAL # for easy backwards matching - - if flagsi == -1: - return compileRegex(str, flags) - - for i in flagsi..str.high: - case str[i] - of '/': discard - of 'i': flags = flags or LRE_FLAG_IGNORECASE - of 'm': flags = flags or LRE_FLAG_MULTILINE - of 's': flags = flags or LRE_FLAG_DOTALL - of 'u': flags = flags or LRE_FLAG_UTF16 - else: assert false - return compileRegex(str.substr(0, flagsi - 1), flags) + return compileRegex(buf2) + +proc compileSearchRegex*(str: string, defaultFlags: LREFlags): + Result[Regex, string] = + # Emulate vim's \c/\C: override defaultFlags if one is found, then remove it + # from str. + var flags = defaultFlags + var s = newStringOfCap(str.len) + var quot = false + for c in str: + if quot: + quot = false + if c == 'c': + flags.incl(LRE_FLAG_IGNORECASE) + continue + elif c == 'C': + flags.excl(LRE_FLAG_IGNORECASE) + continue + else: + s &= '\\' + if c == '\\': + quot = true + else: + s &= c + if quot: + s &= '\\' + flags.incl(LRE_FLAG_GLOBAL) # for easy backwards matching + return compileRegex(s, flags) proc exec*(regex: Regex, str: string, start = 0, length = -1, nocaps = false): RegexResult = let length = if length == -1: @@ -134,7 +124,7 @@ proc exec*(regex: Regex, str: string, start = 0, length = -1, nocaps = false): R let size = sizeof(ptr uint8) * captureCount * 2 capture = cast[ptr UncheckedArray[int]](alloc0(size)) var cstr = cstring(str) - let flags = lre_get_flags(bytecode) + let flags = lre_get_flags(bytecode).toLREFlags var start = start while true: let ret = lre_exec(cast[ptr ptr uint8](capture), bytecode, @@ -151,7 +141,7 @@ proc exec*(regex: Regex, str: string, start = 0, length = -1, nocaps = false): R let s = capture[i * 2] - cstrAddress let e = capture[i * 2 + 1] - cstrAddress result.captures.add((s, e)) - if (flags and LRE_FLAG_GLOBAL) != 1: + if LRE_FLAG_GLOBAL notin flags: break if start >= str.len: break diff --git a/src/js/tojs.nim b/src/js/tojs.nim index c79d1bf2..757552eb 100644 --- a/src/js/tojs.nim +++ b/src/js/tojs.nim @@ -64,6 +64,7 @@ proc toJS*[U, V](ctx: JSContext, t: Table[U, V]): JSValue proc toJS*(ctx: JSContext, opt: Option): JSValue proc toJS*[T, E](ctx: JSContext, opt: Result[T, E]): JSValue proc toJS*(ctx: JSContext, s: seq): JSValue +proc toJS*[T](ctx: JSContext, s: set[T]): JSValue proc toJS*(ctx: JSContext, t: tuple): JSValue proc toJS*(ctx: JSContext, e: enum): JSValue proc toJS*(ctx: JSContext, j: JSValue): JSValue @@ -209,6 +210,16 @@ proc toJS(ctx: JSContext, s: seq): JSValue = return JS_EXCEPTION return a +proc toJS*[T](ctx: JSContext, s: set[T]): JSValue = + #TODO this is a bit lazy :p + var x = newSeq[T]() + for e in s: + x.add(e) + var a = toJS(ctx, x) + if JS_IsException(a): + return a + return JS_CallConstructor(ctx, ctx.getOpaque().Set_ctor, 1, addr a) + proc toJS(ctx: JSContext, t: tuple): JSValue = let a = JS_NewArray(ctx) if not JS_IsException(a): |