PetitCommonMark/software/PetitParser/PPContext.class.st

431 lines
10 KiB
Smalltalk

"
A PPContext is provides contextual information to the parsing function.
Instance Variables
globals: <Dictionary>
properties: <Dictionar>
root: <PPParser>
stream: <PPStream>
globals
- properties that are not restored after backtracking
properties
- properties that are restored after backtracking
root
- the root parser
stream
- input stream
"
Class {
#name : 'PPContext',
#superclass : 'Object',
#instVars : [
'stream',
'root',
'properties',
'globals',
'furthestFailure'
],
#category : 'PetitParser-Core'
}
{ #category : 'stream mimicry' }
PPContext >> atEnd [
^ stream atEnd
]
{ #category : 'stream mimicry' }
PPContext >> back [
^ stream back
]
{ #category : 'checking' }
PPContext >> checkMementoStreamIsSameAsMine: aPPContextMemento [
aPPContextMemento stream == stream ifFalse: [
self error: 'The stream held by the PPContextMemento must be identity-equals to the stream I hold.' ]
]
{ #category : 'stream mimicry' }
PPContext >> collection [
^ stream collection
]
{ #category : 'stream mimicry' }
PPContext >> contents [
^ stream contents
]
{ #category : 'failures' }
PPContext >> furthestFailure [
" the furthest failure encountered while parsing the input stream "
"^ self globalAt: #furthestFailure ifAbsent: [ nil ]"
"performance optimization:"
^ furthestFailure
]
{ #category : 'accessing-globals' }
PPContext >> globalAt: aKey [
"Answer the global property value associated with aKey."
^ self globalAt: aKey ifAbsent: [ self error: 'Property not found' ]
]
{ #category : 'accessing-globals' }
PPContext >> globalAt: aKey ifAbsent: aBlock [
"Answer the global property value associated with aKey or, if aKey isn't found, answer the result of evaluating aBlock."
^ globals isNil
ifTrue: [ aBlock value ]
ifFalse: [ globals at: aKey ifAbsent: aBlock ]
]
{ #category : 'accessing-globals' }
PPContext >> globalAt: aKey ifAbsentPut: aBlock [
"Answer the global property associated with aKey or, if aKey isn't found store the result of evaluating aBlock as new value."
^ self globalAt: aKey ifAbsent: [ self globalAt: aKey put: aBlock value ]
]
{ #category : 'accessing-globals' }
PPContext >> globalAt: aKey put: anObject [
"Set the global property at aKey to be anObject. If aKey is not found, create a new entry for aKey and set is value to anObject. Answer anObject."
^ (globals ifNil: [ globals := Dictionary new: 1 ])
at: aKey put: anObject
]
{ #category : 'accessing-globals' }
PPContext >> globals [
^ globals
]
{ #category : 'accessing-globals' }
PPContext >> hasGlobal: aKey [
"Test if the global property aKey is present."
^ globals notNil and: [ globals includesKey: aKey ]
]
{ #category : 'accessing-properties' }
PPContext >> hasProperty: aKey [
"Test if the property aKey is present."
^ properties notNil and: [ properties includesKey: aKey ]
]
{ #category : '*PetitParser-Ruby-Parser' }
PPContext >> heredocId [
^ self globalAt: #heredocId ifAbsent: nil
]
{ #category : '*PetitParser-Ruby-Parser' }
PPContext >> heredocId: value [
self globalAt: #heredocId put: value
]
{ #category : 'memoization' }
PPContext >> identifier [
"
I provide an identifier that is used by memoizing parser to figure out if the
cache should be flushed or not.
"
^ stream
]
{ #category : 'initialization' }
PPContext >> initialize [
stream := nil.
]
{ #category : 'initialization' }
PPContext >> initializeFor: parser [
root := parser.
]
{ #category : 'stream mimicry' }
PPContext >> isEndOfLine [
^ stream isEndOfLine
]
{ #category : 'stream mimicry' }
PPContext >> isStartOfLine [
^ stream isStartOfLine
]
{ #category : 'stream mimicry' }
PPContext >> next [
^ stream next
]
{ #category : 'stream mimicry' }
PPContext >> next: anInteger [
^ stream next: anInteger
]
{ #category : 'failures' }
PPContext >> noteFailure: aPPFailure [
"record the furthest failure encountered while parsing the input stream "
( furthestFailure isNil or: [ aPPFailure position > furthestFailure position ])
ifTrue: [ furthestFailure := aPPFailure ].
]
{ #category : 'stream mimicry' }
PPContext >> peek [
^ stream peek
]
{ #category : 'stream mimicry' }
PPContext >> peekTwice [
^ stream peekTwice
]
{ #category : '*PetitParser-Ruby-Parser' }
PPContext >> percentStringEnd [
^ self globalAt: #percentStringEnd ifAbsent: nil
]
{ #category : '*PetitParser-Ruby-Parser' }
PPContext >> percentStringStart: value [
| endValue |
endValue := value.
(value == $[) ifTrue: [ endValue := $] ].
(value == $() ifTrue: [ endValue := $) ].
(value == ${) ifTrue: [ endValue := $} ].
self globalAt: #percentStringStart put: value.
self globalAt: #percentStringEnd put: endValue
]
{ #category : 'stream mimicry' }
PPContext >> position [
^ stream position
]
{ #category : 'stream mimicry' }
PPContext >> position: anInteger [
^ stream position: anInteger
]
{ #category : 'initialization' }
PPContext >> postCopy [
super postCopy.
globals := globals copy.
]
{ #category : 'printing' }
PPContext >> printOn: aStream [
super printOn: aStream.
aStream nextPut: $:.
aStream nextPut: $ .
stream printOn: aStream
]
{ #category : 'accessing-properties' }
PPContext >> properties [
^ properties
]
{ #category : 'accessing-properties' }
PPContext >> propertyAt: aKey [
"Answer the property value associated with aKey."
^ self propertyAt: aKey ifAbsent: [ self error: 'Property not found' ]
]
{ #category : 'accessing-properties' }
PPContext >> propertyAt: aKey ifAbsent: aBlock [
"Answer the property value associated with aKey or, if aKey isn't found, answer the result of evaluating aBlock."
^ properties isNil
ifTrue: [ aBlock value ]
ifFalse: [ properties at: aKey ifAbsent: aBlock ]
]
{ #category : 'accessing-properties' }
PPContext >> propertyAt: aKey ifAbsentPut: aBlock [
"Answer the property associated with aKey or, if aKey isn't found store the result of evaluating aBlock as new value."
^ self propertyAt: aKey ifAbsent: [ self propertyAt: aKey put: aBlock value ]
]
{ #category : 'accessing-properties' }
PPContext >> propertyAt: aKey put: anObject [
"Set the property at aKey to be anObject. If aKey is not found, create a new entry for aKey and set is value to anObject. Answer anObject."
^ (properties ifNil: [ properties := Dictionary new: 1 ])
at: aKey put: anObject
]
{ #category : 'memoization' }
PPContext >> remember [
| memento |
memento := PPContextMemento new
stream: stream;
position: stream position;
yourself.
self rememberProperties: memento.
^ memento
]
{ #category : 'memoization' }
PPContext >> rememberProperties: aPPContextMemento [
properties ifNil: [ ^ self ].
properties keysAndValuesDo: [ :key :value |
aPPContextMemento propertyAt: key put: value
].
]
{ #category : 'accessing-globals' }
PPContext >> removeGlobal: aKey [
"Remove the property with aKey. Answer the property or raise an error if aKey isn't found."
^ self removeGlobal: aKey ifAbsent: [ self error: 'Property not found' ]
]
{ #category : 'accessing-globals' }
PPContext >> removeGlobal: aKey ifAbsent: aBlock [
"Remove the global property with aKey. Answer the value or, if aKey isn't found, answer the result of evaluating aBlock."
| answer |
globals isNil ifTrue: [ ^ aBlock value ].
answer := globals removeKey: aKey ifAbsent: aBlock.
globals isEmpty ifTrue: [ globals := nil ].
^ answer
]
{ #category : 'accessing-properties' }
PPContext >> removeProperty: aKey [
"Remove the property with aKey. Answer the property or raise an error if aKey isn't found."
^ self removeProperty: aKey ifAbsent: [ self error: 'Property not found' ]
]
{ #category : 'accessing-properties' }
PPContext >> removeProperty: aKey ifAbsent: aBlock [
"Remove the property with aKey. Answer the value or, if aKey isn't found, answer the result of evaluating aBlock."
| answer |
properties isNil ifTrue: [ ^ aBlock value ].
answer := properties removeKey: aKey ifAbsent: aBlock.
properties isEmpty ifTrue: [ properties := nil ].
^ answer
]
{ #category : 'initialization' }
PPContext >> reset [
properties := nil.
globals := nil.
]
{ #category : 'memoization' }
PPContext >> restore: aPPContextMemento [
aPPContextMemento stream == stream ifFalse: [ self error: 'Oops!' ].
stream position: aPPContextMemento position.
self restoreProperties: aPPContextMemento.
]
{ #category : 'memoization' }
PPContext >> restoreProperties: aPPContextMemento [
aPPContextMemento stream == stream ifFalse: [ self error: 'Oops!' ].
properties ifNil: [ ^ self ].
properties keysDo: [ :key |
(aPPContextMemento hasProperty: key)
ifTrue: [ properties at: key put: (aPPContextMemento propertyAt: key) ]
ifFalse: [ properties removeKey: key ].
].
aPPContextMemento keysAndValuesDo: [ :key :value |
properties at: key put: value
]
]
{ #category : 'acessing' }
PPContext >> root [
^ root
]
{ #category : 'memoization' }
PPContext >> size [
^ stream size
]
{ #category : 'stream mimicry' }
PPContext >> skip: anInteger [
^ stream skip: anInteger
]
{ #category : 'stream mimicry' }
PPContext >> skipTo: anObject [
^ stream skipTo: anObject
]
{ #category : 'stream mimicry' }
PPContext >> skipToAll: aString [
"Set the access position of the receiver to be past the next occurrence of the subCollection. Answer whether subCollection is found. No wildcards, and case does matter."
| pattern startMatch |
pattern := aString readStream.
startMatch := nil.
[ pattern atEnd ] whileFalse:
[ stream atEnd ifTrue: [ ^ false ].
stream next = pattern next
ifTrue: [ pattern position = 1 ifTrue: [ startMatch := stream position ] ]
ifFalse:
[ pattern position: 0.
startMatch ifNotNil:
[ stream position: startMatch.
startMatch := nil ] ] ].
^ true
]
{ #category : 'stream mimicry' }
PPContext >> skipToAnyOf: aCharacterSet [
"Set the access position of the receiver to be past the next occurrence of
a character in the character set. Answer whether a fitting character is found."
[stream atEnd]
whileFalse: [ (aCharacterSet includes: stream next) ifTrue: [^true]].
^false
]
{ #category : 'acessing' }
PPContext >> stream [
^ stream
]
{ #category : 'acessing' }
PPContext >> stream: aStream [
stream := aStream.
]
{ #category : 'stream mimicry' }
PPContext >> uncheckedPeek [
^ stream uncheckedPeek
]
{ #category : 'stream mimicry' }
PPContext >> upTo: anObject [
^ stream upTo: anObject
]
{ #category : 'stream mimicry' }
PPContext >> upToAll: whatever [
^ stream upToAll: whatever
]
{ #category : 'stream mimicry' }
PPContext >> upToAnyOf: whatever [
^ stream upToAnyOf: whatever
]