From 2f02248342c22e4839e111ce5c49d0b57ef5abcf Mon Sep 17 00:00:00 2001 From: Dag Sverre Seljebotn Date: Fri, 15 Aug 2008 23:54:28 +0200 Subject: [PATCH] Changed compiler directive comment format --HG-- rename : tests/compile/c_options.pyx => tests/compile/c_directives.pyx rename : tests/errors/e_options.pyx => tests/errors/e_directives.pyx --- Cython/Compiler/Lexicon.py | 7 ++---- Cython/Compiler/Options.py | 24 +++++++++++++++++++ Cython/Compiler/Parsing.py | 24 ++++++++++++------- Cython/Compiler/Scanning.py | 11 ++++----- .../{c_options.pyx => c_directives.pyx} | 22 ++++++++++------- tests/errors/e_directives.pyx | 15 ++++++++++++ tests/errors/e_options.pyx | 21 ---------------- 7 files changed, 74 insertions(+), 50 deletions(-) rename tests/compile/{c_options.pyx => c_directives.pyx} (50%) create mode 100644 tests/errors/e_directives.pyx delete mode 100644 tests/errors/e_options.pyx diff --git a/Cython/Compiler/Lexicon.py b/Cython/Compiler/Lexicon.py index 0c94dc7d..6b13ecd5 100644 --- a/Cython/Compiler/Lexicon.py +++ b/Cython/Compiler/Lexicon.py @@ -79,9 +79,7 @@ def make_lexicon(): escaped_newline = Str("\\\n") lineterm = Eol + Opt(Str("\n")) - comment_start = Str("#") - comment = comment_start + Rep(AnyBut("\n")) - option_comment = comment_start + Str("cython:") + Rep(AnyBut("\n")) + comment = Str("#") + Rep(AnyBut("\n")) return Lexicon([ (name, 'IDENT'), @@ -98,13 +96,12 @@ def make_lexicon(): #(stringlit, 'STRING'), (beginstring, Method('begin_string_action')), - (option_comment, Method('option_comment')), (comment, IGNORE), (spaces, IGNORE), (escaped_newline, IGNORE), State('INDENT', [ - (option_comment + lineterm, Method('option_comment')), + (comment + lineterm, Method('commentline')), (Opt(spaces) + Opt(comment) + lineterm, IGNORE), (indentation, Method('indentation_action')), (Eof, Method('eof_action')) diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index 69ab2cae..1e3b694e 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -63,6 +63,30 @@ option_defaults = { 'boundscheck' : True } +def parse_option_value(name, value): + """ + Parses value as an option value for the given name and returns + the interpreted value. None is returned if the option does not exist. + + >>> print parse_option_value('nonexisting', 'asdf asdfd') + None + >>> parse_option_value('boundscheck', 'True') + True + >>> parse_option_value('boundscheck', 'true') + Traceback (most recent call last): + ... + ValueError: boundscheck directive must be set to True or False + + """ + type = option_types.get(name) + if not type: return None + if type is bool: + if value == "True": return True + elif value == "False": return False + else: raise ValueError("%s directive must be set to True or False" % name) + else: + assert False + def parse_option_list(s): """ Parses a comma-seperated list of pragma options. Whitespace diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index 5d3009a6..8a900a66 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -2348,14 +2348,20 @@ def p_code(s, level=None): repr(s.sy), repr(s.systring))) return body -def p_option_comments(s): +COMPILER_DIRECTIVE_COMMENT_RE = re.compile(r"^#\s*([a-z]+)\s*=(.*)$") + +def p_compiler_directive_comments(s): result = {} - while s.sy == 'option_comment': - opts = s.systring[len("#cython:"):] - try: - result.update(Options.parse_option_list(opts)) - except ValueError, e: - s.error(e.message, fatal=False) + while s.sy == 'commentline': + m = COMPILER_DIRECTIVE_COMMENT_RE.match(s.systring) + if m: + name = m.group(1) + try: + value = Options.parse_option_value(str(name), str(m.group(2).strip())) + except ValueError, e: + s.error(e.message, fatal=False) + if value is not None: # can be False! + result[name] = value s.next() return result @@ -2369,8 +2375,8 @@ def p_module(s, pxd, full_module_name): else: level = 'module' - option_comments = p_option_comments(s) - s.parse_option_comments = False + option_comments = p_compiler_directive_comments(s) + s.parse_comments = False body = p_statement_list(s, Ctx(level = level), first_statement = 1) if s.sy != 'EOF': s.error("Syntax error in statement [%s,%s]" % ( diff --git a/Cython/Compiler/Scanning.py b/Cython/Compiler/Scanning.py index 618168d8..a2981504 100644 --- a/Cython/Compiler/Scanning.py +++ b/Cython/Compiler/Scanning.py @@ -306,7 +306,7 @@ class PyrexScanner(Scanner): self.compile_time_env = initial_compile_time_env() self.compile_time_eval = 1 self.compile_time_expr = 0 - self.parse_option_comments = True + self.parse_comments = True self.source_encoding = source_encoding self.trace = trace_scanner self.indentation_stack = [0] @@ -316,12 +316,9 @@ class PyrexScanner(Scanner): self.sy = '' self.next() - def option_comment(self, text): - # #cython:-comments should be treated as literals until - # parse_option_comments is set to False, at which point - # they should be ignored. - if self.parse_option_comments: - self.produce('option_comment', text) + def commentline(self, text): + if self.parse_comments: + self.produce('commentline', text) def current_level(self): return self.indentation_stack[-1] diff --git a/tests/compile/c_options.pyx b/tests/compile/c_directives.pyx similarity index 50% rename from tests/compile/c_options.pyx rename to tests/compile/c_directives.pyx index c638cb19..322bd43f 100644 --- a/tests/compile/c_options.pyx +++ b/tests/compile/c_directives.pyx @@ -1,28 +1,34 @@ -#cython: boundscheck=False +# boundscheck = False +# ignoreme = OK + +# This testcase is most useful if you inspect the generated C file print 3 cimport python_dict as asadf, python_exc, cython as cy +def e(object[int, 2] buf): + print buf[3, 2] # no bc + @cy.boundscheck(False) def f(object[int, 2] buf): - print buf[3, 2] + print buf[3, 2] # no bc @cy.boundscheck(True) def g(object[int, 2] buf): - # Please leave this comment, -#cython: this should have no special meaning + # The below line should have no meaning +# boundscheck = False # even if the above line doesn't follow indentation. - print buf[3, 2] + print buf[3, 2] # bc def h(object[int, 2] buf): - print buf[3, 2] + print buf[3, 2] # no bc with cy.boundscheck(True): - print buf[3,2] + print buf[3,2] # bc from cython cimport boundscheck as bc def i(object[int] buf): with bc(True): - print buf[3] + print buf[3] # bs diff --git a/tests/errors/e_directives.pyx b/tests/errors/e_directives.pyx new file mode 100644 index 00000000..c626b4fd --- /dev/null +++ b/tests/errors/e_directives.pyx @@ -0,0 +1,15 @@ + +# nonexistant = True +# boundscheck = true +# boundscheck = 9 + +print 3 + +# Options should not be interpreted any longer: +# boundscheck = true + +_ERRORS = u""" +3:0: boundscheck directive must be set to True or False +4:0: boundscheck directive must be set to True or False +""" + diff --git a/tests/errors/e_options.pyx b/tests/errors/e_options.pyx deleted file mode 100644 index 0c82adc8..00000000 --- a/tests/errors/e_options.pyx +++ /dev/null @@ -1,21 +0,0 @@ - -#cython: nonexistant -#cython: some=9 - -# The one below should NOT raise an error - -#cython: boundscheck=True - -# However this one should -#cython: boundscheck=sadf - -print 3 - -#cython: boundscheck=True - -_ERRORS = u""" -2:0: Expected "=" in option "nonexistant" -3:0: Unknown option: "some" -10:0: Must pass a boolean value for option "boundscheck" -""" - -- 2.26.2