'From Cuis 2.6 of 10 August 2010 [latest update: #540] on 13 August 2010 at 10:40:56 pm'!

!ParseNode methodsFor: 'testing' stamp: 'jmv 8/13/2010 21:41'!
printsInNewLine
	"Used for pretty printing to determine whether to start a new line"

	^self isComplex! !


!BlockNode methodsFor: 'testing' stamp: 'jmv 8/13/2010 21:47'!
printsInNewLine
	"Used for pretty printing to determine whether to start a new line"

	Preferences prettyPrintRectangularBlocks ifFalse: [ ^false ].
	^super printsInNewLine! !

!BlockNode methodsFor: 'printing' stamp: 'jmv 8/13/2010 18:14'!
printArgumentsOn: aStream indent: level
	arguments size = 0 ifTrue: [^ self].
	aStream space.
	arguments do:
		[ :arg | aStream nextPut: $:; nextPutAll: arg key; space ].
	aStream nextPut: $|! !

!BlockNode methodsFor: 'printing' stamp: 'jmv 8/13/2010 22:33'!
printOn: aStream indent: level
	| separateLines |
	aStream nextPut: $[.
	self
		printArgumentsOn: aStream
		indent: level.
	separateLines _ (self
		printTemporaries: temporaries
		on: aStream
		doPrior: [ aStream space ]) or: [arguments size > 0 ].
	Preferences prettyPrintRectangularBlocks
		ifTrue: [
			"If args+temps > 0 and statements > 1 (or just one complex statement),
			put all statements on separate lines"
			separateLines
				ifTrue: [
					(statements size > 1 or: [
						statements size = 1 and: [ statements first isComplex ]])
							ifTrue: [ aStream crtab: (1 max: level) ]
							ifFalse: [ aStream space ] ]
				ifFalse: [
					(statements size = 1 and: [ statements first isComplex not ])
						ifTrue: [ aStream space ]]]
		ifFalse: [
			self isComplex
				ifTrue: [ aStream crtab: (1 max: level) ]
				ifFalse: [ aStream space ] ].
	((self printStatementsOn: aStream indent: level) > 0 and: [ aStream peekLast ~= $] ])
		ifTrue: [ aStream space ].
	aStream nextPut: $]! !

!BlockNode methodsFor: 'printing' stamp: 'jmv 8/13/2010 22:20'!
printStatementsOn: aStream indent: levelOrZero
	| len shown thisStatement level |
	level _ 1 max: levelOrZero.
	comment ifNotNil: [
		self printCommentOn: aStream indent: level.
		aStream crtab: level].
	len _ shown _ statements size.
	(levelOrZero = 0 "top level" and: [statements last isReturnSelf])
		ifTrue: [ shown _ 1 max: shown - 1]
		ifFalse: ["should a trailing nil be printed or not? Not if it is an implicit result."
				(arguments size = 0
				and: [ len >= 1
				and: [ (statements at: len) == NodeNil
				and: [ len = 1
					or: [ len > 1
						and: [(statements at: len - 1) isMessageNode
						and: [(statements at: len - 1) isNilIf ]]]]]])
					ifTrue: [ shown _ shown - 1 ]].
	1 to: shown do: 
		[ :i |
		thisStatement _ statements at: i.
		thisStatement printOn: aStream indent: level.
		i < shown ifTrue: [ aStream nextPut: $.; crtab: level ].
		"Add a final period. This helps when pretty-diffing a method and a version of it that adds stuff after the end."
		(i = shown and: [ levelOrZero = 0 ]) ifTrue: [ aStream nextPut: $. ].
		(thisStatement comment notNil and: [ thisStatement comment size > 0 ])
			ifTrue: [
				i = shown ifTrue: [ aStream crtab: level ].
				thisStatement printCommentOn: aStream indent: level.
				i < shown ifTrue: [ aStream crtab: level ]]].
	^shown! !


!CascadeNode methodsFor: 'printing' stamp: 'jmv 8/13/2010 18:36'!
printOn: aStream indent: level precedence: p
	p > 0 ifTrue: [ aStream nextPut: $( ].
	messages first
		printReceiver: receiver
		on: aStream
		indent: level.
	1
		to: messages size
		do: 
			[ : i | 
			aStream crtab: level + 1.
			(messages at: i)
				printOn: aStream
				indent: level.
			i < messages size ifTrue: [ aStream nextPut:$; ] ].
	p > 0 ifTrue: [ aStream nextPut: $) ]! !


!MessageNode methodsFor: 'printing' stamp: 'jmv 8/13/2010 21:42'!
printCaseOn: aStream indent: level 
	"receiver caseOf: {[key]->[value]. ...} otherwise: [otherwise]"
	| braceNode otherwise extra |
	braceNode := arguments first.
	otherwise := arguments last.
	(arguments size = 1 or: [otherwise isJustCaseError]) ifTrue:
		[otherwise := nil].
	receiver
		printOn: aStream
		indent: level
		precedence: 3.
	aStream nextPutAll: ' caseOf: '.
	braceNode isVariableReference
		ifTrue: [braceNode printOn: aStream indent: level]
		ifFalse: 
			[aStream nextPutAll: '{'; crtab: level + 1.
			 braceNode casesForwardDo:
				[:keyNode :valueNode :last | 
				keyNode printOn: aStream indent: level + 1.
				aStream nextPutAll: ' -> '.
				valueNode printsInNewLine
					ifTrue: 
						[aStream crtab: level + 2.
						extra := 1]
					ifFalse: [extra := 0].
				valueNode printOn: aStream indent: level + 1 + extra.
				last ifTrue: [aStream nextPut: $}]
					ifFalse: [aStream nextPut: $.;
							 crtab: level + 1]]].
	otherwise ifNotNil: [
		aStream crtab: level + 1; nextPutAll: ' otherwise: '.
		 extra := otherwise printsInNewLine
					ifTrue: [
						aStream crtab: level + 2.
						1]
					ifFalse: [0].
		 otherwise printOn: aStream indent: level + 1 + extra]! !

!MessageNode methodsFor: 'printing' stamp: 'jmv 8/13/2010 21:42'!
printKeywords: key arguments: args on: aStream indent: level 
	| keywords indent arg kwd doCrTab |
	args size = 0 ifTrue:
		[ aStream
			 space ;
			 nextPutAll: key.
		^ self ].
	keywords := key keywords.
	doCrTab := args size > 1.
	1
		to: (args size min: keywords size)
		do:
			[ : i | arg := args at: i.
			kwd := keywords at: i.
			doCrTab
				ifTrue:
					[ aStream crtab: level + 1.
					indent := 1
					"newline after big args" ]
				ifFalse:
					[ aStream space.
					indent := 0 ].
			aStream nextPutAll: kwd.
			arg printsInNewLine
				ifTrue: [ aStream crtab: level + indent + 1 ]
				ifFalse: [ aStream space ].
			arg
				printOn: aStream
				indent: level + 1 + indent
				precedence:
					(precedence = 2
						ifTrue: [ 1 ]
						ifFalse: [ precedence ]) ]! !

!MessageNode methodsFor: 'printing' stamp: 'jmv 8/13/2010 21:42'!
printWithClosureAnalysisCaseOn: aStream indent: level 
	"receiver caseOf: {[key]->[value]. ...} otherwise: [otherwise]"
	| braceNode otherwise extra |
	braceNode := arguments first.
	otherwise := arguments last.
	(arguments size = 1 or: [otherwise isJustCaseError]) ifTrue:
		[otherwise := nil].
	receiver
		printWithClosureAnalysisOn: aStream
		indent: level
		precedence: 3.
	aStream nextPutAll: ' caseOf: '.
	braceNode isVariableReference
		ifTrue: [braceNode printWithClosureAnalysisOn: aStream indent: level]
		ifFalse: 
			[aStream nextPutAll: '{'; crtab: level + 1.
			 braceNode casesForwardDo:
				[:keyNode :valueNode :last | 
				keyNode printWithClosureAnalysisOn: aStream indent: level + 1.
				aStream nextPutAll: ' -> '.
				valueNode printsInNewLine
					ifTrue: 
						[aStream crtab: level + 2.
						extra := 1]
					ifFalse: [extra := 0].
				valueNode printWithClosureAnalysisOn: aStream indent: level + 1 + extra.
				last ifTrue: [aStream nextPut: $}]
					ifFalse: [aStream nextPut: $.;
							 crtab: level + 1]]].
	otherwise ifNotNil: [
		aStream crtab: level + 1; nextPutAll: ' otherwise: '.
		 extra := otherwise printsInNewLine
					ifTrue: [
						aStream crtab: level + 2.
						1]
					ifFalse: [0].
		 otherwise printWithClosureAnalysisOn: aStream indent: level + 1 + extra]! !


!MethodNode methodsFor: 'printing' stamp: 'jmv 8/13/2010 18:36'!
printOn: aStream
	| selectorNode |
	selectorNode _ self selectorNode.
	precedence = 1
		ifTrue:
			[selectorNode isForFFICall
				ifTrue: [selectorNode
							printAsFFICallWithArguments: arguments
							on: aStream
							indent: 0]
				ifFalse: [aStream nextPutAll: selectorNode key]]
		ifFalse:
			[selectorNode key keywords withIndexDo:
				[:kwd :i | | arg |
				arg _ arguments at: i.
				i = 1 ifFalse: [ aStream space ].
				aStream nextPutAll: kwd; space; nextPutAll: arg key ]].
	comment ifNotNil: [
		aStream crtab: 1.
		self printCommentOn: aStream indent: 1].
	block printTemporaries: temporaries on: aStream doPrior: [aStream crtab: 1].
	primitive > 0 ifTrue:
		[(primitive between: 255 and: 519) ifFalse:  "Dont decompile quick prims  e.g, ^ self or ^instVar"
			[aStream crtab: 1.
			 self printPrimitiveOn: aStream]].
	self printPropertiesOn: aStream.
	self printPragmasOn: aStream.
	aStream crtab: 1.
	block printStatementsOn: aStream indent: 0! !


!Parser methodsFor: 'expression types' stamp: 'jmv 8/13/2010 22:35'!
statements: argNodes innerBlock: inner blockNode: theBlockNode

	| stmts returns start |
	"give initial comment to block, since others trail statements"
	theBlockNode comment: currentComment.
	currentComment _ nil.
	stmts := OrderedCollection new.
	returns := false.
	hereType ~~ #rightBracket ifTrue:
		[[theBlockNode startOfLastStatement: (start := self startOfNextToken).
		  (returns := self matchReturn)
			ifTrue: 
				[self expression ifFalse:
					[^self expected: 'Expression to return'].
				 self addComment.
				 stmts addLast: (parseNode isReturningIf
								ifTrue: [parseNode]
								ifFalse: [ReturnNode new
											expr: parseNode
											encoder: encoder
											sourceRange: (start to: self endOfLastToken)])]
			ifFalse: 
				[self expression
					ifTrue: 
						[self addComment.
						 stmts addLast: parseNode]
					ifFalse: 
						[self addComment.
						 stmts size = 0 ifTrue: 
							[stmts addLast: 
								(encoder encodeVariable:
									(inner ifTrue: ['nil'] ifFalse: ['self']))]]].
		  returns ifTrue: 
			[self match: #period.
			 (hereType == #rightBracket or: [hereType == #doIt]) ifFalse:
				[^self expected: 'End of block']].
		  returns not and: [self match: #period]] whileTrue].
	theBlockNode
		arguments: argNodes
		statements: stmts
		returns: returns
		from: encoder.
	parseNode := theBlockNode.
	^true! !


!Preferences class methodsFor: 'standard queries' stamp: 'jmv 8/13/2010 22:04'!
prettyPrintRectangularBlocks
	^ self
		valueOfFlag: #prettyPrintRectangularBlocks
		ifAbsent: [false]! !

