[Pkg] The Trunk: Kernel-nice.394.mcz

commits at source.squeak.org commits at source.squeak.org
Sat Feb 13 00:22:39 UTC 2010


Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-nice.394.mcz

==================== Summary ====================

Name: Kernel-nice.394
Author: nice
Time: 13 February 2010, 1:22:00.832 am
UUID: 9e50f78e-d3dd-6245-853f-549a3e120d59
Ancestors: Kernel-nice.393

Comment the NumberParser classes and subclasses.
Add an ExtendedNumberParser that can read all Squeak numbers plus numbers like these:

+1
+1.
+1.e-2
1.e+2
.1
-.1e3
3r.02
3r-1.e-2
.1s2
+1.s3

Cerise sur le gâteau:
   +10r+1.e+2
(use only if you really feel positive)

Now we just have to decide where to connect this ExtendedNumberParser.
It cannot be used in Parser because it would currently gobble the sentence period separator after a digit....
Either we connect it directly in String>>#asNumber
Or we change Parser to use a #smalltalkReadFrom: or SqNumberParser instead of Number>>#readFrom:.

=============== Diff against Kernel-nice.393 ===============

Item was added:
+ ----- Method: ExtendedNumberParser>>nextNumber (in category 'parsing-public') -----
+ nextNumber
+ 	"main method for reading a number.
+ 	This one can read Float Integer and ScaledDecimal"
+ 	
+ 	| numberOfTrailingZeroInIntegerPart |
+ 	base := 10.
+ 	neg := self peekSignIsMinus.
+ 	integerPart := self nextUnsignedIntegerOrNilBase: base.
+ 	integerPart ifNil: [(sourceStream peekFor: $.)
+ 		ifTrue: [
+ 			"Try .1 syntax"
+ 			^self readNumberWithoutIntegerPart]
+ 		ifFalse: [
+ 			"This is not a regular number beginning with a digit
+ 			It is time to check for exceptional condition NaN and Infinity"
+ 			^self readNamedFloatOrFail]].
+ 	numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.
+ 	(sourceStream peekFor: $r)
+ 		ifTrue: ["<base>r<integer>"
+ 			(base := integerPart) < 2
+ 				ifTrue: [^ self expected: 'an integer greater than 1 as valid radix'].
+ 			(self peekSignIsMinus)
+ 				ifTrue: [neg := neg not].
+ 			integerPart := self nextUnsignedIntegerOrNilBase: base.
+ 			integerPart ifNil: [
+ 				(sourceStream peekFor: $.) ifTrue: [^self readNumberWithoutIntegerPart].
+ 				^self expected: ('a digit between 0 and ' copyWith: (Character digitValue: base - 1))].
+ 			numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero].
+ 	^ (sourceStream peekFor: $.)
+ 		ifTrue: [self readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart]
+ 		ifFalse: [self makeIntegerOrScaledInteger]!

Item was added:
+ SqNumberParser subclass: #ExtendedNumberParser
+ 	instanceVariableNames: ''
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Kernel-Numbers'!
+ 
+ !ExtendedNumberParser commentStamp: 'nice 2/13/2010 00:39' prior: 0!
+ An ExtendedNumberParser is extending Squeak number syntax with these rules
+ 
+ - allow partial specification of integer and fraction parts:
+ 1.e2 .1e3 are both 100.0
+ - allow plus sign before number and in exponent
+ 
+ !

Item was added:
+ ----- Method: ExtendedNumberParser>>readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: (in category 'parsing-private') -----
+ readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart
+ 	"at this stage, sign integerPart and a decimal point have been read.
+ 	try and form a number with a fractionPart"
+ 	
+ 	| numberOfNonZeroFractionDigits numberOfTrailingZeroInFractionPart mantissa value |
+ 	fractionPart := self nextUnsignedIntegerOrNilBase: base.
+ 	fractionPart
+ 		ifNil: [
+ 			"No fractionPart found, but can be a 1.e2 syntax"
+ 			fractionPart := 0.
+ 			numberOfNonZeroFractionDigits := 0.
+ 			numberOfTrailingZeroInFractionPart := 0]
+ 		ifNotNil: [.
+ 			numberOfNonZeroFractionDigits := lastNonZero.
+ 			numberOfTrailingZeroInFractionPart := nDigits - lastNonZero].
+ 	self readExponent
+ 		ifFalse: [self readScale
+ 				ifTrue: [^self makeScaledDecimalWithNumberOfNonZeroFractionDigits: numberOfNonZeroFractionDigits
+ 					andNumberOfTrailingZeroInFractionPart: numberOfTrailingZeroInFractionPart]].
+ 
+ 	fractionPart isZero
+ 		ifTrue: [mantissa := integerPart
+ 						// (base raisedToInteger: numberOfTrailingZeroInIntegerPart).
+ 			exponent := exponent + numberOfTrailingZeroInIntegerPart]
+ 		ifFalse: [mantissa := integerPart
+ 						* (base raisedToInteger: numberOfNonZeroFractionDigits) + (fractionPart // (base raisedToInteger: numberOfTrailingZeroInFractionPart)).
+ 			exponent := exponent - numberOfNonZeroFractionDigits].
+ 
+ 	value := self makeFloatFromMantissa: mantissa exponent: exponent base: base.
+ 	^ neg
+ 		ifTrue: [value isZero
+ 				ifTrue: [Float negativeZero]
+ 				ifFalse: [value negated]]
+ 		ifFalse: [value]!

Item was changed:
  NumberParser subclass: #FORTRANNumberParser
  	instanceVariableNames: ''
  	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'Kernel-Numbers'!
+ 
+ !FORTRANNumberParser commentStamp: 'nice 2/13/2010 00:28' prior: 0!
+ FORTRANNumberParser is able to parse ASCII representation of numbers generated by FORTRAN programs.
+ 
+ Possible syntax:
+ 	digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ;
+ 	sign =  '+' | '-';
+ 	integer = [sign] digit{digit} ;
+ 	float = [sign] [digit{digit}] ['.'] digit{digit} [('E' | 'D' ) [sign] digit{digit} ] ;
+ 	number = integer | float ;
+ 	
+ Examples:
+ 	124
+ 	+124
+ 	-124
+ 	1.0
+ 	1.
+ 	.23
+ 	1E+5
+ 	1.0E-3
+ 	.1E-22
+ 	3.01D+55
+ 
+ Not accepted: exponent letter is sometimes omitted for double precision with 3 digits exponent...
+ 	1.001-123
+ 
+ Not accepted: complex numbers into parentheses
+ 	(1.0 , 3.11)
+ !

Item was changed:
  ----- Method: SqNumberParser>>nextNumber (in category 'parsing-public') -----
  nextNumber
  	"main method for reading a number.
  	This one can read Float Integer and ScaledDecimal"
  	
  	| numberOfTrailingZeroInIntegerPart |
  	base := 10.
+ 	neg := self peekSignIsMinus.
- 	neg := sourceStream peekFor: $-.
  	integerPart := self nextUnsignedIntegerOrNilBase: base.
  	integerPart ifNil: [
  		"This is not a regular number beginning with a digit
  		It is time to check for exceptional condition NaN and Infinity"
  		^self readNamedFloatOrFail].
  	numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero.
  	(sourceStream peekFor: $r)
  		ifTrue: ["<base>r<integer>"
  			(base := integerPart) < 2
  				ifTrue: [^ self expected: 'an integer greater than 1 as valid radix'].
  			(sourceStream peekFor: $-)
  				ifTrue: [neg := neg not].
  			integerPart := self nextUnsignedIntegerBase: base.
  			numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero].
  	^ (sourceStream peekFor: $.)
  		ifTrue: [self readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart]
  		ifFalse: [self makeIntegerOrScaledInteger]!

Item was changed:
  NumberParser subclass: #SqNumberParser
  	instanceVariableNames: ''
  	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'Kernel-Numbers'!
  
+ !SqNumberParser commentStamp: 'nice 2/13/2010 00:36' prior: 0!
+ SqNumberParser is a NumberParser specialized in reading Number with Squeak syntax.
- !SqNumberParser commentStamp: 'nice 7/26/2009 01:06' prior: 0!
- This is a class specialized in parsing and building numbers.
- Number syntax should follow Smalltalk syntax with 'NaN' and 'Infinity' extensions.
  
+ Squeak syntax follows general Smalltalk-80 conventions for integer and floats, extended with scaled decimals.
+ Noticeable differences with st-80 and other Smalltalks are:
+ - allow both 2r-10 and -2r10 and even -2r-10
+ - allow floating point with radix 2r10.011
+ - do not allow single s without following digits as ScaledDecimal
+ - handle special case of Float (NaN Infinity and -0.0 as negative zero)!
- If you have to read foreign number syntax, create a subclass.
- 
- Instance variables:
- sourceStream <Stream> the stream of characters from which the number is read
- base <Integer> the radix in which to interpret digits
- neg <Boolean> true in case of minus sign
- integerPart <Integer> the integer part of the number
- fractionPart <Integer> the fraction part of the number if any
- exponent <Integer> the exponent used in scientific notation if any
- scale <Integer> the scale used in case of ScaledDecimal number if any
- nDigits <Integer> number of digits read to form an Integer
- lasNonZero <Integer> position of last non zero digit, starting at 1 from left, 0 if all digits are zero
- requestor <?> could eventually be used to insert an error message in a text editor
- failBlock <BlockClosure> Block to execute whenever an error occurs!

Item was added:
+ ----- Method: ExtendedNumberParser>>allowPlusSign (in category 'accessing') -----
+ allowPlusSign
+ 	^true!

Item was changed:
  Object subclass: #NumberParser
  	instanceVariableNames: 'sourceStream base neg integerPart fractionPart exponent scale nDigits lastNonZero requestor failBlock'
  	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'Kernel-Numbers'!
  
+ !NumberParser commentStamp: 'nice 2/13/2010 00:31' prior: 0!
+ NumberParser is an abstract class for parsing and building numbers from string/stream.
+ It offers a framework with utility methods and exception handling.
- !NumberParser commentStamp: 'nice 7/26/2009 01:06' prior: 0!
- This is a class specialized in parsing and building numbers.
- Number syntax should follow Smalltalk syntax with 'NaN' and 'Infinity' extensions.
  
+ Number syntax is not defined and should be subclassResponsibility.
- If you have to read foreign number syntax, create a subclass.
  
  Instance variables:
  sourceStream <Stream> the stream of characters from which the number is read
  base <Integer> the radix in which to interpret digits
  neg <Boolean> true in case of minus sign
  integerPart <Integer> the integer part of the number
  fractionPart <Integer> the fraction part of the number if any
  exponent <Integer> the exponent used in scientific notation if any
  scale <Integer> the scale used in case of ScaledDecimal number if any
  nDigits <Integer> number of digits read to form an Integer
  lasNonZero <Integer> position of last non zero digit, starting at 1 from left, 0 if all digits are zero
  requestor <?> could eventually be used to insert an error message in a text editor
  failBlock <BlockClosure> Block to execute whenever an error occurs!

Item was added:
+ ----- Method: ExtendedNumberParser>>readNumberWithoutIntegerPart (in category 'parsing-private') -----
+ readNumberWithoutIntegerPart
+ 	"at this stage, sign followed by a decimal point have been read, but no intergerPart
+ 	try and form a number with a fractionPart"
+ 	
+ 	| numberOfNonZeroFractionDigits numberOfTrailingZeroInFractionPart mantissa value |
+ 	integerPart := 0.
+ 	fractionPart := self nextUnsignedIntegerOrNilBase: base.
+ 	fractionPart ifNil: [
+ 		"No integer part, no fractionPart, this does not look like a number..."
+ 		^self expected: 'a digit between 0 and 9'].
+ 	numberOfNonZeroFractionDigits := lastNonZero.
+ 	numberOfTrailingZeroInFractionPart := nDigits - lastNonZero.
+ 	self readExponent
+ 		ifFalse: [self readScale
+ 				ifTrue: [^self makeScaledDecimalWithNumberOfNonZeroFractionDigits: numberOfNonZeroFractionDigits
+ 					andNumberOfTrailingZeroInFractionPart: numberOfTrailingZeroInFractionPart]].
+ 
+ 	fractionPart isZero
+ 		ifTrue: [mantissa := 0]
+ 		ifFalse: [mantissa := (fractionPart // (base raisedToInteger: numberOfTrailingZeroInFractionPart)).
+ 			exponent := exponent - numberOfNonZeroFractionDigits].
+ 
+ 	value := self makeFloatFromMantissa: mantissa exponent: exponent base: base.
+ 	^ neg
+ 		ifTrue: [value isZero
+ 				ifTrue: [Float negativeZero]
+ 				ifFalse: [value negated]]
+ 		ifFalse: [value]!



More information about the Packages mailing list