@@ -758,7 +758,18 @@ pub struct Comment {
758758 pub multi_line : bool ,
759759}
760760
761+ impl Comment {
762+ pub ( crate ) fn is_start_of_ignored_region ( & self ) -> bool {
763+ self . value . trim ( ) == "vhdl_ls off"
764+ }
765+
766+ pub ( crate ) fn is_end_of_ignored_region ( & self ) -> bool {
767+ self . value . trim ( ) == "vhdl_ls on"
768+ }
769+ }
770+
761771use crate :: standard:: VHDLStandard ;
772+ use itertools:: Itertools ;
762773use std:: convert:: AsRef ;
763774use std:: fmt:: { Debug , Display , Formatter } ;
764775use std:: ops:: { Add , AddAssign , Sub } ;
@@ -889,6 +900,45 @@ impl Token {
889900 pub fn equal_format ( & self , other : & Token ) -> bool {
890901 self . kind == other. kind && self . value == other. value
891902 }
903+
904+ pub ( crate ) fn leading_is_start_of_ignored_region ( & self ) -> bool {
905+ let Some ( comments) = & self . comments else {
906+ return false ;
907+ } ;
908+ if let Some ( ( index, _) ) = comments
909+ . leading
910+ . iter ( )
911+ . find_position ( |comment| comment. is_start_of_ignored_region ( ) )
912+ {
913+ // This construct guards against the case where we have a `vhdl_ls on` in the same
914+ // comment block after a a `vhdl_ls off`
915+ !comments. leading [ index..]
916+ . iter ( )
917+ . any ( Comment :: is_end_of_ignored_region)
918+ } else {
919+ false
920+ }
921+ }
922+
923+ pub ( crate ) fn leading_is_end_of_ignored_region ( & self ) -> bool {
924+ let Some ( comments) = & self . comments else {
925+ return false ;
926+ } ;
927+ comments
928+ . leading
929+ . iter ( )
930+ . any ( Comment :: is_end_of_ignored_region)
931+ }
932+
933+ pub ( crate ) fn trailing_is_end_of_ignored_region ( & self ) -> bool {
934+ let Some ( comments) = & self . comments else {
935+ return false ;
936+ } ;
937+ comments
938+ . trailing
939+ . as_ref ( )
940+ . is_some_and ( Comment :: is_end_of_ignored_region)
941+ }
892942}
893943
894944impl Operator {
@@ -1973,7 +2023,38 @@ impl<'a> Tokenizer<'a> {
19732023
19742024 pub fn pop ( & mut self ) -> DiagnosticResult < Option < Token > > {
19752025 match self . pop_raw ( ) {
1976- Ok ( token) => Ok ( token) ,
2026+ Ok ( None ) => Ok ( None ) ,
2027+ Ok ( Some ( token) ) => {
2028+ if token. leading_is_start_of_ignored_region ( ) {
2029+ if !token. trailing_is_end_of_ignored_region ( ) {
2030+ loop {
2031+ match self . pop_raw ( ) {
2032+ Ok ( None ) => {
2033+ // Note: we should probably emit an unterminated error here
2034+ // instead of silently failing.
2035+ return Ok ( None ) ;
2036+ }
2037+ Ok ( Some ( tok) ) => {
2038+ if tok. trailing_is_end_of_ignored_region ( ) {
2039+ break ;
2040+ } else if tok. leading_is_end_of_ignored_region ( ) {
2041+ // Note: to be pedantic, the 'vhdl_ls on' should be
2042+ // removed from the comments. However, because we have
2043+ // no public API and the comments don't really play
2044+ // a crucial role in the language server or binary,
2045+ // we just emit the token for simplicity.
2046+ return Ok ( Some ( tok) ) ;
2047+ }
2048+ }
2049+ Err ( _) => { }
2050+ }
2051+ }
2052+ }
2053+ self . pop ( )
2054+ } else {
2055+ Ok ( Some ( token) )
2056+ }
2057+ }
19772058 Err ( err) => {
19782059 self . state . start = self . reader . state ( ) ;
19792060 Err ( Diagnostic :: syntax_error (
@@ -3106,4 +3187,63 @@ entity -- €
31063187 vec![ View , Default ]
31073188 ) ;
31083189 }
3190+
3191+ #[ test]
3192+ fn ignore_code_in_between_explicitly_ignored_regions ( ) {
3193+ let tokens = kinds_tokenize (
3194+ "\
3195+ entity foo is
3196+ --vhdl_ls off
3197+ I am ignored cod€
3198+ --vhdl_ls on
3199+ end foo;
3200+ " ,
3201+ ) ;
3202+ assert_eq ! (
3203+ & tokens,
3204+ & [ Entity , Identifier , Is , End , Identifier , SemiColon ]
3205+ ) ;
3206+
3207+ let tokens = kinds_tokenize (
3208+ "\
3209+ before Is
3210+ --vhdl_ls off
3211+ single_token
3212+ --vhdl_ls on
3213+ End after
3214+ " ,
3215+ ) ;
3216+ assert_eq ! ( & tokens, & [ Identifier , Is , End , After ] ) ;
3217+ }
3218+
3219+ #[ test]
3220+ fn ignore_code_without_on ( ) {
3221+ // This should potentially emit a warning, but for now we just silently
3222+ // ignore that there should be a `vhdl_ls on` at some point.
3223+ let tokens = kinds_tokenize (
3224+ "\
3225+ before Is
3226+ --vhdl_ls off
3227+ single_token
3228+ End after
3229+ " ,
3230+ ) ;
3231+ assert_eq ! ( & tokens, & [ Identifier , Is ] ) ;
3232+ }
3233+
3234+ #[ test]
3235+ fn on_directly_after_off ( ) {
3236+ // This should potentially emit a warning, but for now we just silently
3237+ // ignore that there should be a `vhdl_ls on` at some point.
3238+ let tokens = kinds_tokenize (
3239+ "\
3240+ before Is
3241+ --vhdl_ls off
3242+ --vhdl_ls on
3243+ single_token
3244+ End after
3245+ " ,
3246+ ) ;
3247+ assert_eq ! ( & tokens, & [ Identifier , Is , Identifier , End , After ] ) ;
3248+ }
31093249}
0 commit comments