77import random
88import sys
99
10- from mathics_scanner .tokeniser import Tokeniser , Token
10+ from mathics_scanner .tokeniser import Tokeniser , Token , is_symbol_name
1111from mathics_scanner .errors import ScanError , IncompleteSyntaxError , InvalidSyntaxError
1212from mathics_scanner .feed import SingleLineFeeder
1313
1414
15+ def check_number (code ):
16+ token = single_token (code )
17+ assert token , Token ("Number" , code , 0 )
18+
19+
20+ def check_symbol (code ):
21+ token = single_token (code )
22+ assert token , Token ("Symbol" , code , 0 )
23+
24+
25+ def check_string (code ):
26+ token = single_token (code )
27+ assert token , Token ("String" , code , 0 )
28+
29+
30+ def incomplete_error (string ):
31+ with pytest .raises (IncompleteSyntaxError ):
32+ tokens (string )
33+
34+
35+ def invalid_error (string ):
36+ with pytest .raises (InvalidSyntaxError ):
37+ tokens (string )
38+
39+
40+ def scan_error (string ):
41+ with pytest .raises (ScanError ):
42+ tokens (string )
43+
44+
45+ def single_token (code ):
46+ toks = tokens (code )
47+ assert len (toks ) == 1
48+ token = toks [0 ]
49+ return token
50+
51+
52+ def tags (code ):
53+ return [token .tag for token in tokens (code )]
54+
55+
1556def tokens (code ):
1657 tokeniser = Tokeniser (SingleLineFeeder (code ))
1758 tokens = []
@@ -24,104 +65,134 @@ def tokens(code):
2465 return tokens
2566
2667
27- def tags (code ):
28- return [token .tag for token in tokens (code )]
68+ def test_apply ():
69+ assert tokens ("f // x" ) == [
70+ Token ("Symbol" , "f" , 0 ),
71+ Token ("Postfix" , "//" , 2 ),
72+ Token ("Symbol" , "x" , 5 ),
73+ ]
74+ assert tokens ("f @ x" ) == [
75+ Token ("Symbol" , "f" , 0 ),
76+ Token ("Prefix" , "@" , 2 ),
77+ Token ("Symbol" , "x" , 4 ),
78+ ]
79+ assert tokens ("f ~ x" ) == [
80+ Token ("Symbol" , "f" , 0 ),
81+ Token ("Infix" , "~" , 2 ),
82+ Token ("Symbol" , "x" , 4 ),
83+ ]
2984
3085
31- def single_token (code ):
32- toks = tokens (code )
33- assert len (toks ) == 1
34- token = toks [0 ]
35- return token
86+ def test_association ():
87+ assert tokens ("<|x -> m|>" ) == [
88+ Token ("RawLeftAssociation" , "<|" , 0 ),
89+ Token ("Symbol" , "x" , 2 ),
90+ Token ("Rule" , "->" , 4 ),
91+ Token ("Symbol" , "m" , 7 ),
92+ Token ("RawRightAssociation" , "|>" , 8 ),
93+ ]
3694
3795
38- def check_number (code ):
39- token = single_token (code )
40- assert token , Token ("Number" , code , 0 )
96+ def test_backslash ():
97+ assert tokens ("\\ [Backslash]" ) == [Token ("Backslash" , "\u2216 " , 0 )]
4198
99+ assert tokens ("\\ a" ) == [Token ("RawBackslash" , "\\ " , 0 ), Token ("Symbol" , "a" , 2 )]
42100
43- def check_symbol (code ):
44- token = single_token (code )
45- assert token , Token ("Symbol" , code , 0 )
101+ incomplete_error ("\\ " )
46102
47103
48- def check_string (code ):
49- token = single_token (code )
50- assert token , Token ("String" , code , 0 )
104+ def test_boxes ():
105+ assert tokens ("\\ (1\\ )" ) == [
106+ Token ("LeftRowBox" , "\\ (" , 0 ),
107+ Token ("Number" , "1" , 2 ),
108+ Token ("RightRowBox" , "\\ )" , 3 ),
109+ ]
51110
52111
53- def test_number ():
54- assert tags ("1.5" ) == ["Number" ]
55- assert tags ("1.5*^10" ) == ["Number" ]
112+ def test_information ():
113+ assert tokens ("??Sin" ) == [Token ("Information" , "??" , 0 ), Token ("Symbol" , "Sin" , 2 )]
56114
115+ assert tokens ("? ?Sin" ) == [
116+ Token ("PatternTest" , "?" , 0 ),
117+ Token ("PatternTest" , "?" , 2 ),
118+ Token ("Symbol" , "Sin" , 3 ),
119+ ]
57120
58- def scan_error (string ):
59- with pytest .raises (ScanError ):
60- tokens (string )
61121
122+ def test_int_repeated ():
123+ assert tokens ("1.." ) == [Token ("Number" , "1" , 0 ), Token ("Repeated" , ".." , 1 )]
124+ assert tokens ("1. ." ) == [Token ("Number" , "1." , 0 ), Token ("Dot" , "." , 3 )]
62125
63- def incomplete_error (string ):
64- with pytest .raises (IncompleteSyntaxError ):
65- tokens (string )
126+
127+ def test_integeral ():
128+ assert tokens ("\u222B x \uF74C y" ) == [
129+ Token ("Integral" , "\u222B " , 0 ),
130+ Token ("Symbol" , "x" , 2 ),
131+ Token ("DifferentialD" , "\uF74C " , 4 ),
132+ Token ("Symbol" , "y" , 6 ),
133+ ]
66134
67135
68- def invalid_error ( string ):
69- with pytest . raises ( InvalidSyntaxError ):
70- tokens ( string )
136+ def test_is_symbol ( ):
137+ assert is_symbol_name ( "Derivative" )
138+ assert not is_symbol_name ( "98" ) # symbols can't start with numbers
71139
72140
73- def testSymbol ():
74- check_symbol ( "xX " )
75- check_symbol ( "context`name " )
76- check_symbol ( "`name " )
77- check_symbol ( "`context`name " )
141+ def test_accuracy ():
142+ scan_error ( "1.5`` " )
143+ check_number ( "1.0``20 " )
144+ check_number ( "1.0``0 " )
145+ check_number ( "1.4``-20 " )
78146
79147
80- def testNumber ():
148+ def test_number ():
149+ assert tags ("1.5" ) == ["Number" ]
150+ assert tags ("1.5*^10" ) == ["Number" ]
81151 check_number ("0" )
82152
83153
84- def testNumberBase ():
154+ def test_number_base ():
85155 check_number ("8^^23" )
86156 check_number ("10*^3" )
87157 check_number ("10*^-3" )
88158 check_number ("8^^23*^2" )
89159
90160
91- def testNumberBig ():
161+ def test_number_big ():
92162 for _ in range (10 ):
93163 check_number (str (random .randint (0 , sys .maxsize )))
94164 check_number (str (random .randint (sys .maxsize , sys .maxsize * sys .maxsize )))
95165
96166
97- def testNumberReal ():
167+ def test_number_real ():
98168 check_number ("1.5" )
99169 check_number ("1.5`" )
100170 check_number ("0.0" )
101171
102172
103- def testString ():
104- check_string ( r'"abc"' )
105- incomplete_error ( r'"abc' )
106- check_string ( r'"abc(*def*)"' )
107- check_string ( r'"a\"b\\c"' )
108- incomplete_error ( r'"\"' )
173+ def test_pre ():
174+ assert tokens ( "++x++" ) == [
175+ Token ( "Increment" , "++" , 0 ),
176+ Token ( "Symbol" , "x" , 2 ),
177+ Token ( "Increment" , "++" , 3 ),
178+ ]
109179
110180
111- def testPrecision ():
181+ def test_precision ():
112182 check_number ("1.5`-5" )
113183 check_number ("1.5`0" )
114184 check_number ("1.5`10" )
115185
116186
117- def testAccuracy ():
118- scan_error ("1.5``" )
119- check_number ("1.0``20" )
120- check_number ("1.0``0" )
121- check_number ("1.4``-20" )
187+ def test_string ():
188+ check_string (r'"abc"' )
189+ incomplete_error (r'"abc' )
190+ check_string (r'"abc(*def*)"' )
191+ check_string (r'"a\"b\\c"' )
192+ incomplete_error (r'"\"' )
122193
123194
124- def testSet ():
195+ def test_set ():
125196 assert tokens ("x = y" ) == [
126197 Token ("Symbol" , "x" , 0 ),
127198 Token ("Set" , "=" , 2 ),
@@ -136,93 +207,24 @@ def testSet():
136207 ]
137208
138209
139- def testUnset ():
210+ def test_symbol ():
211+ check_symbol ("xX" )
212+ check_symbol ("context`name" )
213+ check_symbol ("`name" )
214+ check_symbol ("`context`name" )
215+
216+
217+ def test_unset ():
140218 assert tokens ("=." ) == [Token ("Unset" , "=." , 0 )]
141219
142220 assert tokens ("= ." ) == [Token ("Unset" , "= ." , 0 )]
143221 assert tokens ("=.5" ) == [Token ("Set" , "=" , 0 ), Token ("Number" , ".5" , 1 )]
144222 assert tokens ("= .." ) == [Token ("Set" , "=" , 0 ), Token ("Repeated" , ".." , 2 )]
145223
146224
147- def testIntRepeated ():
148- assert tokens ("1.." ) == [Token ("Number" , "1" , 0 ), Token ("Repeated" , ".." , 1 )]
149- assert tokens ("1. ." ) == [Token ("Number" , "1." , 0 ), Token ("Dot" , "." , 3 )]
150-
151-
152- def testIntegeral ():
153- assert tokens ("\u222B x \uF74C y" ) == [
154- Token ("Integral" , "\u222B " , 0 ),
155- Token ("Symbol" , "x" , 2 ),
156- Token ("DifferentialD" , "\uF74C " , 4 ),
157- Token ("Symbol" , "y" , 6 ),
158- ]
159-
160-
161- def testPre ():
162- assert tokens ("++x++" ) == [
163- Token ("Increment" , "++" , 0 ),
164- Token ("Symbol" , "x" , 2 ),
165- Token ("Increment" , "++" , 3 ),
166- ]
167-
168-
169- def testFunction ():
225+ def test_function ():
170226 assert tokens ("x&" ) == [Token ("Symbol" , "x" , 0 ), Token ("Function" , "&" , 1 )]
171227 assert tokens ("x\uf4a1 " ) == [
172228 Token ("Symbol" , "x" , 0 ),
173229 Token ("Function" , "\uf4a1 " , 1 ),
174230 ]
175-
176-
177- def testApply ():
178- assert tokens ("f // x" ) == [
179- Token ("Symbol" , "f" , 0 ),
180- Token ("Postfix" , "//" , 2 ),
181- Token ("Symbol" , "x" , 5 ),
182- ]
183- assert tokens ("f @ x" ) == [
184- Token ("Symbol" , "f" , 0 ),
185- Token ("Prefix" , "@" , 2 ),
186- Token ("Symbol" , "x" , 4 ),
187- ]
188- assert tokens ("f ~ x" ) == [
189- Token ("Symbol" , "f" , 0 ),
190- Token ("Infix" , "~" , 2 ),
191- Token ("Symbol" , "x" , 4 ),
192- ]
193-
194-
195- def testBackslash ():
196- assert tokens ("\\ [Backslash]" ) == [Token ("Backslash" , "\u2216 " , 0 )]
197-
198- assert tokens ("\\ a" ) == [Token ("RawBackslash" , "\\ " , 0 ), Token ("Symbol" , "a" , 2 )]
199-
200- incomplete_error ("\\ " )
201-
202-
203- def testBoxes ():
204- assert tokens ("\\ (1\\ )" ) == [
205- Token ("LeftRowBox" , "\\ (" , 0 ),
206- Token ("Number" , "1" , 2 ),
207- Token ("RightRowBox" , "\\ )" , 3 ),
208- ]
209-
210-
211- def testInformation ():
212- assert tokens ("??Sin" ) == [Token ("Information" , "??" , 0 ), Token ("Symbol" , "Sin" , 2 )]
213-
214- assert tokens ("? ?Sin" ) == [
215- Token ("PatternTest" , "?" , 0 ),
216- Token ("PatternTest" , "?" , 2 ),
217- Token ("Symbol" , "Sin" , 3 ),
218- ]
219-
220-
221- def testAssociation ():
222- assert tokens ("<|x -> m|>" ) == [
223- Token ("RawLeftAssociation" , "<|" , 0 ),
224- Token ("Symbol" , "x" , 2 ),
225- Token ("Rule" , "->" , 4 ),
226- Token ("Symbol" , "m" , 7 ),
227- Token ("RawRightAssociation" , "|>" , 8 ),
228- ]
0 commit comments