islands/PPIsland.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Tue, 12 May 2015 01:24:03 +0100
changeset 459 4751c407bb40
parent 387 e2b2ccaa4de6
child 642 77d5fddb6462
permissions -rw-r--r--
Merged with PetitCompiler-JanKurs.20150510144201, PetitCompiler-Tests-JanKurs.20150510144201, PetitCompiler-Extras-Tests-JanKurs.20150510144201, PetitCompiler-Benchmarks-JanKurs.20150510144201 Name: PetitCompiler-JanKurs.20150510144201 Author: JanKurs Time: 10-05-2015, 04:42:29.192 PM UUID: 58a4786b-1182-4904-8b44-a13d3918f244 Name: PetitCompiler-Tests-JanKurs.20150510144201 Author: JanKurs Time: 10-05-2015, 04:32:12.870 PM UUID: 2a8fd41a-331b-4dcf-a7a3-752a50ce86e7 Name: PetitCompiler-Extras-Tests-JanKurs.20150510144201 Author: JanKurs Time: 10-05-2015, 04:59:25.308 PM UUID: ef43bd1a-be60-4e88-b749-8b635622c969 Name: PetitCompiler-Benchmarks-JanKurs.20150510144201 Author: JanKurs Time: 10-05-2015, 05:04:54.561 PM UUID: d8e764fd-016b-46e2-9fc1-17c38c18f0e5

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

"{ NameSpace: Smalltalk }"

PPParser subclass:#PPIsland
	instanceVariableNames:'island afterWaterParser beforeWaterParser context
		afterWaterDelegate beforeWaterDelegate water'
	classVariableNames:''
	poolDictionaries:''
	category:'PetitIslands-Parsers'
!

PPIsland comment:'A PPIsland allows for imprecise parsing. One can create it on a parser p by calling: ''p island'' E.g.:

p := x, a island, y              accepts following inputs:
x.....a.....b 
xab

yet fails on:
x....a....c
xb
xac
x..b....a....b

The input represented by dots is called water and water can appear before and after the island. Use it, if you don''t want to define all the grammar rules and you want to skip something.

I am still an experiment, but if you know how to improve me, please contact Jan Kurs at: kurs@iam.unibe.ch

Instance Variables
	afterWaterParser:		<Object>
	awp:		<Object>
	beforeWaterParser:		<Object>
	bwp:		<Object>
	context:		<Object>
	island:		<Object>

afterWaterParser
	- xxxxx

awp
	- xxxxx

beforeWaterParser
	- xxxxx

bwp
	- xxxxx

context
	- xxxxx

island
	- xxxxx
'
!

!PPIsland methodsFor:'accessing'!

children

	^ Array with: water with: island with: water
!

followSet: aPPContext

	^ aPPContext root followSets at: self.	
!

initialize 
	super initialize.
	water := #any asParser name: 'water'; yourself.
!

island

	^ island
!

island: anObject
	island := anObject.
!

nextSet: aPPContext

	^ aPPContext root nextSets at: self.
!

replace: parser with: anotherParser 
	super replace: parser with: anotherParser.
	
	(water == parser) ifTrue: [ water := anotherParser ].
	(island == parser) ifTrue: [ island := anotherParser ].
!

water
	^ water
!

water: aPPParser
	water := aPPParser
! !

!PPIsland methodsFor:'memoization'!

memoized 
	^ PPMemoizingIsland new
		island: self island;
		water: water;
		yourself
!

reset: aPPContext
	context := aPPContext.
	beforeWaterParser := nil.
	afterWaterParser := nil.
! !

!PPIsland methodsFor:'parsing'!

afterWaterParser: aPPContext
	context == aPPContext ifFalse: [ self reset: aPPContext ].

	afterWaterParser ifNil: [
		afterWaterParser := self createAfterWaterParser: aPPContext.
	].
	^ afterWaterParser
!

beforeWaterParser: aPPContext
	context == aPPContext ifFalse: [ self reset: aPPContext ].

	beforeWaterParser ifNil: [
		beforeWaterParser := self createBeforeWaterParser: aPPContext.
	].
	^ beforeWaterParser
!

createAfterWaterParser: aPPContext
	|  nextSet  p |

	nextSet := Set new.
	nextSet addAll: (self nextSet: aPPContext).
	nextSet add: PPInputEnds new.
	
	nextSet := nextSet collect: [ :e | PPNonEmptyParser on: e ].
	
	p := (PPChoiceParser withAll: nextSet) not.
	^ PPWater on: p waterToken: water
!

createBeforeWaterParser: aPPContext
	| nextSet p |
	nextSet := Set new.
	nextSet addAll: (self nextSet: aPPContext).
	nextSet add: PPInputEnds new.
	
	nextSet := nextSet collect: [:e | PPNonEmptyParser on: e].
	
	p := (PPChoiceParser withAll: nextSet) not, (PPNonEmptyParser on: island) not.
	^ PPWater on: p waterToken: water.
!

exampleOn: aStream
	aStream nextPutAll: '~~~~ '.
	island exampleOn: aStream .
	aStream nextPutAll:  ' ~~~~'.
!

parseAfterWater: aPPContext
	^ (self afterWaterParser: aPPContext) parseOn: aPPContext .
!

parseBeforeWater: aPPContext
	^ (self beforeWaterParser: aPPContext) parseOn: aPPContext.
!

parseOn: aPPContext 
	|  bwr awr result retval memento |

	memento := aPPContext remember.
	"Halt ifShiftPressed."
	
	bwr := self parseBeforeWater: aPPContext.
	bwr isPetitFailure ifTrue: 
	[
		self error: 'IMO should never happen'.
	].

	"JK: HACK ALERT, FIX!!"
	(aPPContext waterPosition == aPPContext position) ifTrue:[
		result := (PPNonEmptyParser on: island) parseOn: aPPContext.
	] ifFalse: [
		result := island parseOn: aPPContext.
	].
	

	result isPetitFailure ifTrue: [ 
		retval := PPFailure message: 'Island not found between ', memento position asString, ' and ', aPPContext position asString context: aPPContext.
		aPPContext restore: memento.
		^ retval
	].


	awr := self parseAfterWater: aPPContext.	
	awr isPetitFailure ifTrue: 
	[
		retval := PPFailure message: 'IMO should not happen :(' context: aPPContext.
		aPPContext restore: memento.
		^ retval.
	].

	retval := OrderedCollection with: bwr with: result with: awr.
	^ retval


!

waterToken
	| waterObjects |
	self halt: 'deprecated?'.
	waterObjects := self globalAt: #waterObjects ifAbsent: [ OrderedCollection new ].
	waterObjects add: #any asParser.
	^ PPChoiceParser withAll: waterObjects.
! !

!PPIsland methodsFor:'queries'!

acceptsEpsilon
	"JK: Hack alert?"
	"Let us suppose island is always nullable, it helps to sequences of islands"
	^ true
	"^ island isNullableOpenSet: (IdentitySet with: self)"
!

acceptsEpsilonOpenSet: set
	"JK: Hack alert?"
	^ true
"	^ island isNullableOpenSet: set"
!

name
	^ super name ifNil: [ 'an island '].
! !