Merge pull request #4 from jeremyroman/master
[mspang/inapt.git] / parser.rl
index 2221c57..e0dde39 100644 (file)
--- a/parser.rl
+++ b/parser.rl
@@ -12,7 +12,7 @@
 using namespace std;
 
 #define MAXDEPTH 100
-#define BUFSIZE 128
+#define BUFSIZE 4096
 
 %%{
     machine inapt;
@@ -28,26 +28,33 @@ using namespace std;
         inapt_package *tmp_package = new inapt_package;
         tmp_package->alternates.swap(alternates);
         tmp_package->action = tmp_action->action;
-        tmp_package->linenum = curline;
+        tmp_package->linenum = curline - (*p == '\n');
         tmp_package->filename = curfile;
-        tmp_package->predicates.swap(pkg_predicates);
+        tmp_package->predicates.swap(predicates);
         tmp_action->packages.push_back(tmp_package);
     }
 
     action start_install {
         tmp_action = new inapt_action;
         tmp_action->action = inapt_action::INSTALL;
-        tmp_action->predicates.swap(cmd_predicates);
+        tmp_action->predicates.swap(predicates);
         block_stack.back()->actions.push_back(tmp_action);
     }
 
     action start_remove {
         tmp_action = new inapt_action;
         tmp_action->action = inapt_action::REMOVE;
-        tmp_action->predicates.swap(cmd_predicates);
+        tmp_action->predicates.swap(predicates);
         block_stack.back()->actions.push_back(tmp_action);
     }
 
+    action add_profiles {
+        inapt_profiles *tmp_profiles = new inapt_profiles;
+        tmp_profiles->profiles.swap(profiles);
+        tmp_profiles->predicates.swap(predicates);
+        block_stack.back()->profiles.push_back(tmp_profiles);
+    }
+
     action newline {
         curline += 1;
     }
@@ -58,7 +65,7 @@ using namespace std;
             block_stack.push_back(tmp_block);
             fcall main;
         } else {
-            fatal("%s: %d: Syntax Error: Nesting Too Deep at '}'", curfile, curline);
+            fatal("%s: %d: Syntax Error: Nesting Too Deep at '{'", curfile, curline);
         }
     }
 
@@ -72,7 +79,7 @@ using namespace std;
 
     action start_conditional {
         inapt_conditional *cond = new inapt_conditional;
-        cond->condition = xstrndup(ts, p - ts); ts = 0;
+        cond->predicates.swap(predicates);
         conditional_stack.push_back(cond);
     }
 
@@ -90,39 +97,39 @@ using namespace std;
         block_stack.back()->children.push_back(cond);
     }
 
-    action pkg_predicate {
+    action predicate {
         std::string tmp (ts, p - ts); ts = 0;
-        pkg_predicates.push_back(tmp);
+        predicates.push_back(tmp);
     }
 
-    action cmd_predicate {
+    action profile {
         std::string tmp (ts, p - ts); ts = 0;
-        cmd_predicates.push_back(tmp);
+        profiles.push_back(tmp);
     }
 
     newline = '\n' @newline;
     comment = '#' (any - '\n')* newline;
     whitespace = [\t\v\f\r ] | comment | newline;
-    profile = '!'? alpha (alpha | digit | '-' | '+' | '.')*;
+    profile = alpha (alpha | digit | '-' | '_' | '+' | '.')*;
     package_name = ((lower | digit) (lower | digit | '+' | '-' | '.')+) >strstart;
-    pkg_predicate = '@' profile >strstart %pkg_predicate whitespace+;
-    cmd_predicate = '@' profile >strstart %cmd_predicate whitespace+;
+    predicate = '@' ('!'? profile ('/' '!'? profile)*) >strstart %predicate whitespace+;
     package_alternates = package_name >strstart %add_alternate ('/' package_name >strstart %add_alternate)*;
-    package_list = ((whitespace+ pkg_predicate? package_alternates)+ %add_package whitespace*);
+    package_list = ((whitespace+ predicate* package_alternates)+ %add_package whitespace*);
+    profile_list = (whitespace+ profile >strstart %profile)* whitespace*;
     cmd_install = ('install' @start_install package_list ';');
     cmd_remove = ('remove' @start_remove package_list ';');
-    start_block = '{' @start_block;
+    cmd_profiles = ('profiles' profile_list ';' @add_profiles);
     end_block = '}' @end_block;
-    cmd_if = 'if' whitespace+ profile >strstart %start_conditional whitespace* start_block whitespace*
-             ('else' whitespace* start_block whitespace* ';' @full_conditional | ';' @half_conditional);
-    cmd = whitespace* (cmd_predicate? (cmd_install | cmd_remove) | cmd_if);
+    cmd_if = 'if' whitespace+ predicate+ '{' @start_conditional @start_block whitespace*
+             ('else' whitespace* '{' @start_block whitespace* ';' @full_conditional | ';' @half_conditional);
+    cmd = whitespace* (predicate* (cmd_install | cmd_remove | cmd_profiles) | cmd_if);
     cmd_list = cmd* whitespace* end_block?;
     main := cmd_list;
 }%%
 
 %% write data;
 
-void badsyntax(const char *filename, int lineno, char badchar, const char *message) {
+static void badsyntax(const char *filename, int lineno, char badchar, const char *message) {
     if (!message) {
         if (badchar == '\n')
             message = "Unexpected newline";
@@ -150,8 +157,8 @@ void parser(const char *filename, inapt_block *top_block)
     std::vector<inapt_block *> block_stack;
     std::vector<inapt_conditional *> conditional_stack;
     std::vector<std::string> alternates;
-    std::vector<std::string> cmd_predicates;
-    std::vector<std::string> pkg_predicates;
+    std::vector<std::string> predicates;
+    std::vector<std::string> profiles;
     block_stack.push_back(top_block);
     inapt_action *tmp_action = NULL;
 
@@ -160,19 +167,19 @@ void parser(const char *filename, inapt_block *top_block)
 
     const char *curfile = filename;
 
-    if (filename) {
+    if (!filename || !strcmp(filename, "-")) {
+        curfile = "stdin";
+        fd = 0;
+    } else {
         fd = open(filename, O_RDONLY);
         if (fd < 0)
             fatalpe("open: %s", filename);
-    } else {
-        curfile = "stdin";
-        fd = 0;
     }
 
     %% write init;
 
     while (!done) {
-        char *p = buf + have, *pe, *eof = 0;
+        char *p = buf + have, *pe;
         int len, space = BUFSIZE - have;
 
         if (!space)
@@ -184,7 +191,6 @@ void parser(const char *filename, inapt_block *top_block)
         pe = p + len;
 
         if (!len) {
-            eof = pe;
             done = 1;
         }
 
@@ -203,7 +209,7 @@ void parser(const char *filename, inapt_block *top_block)
     }
 
     if (cs < inapt_first_final)
-        badsyntax(curfile, curline, 0, "Unexpected EOF");
+        badsyntax(curfile, curline, 0, "Unexpected EOF (forgot semicolon?)");
 
     if (top)
         badsyntax(curfile, curline, 0, "Unclosed block at EOF");