@@ -7,6 +7,7 @@ use nom::{
7
7
error:: context,
8
8
multi:: { many1, separated_list0} ,
9
9
sequence:: { delimited, preceded, separated_pair, terminated, tuple} ,
10
+ InputTakeAtPosition ,
10
11
} ;
11
12
12
13
use crate :: { ast:: * , parser:: * } ;
@@ -49,11 +50,17 @@ impl<'i> Parser<'i> for Identifier<'i> {
49
50
impl < ' i > Identifier < ' i > {
50
51
/// Like `Identifier::parse` except it doesn't check if the identifier is a reserved keyword.
51
52
fn parse_maybe_reserved ( i : Input < ' i > ) -> Result < Self > {
53
+ /// These characters aren't allowed in identifiers.
54
+ fn not_allowed_in_identifier < T : nom_unicode:: IsChar > ( item : T ) -> bool {
55
+ let i = item. as_char ( ) ;
56
+ !i. is_alphanumeric ( ) && i != '_'
57
+ }
58
+
52
59
let parser = preceded (
53
- // Identifiers cannot start with a number
60
+ // Identifiers must start with an alphabetic character.
54
61
nom_unicode:: complete:: alpha1,
55
- // But after the first char, they can include numbers.
56
- nom_unicode :: complete :: alphanumeric0 ,
62
+ // But after the first char, they can include numbers and underscores .
63
+ | i : Input < ' i > | i . split_at_position_complete ( not_allowed_in_identifier ) ,
57
64
) ;
58
65
map ( recognize ( parser) , Self ) ( i)
59
66
}
@@ -536,6 +543,15 @@ in y"#,
536
543
assert_parse ( ref_to_tests)
537
544
}
538
545
546
+ #[ test]
547
+ fn test_valid_variables ( ) {
548
+ let tests = vec ! [ (
549
+ Identifier :: from_span( "n_hello" , 0 , 1 ) ,
550
+ Input :: new( "n_hello" ) ,
551
+ ) ] ;
552
+ assert_parse :: < Identifier > ( tests)
553
+ }
554
+
539
555
#[ test]
540
556
fn test_invalid_variables ( ) {
541
557
let invalid_binding_names = [
@@ -546,8 +562,6 @@ in y"#,
546
562
"let" ,
547
563
"in" ,
548
564
"0000000aassdfasdfasdfasdf013423452342134234234234" ,
549
- // TODO: fix this, it should be valid.
550
- "n_hello" ,
551
565
] ;
552
566
for identifier in invalid_binding_names {
553
567
let i = format ! ( "{identifier} = 100" ) ;
0 commit comments