Mailinglist Archive: yast-devel (116 mails)

< Previous Next >
[yast-devel] new YCP builtins
  • From: Arvin Schnell <aschnell@xxxxxxx>
  • Date: Wed, 4 Jun 2008 15:55:33 +0200
  • Message-id: <20080604135532.GA28835@xxxxxxx>

Hi YCP-Hackers,

I've used some ITO time to implement two new YCP builtins:


1. splitlist (var x, list, block using x)

Takes a list and a predicate function and splits the list where the
predicate function says so. Returns a list of lists.

Example:

list<string> l = [ "0", "a", "1", "2", "b", "3", "4" ];
splitlist(string s, l, { return isalpha(s); });

return is [ [ "0" ], [ "a", "1", "2" ], [ "b", "3", "4" ] ]

The difference to splitstring is that the 'delimiter' is included in the
result since that's the way I need it. If desired I could add a parameter
that tells whether the 'delimiter' should be added to the previous list,
the following list or not at all.


2. reducelist (var x, var y, initial value, list, block using x and y)

This is the standard reduce function known from Lisp (but also available in
e.g. C++, Python and Ruby). It takes a list and reduces it to a single
value by applying a function, see:

http://en.wikipedia.org/wiki/Reduce_%28higher-order_function%29

Examples:

// sum and product
integer sum = reducelist(integer x, integer y, 0, [ 1, 2, 3, 4 ], { return x
+ y; });
integer product = reducelist(integer x, integer y, 1, [ 1, 2, 3, 4 ], {
return x * y; });

// min and max
list<integer> l1 = [ 1, 2, 3 ];
integer min = reducelist(integer x, integer y, l1[0]:nil, l1, { return x < y
? x : y; });
integer max = reducelist(integer x, integer y, l1[0]:nil, l1, { return x > y
? x : y; });

// mergestring
list<string> l2 = [ "hello", "openSUSE", "world" ];
string s = reducelist(string x, string y, "", l2, { return x + " " + y; });

// find longest string
string ls = reducelist(string x, string y, "", l2, { return size(x) >
size(y) ? x : y; });

// find length of longest string (note: type of x and y differ)
integer ll = reducelist(integer l, string s, 0, l2, { return size(s) > l ?
size(s) : l; });


Patch is attached. Still missing is documentation and testsuite. The patch
contains a binary incompatibility to libycp by adding the clear() function to
YCPList. If that's not wanted a workaround is included (maybe someone has a
better workaround). Bytecode compatibility is not touched.

It's not possible to add the functions to a module since they use the variable
type feature of YCP.

Please comment.

ciao
Arvin

--
Arvin Schnell, <aschnell@xxxxxxx>
Software Engineer, Research & Development
SUSE LINUX Products GmbH, GF: Markus Rex, HRB 16746 (AG N├╝rnberg)
Index: libycp/src/YCPBuiltinList.cc
===================================================================
--- libycp/src/YCPBuiltinList.cc (revision 48070)
+++ libycp/src/YCPBuiltinList.cc (working copy)
@@ -639,6 +639,76 @@


static YCPValue
+l_splitlist (const YCPSymbol &x, const YCPList &list, const YCPCode &expr)
+{
+ /**
+ * @builtin splitlist
+ * @short Splits a list.
+ * @param any VAR Variable
+ * @param list LIST List to be splitted
+ * @param block<boolean> EXPR Block
+ * @return list<list>
+ *
+ * TODO
+ */
+
+ if (list.isNull())
+ {
+ return YCPNull();
+ }
+
+ SymbolEntryPtr xs = x->asEntry()->entry();
+
+ YCPList ret;
+
+ YCPList tmp;
+
+ for (int i = 0; i < list->size(); i++)
+ {
+ YCPValue element = list->value(i);
+
+ xs->setValue(element);
+
+ YCPValue v = expr->evaluate();
+ if (v.isNull())
+ {
+ ycp2error("Bad 'splitlist' expression %s",
expr->toString().c_str());
+ return YCPNull();
+ }
+ if (v->isVoid())
+ {
+ ycp2error("The expression for 'splitlist' returned 'nil'");
+ continue;
+ }
+ if (v->isBreak())
+ {
+ break;
+ }
+
+ if (v->asBoolean()->value())
+ {
+ ret->add(tmp);
+#if 1
+ tmp->clear();
+#else
+ while (!tmp->isEmpty())
+ tmp->remove(0);
+#endif
+ tmp->add(element);
+ }
+ else
+ {
+ tmp->add(element);
+ }
+ }
+
+ ret->add(tmp);
+
+ return ret;
+}
+
+
+static YCPValue
l_toset (const YCPList &list)
{
/**
@@ -1081,6 +1151,60 @@


static YCPValue
+l_reducelist (const YCPSymbol &x, const YCPSymbol &y, const YCPValue &initial,
const YCPList &list, const YCPCode &expr)
+{
+ /**
+ * @builtin reducelist
+ * @short Reduces a list to a single value.
+ * @param flex1 x
+ * @param flex2 y
+ * @param flex1 value
+ * @param list<flex2> list
+ * @param block<flex1> expr
+ * @return flex1
+ *
+ * TODO
+ */
+
+ if (list.isNull())
+ {
+ return YCPNull();
+ }
+
+ SymbolEntryPtr xs = x->asEntry()->entry();
+ SymbolEntryPtr ys = y->asEntry()->entry();
+
+ YCPValue ret = initial;
+
+ for (int i = 0; i < list->size(); i++)
+ {
+ xs->setValue(ret);
+ ys->setValue(list->value(i));
+
+ YCPValue tmp = expr->evaluate();
+ if (tmp.isNull())
+ {
+ ycp2error("Bad 'reducelist' expression %s",
expr->toString().c_str());
+ continue;
+ }
+ if (tmp->isVoid())
+ {
+ ycp2error("The expression for 'reducelist' returned 'nil'");
+ continue;
+ }
+ if (tmp->isBreak())
+ {
+ break;
+ }
+
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
+static YCPValue
l_tolist (const YCPValue &v)
{
/**
@@ -1124,6 +1248,7 @@
{ "maplist", "list <flex1> (variable <flex2>, const list <flex2>,
const block <flex1>)", (void *)l_maplist,
DECL_LOOP|DECL_SYMBOL|DECL_FLEX },
{ "listmap", "map <flex1,flex2> (variable <flex3>, const list
<flex3>, const block <map <flex1,flex2>>)", (void *)l_listmap,
DECL_LOOP|DECL_SYMBOL|DECL_FLEX },
{ "flatten", "list <flex> (const list <list <flex>>)",
(void *)l_flatten, DECL_FLEX },
+ { "splitlist", "list <list <flex>> (variable <flex>, const list
<flex>, const block <boolean>)", (void *)l_splitlist,
DECL_LOOP|DECL_SYMBOL|DECL_FLEX },
{ "toset", "list <flex> (const list <flex>)",
(void *)l_toset, DECL_FLEX },
{ "sort", "list <flex> (const list <flex>)",
(void *)l_sortlist, DECL_FLEX },
{ "sort", "list <flex> (variable <flex>, variable <flex>, const
list <flex>, const block <boolean>)", (void *)l_sort, DECL_SYMBOL|DECL_FLEX
},
@@ -1137,6 +1262,7 @@
{ "remove", "list <flex> (const list <flex>, const integer)",
(void *)l_remove, DECL_FLEX },
{ "select", "flex (const list <flex>, integer, flex)",
(void *)l_select, DECL_NIL|DECL_FLEX },
{ "foreach", "flex1 (variable <flex2>, const list <flex2>, const
block <flex1>)", (void *)l_foreach,
DECL_LOOP|DECL_SYMBOL|DECL_FLEX },
+ { "reducelist", "flex1 (variable <flex1>, variable <flex2>, const
flex1, const list <flex2>, const block <flex1>)", (void *)l_reducelist,
DECL_LOOP|DECL_SYMBOL|DECL_FLEX },
{ "tolist", "list <any> (const any)",
(void *)l_tolist, DECL_DEPRECATED},
{ 0 }
};
Index: libycp/src/YCPList.cc
===================================================================
--- libycp/src/YCPList.cc (revision 48070)
+++ libycp/src/YCPList.cc (working copy)
@@ -90,6 +90,13 @@


void
+YCPListRep::clear()
+{
+ elements.clear();
+}
+
+
+void
YCPListRep::swap (int x, int y)
{
// FIXME: should produce a warning
Index: libycp/src/include/ycp/YCPList.h
===================================================================
--- libycp/src/include/ycp/YCPList.h (revision 48070)
+++ libycp/src/include/ycp/YCPList.h (working copy)
@@ -88,11 +88,16 @@
void set(const int n, const YCPValue& value);

/**
- * Remove a value from the list.
+ * Remove an element from the list.
*/
void remove(const int n);

/**
+ * Remove all elements from the list.
+ */
+ void clear();
+
+ /**
* Exchanges the elements at the indices x and y. This function
* changes the list.
*/
@@ -208,6 +213,7 @@
void add(const YCPValue& value) { ELEMENT->add (value); }
void set(const int n, const YCPValue& value) { ELEMENT->set (n, value); }
void remove(const int n) { ELEMENT->remove (n); }
+ void clear() { ELEMENT->clear(); }
void swap(int x, int y) { ELEMENT->swap (x, y); }
bool contains (const YCPValue& value) const { return
CONST_ELEMENT->contains (value); }
void sortlist() { ELEMENT->sortlist (); }
< Previous Next >