public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/R_overlay:master commit in: roverlay/packagerules/parser/, roverlay/packagerules/parser/context/, ...
@ 2013-03-01 19:00 André Erdmann
  0 siblings, 0 replies; 4+ messages in thread
From: André Erdmann @ 2013-03-01 19:00 UTC (permalink / raw
  To: gentoo-commits

commit:     ac3164b4c26124636e97d5c7d320d9e07f39a10a
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Mar  1 18:54:20 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Mar  1 18:54:20 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=ac3164b4

packagerules/parser: use line number as priority

This commit adds stable/reliable sorting for package rules (rule-,match- and
action-blocks). The order of the rule entries will be exactly the same as in
the rule file(s).

---
 roverlay/packagerules/abstract/acceptors.py    |    2 +-
 roverlay/packagerules/abstract/rules.py        |    2 +-
 roverlay/packagerules/parser/context/action.py |    6 ++-
 roverlay/packagerules/parser/context/match.py  |   52 +++++++++++++++++-------
 roverlay/packagerules/parser/context/rule.py   |   46 ++++++++++++++-------
 roverlay/packagerules/parser/text.py           |   16 ++++---
 6 files changed, 82 insertions(+), 42 deletions(-)

diff --git a/roverlay/packagerules/abstract/acceptors.py b/roverlay/packagerules/abstract/acceptors.py
index 4533f37..6698a10 100644
--- a/roverlay/packagerules/abstract/acceptors.py
+++ b/roverlay/packagerules/abstract/acceptors.py
@@ -122,9 +122,9 @@ class _AcceptorCompound ( Acceptor ):
 		Raises: EmptyAcceptorError
 		"""
 		if len ( self._acceptors ) > 0:
-			self._acceptors = roverlay.util.priosort ( self._acceptors )
 			for acceptor in self._acceptors:
 				acceptor.prepare()
+			self._acceptors = roverlay.util.priosort ( self._acceptors )
 		else:
 			raise EmptyAcceptorError()
 	# --- end of prepare (...) ---

diff --git a/roverlay/packagerules/abstract/rules.py b/roverlay/packagerules/abstract/rules.py
index 80a7d62..af33bc7 100644
--- a/roverlay/packagerules/abstract/rules.py
+++ b/roverlay/packagerules/abstract/rules.py
@@ -196,9 +196,9 @@ class NestedPackageRule ( PackageRule ):
 		Prepares this rule for usage. Has to be called after adding actions.
 		"""
 		super ( NestedPackageRule, self ).prepare()
-		self._rules = roverlay.util.priosort ( self._rules )
 		for rule in self._rules:
 			rule.prepare()
+		self._rules = roverlay.util.priosort ( self._rules )
 	# --- end of prepare (...) ---
 
 	def apply_actions ( self, p_info ):

diff --git a/roverlay/packagerules/parser/context/action.py b/roverlay/packagerules/parser/context/action.py
index 91f97b6..ff5876c 100644
--- a/roverlay/packagerules/parser/context/action.py
+++ b/roverlay/packagerules/parser/context/action.py
@@ -41,11 +41,12 @@ class RuleActionContext (
 		self._actions = list()
 	# --- end of __init__ (...) ---
 
-	def feed ( self, _str ):
+	def feed ( self, _str, lino ):
 		"""Feeds this action block with input.
 
 		arguments:
 		* _str --
+		* lino --
 
 		Raises:
 		* InvalidContext
@@ -72,7 +73,8 @@ class RuleActionContext (
 					self._actions.append (
 						self.namespace.get_object (
 							evar_cls,
-							roverlay.strutil.unquote ( argv [1] )
+							roverlay.strutil.unquote ( argv [1] ),
+							lino
 						)
 					)
 				else:

diff --git a/roverlay/packagerules/parser/context/match.py b/roverlay/packagerules/parser/context/match.py
index b6e2849..bd7f9ab 100644
--- a/roverlay/packagerules/parser/context/match.py
+++ b/roverlay/packagerules/parser/context/match.py
@@ -102,21 +102,41 @@ class RuleMatchContext (
 		),
 	}
 
-	def __init__ ( self, namespace, level=0, bool_type=None ):
+	def __init__ ( self, namespace, level=0, bool_type=None, priority=-1 ):
+		"""RuleMatchContext constructor.
+
+		arguments:
+		* namespace -- the rule parser's namespace
+		* level     -- the depth of this context
+		* bool_type -- integer that sets the boolean type of this match
+		               context (see BOOL_* above, e.g. BOOL_AND)
+		* priority  -- priority of this match block (used for sorting)
+		"""
 		super ( RuleMatchContext, self ).__init__ (
 			namespace = namespace,
 			level     = level,
 		)
+
 		# match statements defined for this instance (nested ones, e.g. ORed,
 		# are in self._nested)
 		self._bool_type = (
 			bool_type if bool_type is not None else self.BOOL_AND
 		)
-		self._matches = list()
-		self._active  = True
+		self.priority   = priority
+		self._matches   = list()
+		self._active    = True
 	# --- end of __init__ (...) ---
 
-	def _feed ( self, s, match_depth ):
+	def _feed ( self, s, match_depth, lino ):
+		"""(Actually) feeds a match block with text input, either this one
+		(if match_depth is self.level) or a nested one.
+
+		arguments:
+		* s           -- preparsed input (a match statement),
+		                  whitespace and match depth indicators removed
+		* match_depth -- the depth of the match statement
+		* lino        -- line number
+		"""
 		assert match_depth >= self.level
 
 		if not self._active:
@@ -129,16 +149,16 @@ class RuleMatchContext (
 			s_low = s.lower()
 
 			if s_low in self.KEYWORDS_AND:
-				self._new_nested ( bool_type=self.BOOL_AND )
+				self._new_nested ( bool_type=self.BOOL_AND, priority=lino )
 
 			elif s_low in self.KEYWORDS_OR:
-				self._new_nested ( bool_type=self.BOOL_OR )
+				self._new_nested ( bool_type=self.BOOL_OR, priority=lino )
 
 			elif s_low in self.KEYWORDS_XOR1:
-				self._new_nested ( bool_type=self.BOOL_XOR1 )
+				self._new_nested ( bool_type=self.BOOL_XOR1, priority=lino )
 
 			elif s_low in self.KEYWORDS_NOR:
-				self._new_nested ( bool_type=self.BOOL_NOR )
+				self._new_nested ( bool_type=self.BOOL_NOR, priority=lino )
 
 			else:
 				if self._nested:
@@ -159,7 +179,7 @@ class RuleMatchContext (
 					raise NoSuchMatchStatement ( s, "invalid arg count" )
 
 				elif argc == 3:
-				#if argc >= 3:
+				#elif argc >= 3:
 					# <keyword> <op> <arg>
 
 					if argv [1] in self.OP_STRING_EXACT:
@@ -194,7 +214,7 @@ class RuleMatchContext (
 				self._matches.append (
 					self.namespace.get_object (
 						op,
-						100,
+						lino,
 						match_type [1],
 						value
 					)
@@ -202,34 +222,36 @@ class RuleMatchContext (
 
 		else:
 			try:
-				return self.get_nested()._feed ( s, match_depth )
+				return self.get_nested()._feed ( s, match_depth, lino )
 			except IndexError:
 				raise MatchDepthError ( self.level, match_depth )
 	# --- end of _feed (...) ---
 
 	def create ( self ):
 		"""Creates and returns an acceptor for this match block."""
-		acceptor = self._BOOL_MAP [self._bool_type] ( priority=100 )
+
+		acceptor = self._BOOL_MAP [self._bool_type] ( priority=self.priority )
 
 		for match in self._matches:
 			acceptor.add_acceptor ( match )
 
 		for nested in self._nested:
-				acceptor.add_acceptor ( nested.create() )
+			acceptor.add_acceptor ( nested.create() )
 
 		return acceptor
 	# --- end of create (...) ---
 
-	def feed ( self, _str ):
+	def feed ( self, _str, lino ):
 		"""Feeds a match block with input.
 
 		arguments:
 		* _str --
+		* lino --
 		"""
 		# prepare _str for the actual _feed() function
 		# * determine match depth
 		s = _str.lstrip ( self.MATCH_DEPTH_CHARS )
-		return self._feed ( s.lstrip(), len ( _str ) - len ( s ) )
+		return self._feed ( s.lstrip(), len ( _str ) - len ( s ), lino )
 	# --- end of feed (...) ---
 
 # --- end of RuleMatchContext ---

diff --git a/roverlay/packagerules/parser/context/rule.py b/roverlay/packagerules/parser/context/rule.py
index dd1a07b..f14faf6 100644
--- a/roverlay/packagerules/parser/context/rule.py
+++ b/roverlay/packagerules/parser/context/rule.py
@@ -42,17 +42,24 @@ class RuleContext ( base.NestableContext ):
 
 	# -- end of CONTEXT_ --
 
-	def __init__ ( self, namespace, level=0 ):
+	def __init__ ( self, namespace, level=0, priority=-1 ):
 		super ( RuleContext, self ).__init__ ( namespace, level )
 
 		self.context         = self.CONTEXT_MAIN_MATCH
-		self._match_context  = match.RuleMatchContext   ( self.namespace )
+		self.priority        = priority
 		self._action_context = action.RuleActionContext ( self.namespace )
+		self._match_context  = match.RuleMatchContext (
+			namespace = self.namespace,
+			priority  = priority
+		)
 	# --- end of __init__ (...) ---
 
-	def begin_match ( self ):
+	def begin_match ( self, lino ):
 		"""Create/begin a match-block of a nested rule.
 
+		arguments:
+		* lino -- line number
+
 		Raises: InvalidContext,
 		         match-blocks are only allowed within an action-block
 		"""
@@ -61,21 +68,24 @@ class RuleContext ( base.NestableContext ):
 
 		if self.context & self.CONTEXT_MAIN_ACTION:
 			# a nested rule (with depth = 1)
-			self._new_nested()
+			self._new_nested ( priority=lino )
 			self.context = self.CONTEXT_SUB_MATCH
 		elif self.context & self.CONTEXT_SUB_ACTION:
 			# a nested rule inside a nested one (depth > 1)
 			# => redirect to nested
-			self.get_nested().begin_match()
+			self.get_nested().begin_match ( lino )
 			self.context = self.CONTEXT_SUB_MATCH
 		else:
 			# illegal
 			raise self.InvalidContext()
 	# --- end of begin_match (...) ---
 
-	def begin_action ( self ):
+	def begin_action ( self, lino ):
 		"""Create/begin an action block of a rule (nested or "self").
 
+		arguments:
+		* lino -- line number
+
 		Raises: InvalidContext,
 		         an action-block has to be preceeded by a match-block
 		"""
@@ -85,14 +95,14 @@ class RuleContext ( base.NestableContext ):
 		elif self.context & self.CONTEXT_SUB_MATCH:
 			# action-block of a nested rule
 			# => redirect to nested
-			self.get_nested().begin_action()
+			self.get_nested().begin_action ( lino )
 			self.context = self.CONTEXT_SUB_ACTION
 		else:
 			# illegal
 			raise self.InvalidContext()
 	# --- end of begin_action (...) ---
 
-	def end_of_rule ( self ):
+	def end_of_rule ( self, lino ):
 		"""Has to be called whenever an end-of-rule statement has been reached
 		and ends a rule, either this one or a nested one (depending on the
 		context).
@@ -100,6 +110,9 @@ class RuleContext ( base.NestableContext ):
 		Returns True if this rule has been ended, else False (end of a nested
 		rule).
 
+		arguments:
+		* lino -- line number
+
 		Raises: InvalidContext,
 		         rules can only be closed if within an action-block
 		"""
@@ -108,7 +121,7 @@ class RuleContext ( base.NestableContext ):
 			self.context = self.CONTEXT_NONE
 			return True
 		elif self.context & self.CONTEXT_SUB_ACTION:
-			if self.get_nested().end_of_rule():
+			if self.get_nested().end_of_rule ( lino ):
 				# end of child rule (depth=1)
 				self.context = self.CONTEXT_MAIN_ACTION
 
@@ -122,21 +135,22 @@ class RuleContext ( base.NestableContext ):
 			raise self.InvalidContext()
 	# --- end of end_of_rule (...) ---
 
-	def feed ( self, _str ):
+	def feed ( self, _str, lino ):
 		"""Feed this rule with input (text).
 
 		arguments:
 		* _str --
+		* lino -- line number
 
 		Raises: InvalidContext if this rule does not accept input
 		        (if self.context is CONTEXT_NONE)
 		"""
 		if self.context & self.CONTEXT_MAIN_MATCH:
-			return self._match_context.feed ( _str )
+			return self._match_context.feed ( _str, lino )
 		elif self.context & self.CONTEXT_MAIN_ACTION:
-			return self._action_context.feed ( _str )
+			return self._action_context.feed ( _str, lino )
 		elif self.context & self.CONTEXT_SUB:
-			return self.get_nested().feed ( _str )
+			return self.get_nested().feed ( _str, lino )
 		else:
 			raise self.InvalidContext()
 	# --- end of feed (...) ---
@@ -171,7 +185,7 @@ class RuleContext ( base.NestableContext ):
 					"ignore action-block cannot contain nested rules."
 				)
 			else:
-				package_rule = rules.NestedPackageRule()
+				package_rule = rules.NestedPackageRule ( priority=self.priority )
 				for nested in self._nested:
 					package_rule.add_rule ( nested.create() )
 
@@ -180,11 +194,11 @@ class RuleContext ( base.NestableContext ):
 
 		elif actions is None:
 			# ignore rule
-			package_rule = rules.IgnorePackageRule()
+			package_rule = rules.IgnorePackageRule ( priority=self.priority )
 
 		elif actions:
 			# normal rule
-			package_rule = rules.PackageRule()
+			package_rule = rules.PackageRule ( priority=self.priority )
 
 			for action in actions:
 				package_rule.add_action ( action )

diff --git a/roverlay/packagerules/parser/text.py b/roverlay/packagerules/parser/text.py
index 968729e..6badc58 100644
--- a/roverlay/packagerules/parser/text.py
+++ b/roverlay/packagerules/parser/text.py
@@ -11,7 +11,7 @@ class RuleParser ( object ):
 
 	class NotParseable ( ValueError ):
 		def __init__ ( self, line, lino ):
-			super ( NotParseable, self ).__init__ (
+			super ( RuleParser.NotParseable, self ).__init__ (
 				"in line {}: cannot parse '{}'.".format ( lino, line )
 			)
 		# --- end of __init__ (...) ---
@@ -56,22 +56,23 @@ class RuleParser ( object ):
 		if len ( l ) > 0 and l[0] not in self.COMMENT_CHARS:
 			if self._current_rule:
 				if l in self.KEYWORDS_MATCH:
-					self._current_rule.begin_match()
+					self._current_rule.begin_match ( lino )
 				elif l in self.KEYWORDS_ACTION:
-					self._current_rule.begin_action()
+					self._current_rule.begin_action ( lino )
 				elif l in self.KEYWORDS_END:
-					if self._current_rule.end_of_rule():
+					if self._current_rule.end_of_rule ( lino ):
 						# add rule to self._parsed_rules
 						self._parsed_rules.append ( self._current_rule )
 						self._current_rule = None
 					# else end of a nested rule, do nothing
 				else:
-					self._current_rule.feed ( l )
+					self._current_rule.feed ( l, lino )
 
 			elif l in self.KEYWORDS_MATCH:
 				self._current_rule = (
 					roverlay.packagerules.parser.context.rule.RuleContext (
-						self.namespace
+						self.namespace,
+						priority=lino
 					)
 				)
 
@@ -101,7 +102,8 @@ class RuleParser ( object ):
 
 		with open ( rule_file, 'r' ) as FH:
 			for lino, line in enumerate ( FH.readlines() ):
-				self._feed ( line.strip(), lino )
+				# ^lino := 0..(n-1), add +1
+				self._feed ( line.strip(), lino + 1 )
 
 		for rule in self._create():
 			self.add_rule ( rule )


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/packagerules/parser/, roverlay/packagerules/parser/context/, ...
  2013-06-13 16:34 [gentoo-commits] proj/R_overlay:master commit in: roverlay/packagerules/parser/, roverlay/packagerules/parser/context/, André Erdmann
@ 2013-06-13 16:34 ` André Erdmann
  0 siblings, 0 replies; 4+ messages in thread
From: André Erdmann @ 2013-06-13 16:34 UTC (permalink / raw
  To: gentoo-commits

commit:     486d764d1269bfe7e9eb4d6ca807a7c52f2ee744
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jun 13 16:26:41 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jun 13 16:26:41 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=486d764d

remove debug output

---
 roverlay/packagerules/parser/context/match.py | 3 +--
 roverlay/packagerules/parser/namespace.py     | 2 +-
 roverlay/tools/runcmd.py                      | 5 +++--
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/roverlay/packagerules/parser/context/match.py b/roverlay/packagerules/parser/context/match.py
index d4c206d..e18e92e 100644
--- a/roverlay/packagerules/parser/context/match.py
+++ b/roverlay/packagerules/parser/context/match.py
@@ -216,8 +216,7 @@ class RuleMatchContext (
             # -- if;
 
             self._matches.append (
-               self.namespace.get_object (
-                  op,
+               op (
                   lino,
                   match_type [1],
                   value

diff --git a/roverlay/packagerules/parser/namespace.py b/roverlay/packagerules/parser/namespace.py
index a1d3ff8..6af8661 100644
--- a/roverlay/packagerules/parser/namespace.py
+++ b/roverlay/packagerules/parser/namespace.py
@@ -6,7 +6,7 @@
 
 import roverlay.util
 
-DEBUG_GET_OBJECT = True
+DEBUG_GET_OBJECT = False
 
 if DEBUG_GET_OBJECT:
    def debug_get_object ( msg, cls, args, kwargs ):

diff --git a/roverlay/tools/runcmd.py b/roverlay/tools/runcmd.py
index e6b4f19..cda41d0 100644
--- a/roverlay/tools/runcmd.py
+++ b/roverlay/tools/runcmd.py
@@ -4,12 +4,13 @@
 # Distributed under the terms of the GNU General Public License;
 # either version 2 of the License, or (at your option) any later version.
 
+import logging
 import os
 import subprocess
 
 import roverlay.strutil
 
-DEBUG_TO_CONSOLE = True
+DEBUG_TO_CONSOLE = False
 
 def run_command ( cmdv, env, logger, return_success=False ):
    if DEBUG_TO_CONSOLE:
@@ -26,7 +27,7 @@ def run_command ( cmdv, env, logger, return_success=False ):
    output = cmd_call.communicate()
 
    # log stderr
-   if output [1]:
+   if output [1] and logger.isEnabledFor ( logging.WARNING ):
       for line in roverlay.strutil.pipe_lines ( output [1], use_filter=True ):
          logger.warning ( line )
 


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [gentoo-commits] proj/R_overlay:master commit in: roverlay/packagerules/parser/, roverlay/packagerules/parser/context/, ...
@ 2013-06-13 16:34 André Erdmann
  2013-06-13 16:34 ` [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
  0 siblings, 1 reply; 4+ messages in thread
From: André Erdmann @ 2013-06-13 16:34 UTC (permalink / raw
  To: gentoo-commits

commit:     486d764d1269bfe7e9eb4d6ca807a7c52f2ee744
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jun 13 16:26:41 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jun 13 16:26:41 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=486d764d

remove debug output

---
 roverlay/packagerules/parser/context/match.py | 3 +--
 roverlay/packagerules/parser/namespace.py     | 2 +-
 roverlay/tools/runcmd.py                      | 5 +++--
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/roverlay/packagerules/parser/context/match.py b/roverlay/packagerules/parser/context/match.py
index d4c206d..e18e92e 100644
--- a/roverlay/packagerules/parser/context/match.py
+++ b/roverlay/packagerules/parser/context/match.py
@@ -216,8 +216,7 @@ class RuleMatchContext (
             # -- if;
 
             self._matches.append (
-               self.namespace.get_object (
-                  op,
+               op (
                   lino,
                   match_type [1],
                   value

diff --git a/roverlay/packagerules/parser/namespace.py b/roverlay/packagerules/parser/namespace.py
index a1d3ff8..6af8661 100644
--- a/roverlay/packagerules/parser/namespace.py
+++ b/roverlay/packagerules/parser/namespace.py
@@ -6,7 +6,7 @@
 
 import roverlay.util
 
-DEBUG_GET_OBJECT = True
+DEBUG_GET_OBJECT = False
 
 if DEBUG_GET_OBJECT:
    def debug_get_object ( msg, cls, args, kwargs ):

diff --git a/roverlay/tools/runcmd.py b/roverlay/tools/runcmd.py
index e6b4f19..cda41d0 100644
--- a/roverlay/tools/runcmd.py
+++ b/roverlay/tools/runcmd.py
@@ -4,12 +4,13 @@
 # Distributed under the terms of the GNU General Public License;
 # either version 2 of the License, or (at your option) any later version.
 
+import logging
 import os
 import subprocess
 
 import roverlay.strutil
 
-DEBUG_TO_CONSOLE = True
+DEBUG_TO_CONSOLE = False
 
 def run_command ( cmdv, env, logger, return_success=False ):
    if DEBUG_TO_CONSOLE:
@@ -26,7 +27,7 @@ def run_command ( cmdv, env, logger, return_success=False ):
    output = cmd_call.communicate()
 
    # log stderr
-   if output [1]:
+   if output [1] and logger.isEnabledFor ( logging.WARNING ):
       for line in roverlay.strutil.pipe_lines ( output [1], use_filter=True ):
          logger.warning ( line )
 


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [gentoo-commits] proj/R_overlay:master commit in: roverlay/packagerules/parser/, roverlay/packagerules/parser/context/, ...
@ 2013-08-01 12:44 André Erdmann
  0 siblings, 0 replies; 4+ messages in thread
From: André Erdmann @ 2013-08-01 12:44 UTC (permalink / raw
  To: gentoo-commits

commit:     703b273c1559be91ad2e7eeceff1b963e0f91e8a
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Aug  1 12:32:39 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Aug  1 12:32:39 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=703b273c

package rules, syntax: support else-action block

Package rules can now declare an ELSE: block (following the ACTION: block) whose
action statements are executed if the rule's MATCH: block did not match a
package.

"ELSE IF" statements are not supported, but can be realized by placing a nested
rule in the ELSE: block.

Other changes:
* "null"/"pass" action statement. A no-op statement (removed at rule "compile"
  time) which can be used to improve readability (e.g. if a rule has no actions
  in the ACTION: block)
* "do-not-process"/"ignore" is now available as action (in addition to the
  hard-wired IgnorePackageRule class). The rule parser chooses the "correct"
  implementation (which depends on the rule).
  An "do-not-process if <matches...> else do-not-process" rule is forbidden.
  (As "workaround", it can be achieved via "do-not-process if <always true
  condition>.)
* minor fix in RuleActionContext.feed() concerning arg count
* the rule context (responsible for parsing a single rule) manipulates its
  status bitmask (bitwise-AND/OR) now instead of setting it directly

---
 roverlay/packagerules/abstract/actions.py      |   2 +
 roverlay/packagerules/abstract/rules.py        | 181 ++++++++++++++++---
 roverlay/packagerules/acceptors/stringmatch.py |   6 +-
 roverlay/packagerules/actions/evar.py          |   2 +-
 roverlay/packagerules/actions/ignore.py        |  25 +++
 roverlay/packagerules/actions/info.py          |   4 +-
 roverlay/packagerules/actions/trace.py         |   4 +-
 roverlay/packagerules/parser/context/action.py |  18 +-
 roverlay/packagerules/parser/context/base.py   |   2 +-
 roverlay/packagerules/parser/context/rule.py   | 233 +++++++++++++++++++------
 roverlay/packagerules/parser/namespace.py      |   9 +
 roverlay/packagerules/parser/text.py           |  18 +-
 roverlay/packagerules/rules.py                 |  25 ++-
 13 files changed, 419 insertions(+), 110 deletions(-)

diff --git a/roverlay/packagerules/abstract/actions.py b/roverlay/packagerules/abstract/actions.py
index f903398..608d20a 100644
--- a/roverlay/packagerules/abstract/actions.py
+++ b/roverlay/packagerules/abstract/actions.py
@@ -9,6 +9,8 @@ __all__ = [ 'PackageRuleAction', ]
 class PackageRuleAction ( object ):
    """PackageRuleActions manipulate PackageInfo instances."""
 
+   INDENT = 3 * ' '
+
    def __init__ ( self, priority=1000 ):
       super ( PackageRuleAction, self ).__init__()
       self.priority = priority

diff --git a/roverlay/packagerules/abstract/rules.py b/roverlay/packagerules/abstract/rules.py
index 02ce4df..98db68d 100644
--- a/roverlay/packagerules/abstract/rules.py
+++ b/roverlay/packagerules/abstract/rules.py
@@ -14,15 +14,16 @@ class IgnorePackageRule ( object ):
 
    def __init__ ( self, priority=100 ):
       super ( IgnorePackageRule, self ).__init__()
-      self.priority   = priority
-      self._acceptor  = None
-      self.logger     = None
+      self.is_toplevel = False
+      self.priority    = priority
+      self._acceptor   = None
+      self.logger      = None
    # --- end of __init__ (...) ---
 
-   def _iter_rules ( self, with_self=True ):
+   def _iter_all_rules ( self, with_self=True ):
       if with_self:
          yield self
-   # --- end of _iter_rules (...) ---
+   # --- end of _iter_all_rules (...) ---
 
    def accepts ( self, p_info ):
       """Returns True if this rule matches the given PackageInfo else False.
@@ -50,7 +51,7 @@ class IgnorePackageRule ( object ):
       * logger --
       """
       self.logger = logger
-      if hasattr ( self, '_acceptor' ):
+      if self._acceptor:
          self._acceptor.set_logger ( self.logger )
    # --- end of set_logger (...) ---
 
@@ -63,11 +64,20 @@ class IgnorePackageRule ( object ):
       return False
    # --- end of apply_actions (...) ---
 
+   def apply_alternative_actions ( self, p_info ):
+      """Nop.
+
+      arguments:
+      * p_info --
+      """
+      return True
+   # --- end of apply_alternative_actions (...) ---
+
    def prepare ( self ):
       """
       Prepares this rule for usage. Has to be called after adding actions.
       """
-      if hasattr ( self, '_acceptor' ):
+      if self._acceptor:
          self._acceptor.prepare()
    # --- end of prepare (...) ---
 
@@ -75,19 +85,51 @@ class IgnorePackageRule ( object ):
       yield level * '   ' + 'ignore'
    # --- end of _gen_action_str (...) ---
 
+   def _gen_alt_action_str ( self, level ):
+      raise NotImplementedError()
+   # --- end of _gen_alt_action_str (...) ---
+
+   def _gen_alt_rules_str ( self, level ):
+      raise NotImplementedError()
+   # --- end of _gen_alt_rules_str (...) ---
+
+   def has_alternative_actions ( self ):
+      return False
+   # --- end of has_alternative_actions (...) ---
+
+   def has_alternative_rules ( self ):
+      return False
+   # --- end of has_alternative_rules (...) ---
+
    def gen_str ( self, level ):
-      indent = level * '   '
+      indent     = level * '   '
+      next_level = level + 1
 
       yield ( indent + 'MATCH:' )
-      for s in self._acceptor.gen_str ( level=( level + 1 ), match_level=0 ):
+      for s in self._acceptor.gen_str ( level=next_level, match_level=0 ):
          yield s
 
       yield ( indent + 'ACTION:' )
-      for s in self._gen_action_str ( level=( level + 1 ) ):
+      for s in self._gen_action_str ( level=next_level ):
          yield s
 
       if hasattr ( self, '_gen_rules_str' ):
-         for s in self._gen_rules_str ( level=( level + 1 ) ):
+         for s in self._gen_rules_str ( level=next_level ):
+            yield s
+
+      have_alt = False
+
+      if self.has_alternative_actions():
+         yield ( indent + 'ELSE:' )
+         have_alt = True
+         for s in self._gen_alt_action_str ( level=next_level ):
+            yield s
+
+      if self.has_alternative_rules():
+         if not have_alt:
+            yield ( indent + 'ELSE:' )
+            have_alt = True
+         for s in self._gen_alt_rules_str ( level=next_level ):
             yield s
 
       yield ( indent + 'END;' )
@@ -109,15 +151,21 @@ class PackageRule ( IgnorePackageRule ):
 
    def __init__ ( self, priority=1000 ):
       super ( PackageRule, self ).__init__( priority )
-      self._actions = list()
+      self._actions     = list()
+      self._alt_actions = list()
    # --- end of __init__ (...) ---
 
+   def has_alternative_actions ( self ):
+      return bool ( self._alt_actions )
+   # --- end of has_alternative_actions (...) ---
+
    def prepare ( self ):
       """
       Prepares this rule for usage. Has to be called after adding actions.
       """
       super ( PackageRule, self ).prepare()
-      self._actions = roverlay.util.priosort ( self._actions )
+      self._actions     = roverlay.util.priosort ( self._actions )
+      self._alt_actions = roverlay.util.priosort ( self._alt_actions )
    # --- end of prepare (...) ---
 
    def set_logger ( self, logger ):
@@ -127,9 +175,14 @@ class PackageRule ( IgnorePackageRule ):
       * logger --
       """
       super ( PackageRule, self ).set_logger ( logger )
+
       action_logger = self.logger.getChild ( 'Action' )
       for action in self._actions:
          action.set_logger ( action_logger )
+
+      #action_logger = self.logger.getChild ( 'ElseAction' )
+      for action in self._alt_actions:
+         action.set_logger ( action_logger )
    # --- end of set_logger (...) ---
 
    def apply_actions ( self, p_info ):
@@ -148,6 +201,18 @@ class PackageRule ( IgnorePackageRule ):
       return True
    # --- end of apply_actions (...) ---
 
+   def apply_alternative_actions ( self, p_info ):
+      """Applies all 'alternative' actions to the given PackageInfo.
+
+      arguments:
+      * p_info --
+      """
+      for action in self._alt_actions:
+         if action.apply_action ( p_info ) is False:
+            return False
+      return True
+   # --- end of apply_alternative_actions (...) ---
+
    def add_action ( self, action ):
       """Adds an action to this rule.
 
@@ -157,12 +222,27 @@ class PackageRule ( IgnorePackageRule ):
       self._actions.append ( action )
    # --- end of add_action (...) ---
 
+   def add_alternative_action ( self, action ):
+      """Adds an 'alternative' action to this rule.
+
+      arguments:
+      * action --
+      """
+      self._alt_actions.append ( action )
+   # --- end of add_alternative_action (...) ---
+
    def _gen_action_str ( self, level ):
       for x in self._actions:
          for s in x.gen_str ( level=level ):
             yield s
    # --- end of _gen_action_str (...) ---
 
+   def _gen_alt_action_str ( self, level ):
+      for x in self._alt_actions:
+         for s in x.gen_str ( level=level ):
+            yield s
+   # --- end of _gen_alt_action_str (...) ---
+
 # --- end of PackageRule ---
 
 
@@ -171,23 +251,38 @@ class NestedPackageRule ( PackageRule ):
 
    def __init__ ( self, priority=2000 ):
       super ( NestedPackageRule, self ).__init__ ( priority )
-      self._rules = list()
+      self._rules     = list()
+      self._alt_rules = list()
    # --- end of __init__ (...) ---
 
+   def has_alternative_rules ( self ):
+      return bool ( self._alt_rules )
+   # --- end of has_alternative_rules (...) ---
+
    def _gen_rules_str ( self, level ):
       for rule in self._rules:
          for s in rule.gen_str ( level ):
             yield s
    # --- end of _gen_rules_str (...) ---
 
-   def _iter_rules ( self, with_self=True ):
+   def _gen_alt_rules_str ( self, level ):
+      for rule in self._alt_rules:
+         for s in rule.gen_str ( level ):
+            yield s
+   # --- end of _gen_alt_rules_str (...) ---
+
+   def _iter_all_rules ( self, with_self=True ):
       if with_self:
          yield self
 
       for rule in self._rules:
-         for nested_rule in rule._iter_rules ( with_self=True ):
+         for nested_rule in rule._iter_all_rules ( with_self=True ):
+            yield nested_rule
+
+      for rule in self._alt_rules:
+         for nested_rule in rule._iter_all_rules ( with_self=True ):
             yield nested_rule
-   # --- end of _iter_rules (...) ---
+   # --- end of _iter_all_rules (...) ---
 
    def set_logger ( self, logger ):
       """Assigns a logger to this package rule and all actions.
@@ -196,13 +291,17 @@ class NestedPackageRule ( PackageRule ):
       * logger --
       """
       super ( NestedPackageRule, self ).set_logger ( logger )
-      if hasattr ( self, 'is_toplevel' ) and self.is_toplevel:
+
+      if self.is_toplevel:
          nested_logger = self.logger.getChild ( 'nested' )
-         for nested_rule in self._rules:
-            nested_rule.set_logger ( nested_logger )
       else:
-         for nested_rule in self._rules:
-            nested_rule.set_logger ( self.logger )
+         nested_logger = self.logger
+
+      for nested_rule in self._rules:
+         nested_rule.set_logger ( nested_logger )
+
+      for nested_rule in self._alt_rules:
+         nested_rule.set_logger ( nested_logger )
    # --- end of set_logger (...) ---
 
    def prepare ( self ):
@@ -212,7 +311,8 @@ class NestedPackageRule ( PackageRule ):
       super ( NestedPackageRule, self ).prepare()
       for rule in self._rules:
          rule.prepare()
-      self._rules = roverlay.util.priosort ( self._rules )
+      self._rules     = roverlay.util.priosort ( self._rules )
+      self._alt_rules = roverlay.util.priosort ( self._alt_rules )
    # --- end of prepare (...) ---
 
    def apply_actions ( self, p_info ):
@@ -226,13 +326,37 @@ class NestedPackageRule ( PackageRule ):
       """
       if super ( NestedPackageRule, self ).apply_actions ( p_info ):
          for rule in self._rules:
-            if rule.accepts ( p_info ) and not rule.apply_actions ( p_info ):
+            if rule.accepts ( p_info ):
+               if not rule.apply_actions ( p_info ):
+                  return False
+            elif not rule.apply_alternative_actions ( p_info ):
                return False
          return True
       else:
          return False
    # --- end of apply_actions (...) ---
 
+   def apply_alternative_actions ( self, p_info ):
+      """Applies all 'alternative' actions to the given PackageInfo.
+
+      arguments:
+      * p_info --
+      """
+      if ( super (
+         NestedPackageRule, self ).apply_alternative_actions ( p_info )
+      ):
+         for rule in self._alt_rules:
+            if rule.accepts ( p_info ):
+               if not rule.apply_actions ( p_info ):
+                  return False
+            elif not rule.apply_alternative_actions ( p_info ):
+               return False
+
+         return True
+      else:
+         return False
+   # --- end of apply_alternative_actions (...) ---
+
    def add_rule ( self, rule ):
       """Adds a rule.
 
@@ -242,4 +366,13 @@ class NestedPackageRule ( PackageRule ):
       self._rules.append ( rule )
    # --- end of add_rule (...) ---
 
+   def add_alternative_rule ( self, rule ):
+      """Adds an 'alternative' rule.
+
+      arguments:
+      * rule --
+      """
+      self._alt_rules.append ( rule )
+   # --- end of add_alternative_rule (...) ---
+
 # --- end of NestedPackageRule ---

diff --git a/roverlay/packagerules/acceptors/stringmatch.py b/roverlay/packagerules/acceptors/stringmatch.py
index f5da49f..b6007b6 100644
--- a/roverlay/packagerules/acceptors/stringmatch.py
+++ b/roverlay/packagerules/acceptors/stringmatch.py
@@ -103,8 +103,10 @@ class RegexAcceptor (
                self.__class__.__name__
             )
          )
-
-      self._regex = regex_compiled if regex_compiled else re.compile ( regex )
+      elif regex_compiled:
+         self._regex = regex_compiled
+      else:
+         self._regex = re.compile ( regex )
    # --- end of __init__ (...) ---
 
    def _matches ( self, value ):

diff --git a/roverlay/packagerules/actions/evar.py b/roverlay/packagerules/actions/evar.py
index c789219..17f46fe 100644
--- a/roverlay/packagerules/actions/evar.py
+++ b/roverlay/packagerules/actions/evar.py
@@ -46,7 +46,7 @@ class EvarAction ( roverlay.packagerules.abstract.actions.PackageRuleAction ):
 
    def gen_str ( self, level ):
       yield (
-         level * '   ' + self._evar.name.lower()
+         ( level * self.INDENT ) + self._evar.name.lower()
          + ' "' + self._evar.value + '"'
       )
    # --- end of gen_str (...) ---

diff --git a/roverlay/packagerules/actions/ignore.py b/roverlay/packagerules/actions/ignore.py
new file mode 100644
index 0000000..5ee19f9
--- /dev/null
+++ b/roverlay/packagerules/actions/ignore.py
@@ -0,0 +1,25 @@
+# R overlay -- package rule actions, ignore package
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+import roverlay.packagerules.abstract.actions
+
+__all__ = [ 'IgnoreAction', ]
+
+class IgnoreAction (
+   roverlay.packagerules.abstract.actions.PackageRuleAction
+):
+
+   KEYWORD = 'ignore'
+
+   def apply_action ( self, p_info ):
+      return False
+   # --- end of apply_action (...) ---
+
+   def gen_str ( self, level ):
+      yield ( level * self.INDENT ) + self.KEYWORD
+   # --- end of gen_str (...) ---
+
+# --- end of IgnoreAction ---

diff --git a/roverlay/packagerules/actions/info.py b/roverlay/packagerules/actions/info.py
index 538fdef..d9f1390 100644
--- a/roverlay/packagerules/actions/info.py
+++ b/roverlay/packagerules/actions/info.py
@@ -59,7 +59,7 @@ class InfoRenameAction (
       # FIXME: that's not always correct!
       # (could be solved by storing the original regex delimiter)
       yield (
-         level * '   ' + 'rename ' + self.key
+         level * self.INDENT + 'rename ' + self.key
          + ' s/' + self.regex.pattern + '/' + self.subst + '/' # + flags
       )
    # --- end of gen_str (...) ---
@@ -162,7 +162,7 @@ class InfoSetToAction (
    # --- end of apply_action (...) ---
 
    def gen_str ( self, level ):
-      yield ( level * '   ' + 'set ' + self.key + ' ' + self.value )
+      yield ( level * self.INDENT + 'set ' + self.key + ' ' + self.value )
    # --- end of gen_str (...) ---
 
 # --- end of InfoSetToAction ---

diff --git a/roverlay/packagerules/actions/trace.py b/roverlay/packagerules/actions/trace.py
index 669969a..c16f6c6 100644
--- a/roverlay/packagerules/actions/trace.py
+++ b/roverlay/packagerules/actions/trace.py
@@ -38,7 +38,7 @@ class TraceAction (
    # --- end of apply_action (...) ---
 
    def gen_str ( self, level ):
-      yield ( level * '   ' ) + "trace " + str ( self._ident )
+      yield ( level * self.INDENT ) + "trace " + str ( self._ident )
    # --- end of gen_str (...) ---
 
 
@@ -57,5 +57,5 @@ class MarkAsModifiedAction (
    # --- end of apply_action (...) ---
 
    def gen_str ( self, level ):
-      yield ( level * '   ' ) + "trace"
+      yield ( level * self.INDENT ) + "trace"
    # --- end of gen_str (...) ---

diff --git a/roverlay/packagerules/parser/context/action.py b/roverlay/packagerules/parser/context/action.py
index 22936cc..49ed7db 100644
--- a/roverlay/packagerules/parser/context/action.py
+++ b/roverlay/packagerules/parser/context/action.py
@@ -37,14 +37,16 @@ class RuleActionContext (
    """RuleActionContext parses action-blocks."""
 
    # keywords for the "ignore" action
-   KEYWORDS_ACTION_IGNORE = frozenset ((
+   KEYWORDS_ACTION_IGNORE = frozenset ({
       'ignore',
       'do-not-process'
-   ))
+   })
 
-   KEYWORDS_ACTION_TRACE = frozenset ((
+   KEYWORDS_ACTION_TRACE = frozenset ({
       'trace',
-   ))
+   })
+
+   KEYWORDS_NO_ACTION = frozenset ({ 'pass', 'null', })
 
    # dict ( <keyword> => <evar class> )
    # Dict of evar action keywords (with corresponding classes)
@@ -225,7 +227,9 @@ class RuleActionContext (
       Raises:
       * InvalidContext
       """
-      if _str in self.KEYWORDS_ACTION_IGNORE:
+      if _str in self.KEYWORDS_NO_ACTION:
+         pass
+      elif _str in self.KEYWORDS_ACTION_IGNORE:
          if not self._actions:
             self._actions = None
          else:
@@ -255,7 +259,9 @@ class RuleActionContext (
                   )
                )
 
-         elif self._add_as_info_action ( argv [0], argv [1], _str, lino ):
+         elif len ( argv ) > 1 and (
+            self._add_as_info_action ( argv [0], argv [1], _str, lino )
+         ):
             pass
 
          else:

diff --git a/roverlay/packagerules/parser/context/base.py b/roverlay/packagerules/parser/context/base.py
index 1a09a79..9bd97b7 100644
--- a/roverlay/packagerules/parser/context/base.py
+++ b/roverlay/packagerules/parser/context/base.py
@@ -15,7 +15,7 @@ class BaseContext ( object ):
       self.namespace = namespace
    # --- end of __init__ (...) ---
 
-   def feed ( self, _str ):
+   def feed ( self, _str, lino ):
       raise NotImplementedError()
    # --- end of feed (...) ---
 

diff --git a/roverlay/packagerules/parser/context/rule.py b/roverlay/packagerules/parser/context/rule.py
index 2601d7e..0f6f342 100644
--- a/roverlay/packagerules/parser/context/rule.py
+++ b/roverlay/packagerules/parser/context/rule.py
@@ -4,11 +4,18 @@
 # Distributed under the terms of the GNU General Public License;
 # either version 2 of the License, or (at your option) any later version.
 
-from roverlay.packagerules.abstract import rules
+import roverlay.packagerules.abstract.rules
+from roverlay.packagerules.abstract.rules import \
+   IgnorePackageRule, PackageRule, NestedPackageRule
 
-from . import base, match, action
+import roverlay.packagerules.parser.context.action
+import roverlay.packagerules.parser.context.base
+import roverlay.packagerules.parser.context.match
 
-class RuleContext ( base.NestableContext ):
+
+class RuleContext (
+   roverlay.packagerules.parser.context.base.NestableContext
+):
    """Class for creating rules from text input (feed(<>)) plus using a few
    control flow functions (end_of_rule(), begin_match(), begin_action()).
    """
@@ -29,28 +36,55 @@ class RuleContext ( base.NestableContext ):
    #
    # (use bitwise operators to check against these values)
    #
-   CONTEXT_NONE        = 0 # == only
-   CONTEXT_MAIN_MATCH  = 1
-   CONTEXT_MAIN_ACTION = 2
-   CONTEXT_SUB_MATCH   = 4
-   CONTEXT_SUB_ACTION  = 8
+   CONTEXT_NONE            = 0 # == only
+   CONTEXT_MAIN_MATCH      = 1
+   CONTEXT_MAIN_ACTION     = 2
+   CONTEXT_MAIN_ALT_ACTION = 4
+   CONTEXT_SUB_MATCH       = 8
+   CONTEXT_SUB_ACTION      = 16
+   # else-block is a non-propagating status
+   #CONTEXT_SUB_ALT_ACTION
+
+   CONTEXT_MATCH           = CONTEXT_MAIN_MATCH      | CONTEXT_SUB_MATCH
+   CONTEXT_ACTION          = CONTEXT_MAIN_ACTION     | CONTEXT_SUB_ACTION
+   CONTEXT_MAIN_ANY_ACTION = CONTEXT_MAIN_ALT_ACTION | CONTEXT_MAIN_ACTION
+   CONTEXT_SUB             = CONTEXT_SUB_MATCH       | CONTEXT_SUB_ACTION
+
+   CONTEXT_MAIN = (
+      CONTEXT_MAIN_MATCH | CONTEXT_MAIN_ACTION | CONTEXT_MAIN_ALT_ACTION
+   )
 
-   CONTEXT_MATCH  = CONTEXT_MAIN_MATCH  | CONTEXT_SUB_MATCH
-   CONTEXT_ACTION = CONTEXT_MAIN_ACTION | CONTEXT_SUB_ACTION
-   CONTEXT_MAIN   = CONTEXT_MAIN_MATCH  | CONTEXT_MAIN_ACTION
-   CONTEXT_SUB    = CONTEXT_SUB_MATCH   | CONTEXT_SUB_ACTION
 
    # -- end of CONTEXT_ --
 
-   def __init__ ( self, namespace, level=0, priority=-1 ):
+   def __init__ ( self, namespace, level=0, priority=-1, mode=None ):
       super ( RuleContext, self ).__init__ ( namespace, level )
 
-      self.context         = self.CONTEXT_MAIN_MATCH
-      self.priority        = priority
-      self._action_context = action.RuleActionContext ( self.namespace )
-      self._match_context  = match.RuleMatchContext (
-         namespace = self.namespace,
-         priority  = priority
+      if mode is None:
+         if level == 0:
+            self.mode = self.CONTEXT_MAIN_ACTION
+         else:
+            raise Exception ( "mode has to be set if level is non-zero." )
+      else:
+         self.mode = mode
+
+      self.context             = self.CONTEXT_MAIN_MATCH
+      self.priority            = priority
+      self._action_context     = (
+         roverlay.packagerules.parser.context.action.RuleActionContext (
+            self.namespace
+         )
+      )
+      self._alt_action_context = (
+         roverlay.packagerules.parser.context.action.RuleActionContext (
+            self.namespace
+         )
+      )
+      self._match_context      = (
+         roverlay.packagerules.parser.context.match.RuleMatchContext (
+            namespace = self.namespace,
+            priority  = priority
+         )
       )
    # --- end of __init__ (...) ---
 
@@ -66,15 +100,22 @@ class RuleContext ( base.NestableContext ):
       # nested rules are stored in self._nested (and not in
       # self._action_context where they syntactically belong to)
 
-      if self.context & self.CONTEXT_MAIN_ACTION:
-         # a nested rule (with depth = 1)
-         self._new_nested ( priority=lino )
-         self.context = self.CONTEXT_SUB_MATCH
-      elif self.context & self.CONTEXT_SUB_ACTION:
+      if self.context & self.CONTEXT_SUB_ACTION:
          # a nested rule inside a nested one (depth > 1)
          # => redirect to nested
          self.get_nested().begin_match ( lino )
-         self.context = self.CONTEXT_SUB_MATCH
+         self.context |= self.CONTEXT_SUB_MATCH
+
+      elif self.context & self.CONTEXT_MAIN_ACTION:
+         # a nested rule (with depth = 1)
+         self._new_nested ( priority=lino, mode=self.CONTEXT_MAIN_ACTION )
+         self.context |= self.CONTEXT_SUB_MATCH
+
+      elif self.context & self.CONTEXT_MAIN_ALT_ACTION:
+         # a new nested rule in the else block (with depth = 1)
+         self._new_nested ( priority=lino, mode=self.CONTEXT_MAIN_ALT_ACTION )
+         self.context |= self.CONTEXT_SUB_MATCH
+
       else:
          # illegal
          raise self.InvalidContext()
@@ -87,21 +128,50 @@ class RuleContext ( base.NestableContext ):
       * lino -- line number
 
       Raises: InvalidContext,
-               an action-block has to be preceeded by a match-block
+               an action block has to be preceeded by a match block
       """
-      if self.context & self.CONTEXT_MAIN_MATCH:
-         # begin of the main action-block
-         self.context = self.CONTEXT_MAIN_ACTION
-      elif self.context & self.CONTEXT_SUB_MATCH:
+      if self.context & self.CONTEXT_SUB_MATCH:
          # action-block of a nested rule
          # => redirect to nested
          self.get_nested().begin_action ( lino )
-         self.context = self.CONTEXT_SUB_ACTION
+         self.context &= ~self.CONTEXT_SUB_MATCH
+         self.context |= self.CONTEXT_SUB_ACTION
+
+      elif self.context & self.CONTEXT_MAIN_MATCH:
+         # begin of the main action-block
+         self.context &= ~self.CONTEXT_MAIN_MATCH
+         self.context |= self.CONTEXT_MAIN_ACTION
+
       else:
          # illegal
          raise self.InvalidContext()
    # --- end of begin_action (...) ---
 
+   def begin_alternative_action ( self, lino ):
+      """Create/begin an else-action block of a rule (nested or "self").
+
+      arguments:
+      * lino -- line number
+
+      Raises: InvalidContext,
+               an else-action block has to be preceeded by an action block
+      """
+      if self.context & self.CONTEXT_SUB_ACTION:
+         # else-action-block of a nested rule
+         #  => redirect to nested
+         #  no status change as else-blocks are handled non-recursively
+         self.get_nested().begin_alternative_action ( lino )
+
+      elif self.context & self.CONTEXT_MAIN_ACTION:
+         # begin of the main else-action-block
+         self.context &= ~self.CONTEXT_MAIN_ACTION
+         self.context |= self.CONTEXT_MAIN_ALT_ACTION
+
+      else:
+         # illegal
+         raise self.InvalidContext()
+   # --- end of begin_alternative_action (...) ---
+
    def end_of_rule ( self, lino ):
       """Has to be called whenever an end-of-rule statement has been reached
       and ends a rule, either this one or a nested one (depending on the
@@ -116,14 +186,10 @@ class RuleContext ( base.NestableContext ):
       Raises: InvalidContext,
                rules can only be closed if within an action-block
       """
-      if self.context & self.CONTEXT_MAIN_ACTION:
-         # end of this rule
-         self.context = self.CONTEXT_NONE
-         return True
-      elif self.context & self.CONTEXT_SUB_ACTION:
+      if self.context & self.CONTEXT_SUB_ACTION:
          if self.get_nested().end_of_rule ( lino ):
             # end of child rule (depth=1)
-            self.context = self.CONTEXT_MAIN_ACTION
+            self.context &= ~self.CONTEXT_SUB_ACTION
 
 # no-op, since self.context is already CONTEXT_SUB_ACTION
 #         else:
@@ -131,6 +197,17 @@ class RuleContext ( base.NestableContext ):
 #            self.context = self.CONTEXT_SUB_ACTION
 
          return False
+
+      elif self.context & self.CONTEXT_MAIN_ANY_ACTION:
+         # end of this rule
+         #self.context = self.CONTEXT_NONE
+         self.context &= ~self.CONTEXT_MAIN_ANY_ACTION
+         if self.context != self.CONTEXT_NONE:
+            raise AssertionError (
+               "broken context bit mask {:d}!".format ( self.context )
+            )
+         return True
+
       else:
          raise self.InvalidContext()
    # --- end of end_of_rule (...) ---
@@ -145,12 +222,18 @@ class RuleContext ( base.NestableContext ):
       Raises: InvalidContext if this rule does not accept input
               (if self.context is CONTEXT_NONE)
       """
-      if self.context & self.CONTEXT_MAIN_MATCH:
+      if self.context & self.CONTEXT_SUB:
+         return self.get_nested().feed ( _str, lino )
+
+      elif self.context & self.CONTEXT_MAIN_MATCH:
          return self._match_context.feed ( _str, lino )
+
       elif self.context & self.CONTEXT_MAIN_ACTION:
          return self._action_context.feed ( _str, lino )
-      elif self.context & self.CONTEXT_SUB:
-         return self.get_nested().feed ( _str, lino )
+
+      elif self.context & self.CONTEXT_MAIN_ALT_ACTION:
+         return self._alt_action_context.feed ( _str, lino )
+
       else:
          raise self.InvalidContext()
    # --- end of feed (...) ---
@@ -171,37 +254,71 @@ class RuleContext ( base.NestableContext ):
          raise self.InvalidContext ( "end_of_rule not reached." )
       # -- if;
 
-      package_rule = None
-      actions      = self._action_context.create()
-      acceptor     = self._match_context.create()
+      package_rule  = None
+      actions       = self._action_context.create()
+      alt_actions   = self._alt_action_context.create()
+      acceptor      = self._match_context.create()
+      ACTION_IGNORE = self.namespace.get_ignore_action()
 
       if not acceptor:
          raise Exception ( "empty match-block makes no sense." )
 
+      elif actions is None and alt_actions is None:
+         raise Exception ( "ignore-all rule makes no sense." )
+
       elif len ( self._nested ) > 0:
          # nested rule
+         package_rule = NestedPackageRule ( priority=self.priority )
+         for nested in self._nested:
+            nested_rule = nested.create()
+            if nested.mode == self.CONTEXT_MAIN_ACTION:
+               package_rule.add_rule ( nested_rule )
+            elif nested.mode == self.CONTEXT_MAIN_ALT_ACTION:
+               package_rule.add_alternative_rule ( nested_rule )
+            else:
+               raise Exception ( "nested rule has invalid mode" )
+
          if actions is None:
-            raise Exception (
-               "ignore action-block cannot contain nested rules."
-            )
+            package_rule.add_action ( ACTION_IGNORE )
          else:
-            package_rule = rules.NestedPackageRule ( priority=self.priority )
-            for nested in self._nested:
-               package_rule.add_rule ( nested.create() )
+            for rule_action in actions:
+               package_rule.add_action ( rule_action )
 
-            for action in actions:
-               package_rule.add_action ( action )
+         if alt_actions is None:
+            package_rule.add_alternative_action ( ACTION_IGNORE )
+         else:
+            for rule_action in alt_actions:
+               package_rule.add_alternative_action ( rule_action )
 
       elif actions is None:
-         # ignore rule
-         package_rule = rules.IgnorePackageRule ( priority=self.priority )
+         if alt_actions:
+            # ignore rule with else-action block
+            package_rule = PackageRule ( priority=self.priority )
+            package_rule.add_action ( ACTION_IGNORE )
+
+            for rule_action in alt_actions:
+               package_rule.add_alternative_action ( rule_action )
+         else:
+            # ignore rule
+            package_rule = IgnorePackageRule ( priority=self.priority )
+
+      elif alt_actions is None:
+         # normal rule with else-ignore block
+         package_rule = PackageRule ( priority=self.priority )
+         package_rule.add_alternative_action ( ACTION_IGNORE )
+
+         for rule_action in actions:
+            package_rule.add_action ( rule_action )
+
+      elif actions or alt_actions:
+         # normal rule with action and/or else-action block
+         package_rule = PackageRule ( priority=self.priority )
 
-      elif actions:
-         # normal rule
-         package_rule = rules.PackageRule ( priority=self.priority )
+         for rule_action in actions:
+            package_rule.add_action ( rule_action )
 
-         for action in actions:
-            package_rule.add_action ( action )
+         for rule_action in alt_actions:
+            package_rule.add_alternative_action ( rule_action )
 
       else:
          raise Exception ( "empty action-block makes no sense." )

diff --git a/roverlay/packagerules/parser/namespace.py b/roverlay/packagerules/parser/namespace.py
index 6af8661..ab9b7d8 100644
--- a/roverlay/packagerules/parser/namespace.py
+++ b/roverlay/packagerules/parser/namespace.py
@@ -6,6 +6,8 @@
 
 import roverlay.util
 
+import roverlay.packagerules.actions.ignore
+
 DEBUG_GET_OBJECT = False
 
 if DEBUG_GET_OBJECT:
@@ -36,8 +38,15 @@ class RuleNamespace ( object ):
       #  )
       #
       self._objects = dict()
+      self._ignore_action = (
+         roverlay.packagerules.actions.ignore.IgnoreAction()
+      )
    # --- end of __init__ (...) ---
 
+   def get_ignore_action ( self ):
+      return self._ignore_action
+   # --- end of get_ignore_action (...) ---
+
    def get_object ( self, cls, *args, **kwargs ):
       """Returns the desired object.
 

diff --git a/roverlay/packagerules/parser/text.py b/roverlay/packagerules/parser/text.py
index 4060e95..87db0b0 100644
--- a/roverlay/packagerules/parser/text.py
+++ b/roverlay/packagerules/parser/text.py
@@ -20,17 +20,16 @@ class RuleParser ( object ):
    # control flow statements
    #  all other keywords are defined in the respective context classes,
    #  namely RuleContext, RuleMatchContext and RuleActionContext
-   KEYWORDS_MATCH  = frozenset (( 'match:', 'MATCH:', ))
-   KEYWORDS_ACTION = frozenset (( 'action:', 'ACTION:' ))
-   KEYWORDS_END    = frozenset (( 'end;', 'END;' ))
+   KEYWORDS_MATCH       = frozenset ({ 'match:', 'MATCH:', })
+   KEYWORDS_ACTION      = frozenset ({ 'action:', 'ACTION:' })
+   KEYWORDS_ACTION_ELSE = frozenset ({ 'else:', 'ELSE:' })
+   KEYWORDS_END         = frozenset ({ 'end;', 'END;' })
 
-   COMMENT_CHARS   = frozenset ( "#;" )
+   COMMENT_CHARS        = frozenset ({ '#', ';' })
 
    def _zap ( self ):
       self.namespace.zap ( zap_object_db=False )
-      # the rule block (RuleContext) that is currently active
       self._current_rule = None
-      # previous rule blocks
       self._parsed_rules = list()
    # --- end of _zap (...) ---
 
@@ -44,6 +43,11 @@ class RuleParser ( object ):
       self.namespace = roverlay.packagerules.parser.namespace.RuleNamespace()
       self.add_rule = add_rule_method
       self._zap()
+
+      # the rule block (RuleContext) that is currently active
+      self._current_rule = None
+      # previous rule blocks
+      self._parsed_rules = None
    # --- end of __init__ (...) ---
 
    def _feed ( self, l, lino ):
@@ -59,6 +63,8 @@ class RuleParser ( object ):
                self._current_rule.begin_match ( lino )
             elif l in self.KEYWORDS_ACTION:
                self._current_rule.begin_action ( lino )
+            elif l in self.KEYWORDS_ACTION_ELSE:
+               self._current_rule.begin_alternative_action ( lino )
             elif l in self.KEYWORDS_END:
                if self._current_rule.end_of_rule ( lino ):
                   # add rule to self._parsed_rules

diff --git a/roverlay/packagerules/rules.py b/roverlay/packagerules/rules.py
index 649343a..9ca91e5 100644
--- a/roverlay/packagerules/rules.py
+++ b/roverlay/packagerules/rules.py
@@ -45,7 +45,6 @@ class PackageRules ( roverlay.packagerules.abstract.rules.NestedPackageRule ):
 
    def __init__ ( self ):
       super ( PackageRules, self ).__init__ ( priority=-1 )
-      del self._acceptor
       self.logger = logging.getLogger ( self.__class__.__name__ )
       self.is_toplevel = True
    # --- end of __init__ (...) ---
@@ -69,17 +68,27 @@ class PackageRules ( roverlay.packagerules.abstract.rules.NestedPackageRule ):
       return True
    # --- end of accepts (...) ---
 
+   def apply_alternative_actions ( self, p_info ):
+      raise Exception ( "toplevel rule does not contain else-block actions." )
+   # --- end of apply_alternative_actions (...) ---
+
+   def add_alternative_action ( self, action ):
+      raise Exception ( "toplevel rule does not accept else-block actions." )
+   # --- end of add_alternative_action (...) ---
+
    def add_trace_actions ( self ):
       """Adds MarkAsModified actions to this rule and all nested ones.
 
-      Meant for testing the package rule system."""
-
+      Meant for testing the package rule system.
+      """
       marker = roverlay.packagerules.actions.trace.MarkAsModifiedAction ( -1 )
-      for rule in filter (
-         lambda rule : hasattr ( rule, 'add_action' ),
-         self._iter_rules ( with_self=False )
-      ):
-         rule.add_action ( marker )
+
+      for rule in self._iter_all_rules ( with_self=False ):
+         if hasattr ( rule, 'add_action' ):
+            rule.add_action ( marker )
+
+         if hasattr ( rule, 'add_alternative_action' ):
+            rule.add_alternative_action ( marker )
 
       self.prepare()
    # --- end of add_trace_actions (...) ---


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-08-01 12:45 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-13 16:34 [gentoo-commits] proj/R_overlay:master commit in: roverlay/packagerules/parser/, roverlay/packagerules/parser/context/, André Erdmann
2013-06-13 16:34 ` [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
  -- strict thread matches above, loose matches on Subject: below --
2013-08-01 12:44 [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-03-01 19:00 André Erdmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox