Newsgroups: comp.lang.smalltalk
Path: cantaloupe.srv.cs.cmu.edu!bb3.andrew.cmu.edu!newsfeed.pitt.edu!newsflash.concordia.ca!sunqbc.risq.net!news.total.net!enews.sgi.com!news.mathworks.com!howland.erols.net!EU.net!Norway.EU.net!nntp.uio.no!nntp.zit.th-darmstadt.de!fu-berlin.de!unlisys!news.maz.net!news.ppp.net!blackbush.xlink.net!ins.net!heeg.de!hmm
From: hmm@heeg.de (Hans-Martin Mosner)
Subject: [SQ] Code: using := for assignment
Message-ID: <DzMBHL.MJx@heeg.de>
Sender: uucp@heeg.de
Organization: Georg Heeg Objektorientierte Systeme, Dortmund, FRG
X-Newsreader: TIN [version 1.2 PL2]
Date: Mon, 21 Oct 1996 08:56:09 GMT
Lines: 172

Here's some code to make Squeak recognize := for assignment, and free the _
character to be used as a letter replacement (i.e. identifiers may contain
or begin with _).

To switch the left arrow assignment on or off, use
	Scanner assignmentLeftArrow: aBoolean
To switch := assignement on or off, use
	Scanner assignmentColonEquals: aBoolean

Note that, naturally, at least one of the options must be true.
The use of _ in identifiers is only supported if assignmentLeftArrow is
false, of course. In this case, method sources that are displayed are
automatically converted to use := for assignment (and yes, I do handle
_ in literals and comments correctly!).
The glyph for the _ character in the standard font is also changed from
a left arrow to an underbar if assignmentLeftArrow is switched off, and
reverts to the left arrow sign when it is switched on again.
I did not implement this for the other fonts, that's left as an exercise
for the reader :-) (I admit, I was too lazy to do it)

I would like to propose to the emerging Squeak community to adopt this
assignment style to stay in line with the evoluted standards of the
language. Can we have a semi-official word from Apple on this?

Hans-Martin

'From Squeak 1.1 of September 21, 1996 on 21 October 1996 at 10:42:15 am'!


!AssignmentNode methodsFor: 'printing'!
printOn: aStream indent: level

	variable printOn: aStream indent: level.
	aStream nextPutAll: (Scanner assignmentColonEquals ifTrue: [' := '] ifFalse: [' _ ']).
	value printOn: aStream indent: level + 2! !

!CompiledMethod methodsFor: 'source code management'!
getSource
	"Answer the source code for the receiver. Answer nil if there are no 
	source files specified in the global SourceFiles."
	| source position |
	(SourceFiles at: self fileIndex) == nil ifTrue: [^nil].
	Cursor read
		showWhile: 
			[position _ self filePosition.
			position = 0
				ifTrue: [source _ nil]
				ifFalse: [source _ (RemoteString newFileNumber: self fileIndex
												position: position) string]].
	source == nil ifFalse: [Scanner assignmentLeftArrow ifFalse: [source _ source convertLeftArrows]].
	^source! !

!Scanner methodsFor: 'multi-character scans'!
xColon
	"interpret := as assignment"
	aheadChar = $=
		ifTrue: [self step; step.
			token _ $_ asSymbol.
			tokenType _ #leftArrow]
		ifFalse: [token _ self step asSymbol.
			tokenType _ #colon]!
xLetter
	"Form a word or keyword."

	| type |
	buffer reset.
	[(type _ typeTable at: hereChar asciiValue) == #xLetter or: [type == #xDigit]]
		whileTrue:
			["open code step for speed"
			buffer nextPut: hereChar.
			hereChar _ aheadChar.
			source atEnd
				ifTrue: [aheadChar _ 30 asCharacter "doit"]
				ifFalse: [aheadChar _ source next]].
	(type == #colon or: [type == #xColon and: [aheadChar ~= $=]])
		ifTrue: 
			[buffer nextPut: self step.
			tokenType _ #keyword]
		ifFalse: 
			[tokenType _ #word].
	token _ buffer contents! !

!Scanner class methodsFor: 'class initialization'!
assignmentColonEquals
	^(TypeTable at: $: asInteger) == #xColon!
assignmentColonEquals: aBoolean
	"Enable or disable the := sequence as the assignment operator."
	"Scanner assignmentColonEquals: true"

	aBoolean | self assignmentLeftArrow ifFalse: [^self error: 'You cannot switch off both kinds of assignment operator!!'].
	TypeTable at: $: asInteger put:
		(aBoolean ifTrue: [#xColon] ifFalse: [#colon])!
assignmentLeftArrow
	^(TypeTable at: $_ asInteger) == #leftArrow!
assignmentLeftArrow: aBoolean
	"Enable or disable the left arrow as the assignment operator.
	If it is disabled, the glyph in the default font is changed
	to the more familiar underscore."
	"Scanner assignmentLeftArrow: false"

	aBoolean | self assignmentColonEquals ifFalse: [^self error: 'You cannot switch off both kinds of assignment operator!!'].
	TypeTable at: $_ asInteger put:
		(aBoolean ifTrue: [#leftArrow] ifFalse: [#xLetter]).
	(TextStyle default fontAt: 1) characterFormAt: $_ put: (Form
		extent: 8@15
		fromArray: (aBoolean
			ifTrue: [#( 0 0 0 0 536870912 1073741824 4227858432 1073741824 536870912 0 0 0)]
			ifFalse: [#( 0 0 0 0 0 0 0 0 0 4227858432 0 0 0 0 0)])
		offset: 0@0)! !
!Scanner class methodsFor: 'testing'!
isLiteralSymbol: aSymbol 
	"Test whether a symbol can be stored as # followed by its characters.  
	Symbols created internally with asSymbol may not have this property, 
	e.g. '3' asSymbol."

	| i ascii type |
	i _ aSymbol size.
	i = 0 ifTrue: [^false].
	ascii _ (aSymbol at: 1) asciiValue.
	"TypeTable should have been origined at 0 rather than 1 ..."
	ascii = 0 ifTrue: [^false].
	type _ TypeTable at: ascii.
	(type == #colon or: [type == #xColon or: [type == #verticalBar]])
		ifTrue: [^i = 1].
	type == #xBinary
		ifTrue: 
			[[i > 1]
				whileTrue: 
					[ascii _ (aSymbol at: i) asciiValue.
					ascii = 0 ifTrue: [^false].
					(TypeTable at: ascii) == #xBinary ifFalse: [^false].
					i _ i - 1].
			^true].
	type == #xLetter
		ifTrue: 
			[[i > 1]
				whileTrue: 
					[ascii _ (aSymbol at: i) asciiValue.
					ascii = 0 ifTrue: [^false].
					type _ TypeTable at: ascii.
					(type == #xLetter or: [type == #xDigit or: [type == #colon or: [type == #xColon]]])
						ifFalse: [^false].
					i _ i - 1].
			^true].
	^false! !

!String methodsFor: 'converting'!
convertLeftArrows
	"Return a String where all assignment operators are changed
	from _ to :=. Literals and comments are not converted."

	| out inString inComment inCharacter |
	out _ WriteStream on: (String new: self size + 30).
	inString _ inComment _ inCharacter _ false.
	self do: [:char |
		inString		ifTrue: [char = $' ifTrue: [inString _ false]] ifFalse: [
		inComment	ifTrue: [char = $" ifTrue: [inComment _ false]] ifFalse: [
		inCharacter	ifTrue: [inCharacter _ false] ifFalse: [
		char = $'	ifTrue: [inString _ true] ifFalse: [
		char = $"	ifTrue: [inComment _ true] ifFalse: [
		char = $$	ifTrue: [inCharacter _ true] ifFalse: [
		char = $#	ifTrue: [inCharacter _ true] ifFalse: [
		char = $_	ifTrue: [out nextPutAll: ':='. char _ nil]]]]]]]].
		char == nil ifFalse: [out nextPut: char]].
	^out contents! !


--
+--- Hans-Martin Mosner ---- Senior Smalltalk Guru :-) ---+
| These opinions are entirely ficticious.  Any similarity |
| to real opinions is purely coincidental and unintended. |
+--- <hmm@heeg.de> ------ URL:http://www.heeg.de/~hmm/ ---+
