Permalink
Browse files

Added methods for table: clone, slice, keys, values...

For tuple: slice. For bytes and string: clone
Added support for negative arguments for string.slice
Changed API's for potion_type_error_want
  • Loading branch information...
1 parent d0316fa commit c2314c7a3ec5a082169677f60fb510fcef420879 @rurban rurban committed Oct 20, 2013
Showing with 103 additions and 59 deletions.
  1. +4 −1 ChangeLog
  2. +3 −3 core/internal.c
  3. +10 −8 core/potion.h
  4. +31 −2 core/string.c
  5. +29 −24 core/table.c
  6. +12 −12 lib/aio.c
  7. +14 −9 test/tables/slice.pn
View
5 ChangeLog
@@ -1,7 +1,10 @@
v0.2 planned: Dec 21 2013 rurban
* print and say methods return "" instead of nil.
- * Added methods for table: clone, slice, keys, values. For tuple: slice
+ * Added methods for table: clone, slice, keys, values.
+ For tuple: slice. For bytes and string: clone
+ * Added support for negative arguments for string.slice
+ * Changed API's for potion_type_error_want
v0.1 Wed Oct 16 13:08:38 2013 rurban
View
6 core/internal.c
@@ -261,9 +261,9 @@ PN potion_type_error(Potion *P, PN obj) {
return potion_error(P, potion_str_format(P, "Invalid type %s", potion_type_name(P, obj)),
0, 0, 0);
}
-PN potion_type_error_want(Potion *P, PN obj, const char *name) {
- return potion_error(P, potion_str_format(P, "Invalid type %s, expected %s",
- potion_type_name(P, obj), name),
+PN potion_type_error_want(Potion *P, const char *param, PN obj, const char *type) {
+ return potion_error(P, potion_str_format(P, "Invalid type %s for %s, expected %s",
+ potion_type_name(P, obj), param, type),
0, 0, 0);
}
View
18 core/potion.h
@@ -184,17 +184,19 @@ struct PNVtable;
#define PN_IS_FFIPTR(p) ((PN_IS_PTR(p) && !(p >= (_PN)P->mem && p <= (_PN)P->mem->birth_hi)) \
|| (!PN_IS_PTR(p) && p > (_PN)P->mem->birth_hi))
-#define PN_CHECK_STR(obj) if (!PN_IS_STR(obj)) return potion_type_error_want(P, obj, "String")
-#define PN_CHECK_INT(obj) if (!PN_IS_NUM(obj)) return potion_type_error_want(P, obj, "Integer")
-#define PN_CHECK_BOOL(obj) if (!PN_IS_BOOL(obj)) return potion_type_error_want(P, obj, "Bool")
-#define PN_CHECK_TUPLE(obj) if (!PN_IS_TUPLE(obj)) return potion_type_error_want(P, obj, "Tuple")
-#define PN_CHECK_CLOSURE(obj) if (!PN_IS_CLOSURE(obj)) return potion_type_error_want(P, obj, "Closure")
+#define PN_CHECK_STR(obj) if (!PN_IS_STR(obj)) return potion_type_error_want(P, ""#obj, (PN)obj, "String")
+#define PN_CHECK_INT(obj) if (!PN_IS_NUM(obj)) return potion_type_error_want(P, ""#obj, (PN)obj, "Integer")
+#define PN_CHECK_BOOL(obj) if (!PN_IS_BOOL(obj)) return potion_type_error_want(P, ""#obj, (PN)obj, "Bool")
+#define PN_CHECK_TUPLE(obj) if (!PN_IS_TUPLE(obj)) return potion_type_error_want(P, ""#obj, (PN)obj, "Tuple")
+#define PN_CHECK_CLOSURE(obj) if (!PN_IS_CLOSURE(obj)) return potion_type_error_want(P, ""#obj, (PN)obj, "Closure")
//TODO: check parents and mixins via bind
-#define PN_CHECK_TYPE(obj,type) if (type != PN_TYPE(obj)) return potion_type_error(P, obj)
+#define PN_CHECK_TYPE(obj,type) if (type != PN_TYPE(obj)) return potion_type_error(P, (PN)obj)
#ifdef DEBUG
-#define DBG_CHECK_TYPE(obj,type) PN_CHECK_TYPE((PN)obj,type)
+#define DBG_CHECK_TYPE(obj,type) PN_CHECK_TYPE(obj,type)
+#define DBG_CHECK_INT(obj) PN_CHECK_INT(obj)
#else
#define DBG_CHECK_TYPE(obj,type)
+#define DBG_CHECK_INT(obj)
#endif
///\class PNNumber
@@ -785,7 +787,7 @@ void potion_fatal(char *);
void potion_allocation_error(void);
PN potion_io_error(Potion *, const char *);
PN potion_type_error(Potion *, PN);
-PN potion_type_error_want(Potion *, PN, const char *);
+PN potion_type_error_want(Potion *, const char *, PN, const char *);
void potion_syntax_error(Potion *, const char *, ...)
__attribute__ ((format (printf, 2, 3)));
PNType potion_kind_of(PN);
View
33 core/string.c
@@ -134,6 +134,12 @@ static PN potion_str_string(Potion *P, PN cl, PN self) {
}
///\memberof PNString
+/// "clone" method. Returns self, strings are immutable.
+static PN potion_str_clone(Potion *P, PN cl, PN self) {
+ return self;
+}
+
+///\memberof PNString
/// "print" method. fwrite to stdout
///\returns nil
static PN potion_str_print(Potion *P, PN cl, PN self) {
@@ -221,8 +227,18 @@ inline static PN potion_str_slice_index(PN index, size_t len, int nilvalue) {
static PN potion_str_slice(Potion *P, PN cl, PN self, PN start, PN end) {
char *str = PN_STR_PTR(self);
size_t len = potion_cp_strlen_utf8(str);
- size_t startoffset = potion_utf8char_offset(str, PN_INT(potion_str_slice_index(start, len, 0)));
size_t endoffset;
+ if (!start)
+ return self;
+ else {
+ DBG_CHECK_TYPE(start, PN_TNUMBER);
+ }
+ size_t startoffset = potion_utf8char_offset(str, PN_INT(potion_str_slice_index(start, len, 0)));
+ if (!end)
+ end = PN_NUM(len);
+ else {
+ DBG_CHECK_INT(end);
+ }
if (end < start) {
endoffset = potion_utf8char_offset(str, PN_INT(potion_str_slice_index(start+end, len, len)));
} else {
@@ -297,6 +313,17 @@ PN potion_bytes(Potion *P, size_t len) {
return (PN)s;
}
+///\memberof PNBytes
+/// "clone" returns a copy of the byte buffer
+///\return PNBytes
+PN potion_bytes_clone(Potion *P, PN cl, PN self) {
+ vPN(Bytes) b = (struct PNBytes *)potion_fwd(self);
+ vPN(Bytes) s = PN_ALLOC_N(PN_TBYTES, struct PNBytes, b->siz);
+ s->siz = b->siz;
+ s->len = b->len;
+ return (PN)s;
+}
+
PN_SIZE pn_printf(Potion *P, PN bytes, const char *format, ...) {
PN_SIZE len;
va_list args;
@@ -434,7 +461,8 @@ void potion_str_init(Potion *P) {
potion_method(str_vt, "number", potion_str_number, 0);
potion_method(str_vt, "print", potion_str_print, 0);
potion_method(str_vt, "string", potion_str_string, 0);
- potion_method(str_vt, "slice", potion_str_slice, "start=N,end=N");
+ potion_method(str_vt, "clone", potion_str_clone, 0);
+ potion_method(str_vt, "slice", potion_str_slice, "start=N|end=N");
potion_method(str_vt, "bytes", potion_str_bytes, 0);
potion_method(str_vt, "+", potion_str_add, "str=S");
potion_method(str_vt, "ord", potion_str_ord, "|index=N");
@@ -445,6 +473,7 @@ void potion_str_init(Potion *P) {
potion_method(byt_vt, "length", potion_bytes_length, 0);
potion_method(byt_vt, "print", potion_bytes_print, 0);
potion_method(byt_vt, "string", potion_bytes_string, 0);
+ potion_method(byt_vt, "clone", potion_bytes_clone, 0);
potion_method(byt_vt, "ord", potion_str_ord, 0);
potion_method(byt_vt, "each", potion_bytes_each, "block=&");
}
View
53 core/table.c
@@ -175,14 +175,16 @@ PN potion_table_slice(Potion *P, PN cl, PN self, PN keys) {
DBG_CHECK_TYPE(keys,PN_TTUPLE);
}
vPN(Table) t2 = (vPN(Table))PN_ALLOC_N(PN_TTABLE, struct PNTable, 0);
- t2 = kh_resize_PN(P, t2, PN_TUPLE_LEN(keys));
- int ret;
+ t2 = kh_resize_PN(P, t2, PN_TUPLE_LEN(keys)); //ca, could overshoot for dupl and outliers
PN_TUPLE_EACH(keys, i, v, {
- if (kh_exist(PN, t, v)) {
- unsigned key = kh_put(PN, t2, kh_key(PN, t, v), &ret);
+ DBG_vt("%d:%ld ", i, PN_INT(v));
+ unsigned k = kh_get(PN, t, v);
+ if (k != kh_end(t)) {
+ int ret;
+ unsigned k2 = kh_put(PN, t2, v, &ret);
PN_QUICK_FWD(struct PNTable *, t);
PN_QUICK_FWD(struct PNTable *, t2);
- kh_val(PN, t2, key) = kh_val(PN, t, v);
+ kh_val(PN, t2, k2) = kh_val(PN, t, k);
}
});
PN_TOUCH(t2);
@@ -327,42 +329,45 @@ PN potion_tuple_clone(Potion *P, PN cl, PN self) {
}
/**\memberof PNTuple
- Extract slice copy of a tuple
+ Extract slice copy of a tuple, similar to strings. Supports negative indices and end<start.
\code
(0,1,2) slice #=> (0,1,2)
(0,1,2) slice(1) #=> (1,2)
- (0,1,2) slice(0,2) #=> (0,1)
+ (0,1,2) slice(0,1) #=> (0,1)
(0,1,2) slice(-1) #=> (2)
(0,1,2) slice(1,1) #=> (1)
- (0,1,2) slice(1,-1) #=> (0)
- (0,1,2) slice(2,-1) #=> (1)
- (0,1,2) slice(-1,-1) #=> (1)
+ (0,1,2) slice(1,-1) #=> (0,1)
+ (0,1,2) slice(2,-1) #=> (2)
+ (0,1,2) slice(-1,-2) #=> (0,1)
\endcode
- \param index PNNumber. Optional offset, default 0. If negative, count from end. If too large, return nil.
- \param length PNNumber. Optional, default to the end. If negative, count reverse. If too large, return nil.
+ \param start PNNumber. Default 0. If negative, count from end. If too large, return nil.
+ \param end PNNumber. Optional, default last index. If negative, count from end. If too large, return nil.
\return new PNTuple */
static
-PN potion_tuple_slice(Potion *P, PN cl, PN self, PN index, PN length) {
+PN potion_tuple_slice(Potion *P, PN cl, PN self, PN start, PN end) {
vPN(Tuple) t1 = PN_GET_TUPLE(self);
long i, l;
DBG_CHECK_TYPE(t1,PN_TTUPLE);
- if (!index)
+ if (!start)
return potion_tuple_clone(P, cl, self);
else {
- DBG_CHECK_TYPE(index,PN_TNUMBER);
- i = PN_INT(index);
+ DBG_CHECK_INT(start);
+ i = PN_INT(start);
if (i < 0) i = t1->len + i;
}
- if (!length || length == PN_NUM(0)) {
+ if (!end)
l = t1->len - i;
- }
else {
- DBG_CHECK_TYPE(length,PN_TNUMBER);
- l = PN_INT(length);
- if (l < 0) { i += l; l = abs(l); }
+ long e = PN_INT(end);
+ DBG_CHECK_INT(end);
+ if (e < 0) e = t1->len + e;
+ l = e - i;
+ if (l < 0) { i = e; l = abs(l) + 1; }
+ else l++;
+ if (l > t1->len) l = t1->len; // permit overshoots
}
- DBG_v("; splice(%ld,%ld)\n", i, l);
- if (l > t1->len || i > t1->len) return PN_NIL;
+ DBG_vt("; splice(i=%ld,len=%ld)\n", i, l);
+ if (!l || i >= t1->len) return PN_NIL;
NEW_TUPLE(t2, l);
PN_MEMCPY_N(&t2->set[0], &t1->set[i], PN, l);
t2->alloc = l;
@@ -849,7 +854,7 @@ void potion_table_init(Potion *P) {
potion_method(tpl_vt, "nreverse", potion_tuple_nreverse, 0);
potion_method(tpl_vt, "remove", potion_tuple_remove, "index=N");
potion_method(tpl_vt, "delete", potion_tuple_delete, "index=N");
- potion_method(tpl_vt, "slice", potion_tuple_slice, "|from=N,to=N");
+ potion_method(tpl_vt, "slice", potion_tuple_slice, "start:=0,end:=nil");
potion_method(tpl_vt, "unshift", potion_tuple_unshift, "value=o");
potion_method(tpl_vt, "shift", potion_tuple_shift, 0);
potion_method(tpl_vt, "bsearch", potion_tuple_bsearch, "value=o");
View
24 lib/aio.c
@@ -146,7 +146,7 @@ static PN aio_error(Potion *P, char *name, int status) {
//checks inheritence
#define CHECK_AIO_TYPE(self, T) \
- if (!potion_bind(P, self, PN_STR("Aio_"_XSTR(T)))) return potion_type_error_want(P, self, ""_XSTR(T))
+ if (!potion_bind(P, self, PN_STR("Aio_"_XSTR(T)))) return potion_type_error_want(P, "self", self, ""_XSTR(T))
#define CHECK_AIO_STREAM(stream) \
{ \
PNType _t = PN_VTYPE(stream); \
@@ -156,7 +156,7 @@ static PN aio_error(Potion *P, char *name, int status) {
_t != aio_pipe_type && \
_t != aio_tty_type && \
!potion_bind(P, stream, PN_STR("listen"))) \
- return potion_type_error_want(P, stream, "Aio_stream");\
+ return potion_type_error_want(P, "stream", stream, "Aio_stream"); \
}
//if (PN_VTYPE(self) != aio_##T##_type) {
#define FATAL_AIO_TYPE(self, T) \
@@ -187,10 +187,10 @@ static PN aio_error(Potion *P, char *name, int status) {
#define AIO_DATA(T,ARG) \
(aio_##T##_t*)PN_DATA(potion_fwd(ARG)); \
- CHECK_AIO_TYPE(potion_fwd(ARG),T)
+ CHECK_AIO_TYPE(ARG,T)
#define AIO_STREAM(ARG) \
(aio_stream_t*)PN_DATA(potion_fwd(ARG)); \
- CHECK_AIO_STREAM(potion_fwd(ARG))
+ CHECK_AIO_STREAM(ARG)
//cb wrappers
#define DEF_AIO_CB(T) \
@@ -267,7 +267,7 @@ static PN aio_udp_new(Potion *P, PN cl, PN self, PN loop) {
\param key PNString, One of "broadcast", "multicast_loop", "multicast_ttl", "ttl"
\see http://nikhilm.github.io/uvbook/networking.html#udp */
static PN aio_udp_get(Potion *P, PN cl, PN self, PN key, PN value) {
- CHECK_AIO_TYPE(potion_fwd(self),udp);
+ CHECK_AIO_TYPE(self,udp);
PN_CHECK_STR(key);
PN v = potion_obj_get(P, 0, self, key);
return v ? v : potion_error(P, potion_str_format(P, "Invalid key %s",
@@ -282,7 +282,7 @@ static PN aio_udp_get(Potion *P, PN cl, PN self, PN key, PN value) {
static PN aio_udp_set(Potion *P, PN cl, PN self, PN key, PN value) {
uv_udp_t *udp;
udp = (uv_udp_t*)PN_DATA(potion_fwd(self));
- CHECK_AIO_TYPE(potion_fwd(self),udp);
+ CHECK_AIO_TYPE(self,udp);
PN_CHECK_STR(key);
char *k = PN_STR_PTR(key);
if (!strcmp(k, "broadcast")) {
@@ -499,7 +499,7 @@ static PN aio_getaddrinfo_new(Potion *P, PN cl, PN self,
const char *service_c = PN_IS_STR(service) ? PN_STR_PTR(service) : NULL;
struct addrinfo* hints_c = (struct addrinfo*)PN_DATA(hints);
if (!node_c && !service_c) {
- return potion_type_error_want(P, !node_c ? node : service, "String");
+ return potion_type_error_want(P, "node or service", !node_c ? node : service, "String");
}
int r = uv_getaddrinfo(l, handle, getaddrinfo_cb, node_c, service_c, (const struct addrinfo*)hints_c);
if (r) return aio_error(P, "Aio_getaddrinfo", r);
@@ -1476,7 +1476,7 @@ aio_signal_stop(Potion *P, PN cl, PN self) {
"gid", "stdio_count", "stdio", "uid"
\see http://nikhilm.github.io/uvbook/networking.html#process_options */
static PN aio_process_options_get(Potion *P, PN cl, PN self, PN key) {
- CHECK_AIO_TYPE(potion_fwd(self),process_options);
+ CHECK_AIO_TYPE(self,process_options);
PN_CHECK_STR(key);
PN v = potion_obj_get(P, 0, self, key);
return v ? v : potion_error(P, potion_str_format(P, "Invalid key %s",
@@ -1490,7 +1490,7 @@ static PN aio_process_options_get(Potion *P, PN cl, PN self, PN key) {
\param value
\see http://nikhilm.github.io/uvbook/processes.html#spawning-child-processes */
static PN aio_process_options_set(Potion *P, PN cl, PN self, PN key, PN value) {
- CHECK_AIO_TYPE(potion_fwd(self),process_options);
+ CHECK_AIO_TYPE(self,process_options);
PN_CHECK_STR(key);
char *k = PN_STR_PTR(key);
if (!strcmp(k, "file")) { PN_CHECK_STR(value); }
@@ -1499,17 +1499,17 @@ static PN aio_process_options_set(Potion *P, PN cl, PN self, PN key, PN value) {
else if (!strcmp(k, "uid")) { PN_CHECK_INT(value); } //fails on windows!
else if (!strcmp(k, "flags")) { PN_CHECK_INT(value); }
else if (!strcmp(k, "args")) {
- if (!value || !PN_IS_TUPLE(value)) return potion_type_error_want(P, value, "Tuple");
+ if (!value || !PN_IS_TUPLE(value)) return potion_type_error_want(P, "value", value, "Tuple");
vPN(Tuple) t = PN_GET_TUPLE(value);
PN_TUPLE_EACH(t, i, v, { PN_CHECK_STR(v); });
}
else if (!strcmp(k, "env")) {
- if (!value || !PN_IS_TUPLE(value)) return potion_type_error_want(P, value, "Tuple");
+ if (!value || !PN_IS_TUPLE(value)) return potion_type_error_want(P, "value", value, "Tuple");
vPN(Tuple) t = PN_GET_TUPLE(value);
PN_TUPLE_EACH(t, i, v, { PN_CHECK_STR(v); });
}
else if (!strcmp(k, "stdio")) {
- if (!value || !PN_IS_TUPLE(value)) return potion_type_error_want(P, value, "Tuple");
+ if (!value || !PN_IS_TUPLE(value)) return potion_type_error_want(P, "value", value, "Tuple");
vPN(Tuple) t = PN_GET_TUPLE(value); //all must be numbers
PN_TUPLE_EACH(t, i, v, { PN_CHECK_INT(v); });
}
View
23 test/tables/slice.pn
@@ -1,10 +1,15 @@
t = (0,1,2)
-(t slice,
- t slice(1),
- t slice(0,2),
- t slice(-1),
- t slice(1,1),
- t slice(1,-1),
- t slice(2,-1),
- t slice(-1,-1)) join(",") print
-#=> (0, 1, 2),(1, 2),(0, 1),(2),(1),(0),(1),(1)nil
+t slice(0,nil) say #=> (0, 1, 2)
+t slice(1,nil) say #=> (1, 2)
+t slice(0,1) say #=> (0, 1)
+t slice(-1,nil) say #=> (2)
+t slice(1,1) say #=> (1)
+t slice(1,-1) say #=> (1, 2)
+t slice(2,-1) say #=> (2)
+t slice(-1,-2) say #=> (1, 2)
+
+t = (0="a", 1="b", 2="c")
+t slice say #=> (0=a, 2=c, 1=b)
+t slice((1,2,3)) keys sort(true) say #=> (1, 2)
+t slice(()) say #=> ()
+#=> nil

0 comments on commit c2314c7

Please sign in to comment.