]> mj.ucw.cz Git - moe.git/blobdiff - t/moe/config_parser.py
Minor updates (docs, status.py)
[moe.git] / t / moe / config_parser.py
index 73b5406cbd6433e62712bde7b6b2f7f8717d3ae4..2da6facfa2daa9062c78b2cfc9d9fe52cdddaf16 100644 (file)
@@ -1,47 +1,44 @@
-"""
-config_parser.py
-------------
-
+r"""
 Simple Moe configuration file syntax parser. 
 
-TODO: decide neccessity of '()' in/around formulas
-TODO: check escaping in expressions
-TODO: should whitespace (incl. '\\n') be allowed (almost) everywhere?
-      can comment be anywhere whitespace can?
+Generally, whitespace and comments are alowed everywhere except in variable names and inside expressions,
+``\\n`` ends a ``COMMENT``.
 
-Generally, whitespace and comments are alowed everywhere except in variable names and inside expressions. 
-Also, COMMENT must not contain '\\n'
+``FILE``, ``BLOCK``, ``STATEMENT``, ``OPERATION``, ``SUBTREE``, ``CONDITION``, ``FORMULA``, ``AND``, ``OR`` 
+and ``NOT`` ignore any preceding whitespace
 
-FILE, BLOCK, STATEMENT, OPERATION, SUBTREE, CONDITION, FORMULA, AND, OR and NOT eat any preceding whitespace. TODO: check?
+.. highlight:: none
 
-The configuration syntax is the following:
+The configuration syntax is the following::
 
-FILE = BLOCK 
-BLOCK = WS | STATEMENT ( SEP STATEMENT )* 
+    FILE = BLOCK 
+    BLOCK = WS | STATEMENT ( SEP STATEMENT )* 
 
-SEP = ( '\\n' | ';' )
-WS = ( ' ' | '\\t' | '\\n' | COMMENT )*
+    SEP = ( '\n' | ';' )
+    WS = ( ' ' | '\t' | '\n' | COMMENT )*
 
-COMMENT = re('#[^\\n]*\\n')
+    COMMENT = re('#[^\n]*\n')
 
-STATEMENT = CONDITION | OPERATION | SUBTREE
+    STATEMENT = CONDITION | OPERATION | SUBTREE
 
-OPERATION = WS VARNAME WS ( '=' | '+=' ) WS EXPRESSION
-SUBTREE = WS VARNAME WS '{' BLOCK WS '}'
-CONDITION = WS 'if' FORMULA WS '{' BLOCK WS '}'
+    OPERATION = WS VARNAME WS ( '=' | '+=' ) WS EXPRESSION
+    SUBTREE = WS VARNAME WS '{' BLOCK WS '}'
+    CONDITION = WS 'if' FORMULA WS '{' BLOCK WS '}'
 
-FORMULA = WS (( EXPRESSION WS ( '!=' | '==' ) WS EXPRESSION ) | '(' AND WS ')' | '(' OR WS ')' | NOT )
-AND = FORMULA WS 'and' FORMULA
-OR = FORMULA WS 'or' FORMULA
-NOT = WS 'not' FORMULA 
+    FORMULA = WS (( EXPRESSION WS ( '!=' | '==' ) WS EXPRESSION ) | 
+      '(' AND WS ')' | '(' OR WS ')' | NOT )
+    AND = FORMULA WS 'and' FORMULA
+    OR = FORMULA WS 'or' FORMULA
+    NOT = WS 'not' FORMULA 
 
-NOTE: ';' or '\n' is currently required even after CONDITION and SUBTREE block 
-  TODO: change to OPERATION only
-NOTE: Formula may contain additional/extra parentheses
+    EXPRESSION = '"' ( ECHAR | '{' VARNAME '}' )* '"' | re"'[^'\n]*'" | VARNAME
+    ECHAR = re('([^\{}]|\\|\{|\}|\\n)*')
+    VARNAME = re('[a-zA-Z0-9-_]+(\.[a-zA-Z0-9-_]+)*')
 
-EXPRESSION = '"' ( ECHAR | '{' VARNAME '}' )* '"' | re"'[^'\\n]*'" | VARNAME
-ECHAR = re('([^\\{}]|\\\\|\\{|\\}|\\n)*')
-VARNAME = re('[a-zA-Z0-9-_]+(\.[a-zA-Z0-9-_]+)*')
+.. todo:: should whitespace (incl. '\n') be allowed (almost) everywhere? 
+         can comment be anywhere whitespace can?
+.. note:: ';' or '\\n' is currently required even after CONDITION and SUBTREE block 
+.. note:: Formula can contain additional/unnecessary parentheses
 """
 
 import re, types, itertools, logging as log
@@ -50,6 +47,16 @@ import traceback
 import moe.config as cf
 
 
+def config_escape(s):
+  """
+  Escape any ``{``, ``}``, ``"`` and ``\\`` in the given string, making it safe for parsing.
+  """
+  s = s.replace('\\', '\\\\')
+  s = s.replace('{', '\\{')
+  s = s.replace('}', '\\}')
+  s = s.replace('"', '\\"')
+  return s
+
 class ConfigSyntaxError(cf.ConfigError):
 
   def __init__(self, msg, source='<unknown>', line=None, column=None):
@@ -242,8 +249,10 @@ class ConfigParser(object):
       op = 'SET'
     elif self.nexts(self.c_append):
       op = 'APPEND'
+    elif self.eof():
+      self.syntax_error('Unexpected end of file.')
     else:
-      self.syntax_error('Unknown operation.')
+      self.syntax_error('Unknown operation: %r...', self.peek(10))
     self.p_WS()
     exp = self.p_EXPRESSION()
     vname = (self.prefix+self.c_varname_sep+varname).lstrip(self.c_varname_sep)