Ejemplo n.º 1
0
    def handle_stmt(self, stmt, p_elem, pset={}):
        """
        Run handler method for statement `stmt`.

        `p_elem` is the parent node in the output schema. `pset` is
        the current "patch set" - a dictionary with keys being QNames
        of schema nodes at the current level of hierarchy for which
        (or descendants thereof) any pending patches exist. The values
        are instances of the Patch class.

        All handler methods are defined below and must have the same
        arguments as this method. They should create the output schema
        fragment corresponding to `stmt`, apply all patches from
        `pset` belonging to `stmt`, insert the fragment under `p_elem`
        and perform all side effects as necessary.
        """
        if self.debug > 0:
            sys.stderr.write("Handling '%s %s'\n" %
                             (util.keyword_to_str(stmt.raw_keyword), stmt.arg))
        try:
            method = self.stmt_handler[stmt.keyword]
        except KeyError:
            if isinstance(stmt.keyword, tuple): # extension
                self.handle_extension(stmt, p_elem)
                return
            else:
                raise error.EmitError(
                    "Unknown keyword %s - this should not happen.\n"
                    % stmt.keyword)

        method(stmt, p_elem, pset)
Ejemplo n.º 2
0
    def handle_stmt(self, stmt, p_elem, pset={}):
        """
        Run handler method for statement `stmt`.

        `p_elem` is the parent node in the output schema. `pset` is
        the current "patch set" - a dictionary with keys being QNames
        of schema nodes at the current level of hierarchy for which
        (or descendants thereof) any pending patches exist. The values
        are instances of the Patch class.

        All handler methods are defined below and must have the same
        arguments as this method. They should create the output schema
        fragment corresponding to `stmt`, apply all patches from
        `pset` belonging to `stmt`, insert the fragment under `p_elem`
        and perform all side effects as necessary.
        """
        if self.debug > 0:
            sys.stderr.write("Handling '%s %s'\n" %
                             (util.keyword_to_str(stmt.raw_keyword), stmt.arg))
        try:
            method = self.stmt_handler[stmt.keyword]
        except KeyError:
            if isinstance(stmt.keyword, tuple):
                try:
                    method = self.ext_handler[stmt.keyword[0]][stmt.keyword[1]]
                except KeyError:
                    method = self.rng_annotation
                method(stmt, p_elem)
                return
            else:
                raise error.EmitError(
                    "Unknown keyword %s - this should not happen.\n"
                    % stmt.keyword)
        method(stmt, p_elem, pset)
Ejemplo n.º 3
0
def _chk_stmts(ctx, pos, stmts, parent, spec, canonical):
    for stmt in stmts:
        stmt.is_grammatically_valid = False
        if not util.is_prefixed(stmt.keyword):
            chk_grammar = True
        else:
            (modname, _identifier) = stmt.keyword
            if modname in extension_modules:
                chk_grammar = True
            else:
                chk_grammar = False
        if chk_grammar == True:
            match_res = _match_stmt(ctx, stmt, spec, canonical)
        else:
            match_res = None
        if match_res is None and chk_grammar == True:
            error.err_add(ctx.errors, stmt.pos, 'UNEXPECTED_KEYWORD', 
                          util.keyword_to_str(stmt.raw_keyword))
        elif match_res is not None and chk_grammar == True:
            try:
                (arg_type, subspec) = stmt_map[stmt.keyword]
            except KeyError:
                error.err_add(ctx.errors, stmt.pos, 'UNEXPECTED_KEYWORD', 
                              util.keyword_to_str(stmt.raw_keyword))
                return
            # verify the statement's argument
            if arg_type is None and stmt.arg is not None:
                error.err_add(ctx.errors, stmt.pos,
                              'UNEXPECTED_ARGUMENT', stmt.arg)
            elif arg_type is not None and stmt.arg is None:
                error.err_add(ctx.errors, stmt.pos,
                              'EXPECTED_ARGUMENT',
                              util.keyword_to_str(stmt.keyword))
            elif (arg_type is not None and arg_type != 'string' and
                  syntax.arg_type_map[arg_type](stmt.arg) == False):
                error.err_add(ctx.errors, stmt.pos,
                              'BAD_VALUE', (stmt.arg, arg_type))
            else:
                stmt.is_grammatically_valid = True

            _chk_stmts(ctx, stmt.pos, stmt.substmts, stmt, subspec, canonical)
            spec = match_res
        else:
            # unknown extension
            stmt.is_grammatically_valid = True
            _chk_stmts(ctx, stmt.pos, stmt.substmts, stmt, 
                       [('$any', '*')], canonical)
        # update last know position
        pos = stmt.pos
    # any non-optional statements left are errors
    for (keywd, occurance) in spec:
        if occurance == '1' or occurance == '+':
            if parent is None:
                error.err_add(ctx.errors, pos, 'EXPECTED_KEYWORD',
                              util.keyword_to_str(keywd))
            else:
                error.err_add(ctx.errors, pos, 'EXPECTED_KEYWORD_2',
                              (util.keyword_to_str(keywd),
                               util.keyword_to_str(parent.raw_keyword)))
Ejemplo n.º 4
0
def _chk_stmts(ctx, pos, stmts, parent, spec, canonical):
    for stmt in stmts:
        stmt.is_grammatically_valid = False
        if not util.is_prefixed(stmt.keyword):
            chk_grammar = True
        else:
            (modname, _identifier) = stmt.keyword
            if modname in extension_modules:
                chk_grammar = True
            else:
                chk_grammar = False
        if chk_grammar == True:
            match_res = _match_stmt(ctx, stmt, spec, canonical)
        else:
            match_res = None
        if match_res is None and chk_grammar == True:
            error.err_add(ctx.errors, stmt.pos, 'UNEXPECTED_KEYWORD',
                          util.keyword_to_str(stmt.raw_keyword))
        elif match_res is not None and chk_grammar == True:
            try:
                (arg_type, subspec) = stmt_map[stmt.keyword]
            except KeyError:
                error.err_add(ctx.errors, stmt.pos, 'UNEXPECTED_KEYWORD',
                              util.keyword_to_str(stmt.raw_keyword))
                return
            # verify the statement's argument
            if arg_type is None and stmt.arg is not None:
                error.err_add(ctx.errors, stmt.pos, 'UNEXPECTED_ARGUMENT',
                              stmt.arg)
            elif arg_type is not None and stmt.arg is None:
                error.err_add(ctx.errors, stmt.pos, 'EXPECTED_ARGUMENT',
                              util.keyword_to_str(stmt.keyword))
            elif (arg_type is not None and arg_type != 'string'
                  and syntax.arg_type_map[arg_type](stmt.arg) == False):
                error.err_add(ctx.errors, stmt.pos, 'BAD_VALUE',
                              (stmt.arg, arg_type))
            else:
                stmt.is_grammatically_valid = True

            _chk_stmts(ctx, stmt.pos, stmt.substmts, stmt, subspec, canonical)
            spec = match_res
        else:
            # unknown extension
            stmt.is_grammatically_valid = True
            _chk_stmts(ctx, stmt.pos, stmt.substmts, stmt, [('$any', '*')],
                       canonical)
        # update last know position
        pos = stmt.pos
    # any non-optional statements left are errors
    for (keywd, occurance) in spec:
        if occurance == '1' or occurance == '+':
            if parent is None:
                error.err_add(ctx.errors, pos, 'EXPECTED_KEYWORD',
                              util.keyword_to_str(keywd))
            else:
                error.err_add(ctx.errors, pos, 'EXPECTED_KEYWORD_2',
                              (util.keyword_to_str(keywd),
                               util.keyword_to_str(parent.raw_keyword)))
def _match_stmt(ctx, stmt, spec, canonical):
    """Match stmt against the spec.

    Return None | spec'
    spec' is an updated spec with the matching spec consumed
    """
    i = 0
    while i < len(spec):
        (keywd, occurance) = spec[i]
        if keywd == '$any':
            return spec
        elif keywd == stmt.keyword:
            if occurance == '1' or occurance == '?':
                # consume this match
                if canonical == True:
                    return spec[i+1:]
                else:
                    return spec[:i] + spec[i+1:]
            if occurance == '+':
                # mark that we have found the one that was needed
                c = (keywd, '*')
                if canonical == True:
                    return [c] + spec[i+1:]
                else:
                    return spec[:i] + [c] + spec[i+1:]
            else:
                # occurane == '*'
                if canonical == True:
                    return spec[i:]
                else:
                    return spec
        elif keywd == '$choice':
            cases = occurance
            j = 0
            while j < len(cases):
                # check if this alternative matches - check for a
                # match with each optional keyword
                save_errors = ctx.errors
                match_res = _match_stmt(ctx, stmt, cases[j], False)
                if match_res != None:
                    # this case branch matched, use it
                    # remove the choice and add res to the spec
                    return spec[:i] + match_res + spec[i+1:]
                # we must not report errors on non-matching branches
                ctx.errors = save_errors
                j += 1
        elif keywd == '$interleave':
            cspec = occurance
            match_res = _match_stmt(ctx, stmt, cspec, canonical)
            if match_res != None:
                # we got a match
                return spec
        elif util.is_prefixed(stmt.keyword):
            # allow extension statements mixed with these
            # set canonical to False in this call to just remove the
            # matching stmt from the spec
            match_res = _match_stmt(ctx, stmt, spec[i+1:], False)
            if match_res != None:
                return spec[:i+1] + match_res
            else:
                return None
        elif keywd == '$cut':
            # any non-optional statements left are errors
            for (keywd, occurance) in spec[:i]:
                if occurance == '1' or occurance == '+':
                    error.err_add(ctx.errors, stmt.pos, 'UNEXPECTED_KEYWORD_1',
                                  (util.keyword_to_str(stmt.raw_keyword),
                                   util.keyword_to_str(keywd)))
            # consume them so we don't report the same error again
            spec = spec[i:]
            i = 0
        elif canonical == True:
            if occurance == '1' or occurance == '+':
                error.err_add(ctx.errors, stmt.pos, 'UNEXPECTED_KEYWORD_1',
                              (util.keyword_to_str(stmt.raw_keyword),
                               util.keyword_to_str(keywd)))
                # consume it so we don't report the same error again
                spec = spec[i:]
                i = 0
        # check next in spec
        i += 1
    return None
Ejemplo n.º 6
0
def _match_stmt(ctx, stmt, spec, canonical):
    """Match stmt against the spec.

    Return None | spec'
    spec' is an updated spec with the matching spec consumed
    """
    i = 0
    while i < len(spec):
        (keywd, occurance) = spec[i]
        if keywd == '$any':
            return spec
        elif keywd == stmt.keyword:
            if occurance == '1' or occurance == '?':
                # consume this match
                if canonical == True:
                    return spec[i + 1:]
                else:
                    return spec[:i] + spec[i + 1:]
            if occurance == '+':
                # mark that we have found the one that was needed
                c = (keywd, '*')
                if canonical == True:
                    return [c] + spec[i + 1:]
                else:
                    return spec[:i] + [c] + spec[i + 1:]
            else:
                # occurane == '*'
                if canonical == True:
                    return spec[i:]
                else:
                    return spec
        elif keywd == '$choice':
            cases = occurance
            j = 0
            while j < len(cases):
                # check if this alternative matches - check for a
                # match with each optional keyword
                save_errors = ctx.errors
                match_res = _match_stmt(ctx, stmt, cases[j], canonical)
                if match_res != None:
                    # this case branch matched, use it
                    # remove the choice and add res to the spec
                    return spec[:i] + match_res + spec[i + 1:]
                # we must not report errors on non-matching branches
                ctx.errors = save_errors
                j += 1
        elif keywd == '$interleave':
            cspec = occurance
            match_res = _match_stmt(ctx, stmt, cspec, canonical)
            if match_res != None:
                # we got a match
                return spec
        elif util.is_prefixed(stmt.keyword):
            # allow extension statements mixed with these
            # set canonical to False in this call to just remove the
            # matching stmt from the spec
            match_res = _match_stmt(ctx, stmt, spec[i + 1:], False)
            if match_res != None:
                return spec[:i + 1] + match_res
            else:
                return None
        elif keywd == '$cut':
            # any non-optional statements left are errors
            for (keywd, occurance) in spec[:i]:
                if occurance == '1' or occurance == '+':
                    error.err_add(ctx.errors, stmt.pos, 'UNEXPECTED_KEYWORD_1',
                                  (util.keyword_to_str(stmt.raw_keyword),
                                   util.keyword_to_str(keywd)))
            # consume them so we don't report the same error again
            spec = spec[i:]
            i = 0
        elif canonical == True:
            if occurance == '1' or occurance == '+':
                error.err_add(ctx.errors, stmt.pos, 'UNEXPECTED_KEYWORD_1',
                              (util.keyword_to_str(stmt.raw_keyword),
                               util.keyword_to_str(keywd)))
                # consume it so we don't report the same error again
                spec = spec[i:]
                i = 0
        # check next in spec
        i += 1
    return None