Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failsafe tonel #108

Open
wants to merge 2 commits into
base: Pharo12
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ method
| type selector |

type := self untilIncluding: '>>'.
selector := self cleanSelector: (self untilExcluding: '[').
selector := self cleanSelector: (self selector).
type := type trimBoth substrings: ' '.
type size = 1 ifTrue: [ type := type copyWith: nil ].
^ {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
parsing
selector

^ String streamContents: [ :out |
[ stream atEnd or: [ stream peek isSeparator not ] ] whileFalse: [ stream next ].
[ stream atEnd or: [ stream peek isSeparator ] ] whileFalse: [
out nextPut: stream next ].
[ stream atEnd or: [ '[!' includes: stream peek ] ] whileFalse: [
out nextPut: stream next ] ]
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
scanning
scan
self prepareToScan.
stream peek = $! ifTrue: [
"Robust mode, source use a *chunk* format. existing ! are escaped (doubled)"
stream next.
^ (String streamContents: [ :str |
| ch |
[ ch := stream peek.
ch ~= $! or: [
stream next.
ch := stream peek.
ch = $! ] ]
whileTrue: [ str nextPut: stream next ] ] ) withInternalLineEndings ].

stream peek = $[ ifFalse: [ TonelParseError signal: 'Can''t parse method body' ].
[ stream atEnd or: [ isFinished ] ]
whileFalse: [ self scanNextChunk ].
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
private - writing
writeMethodBody: methodBody on: aStream

| nl reader |
nl := self newLine.

"Check is the current body is robust. The most correct approach is to try to read it back"
reader := ('[' , methodBody , ']') readStream.
[ (TonelSourceScanner on: reader) scan ] on: TonelParseError do: [ reader := nil ].
(reader isNotNil and: [ reader atEnd ]) ifFalse: [
"If parse failed, then use an alternative robust *chunk* format instead.
Body is strictly delimited by `!` and existing `!` in the content are doubled"
aStream << ' !'.
methodBody do: [ :each |
each = $! ifTrue: [ aStream << $! ].
aStream << each ].
aStream << '!' << nl.
^ self ].
aStream << ' [' << methodBody << nl << ']' << nl
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ writeMethodDefinition: aMethodDefinition parent: aClassDefinition on: aStream
aStream
<< nl
<< (self methodDefinitionOf: aMethodDefinition) << nl
<< fullClassName << ' >> ' << methodDeclaration
<< ' [' << methodBody << nl << ']' << nl ]
<< fullClassName << ' >> ' << methodDeclaration.
self writeMethodBody: methodBody on: aStream ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
tests
testMethodRobustBody
self
assertParse: '!¿["''#(#{({!'
rule: #methodBody
equals: '¿["''#(#{({'.
self
assertParse: '!])}¿!'
rule: #methodBody
equals: '])}¿'.
self
assertParse: '!!!!'
rule: #methodBody
equals: '!'.
self
assertParse: '!!!a!!!!b!!!'
rule: #methodBody
equals: '!a!!b!'.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
tests
testWriteRobustMethodDefinitionOn

| writer def stream |
writer := self actualClass new.

"To much closer"
stream := String new writeStream.
def := MCMethodDefinition
className: #Object
classIsMeta: false
selector: #selector
category: 'accessing'
timeStamp: nil
source: 'selector ^ ] 42'.
writer writeMethodDefinition: def on: stream.
self
assert: stream contents lines last
equals: 'Object >> selector ! ^ ] 42!'.

"To much opener"
stream := String new writeStream.
def := MCMethodDefinition
className: #Object
classIsMeta: false
selector: #selector
category: 'accessing'
timeStamp: nil
source: 'selector ^ [ 42'.
writer writeMethodDefinition: def on: stream.
self
assert: stream contents lines last
equals: 'Object >> selector ! ^ [ 42!'.

"To much quotes"
stream := String new writeStream.
def := MCMethodDefinition
className: #Object
classIsMeta: false
selector: #selector
category: 'accessing'
timeStamp: nil
source: 'selector ^ " 42'.

writer writeMethodDefinition: def on: stream.
self
assert: stream contents lines last
equals: 'Object >> selector ! ^ " 42!'.

"To much everything"
stream := String new writeStream.
def := MCMethodDefinition
className: #Object
classIsMeta: false
selector: #selector
category: 'accessing'
timeStamp: nil
source: 'selector ^ " '' #[ [ #( { ! !! 42 " '' ] ) }'.

writer writeMethodDefinition: def on: stream.
self
assert: stream contents lines last
equals: 'Object >> selector ! ^ " '' #[ [ #( { !! !!!! 42 " '' ] ) }!'.