146 lines
4.4 KiB
Smalltalk
146 lines
4.4 KiB
Smalltalk
Object subclass: AOC []
|
|
AOC class extend [
|
|
| savedP1 savedP2 mapper getArg |
|
|
part1: p1Block [ savedP1 := p1Block ]
|
|
part2: p2Block [ savedP2 := p2Block ]
|
|
map: mapBlock [ mapper := mapBlock ]
|
|
arg: argBlock [ getArg := argBlock ]
|
|
|
|
output: value part: part
|
|
[ FileStream stdout << 'Part '; << part; << ': '; << value; nl. ]
|
|
|
|
runPart: saved part: part arg: arg
|
|
[ saved ifNotNil: [
|
|
| mapped |
|
|
mapped := mapper value: arg value: saved.
|
|
self output: mapped part: part ] ]
|
|
|
|
run
|
|
[ | arg |
|
|
arg := getArg value.
|
|
self runPart: savedP1 part: 1 arg: arg.
|
|
self runPart: savedP2 part: 2 arg: arg. ]
|
|
|
|
"TODO: save as an image?"
|
|
finish [ self run ]
|
|
]
|
|
|
|
Iterable extend [
|
|
sum [ ^self fold: [ :l :r | l + r ] ]
|
|
toList
|
|
[ | list |
|
|
list := OrderedCollection new.
|
|
self do: [:x | list add: x].
|
|
^list ]
|
|
]
|
|
|
|
Object subclass: ScannerState [
|
|
| scanner oc dispatch failed |
|
|
init: sc
|
|
[ scanner := sc.
|
|
oc := OrderedCollection new.
|
|
dispatch := nil.
|
|
failed := false. ]
|
|
|
|
failed [ ^failed ]
|
|
|
|
accept: c on: stream
|
|
[ dispatch ifNotNil:
|
|
[ :dp | dispatch := nil. dp value: c value: stream ] ifNil:
|
|
[ (c = $%) ifTrue:
|
|
[ dispatch := [ :c :stream | self dispatch: c on: stream ] ]
|
|
ifFalse: [ self require: c on: stream ] ] ]
|
|
|
|
dispatch: c on: stream [ (scanner dispatchFor: c) value: self value: stream ]
|
|
require: c on: stream
|
|
[ c isSeparator ifTrue:
|
|
[ stream whilePeek: [ :c | c isSeparator ] do: [ :ignored | nil ] ] ifFalse:
|
|
[ failed := (stream peekFor: c) not ] ]
|
|
parseCharOn: stream [ oc add: stream next ]
|
|
badCmd: c [ self error: 'Bad command' ]
|
|
finish [ ^oc asArray ]
|
|
|
|
parseIntOn: stream
|
|
[ | d |
|
|
d := 0.
|
|
stream whilePeek: [ :c | c isDigit ] do:
|
|
[ :c | d := d * 10 + c digitValue ].
|
|
oc add: d ]
|
|
|
|
parseStringOn: stream
|
|
[ | s | s := OrderedCollection new.
|
|
stream whilePeek: [ :c | c isSeparator not ] do:
|
|
[ :c | s add: c ].
|
|
oc add: s asString ]
|
|
|
|
parseCharsetOn: stream [ dispatch := [ :c :stream | self parseCharset: c on: stream set: Set new ] ]
|
|
parseCharset: c on: stream set: set
|
|
[ (c = $^) ifTrue:
|
|
[ dispatch := [
|
|
:c :stream |
|
|
self parseCharset: c on: stream inv: true set: set ] ] ifFalse:
|
|
[ self parseCharset: c on: stream inv: false set: set ] ]
|
|
parseCharset: c on: stream inv: inv set: set
|
|
[ (c = $]) ifTrue:
|
|
[ self parseCharsetOn: stream inv: inv set: set ] ifFalse:
|
|
[ set add: c.
|
|
dispatch := [
|
|
:c :stream |
|
|
self parseCharset: c on: stream inv: inv set: set ] ] ]
|
|
parseCharsetOn: stream inv: inv set: set
|
|
[ | s | s := OrderedCollection new.
|
|
stream whilePeek: [ :c | inv ~= (set includes: c) ] do:
|
|
[ :c | s add: c ].
|
|
oc add: s asString ]
|
|
]
|
|
ScannerState class extend [
|
|
new: sc [ |r| r := super new. r init: sc. ^r ]
|
|
]
|
|
Object subclass: Scanner [
|
|
| dispatch |
|
|
init
|
|
[ dispatch := Dictionary new.
|
|
dispatch at: $% put: [ :s :st | s require: $% on: st ].
|
|
dispatch at: $d put: [ :s :st | s parseIntOn: st ].
|
|
dispatch at: $c put: [ :s :st | s parseCharOn: st ].
|
|
dispatch at: $s put: [ :s :st | s parseStringOn: st ].
|
|
dispatch at: $[ put: [ :s :st | s parseCharsetOn: st ]. ]
|
|
|
|
dispatchFor: c [ ^dispatch at: c ifAbsent: [[ :s :st | s badCmd: c ]] ]
|
|
|
|
scanf: fmt on: stream
|
|
[ | s |
|
|
s := ScannerState new: self.
|
|
fmt do: [ :c | s accept: c on: stream.
|
|
s failed ifTrue: [ ^nil ] ].
|
|
^s finish ]
|
|
]
|
|
Scanner class extend [
|
|
| defaultsc |
|
|
default [ ^defaultsc ]
|
|
default: it [ defaultsc := it ]
|
|
new [ |r| r := super new. r init. ^r ]
|
|
]
|
|
Scanner default: Scanner new.
|
|
|
|
Object extend [
|
|
memfn: selector [ DirectedMessage receiver: self selector: selector ]
|
|
]
|
|
|
|
Stream extend [
|
|
toLines [ ^self lines toList ]
|
|
|
|
scanf: fmt [ ^Scanner default scanf: fmt on: self ]
|
|
scanf: fmt with: block
|
|
[ ^(self scanf: fmt) ifNotNil: [ :it | block valueWithArguments: it ] ]
|
|
|
|
whilePeek: pred do: block
|
|
[ [ self peek ifNil: [ false ]
|
|
ifNotNil: [ :it | pred value: it ] ]
|
|
whileTrue: [ block value: self next ] ]
|
|
]
|
|
|
|
String extend [
|
|
scanf: fmt [ ^(ReadStream on: self) scanf: fmt ]
|
|
scanf: fmt with: block [ ^(ReadStream on: self) scanf: fmt with: block ]
|
|
]
|