compiler/PEGFsaGenerator.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Fri, 24 Jul 2015 15:37:23 +0100
changeset 503 ff58cd9f1f3c
parent 502 1e45d3c96ec5
child 515 b5316ef15274
permissions -rw-r--r--
Merge

"{ Package: 'stx:goodies/petitparser/compiler' }"

"{ NameSpace: Smalltalk }"

PPCNodeVisitor subclass:#PEGFsaGenerator
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	category:'PetitCompiler-FSA'
!

!PEGFsaGenerator methodsFor:'as yet unclassified'!

visitCharSetPredicateNode: node
    | stop start fsa |
    start := PEGFsaState new.
    stop := PEGFsaState new.
    
    fsa := PEGFsa new
        addState: start;
        addState: stop;
        
        startState: start;
        finalState: stop;
        yourself.
    
    fsa addTransitionFrom: start to: stop onCharacterSet: (node predicate classification).
        
    ^ fsa
!

visitCharacterNode: node
    | stop start |
    start := PEGFsaState new.
    stop := PEGFsaState new.
    stop name: node character storeString.
    
    ^ PEGFsa new
        addState: start;
        addState: stop;
        
        startState: start;
        finalState: stop;

        addTransitionFrom: start to: stop on: node character;
        yourself
!

visitChoiceNode: node
    | priority childrenFsa fsa start |
    
    childrenFsa := node children collect: [ :child | child accept: self ].
    fsa := PEGFsa new.
    start := PEGFsaState new.
    
    fsa addState: start.
    fsa startState: start.

    priority := 0.
    childrenFsa do: [ :childFsa |
        fsa adopt: childFsa.
        fsa addTransitionFrom: start to: childFsa startState priority: priority.
        priority := priority + childFsa minPriority.
    ].

    ^ fsa
!

visitLiteralNode: node
    | states fsa |

    states := OrderedCollection new.
    (node literal size + 1) timesRepeat: [
        states add: PEGFsaState new
    ].

    fsa := PEGFsa new.
    states do: [ :state | fsa addState: state ].	
    fsa	 startState: states first;
         finalState: states last;
         yourself.
        
    (1 to: (states size - 1)) do: [ :index |
        fsa addTransitionFrom: (states at: index)
         	 to: (states at: index + 1)
             on: (node literal at: index).
        "set the name"
        (states at: (index + 1)) name: (node literal at: index). 
    ].

    fsa name: node literal.
    ^ fsa
!

visitNode: node
    self error: 'node not supported'
!

visitNotNode: node
    | fsa finalState |
    fsa := node child accept: self.
    finalState := PEGFsaState new
        name: '!!', fsa name asString;
        yourself.
    
    fsa finalStates do: [ :fs |
        fs retval: PEGFsaFailure new.
    ].
    
    fsa addState: finalState.
    fsa finalState: finalState.

    fsa addTransitionFrom: fsa startState to: finalState priority: -1.
    ^ fsa
!

visitOptionalNode: node
    | fsa startState finalState |

    fsa := node child accept: self.
    startState := PEGFsaState new
        yourself.

    finalState := PEGFsaState new
        final: true;
        yourself.

    fsa addState: startState.
    fsa addState: finalState.
    
    fsa addTransitionFrom: startState to: fsa startState priority: 0.
    fsa addTransitionFrom: startState to: finalState priority: fsa minPriority.

    fsa startState: startState.

    ^ fsa
!

visitPlusNode: node
    | fsa finalState |

    finalState := PEGFsaState new.
    fsa := node child accept: self.
    fsa addState: finalState.
    
    fsa finalStates do: [ :state |
        fsa addTransitionFrom: state to: (fsa startState).
        fsa addTransitionFrom: state to: finalState priority: -1.
        self assert: (state hasPriority not).
        state priority: 0.
        state final: false.
    ].

    fsa finalState: finalState.	
    
    ^ fsa
!

visitPredicateNode: node
    | stop start fsa  |
    start := PEGFsaState new.
    stop := PEGFsaState new.
    
    fsa := PEGFsa new
        addState: start;
        addState: stop;
        
        startState: start;
        finalState: stop;
        yourself.
    
    fsa addTransitionFrom: start to: stop onCharacterSet: (node predicate classification).
        
    ^ fsa
!

visitSequenceNode: node
    | childrenFsa fsa start previousFinalStates  |

    childrenFsa := node children collect: [ :child | child accept: self ].

    fsa := PEGFsa new.
    start := PEGFsaState new name: 'start'; yourself.
    fsa addState: start.
    fsa startState: start.

    fsa adopt: childrenFsa first.	
    fsa addTransitionFrom: start to: childrenFsa first startState.

    previousFinalStates := childrenFsa first finalStates.
    childrenFsa allButFirst do: [ :childFsa | 
        | newFinalStates |
        newFinalStates := IdentitySet new.
        previousFinalStates do: [ :state |
            | copy |
            copy := childFsa copy.
            fsa adopt: copy.
            
            state isFailure ifFalse: [ 
                state final: false.
                fsa addTransitionFrom: state to: copy startState.
            ].
            newFinalStates addAll: copy finalStates.
        ].
        previousFinalStates := newFinalStates.
    ].
    ^ fsa
!

visitStarNode: node
    | fsa finalState |

    finalState := PEGFsaState new.
    fsa := node child accept: self.
    fsa addState: finalState.
    
    fsa finalStates do: [ :state |
        fsa addTransitionFrom: state to: (fsa startState).
        self assert: (state hasPriority not).
        state priority: 0.
        state final: false.
    ].

    fsa addTransitionFrom: fsa startState to: finalState priority: -1.
    fsa finalState: finalState.

    ^ fsa
! !