diff options
author | bptato <nincsnevem662@gmail.com> | 2023-06-28 04:07:22 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2023-06-28 04:07:22 +0200 |
commit | 7e0d0d96e4b8143509ae7d118f9e3dfc1077c468 (patch) | |
tree | 89ac493b661256884c680f6213508f999b4a43f4 /src/js/javascript.nim | |
parent | c1975f3cd58ef1c1e8e2105ad486619cea4ad23e (diff) | |
download | chawan-7e0d0d96e4b8143509ae7d118f9e3dfc1077c468.tar.gz |
Refactor fromJS body
Diffstat (limited to 'src/js/javascript.nim')
-rw-r--r-- | src/js/javascript.nim | 153 |
1 files changed, 87 insertions, 66 deletions
diff --git a/src/js/javascript.nim b/src/js/javascript.nim index 352a000e..013bbed3 100644 --- a/src/js/javascript.nim +++ b/src/js/javascript.nim @@ -399,6 +399,8 @@ func getMinArgs(params: seq[FuncParam]): int = return params.len func fromJSInt[T: SomeInteger](ctx: JSContext, val: JSValue): Opt[T] = + if not JS_IsNumber(val): + return err() when T is int: # Always int32, so we don't risk 32-bit only breakage. # If int64 is needed, specify it explicitly. @@ -432,6 +434,14 @@ func fromJSInt[T: SomeInteger](ctx: JSContext, val: JSValue): Opt[T] = return err() return ok(cast[uint64](ret)) +proc fromJSFloat[T: SomeFloat](ctx: JSContext, val: JSValue): Opt[T] = + if not JS_IsNumber(val): + return err() + var f64: float64 + if JS_ToFloat64(ctx, addr f64, val) < 0: + return err() + return ok(cast[T](f64)) + proc fromJS*[T](ctx: JSContext, val: JSValue): Opt[T] macro len(t: type tuple): int = @@ -673,44 +683,85 @@ macro unpackArg0(f: typed) = let rvv = rv[1] result = quote do: `rvv` +proc fromJSChar(ctx: JSContext, val: JSValue): Opt[char] = + let s = ?toString(ctx, val) + if s.len > 1: + return err() + return ok(s[0]) + +proc fromJSRune(ctx: JSContext, val: JSValue): Opt[Rune] = + let s = ?toString(ctx, val) + var i = 0 + var r: Rune + fastRuneAt(s, i, r) + if i < s.len: + return err() + return ok(r) + +template optionType[T](o: type Option[T]): auto = + T + +# wrap +proc fromJSOption[T](ctx: JSContext, val: JSValue): Opt[Option[T]] = + if JS_IsUndefined(val): + #TODO what about null? + return err() + let res = ?fromJS[T](ctx, val) + return ok(some(res)) + +# unwrap +proc fromJSOpt[T](ctx: JSContext, val: JSValue): Opt[T] = + if JS_IsUndefined(val): + #TODO what about null? + return err() + let res = ?fromJS[T](ctx, val) + return ok(res) + +proc fromJSBool(ctx: JSContext, val: JSValue): Opt[bool] = + let ret = JS_ToBool(ctx, val) + if ret == -1: # exception + return err() + if ret == 0: + return ok(false) + return ok(true) + +proc fromJSEnum[T: enum](ctx: JSContext, val: JSValue): Opt[T] = + if JS_IsException(val): + return err() + let s = ?toString(ctx, val) + try: + return ok(parseEnum[T](s)) + except ValueError: + JS_ThrowTypeError(ctx, "`%s' is not a valid value for enumeration %s", + cstring(s), $T) + return err() + +proc fromJSObject[T: ref object](ctx: JSContext, val: JSValue): Opt[T] = + if JS_IsException(val): + return err() + if JS_IsNull(val): + return ok(T(nil)) + if ctx.isGlobal($T): + return getGlobalOpaque[T](ctx, val) + if not JS_IsObject(val): + JS_ThrowTypeError(ctx, "Value is not an object") + return err() + let op = getOpaque0(val) + return ok(cast[T](op)) + proc fromJS*[T](ctx: JSContext, val: JSValue): Opt[T] = when T is string: return toString(ctx, val) elif T is char: - let s = toString(ctx, val) - if s.isNone: - return none(char) - if s.get.len > 1: - return none(char) - return some(s.get[0]) + return fromJSChar(ctx, val) elif T is Rune: - let s = toString(ctx, val) - if s.isNone: - return none(Rune) - var i = 0 - var r: Rune - fastRuneAt(s.get, i, r) - if i < s.get.len: - return none(Rune) - return some(r) + return fromJSRune(ctx, val) elif T is (proc): return fromJSFunction1[typeof(unpackReturnType(T)), typeof(unpackArg0(T))](ctx, val) - elif T is Option: # convert - if JS_IsUndefined(val): - #TODO what about null? - return err() - let res = fromJS[typeof(result.get.get)](ctx, val) - if res.isNone: - return err() - return ok(some(res.get)) - elif typeof(result).valType is Opt: # unwrap - if JS_IsUndefined(val): - #TODO what about null? - return err() - let res = fromJS[typeof(T.valType)](ctx, val) - if res.isNone: - return err() - return ok(res) + elif T is Option: + return fromJSOption[optionType(T)](ctx, val) + elif T is Opt: # unwrap + return fromJSOpt[T](ctx, val) elif T is seq: return fromJSSeq[typeof(result.get.items)](ctx, val) elif T is set: @@ -718,49 +769,19 @@ proc fromJS*[T](ctx: JSContext, val: JSValue): Opt[T] = elif T is tuple: return fromJSTuple[T](ctx, val) elif T is bool: - let ret = JS_ToBool(ctx, val) - if ret == -1: # exception - return err() - if ret == 0: - return ok(false) - return ok(true) + return fromJSBool(ctx, val) elif typeof(result).valType is Table: return fromJSTable[typeof(result.get.keys), typeof(result.get.values)](ctx, val) elif T is SomeInteger: - if JS_IsNumber(val): - return fromJSInt[T](ctx, val) + return fromJSInt[T](ctx, val) elif T is SomeFloat: - if JS_IsNumber(val): - var f64: float64 - if JS_ToFloat64(ctx, addr f64, val) < 0: - return err() - return ok(cast[T](f64)) + return fromJSFloat[T](ctx, val) elif T is enum: - #TODO implement enum handling... - if JS_IsException(val): - return err() - let s = toString(ctx, val) - if s.isErr: - return err() - try: - return ok(parseEnum[T](s.get)) - except ValueError: - JS_ThrowTypeError(ctx, "`%s' is not a valid value for enumeration %s", cstring(s.get), $T) - return err() + return fromJSEnum[T](ctx, val) elif T is JSValue: return ok(val) elif T is ref object: - if JS_IsException(val): - return err() - if JS_IsNull(val): - return ok(T(nil)) - if ctx.isGlobal($T): - return getGlobalOpaque[T](ctx, val) - if not JS_IsObject(val): - JS_ThrowTypeError(ctx, "Value is not an object") - return err() - let op = getOpaque0(val) - return ok(cast[T](op)) + return fromJSObject[T](ctx, val) else: static: doAssert false |