PPContext.st
changeset 377 6112a403a52d
child 405 0470a5e6e712
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PPContext.st	Fri Oct 03 02:33:08 2014 +0100
@@ -0,0 +1,269 @@
+"{ Package: 'stx:goodies/petitparser' }"
+
+Object subclass:#PPContext
+	instanceVariableNames:'stream root properties globals'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'PetitParser-Core'
+!
+
+!PPContext class methodsFor:'as yet unclassified'!
+
+on: aPPParser stream: aStream
+	^ self basicNew 
+		initialize;
+		root: aPPParser;
+		stream: aStream asPetitStream;
+		yourself
+! !
+
+!PPContext methodsFor:'accessing-globals'!
+
+globalAt: aKey
+	"Answer the global property value associated with aKey."
+	
+	^ self globalAt: aKey ifAbsent: [ self error: 'Property not found' ]
+!
+
+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 ]
+!
+
+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 ]
+!
+
+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
+!
+
+hasGlobal: aKey
+	"Test if the global property aKey is present."
+	
+	^ globals notNil and: [ globals includesKey: aKey ]
+!
+
+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' ]
+!
+
+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
+! !
+
+!PPContext methodsFor:'accessing-properties'!
+
+hasProperty: aKey
+	"Test if the property aKey is present."
+	
+	^ properties notNil and: [ properties includesKey: aKey ]
+!
+
+propertyAt: aKey
+	"Answer the property value associated with aKey."
+	
+	^ self propertyAt: aKey ifAbsent: [ self error: 'Property not found' ]
+!
+
+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 ]
+!
+
+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 ]
+!
+
+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
+!
+
+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' ]
+!
+
+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
+! !
+
+!PPContext methodsFor:'acessing'!
+
+root
+	^ root 
+!
+
+stream
+	^ stream
+!
+
+stream: aStream
+	stream := aStream.
+! !
+
+!PPContext methodsFor:'failures'!
+
+furthestFailure
+	" the furthest failure encountered while parsing the input stream "
+	
+	^ self globalAt: #furthestFailure ifAbsent: [ nil ]
+!
+
+noteFailure: aPPFailure
+	"record the furthest failure encountered while parsing the input stream "
+
+	| furthestFailure |
+	furthestFailure := self furthestFailure.
+	( furthestFailure isNil or: [ aPPFailure position > furthestFailure position ]) 
+		ifTrue: [ self globalAt: #furthestFailure put: aPPFailure ].
+! !
+
+!PPContext methodsFor:'initialization'!
+
+initialize
+	stream := nil.
+!
+
+initializeFor: parser
+	parser == root ifTrue: [ ^ self ].
+	
+	root := parser.
+	root allParsersDo: [ :p | 
+		p updateContext: self
+	]
+! !
+
+!PPContext methodsFor:'memoization'!
+
+remember
+	| memento |
+	memento := PPContextMemento new
+		stream: stream;
+		position: stream position;
+		yourself.
+		
+	self rememberProperties: memento.
+	^ memento
+!
+
+rememberProperties: aPPContextMemento
+	properties ifNil: [ ^ self ].
+	
+	properties keysAndValuesDo: [ :key :value |
+		aPPContextMemento propertyAt: key put: value
+	].
+!
+
+restore: aPPContextMemento
+	aPPContextMemento stream == stream ifFalse: [ self error: 'Oops!!' ].
+
+	stream position: aPPContextMemento position.
+	self restoreProperties: aPPContextMemento.
+!
+
+restoreProperties: aPPContextMemento
+	aPPContextMemento stream == stream ifFalse: [ self error: 'Oops!!' ].
+	
+	aPPContextMemento keysAndValuesDo: [ :key :value |
+		self propertyAt: key put: value
+	].
+! !
+
+!PPContext methodsFor:'stream mimicry'!
+
+atEnd
+	^ stream atEnd
+!
+
+back
+	^ stream back
+!
+
+collection
+	^ stream collection  
+!
+
+contents 
+	^ stream contents
+!
+
+isStartOfLine
+	^ stream isStartOfLine
+!
+
+next
+	^ stream next
+!
+
+next: anInteger
+	^ stream next: anInteger
+!
+
+peek
+	^ stream peek
+!
+
+peekTwice
+	^ stream peekTwice
+!
+
+position
+	^ stream position
+!
+
+position: anInteger
+	^ stream position: anInteger
+!
+
+skip: anInteger 
+	^ stream skip: anInteger 
+!
+
+uncheckedPeek
+	^ stream uncheckedPeek
+!
+
+upTo: anObject
+	^ stream upTo: anObject
+!
+
+upToAll: whatever
+	^ stream upToAll: whatever
+!
+
+upToAnyOf: whatever
+	^ stream upToAnyOf: whatever
+! !
+