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)
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)
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
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