Beispiel #1
0
def _add_newline(psml, SmNewlineOriginal):
    """Add a pair (newline state machine, terminal on newline) to 'psml'.

    When a newline occurs, the column count can be set to 1 and the line number
    is incremented. Then the indentation counting restarts.
    """
    assert SmNewlineOriginal is not None

    # Disconnect from machines being used elsewhere.
    SmNewline = SmNewlineOriginal.clone()
    SmNewline.set_id(dial_db.new_incidence_id())

    # The SmNewline has been used before in the main state machine with a
    # different incidence id. It is essential to clone!

    cl = [
        LineCountAdd(1),
        AssignConstant(E_R.Column, 1),
        GotoDoorId(DoorID.incidence(E_IncidenceIDs.INDENTATION_HANDLER))
    ]
    terminal = Terminal(CodeTerminal(Lng.COMMAND_LIST(cl)),
                        "<INDENTATION NEWLINE>")
    terminal.set_incidence_id(SmNewline.get_id())

    psml.append((SmNewline, terminal))
Beispiel #2
0
def _add_suppressed_newline(psml, SmSuppressedNewlineOriginal):
    """Add a pair (suppressed newline, terminal on suppressed newline to 'psml'.

    A suppresed newline is not like a newline--the next line is considered as 
    being appended to the current line. Nevertheless the line number needs to
    incremented, just the column number is not reset to 1. Then, it continues
    with indentation counting.
    """
    if SmSuppressedNewlineOriginal is None:
        return

    # Disconnect from machines being used elsewhere.
    SmSuppressedNewline = SmSuppressedNewlineOriginal.clone()
    SmSuppressedNewline.set_id(dial_db.new_incidence_id())

    # The parser MUST ensure that if there is a newline suppressor, there MUST
    # be a newline being defined.

    cl = [
        LineCountAdd(1),
        AssignConstant(E_R.Column, 1),
        GotoDoorId(DoorID.incidence(E_IncidenceIDs.INDENTATION_HANDLER)),
    ]
    terminal = Terminal(CodeTerminal(Lng.COMMAND_LIST(cl)),
                        "<INDENTATION SUPPRESSED NEWLINE>")
    terminal.set_incidence_id(SmSuppressedNewline.get_id())

    psml.append((SmSuppressedNewline, terminal))
Beispiel #3
0
def _add_comment(psml, SmCommentOriginal, CounterDb):
    """On matching the comment state machine goto a terminal that does the 
    following:
    """
    if SmCommentOriginal is None: return

    comment_skip_iid = dial_db.new_incidence_id()

    # Disconnect from machines being used elsewhere.
    SmComment = SmCommentOriginal.clone()
    SmComment.set_id(comment_skip_iid)

    if SmComment.last_character_set().contains_only(ord('\n')):
        code = Lng.COMMAND_LIST([
            LineCountAdd(1),
            AssignConstant(E_R.Column, 1),
        ])
    else:
        count_info = CountInfo.from_StateMachine(
            SmComment, CounterDb, CodecTrafoInfo=Setup.buffer_codec)
        code = [
            Lng.COMMAND(Assign(E_R.ReferenceP, E_R.LexemeStartP)),
            CounterDb.do_CountInfo(count_info),
            Lng.COMMAND(Assign(E_R.LexemeStartP, E_R.ReferenceP))
        ]

    code.append(Lng.GOTO(DoorID.incidence(E_IncidenceIDs.INDENTATION_HANDLER)))

    terminal = Terminal(CodeTerminal(code), "INDENTATION COMMENT")
    terminal.set_incidence_id(comment_skip_iid)

    psml.append((SmComment, terminal))
Beispiel #4
0
 def _get_terminal(X, get_appendix):
     cl = self._command(X.cc_type, X.parameter)
     appendix = get_appendix(self, X.cc_type)
     terminal = Terminal(CodeTerminal(
         Lng.COMMAND_LIST(chain(cl, appendix))),
                         Name="%s" % X.cc_type)
     terminal.set_incidence_id(X.incidence_id)
     return terminal
Beispiel #5
0
    def __counter_code(self, LCCI):
        """Get the text of the source code required for 'counting'. This information
        has been stored along with the pattern before any transformation happened.
        No database or anything is required as this point.
        """
        run_time_counter_required_f, \
        cmd_list                     = SmLineColumnCountInfo.get_OpList(LCCI, ModeName=self.mode_name)

        self.run_time_counter_required_f |= run_time_counter_required_f
        text                              = Lng.COMMAND_LIST(cmd_list, self.dial_db)
        return "".join(Lng.REPLACE_INDENT(text))
Beispiel #6
0
 def __get_terminal_beyond(OnBeyond, BeyondIid):
     """Generate Terminal to be executed upon exit from the 'loop'.
     
        BeyondIid  -- 'Beyond Incidence Id', that is the incidencen id if of
                      the terminal to be generated.
     """
     code_on_beyond = CodeTerminal(Lng.COMMAND_LIST(OnBeyond))
     result = Terminal(code_on_beyond,
                       "<BEYOND>")  # Put last considered character back
     result.set_incidence_id(BeyondIid)
     return result
Beispiel #7
0
def _get_indentation_handler_terminal(ModeName, dial_db):
    code = Lng.COMMAND_LIST([
        Op.IndentationHandlerCall(ModeName),
        Op.GotoDoorId(DoorID.continue_without_on_after_match(dial_db))
    ], dial_db)
    incidence_id = dial.new_incidence_id()
    terminal = Terminal(CodeTerminal(code),
                        "<CALL INDENTATION HANDLER>",
                        incidence_id,
                        dial_db=dial_db)

    return DoorID.incidence(incidence_id, dial_db), terminal
Beispiel #8
0
def _get_state_machine_and_terminal(Sequence, Name, OpList):
    """Create state machine that detects the 'Sequence', names the terminal
    with 'Name', and implements the 'CmdList' in the terminal.

    RETURNS: (state machine, terminal)
    """
    sm = StateMachine.from_sequence(Sequence)
    sm.set_id(dial_db.new_incidence_id())
    terminal = Terminal(CodeTerminal(Lng.COMMAND_LIST(OpList)), Name,
                        sm.get_id())
    terminal.set_requires_goto_loop_entry_f()  # --> Goto Loop Entry

    return sm, terminal
Beispiel #9
0
    def _prepare_skip_character_set(self, MHI, Loopers, CaMap, ReloadState):
        """MHI = Mode hierarchie index."""
        if Loopers.skip is None: return [], [], []

        skipped_character_set, \
        pattern_str,           \
        aux_source_reference   = Loopers.combined_skip(CaMap)

        new_analyzer_list,        \
        new_terminal_list,    \
        loop_map,             \
        required_register_set = skip_character_set.do(self.terminal_factory.mode_name,
                                                      CaMap, skipped_character_set,
                                                      ReloadState,
                                                      self.terminal_factory.dial_db)

        self.required_register_set.update(required_register_set)

        extra_terminal_list = [
            self._terminal_goto_to_looper(new_analyzer_list,
                                          E_IncidenceIDs.SKIP, "<skip>",
                                          required_register_set)
        ]
        extra_terminal_list.extend(t for t in new_terminal_list)

        # Any skipped character must enter the skipper entry.
        goto_code = [
            Op.GotoDoorId(
                DoorID.incidence(E_IncidenceIDs.SKIP,
                                 self.terminal_factory.dial_db))
        ]
        new_ppt_list = []
        for lei in loop_map:
            new_incidence_id = dial.new_incidence_id()
            pattern = Pattern.from_character_set(lei.character_set,
                                                 new_incidence_id,
                                                 PatternString="<skip>",
                                                 Sr=aux_source_reference)
            # There is no reference pointer => Add directly
            count_code = lei.aux_count_action.get_OpList(None)
            code = Lng.COMMAND_LIST(count_code + goto_code,
                                    self.terminal_factory.dial_db)
            terminal = Terminal(CodeTerminal(code),
                                "ENTER SKIP:",
                                new_incidence_id,
                                dial_db=self.terminal_factory.dial_db)

            new_ppt_list.append(
                PPT(PatternPriority(MHI, new_incidence_id), pattern, terminal))

        return new_ppt_list, new_analyzer_list, extra_terminal_list
Beispiel #10
0
    def get_loop_terminal_code(self, TheLoopMapEntry, DoorIdLoop,
                               DoorIdLoopExit):
        """RETURNS: A loop terminal. 

        A terminal: (i)    Counts,
                    (ii)   checks possibly for the lexeme end, and
                    (iii)a either re-enters the loop, or
                    (iii)b transits to an appendix state machine (couple terminal).
        """
        IncidenceId = TheLoopMapEntry.incidence_id
        AppendixSmId = TheLoopMapEntry.appendix_sm_id
        TheCountAction = TheLoopMapEntry.count_action

        code = []
        if TheCountAction is not None:
            code.extend(
                TheCountAction.get_OpList(self.column_number_per_code_unit))

        if AppendixSmId is not None:
            if not lei.appendix_sm_has_transitions_f:
                # If there is no appendix, directly goto to the terminal.
                code.extend([Op.GotoDoorId(DoorID.incidence_id(AppendixSmId))])
            else:
                assert not self.lexeme_end_check_f
                # Couple Terminal: transit to appendix state machine.
                code.extend([
                    Op.Assign(E_R.ReferenceP, E_R.InputP),
                    Op.GotoDoorId(DoorID.state_machine_entry(AppendixSmId))
                ])
        elif not self.lexeme_end_check_f:
            # Loop Terminal: directly re-enter loop.
            code.append(Op.GotoDoorId(DoorIdLoop))
        else:
            # Check Terminal: check against lexeme end before re-entering loop.
            code.append(
                Op.GotoDoorIdIfInputPNotEqualPointer(DoorIdLoop,
                                                     E_R.LexemeEnd))
            if     self.column_number_per_code_unit is not None \
               and TheCountAction is not None \
               and TheCountAction.cc_type == E_CharacterCountType.COLUMN:
                # With reference counting, no column counting while looping.
                # => Do it now, before leaving.
                code.append(
                    Op.ColumnCountReferencePDeltaAdd(
                        E_R.InputP, self.column_number_per_code_unit, False))
            code.append(Op.GotoDoorId(DoorIdLoopExit))

        return Terminal(CodeTerminal(Lng.COMMAND_LIST(code)),
                        "<LOOP TERMINAL %i>" % IncidenceId, IncidenceId)
Beispiel #11
0
def _get_terminal_list_for_loop(loop_map, loop_config, DoorIdLoop):
    """RETURNS: List of terminals of the loop state:

        (i)   Counting terminals: Count and return to loop entry.
        (ii)  Couple terminals:   Count and goto appendix state machine.
        (iii) Exit terminal:      Exit loop.

    The '<LOOP>' terminal serves as an address for the appendix state machines.
    If they fail, they can accept its incidence id and re-enter the loop from
    there.
    """
    # Terminal: Normal Loop Characters
    # (LOOP EXIT terminal is generated later, see below).
    result = []
    done = set()
    for lme in loop_map:
        if lme.iid_couple_terminal in done: continue
        elif lme.iid_couple_terminal == loop_config.iid_loop_exit: continue
        elif lme.code is None: continue
        done.add(lme.iid_couple_terminal)

        result.append(
            Terminal(loop_config.CodeTerminal_without_Lazy_DoorIdLoop(
                lme.code, DoorIdLoop),
                     "<LOOP TERMINAL %s>" % lme.iid_couple_terminal,
                     IncidenceId=lme.iid_couple_terminal,
                     dial_db=loop_config.dial_db))

    # Terminal: Re-enter Loop
    if loop_config.iid_loop_after_appendix_drop_out is not None:
        txt = Lng.COMMAND_LIST(
            loop_config.events.on_loop_after_appendix_drop_out(
                DoorIdLoop, loop_config.column_number_per_code_unit),
            loop_config.dial_db)
        result.append(
            Terminal(CodeTerminal(txt),
                     "<LOOP>",
                     loop_config.iid_loop_after_appendix_drop_out,
                     dial_db=loop_config.dial_db))

    # Terminal: Exit Loop
    result.append(
        Terminal(CodeTerminal(
            loop_config.events.on_loop_exit_text(loop_config.dial_db)),
                 "<LOOP EXIT>",
                 loop_config.iid_loop_exit,
                 dial_db=loop_config.dial_db))

    return result
Beispiel #12
0
def __code(Node, TheState, done_set, GlobalEntryF):
    """Code a node of the command tree in a sequence of nodes from leaf to
    root, parent by parent. As long as the parent is in the list, no goto is
    required. If the parent is implemented already, an explicit goto is 
    implemented.

    RETURNS: list of strings = code for node.
    """
    done_set.add(Node.door_id)

    txt = []
    __label_node(txt, Node)
    __comment(txt, Node, TheState, GlobalEntryF)

    # (*) The code of commands of the node
    txt.extend(
        Lng.COMMAND_LIST(Node.command_list)
    )

    # (*) AFTER: COMMAND_LIST -- The state debug info.
    txt.append(Lng.STATE_DEBUG_INFO(TheState, GlobalEntryF))

    # (*) The 'goto parent'.
    if Node.parent is None:
        # This is the root. 
        return txt

    elif Node.parent.door_id not in done_set:
        # As long as the parent is not done, it will be implemented immediately
        # after this node--no goto is required.
        return txt

    elif Node.command_list and Node.command_list[-1].is_conditionless_goto(): 
        # Goto is futile if the last command is an unconditional goto.
        return txt

    # Append the 'goto parent'
    txt.append("    %s\n" % Lng.GOTO(Node.parent.door_id))
    return txt
Beispiel #13
0
 def on_loop_exit_text(self, dial_db):
     return Lng.COMMAND_LIST(self.on_loop_exit, dial_db)
Beispiel #14
0
 def on_loop_exit_text(self):
     return Lng.COMMAND_LIST(self.on_loop_exit)
Beispiel #15
0
 def on_loop_after_appendix_drop_out(self, DoorIdLoop):
     # 'CharacterBeginP' has been assigned in the 'Couple Terminal'.
     # (see ".get_loop_terminal_code()").
     return Lng.COMMAND_LIST(
         [Op.Assign(E_R.InputP, E_R.ReferenceP),
          Op.GotoDoorId(DoorIdLoop)])
Beispiel #16
0
def do(ModeName, CaMap, OpenerPattern, CloserPattern, DoorIdExit, ReloadState,
       dial_db):
    """
                                    .---<---+----------<------+------------------.
                                    |       |                 |                  |
                                    |       | not             | open_n += 1      |  
                                  .------.  | Closer[0]       |                  |
       -------------------------->| Loop +--'                 |                  |
                                  |      |                    | yes              | 
                                  |      |                    |                  |
                                  |      |          .-------------.              |
                                  |      +----->----| Opener[1-N] |              |
                                  |      |          |      ?      |              |
                                  |      |          '-------------'              |
                                  |      |                                       | open_n > 0
                                  |      |          .-------------.              | 
                                  |      +----->----| Closer[1-N] |--------------+------> RESTART
                                  |      |          |      ?      | open_n -= 1    else
                                  |      |          '-------------'             
                                  |      |                             
                                  |  BLC +-->-.  
                              .->-|      |     \                 Reload State 
            .-DoorID(S, 1)--./    '------'      \            .------------------.
         .--| after_reload  |                    \          .---------------.   |
         |  '---------------'                     '---------| before_reload |   |
         |                                                  '---------------'   |
         '---------------------------------------------------|                  |
                                                     success '------------------'     
                                                                     | failure      
                                                                     |            
                                                              .---------------.       
                                                              | SkipRangeOpen |       
                                                              '---------------'                                                                   

    """
    psml, \
    iid_aux_reentry = _get_state_machine_vs_terminal_list(CloserPattern, OpenerPattern,
                                                          DoorIdExit, dial_db)

    if ReloadState: engine_type = ReloadState.engine_type
    else: engine_type = None

    # The first opening pattern must have matched --> counter = 1
    entry_op_list = OpList(Op.AssignConstant(E_R.Counter, 1))

    analyzer_list,         \
    terminal_list,         \
    loop_map,              \
    door_id_loop,          \
    required_register_set, \
    run_time_counter_f     = loop.do(CaMap,
                                     BeforeEntryOpList          = entry_op_list,
                                     OnLoopExitDoorId           = DoorIdExit,
                                     EngineType                 = engine_type,
                                     ReloadStateExtern          = ReloadState,
                                     ParallelSmTerminalPairList = psml,
                                     dial_db                    = dial_db,
                                     ModeName                   = ModeName)

    reentry_op_list = [Op.GotoDoorId(door_id_loop)]
    terminal_list.append(
        Terminal(CodeTerminal(Lng.COMMAND_LIST(reentry_op_list, dial_db)),
                 Name="<SKIP NESTED RANGE REENTRY>",
                 IncidenceId=iid_aux_reentry,
                 dial_db=dial_db))

    required_register_set.add(E_R.Counter)
    return analyzer_list, \
           terminal_list, \
           required_register_set, \
           run_time_counter_f
Beispiel #17
0
 def sm_terminal_pair(Pattern, Name, OpList, dial_db):
     sm = Pattern.get_cloned_sm(StateMachineId=dial.new_incidence_id())
     terminal = loop.MiniTerminal(Lng.COMMAND_LIST(OpList, dial_db), Name,
                                  sm.get_id())
     return sm, terminal
Beispiel #18
0
 def get_code(self, LoopStateMachineId):
     return Lng.COMMAND_LIST(self.__cmd_list)
Beispiel #19
0
 def CodeTerminal_without_Lazy_DoorIdLoop(self, CmdList, DoorIdLoop):
     return CodeTerminal(
         Lng.COMMAND_LIST(self.replace_Lazy_DoorIdLoop(CmdList, DoorIdLoop),
                          self.dial_db))