Make conditionals functional
authorMichael Spang <mspang@csclub.uwaterloo.ca>
Fri, 11 Dec 2009 21:34:08 +0000 (16:34 -0500)
committerMichael Spang <mspang@csclub.uwaterloo.ca>
Tue, 22 Dec 2009 03:11:47 +0000 (22:11 -0500)
Currently the condition must be "true" or "false", which is useful
only for testing.

Signed-off-by: Michael Spang <mspang@csclub.uwaterloo.ca>
inapt.cc
inapt.h
parser.rl

index e04b3e1..444608b 100644 (file)
--- a/inapt.cc
+++ b/inapt.cc
@@ -182,6 +182,18 @@ static void usage() {
     exit(2);
 }
 
+static void eval_block(inapt_block *block, std::vector<inapt_action *> *final_actions) {
+    for (vector<inapt_action *>::iterator i = block->actions.begin(); i < block->actions.end(); i++)
+        final_actions->push_back(*i);
+
+    for (vector<inapt_conditional *>::iterator i = block->children.begin(); i < block->children.end(); i++) {
+        if (strcmp((*i)->condition, "false"))
+            eval_block((*i)->then_block, final_actions);
+        else
+            eval_block((*i)->else_block, final_actions);
+    }
+}
+
 int main(int argc, char *argv[]) {
     int opt;
     char *filename = NULL;
@@ -202,7 +214,7 @@ int main(int argc, char *argv[]) {
     else if (argc - optind > 0)
         usage();
 
-    inapt_context context;
+    inapt_block context;
 
     pkgInitConfig(*_config);
     pkgInitSystem(*_config, _system);
@@ -222,14 +234,17 @@ int main(int argc, char *argv[]) {
 
     parser(filename, &context);
 
-    for (vector<inapt_action *>::iterator i = context.actions.begin(); i < context.actions.end(); i++) {
+    vector<inapt_action *> final_actions;
+    eval_block(&context, &final_actions);
+
+    for (vector<inapt_action *>::iterator i = final_actions.begin(); i < final_actions.end(); i++) {
         pkgCache::PkgIterator pkg = cache->FindPkg((*i)->package);
         if (pkg.end())
             fatal("%s:%d: No such package: %s", (*i)->filename, (*i)->linenum, (*i)->package);
         (*i)->obj = &pkg;
     }
 
-    for (vector<inapt_action *>::iterator i = context.actions.begin(); i < context.actions.end(); i++) {
+    for (vector<inapt_action *>::iterator i = final_actions.begin(); i < final_actions.end(); i++) {
         pkgCache::PkgIterator j = *(pkgCache::PkgIterator *)(*i)->obj;
         switch ((*i)->action) {
             case inapt_action::INSTALL:
@@ -245,7 +260,7 @@ int main(int argc, char *argv[]) {
         }
     }
 
-    for (vector<inapt_action *>::iterator i = context.actions.begin(); i < context.actions.end(); i++) {
+    for (vector<inapt_action *>::iterator i = final_actions.begin(); i < final_actions.end(); i++) {
         pkgCache::PkgIterator j = *(pkgCache::PkgIterator *)(*i)->obj;
         switch ((*i)->action) {
             case inapt_action::INSTALL:
@@ -294,9 +309,9 @@ int main(int argc, char *argv[]) {
 
     pkgProblemResolver fix (DCache);
 
-    for (vector<inapt_action *>::iterator i = context.actions.begin(); i < context.actions.end(); i++)
+    for (vector<inapt_action *>::iterator i = final_actions.begin(); i < final_actions.end(); i++)
            fix.Protect(cache->FindPkg((*i)->package));
-    for (vector<inapt_action *>::iterator i = context.actions.begin(); i < context.actions.end(); i++)
+    for (vector<inapt_action *>::iterator i = final_actions.begin(); i < final_actions.end(); i++)
            fix.Protect(cache->FindPkg((*i)->package));
     fix.Resolve();
 
diff --git a/inapt.h b/inapt.h
index 2b24a38..8b600a7 100644 (file)
--- a/inapt.h
+++ b/inapt.h
@@ -1,5 +1,7 @@
 #include <vector>
 
+struct inapt_conditional;
+
 struct inapt_action {
     const char *package;
     enum action_t { INSTALL, REMOVE, UNSET } action;
@@ -8,10 +10,15 @@ struct inapt_action {
     void *obj;
 };
 
-struct inapt_context {
-    const char *condition;
+struct inapt_block {
     std::vector<inapt_action *> actions;
-    std::vector<inapt_context *> children;
+    std::vector<inapt_conditional *> children;
+};
+
+struct inapt_conditional {
+    const char *condition;
+    struct inapt_block *then_block;
+    struct inapt_block *else_block;
 };
 
-void parser(const char *filename, inapt_context *context);
+void parser(const char *filename, inapt_block *context);
index e664252..75b3f1c 100644 (file)
--- a/parser.rl
+++ b/parser.rl
@@ -24,7 +24,7 @@ using namespace std;
         tmp_action->action = curaction;
         tmp_action->linenum = curline;
         tmp_action->filename = curfile;
-        cur_context->actions.push_back(tmp_action);
+        block_stack.back()->actions.push_back(tmp_action);
     }
 
     action install {
@@ -41,6 +41,8 @@ using namespace std;
 
     action start_block {
         if (depth++ < MAXDEPTH) {
+            inapt_block *tmp_block = new inapt_block;
+            block_stack.push_back(tmp_block);
             fcall main;
         } else {
             fatal("%s: %d: Syntax Error: Nesting Too Deep at '}'", curfile, curline);
@@ -55,6 +57,26 @@ using namespace std;
         }
     }
 
+    action start_conditional {
+        inapt_conditional *cond = new inapt_conditional;
+        cond->condition = xstrndup(ts, p - ts);
+        conditional_stack.push_back(cond);
+    }
+
+    action full_conditional {
+        inapt_conditional *cond = conditional_stack.back(); conditional_stack.pop_back();
+        cond->else_block = block_stack.back(); block_stack.pop_back();
+        cond->then_block = block_stack.back(); block_stack.pop_back();
+        block_stack.back()->children.push_back(cond);
+    }
+
+    action half_conditional {
+        inapt_conditional *cond = conditional_stack.back(); conditional_stack.pop_back();
+        cond->else_block = NULL;
+        cond->then_block = block_stack.back(); block_stack.pop_back();
+        block_stack.back()->children.push_back(cond);
+    }
+
     newline = '\n' @newline;
     comment = '#' (any - '\n')* newline;
     whitespace = [\t\v\f\r ] | comment | newline;
@@ -65,7 +87,8 @@ using namespace std;
     simple_cmd = cmd_install | cmd_remove;
     start_block = '{' @start_block;
     end_block = '}' @end_block;
-    cmd_if = 'if' whitespace+ alpha+ whitespace* start_block whitespace* ('else' whitespace* start_block)?;
+    cmd_if = 'if' whitespace+ alpha+ >pkgstart %start_conditional whitespace* start_block whitespace*
+             ('else' whitespace* start_block whitespace* ';' @full_conditional | ';' @half_conditional);
     cmd_list = (simple_cmd | cmd_if | whitespace)* end_block?;
     main := cmd_list;
 }%%
@@ -90,7 +113,7 @@ void badsyntax(const char *filename, int lineno, char badchar, const char *messa
         fatal("%s: %d: %s", filename, lineno, message);
 }
 
-void parser(const char *filename, inapt_context *top_context)
+void parser(const char *filename, inapt_block *top_block)
 {
     static char buf[BUFSIZE];
     int fd;
@@ -98,7 +121,11 @@ void parser(const char *filename, inapt_context *top_context)
     int done = 0;
     int curline = 1;
     char *ts = 0, *te = 0;
-    inapt_context *cur_context = top_context;
+
+    std::vector<inapt_block *> block_stack;
+    std::vector<inapt_conditional *> conditional_stack;
+    block_stack.push_back(top_block);
+
     int stack[MAXDEPTH];
     int top = 0; /* TODO: resize */
     int depth = 0;