@@ -19,13 +19,47 @@ pub struct TokenStream<'a> {
1919}
2020
2121impl < ' a > TokenStream < ' a > {
22+ /// Special handling for a tool directive of the form
23+ /// ```vhdl
24+ /// `identifier { any chars until newline }
25+ /// ```
26+ /// This needs special handling as the text that follows the identifier is arbitrary.
27+ fn handle_tool_directive (
28+ grave_accent : Token ,
29+ tokenizer : & mut Tokenizer ,
30+ diagnostics : & mut dyn DiagnosticHandler ,
31+ ) {
32+ let start_pos = grave_accent. pos . clone ( ) ;
33+ match tokenizer. pop ( ) {
34+ Ok ( Some ( tok) ) => {
35+ if tok. kind != Identifier {
36+ diagnostics. error ( tok, "Expecting identifier" ) ;
37+ let _ = tokenizer. text_until_newline ( ) ; // skip potentially invalid tokens
38+ return ;
39+ }
40+ }
41+ Err ( err) => diagnostics. push ( err) ,
42+ Ok ( None ) => {
43+ diagnostics. error ( start_pos, "Expecting identifier" ) ;
44+ return ;
45+ }
46+ }
47+ match tokenizer. text_until_newline ( ) {
48+ Ok ( _) => { }
49+ Err ( err) => diagnostics. push ( err) ,
50+ }
51+ }
52+
2253 pub fn new (
2354 mut tokenizer : Tokenizer < ' a > ,
2455 diagnostics : & mut dyn DiagnosticHandler ,
2556 ) -> TokenStream < ' a > {
2657 let mut tokens = Vec :: new ( ) ;
2758 loop {
2859 match tokenizer. pop ( ) {
60+ Ok ( Some ( token) ) if token. kind == GraveAccent => {
61+ TokenStream :: handle_tool_directive ( token, & mut tokenizer, diagnostics)
62+ }
2963 Ok ( Some ( token) ) => tokens. push ( token) ,
3064 Ok ( None ) => break ,
3165 Err ( err) => diagnostics. push ( err) ,
@@ -259,6 +293,12 @@ mod tests {
259293 let tokenizer = Tokenizer :: new( & $code. symbols, source, ContentReader :: new( & contents) ) ;
260294 let $stream = TokenStream :: new( tokenizer, & mut NoDiagnostics ) ;
261295 } ;
296+ ( $code: ident, $stream: ident, $diagnostics: ident) => {
297+ let source = $code. source( ) ;
298+ let contents = source. contents( ) ;
299+ let tokenizer = Tokenizer :: new( & $code. symbols, source, ContentReader :: new( & contents) ) ;
300+ let $stream = TokenStream :: new( tokenizer, & mut $diagnostics) ;
301+ } ;
262302 }
263303
264304 #[ test]
@@ -388,4 +428,38 @@ mod tests {
388428 assert ! ( stream. skip_until( |ref k| matches!( k, Plus ) ) . is_ok( ) ) ;
389429 assert_eq ! ( stream. peek( ) . map( |t| t. kind) , Some ( Plus ) ) ;
390430 }
431+
432+ #[ test]
433+ fn tokenize_simple_identifier_directive ( ) {
434+ let code = Code :: new ( "`protect begin" ) ;
435+ new_stream ! ( code, _stream) ;
436+ }
437+
438+ #[ test]
439+ fn tokenize_extended_identifier_directive ( ) {
440+ let code = Code :: new ( "`\\ extended ident\\ begin other words" ) ;
441+ new_stream ! ( code, _stream) ;
442+ }
443+
444+ #[ test]
445+ fn tokenize_directive_illegal_identifier ( ) {
446+ let code = Code :: new ( "`123 begin other words" ) ;
447+ let mut diagnostics: Vec < Diagnostic > = vec ! [ ] ;
448+ new_stream ! ( code, _stream, diagnostics) ;
449+ assert_eq ! (
450+ diagnostics,
451+ vec![ Diagnostic :: error( code. s1( "123" ) , "Expecting identifier" ) ]
452+ )
453+ }
454+
455+ #[ test]
456+ fn tokenize_directive_then_end_of_stream ( ) {
457+ let code = Code :: new ( "`" ) ;
458+ let mut diagnostics: Vec < Diagnostic > = vec ! [ ] ;
459+ new_stream ! ( code, _stream, diagnostics) ;
460+ assert_eq ! (
461+ diagnostics,
462+ vec![ Diagnostic :: error( code. s1( "`" ) , "Expecting identifier" ) ]
463+ )
464+ }
391465}
0 commit comments