" A PPContext is provides contextual information to the parsing function. Instance Variables globals: properties: root: stream: 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 ]