#!/usr/bin/tclsh # Copyright JS Foundation and other contributors, http://js.foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # switch-case foreach fileName [getSourceFileNames] { set is_in_comment "no" set is_in_pp_define "no" foreach token [getTokens $fileName 1 0 -1 -1 {}] { set type [lindex $token 3] set lineNumber [lindex $token 1] if {$is_in_comment == "yes"} { set is_in_comment "no" } if {$type == "newline"} { set is_in_pp_define "no" } elseif {$type == "ccomment"} { set is_in_comment "yes" } elseif {[string first "pp_" $type] == 0} { if {$type == "pp_define"} { set is_in_pp_define "yes" } } elseif {$type == "space"} { } elseif {$type != "eof"} { if {$is_in_pp_define == "no" && $type == "switch"} { set next_token_start [lindex $token 2] incr next_token_start 1 set line_num 0 set state "switch" set case_block "no" set seen_braces 0 foreach next_token [getTokens $fileName $lineNumber $next_token_start -1 -1 {}] { set next_token_type [lindex $next_token 3] set next_token_value [lindex $next_token 0] if {$state == "switch"} { if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { continue } elseif {$next_token_type == "leftbrace"} { set state "first-case" continue } else { # TODO: check switch continue } } elseif {$state == "first-case"} { if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { continue } elseif {$next_token_type == "case"} { set state "case" continue } elseif {$next_token_type == "default"} { set state "default" continue } else { # Macros magic: give up break } } elseif {$state == "case"} { if {$next_token_type == "space"} { set state "space-after-case" continue } else { report $fileName [lindex $next_token 1] "There should be single space character after 'case' keyword (state $state)" } } elseif {$state == "space-after-case"} { if {$next_token_type != "identifier" && $next_token_type != "intlit" && $next_token_type != "charlit" && $next_token_type != "sizeof"} { report $fileName [lindex $next_token 1] "There should be single space character after 'case' keyword (state $state, next_token_type $next_token_type)" } else { set state "case-label" continue } } elseif {$state == "case-label" || $state == "default"} { set case_block "no" if {$next_token_type != "colon"} { continue } else { set state "colon" continue } } elseif {$state == "after-colon-preprocessor"} { if {$next_token_type == "newline"} { set state "colon" } } elseif {$state == "colon"} { if {$next_token_type == "space" || $next_token_type == "newline"} { continue } elseif {$next_token_type == "ccomment"} { if {[string match "*FALL*" $next_token_value]} { set state "fallthru" set line_num [lindex $next_token 1] continue } else { continue } } elseif {$next_token_type == "case"} { set state "case" continue } elseif {$next_token_type == "default"} { set state "default" continue } elseif {$next_token_type == "leftbrace"} { set case_block "yes" set state "wait-for-break" continue } elseif {$next_token_type == "identifier"} { if {[string compare "JERRY_UNREACHABLE" $next_token_value] == 0 || [string first "JERRY_UNIMPLEMENTED" $next_token_value] == 0} { set state "wait-for-semicolon" continue } else { set state "wait-for-break" continue } } elseif {$next_token_type == "break" || $next_token_type == "continue" || $next_token_type == "return"} { set state "wait-for-semicolon" continue } elseif {[string first "pp_" $next_token_type] == 0} { set state "after-colon-preprocessor" } else { set state "wait-for-break" continue } } elseif {$state == "wait-for-semicolon"} { if {$next_token_type == "semicolon"} { set state "break" } continue } elseif {$state == "wait-for-break"} { if {$next_token_type == "case" || $next_token_type == "default"} { report $fileName [lindex $next_token 1] "Missing break, continue or FALLTHRU comment before case (state $state)" } elseif {$next_token_type == "leftbrace"} { set state "inside-braces" incr seen_braces 1 continue } elseif {$next_token_type == "rightbrace"} { if {$case_block == "yes"} { set state "case-blocks-end" continue } else { break } } elseif {[string compare "JERRY_UNREACHABLE" $next_token_value] == 0 || [string first "JERRY_UNIMPLEMENTED" $next_token_value] == 0} { set state "wait-for-semicolon" continue } elseif {$next_token_type == "ccomment" && [string match "*FALL*" $next_token_value]} { set state "fallthru" set line_num [lindex $next_token 1] continue } elseif {$next_token_type == "break" || $next_token_type == "continue" || $next_token_type == "return" || $next_token_type == "goto"} { set state "wait-for-semicolon" continue } continue } elseif {$state == "break" || $state == "fallthru"} { if {$case_block == "no"} { if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { continue } elseif {$next_token_type == "case"} { set state "case" continue } elseif {$next_token_type == "default"} { set state "default" continue } elseif {$next_token_type == "leftbrace"} { set state "inside-braces" incr seen_braces 1 continue } elseif {$next_token_type == "rightbrace"} { lappend switch_ends [lindex $next_token 1] break } elseif {$next_token_type == "break" || $next_token_type == "continue" || $next_token_type == "return"} { set state "wait-for-semicolon" continue } else { set state "wait-for-break" continue } } else { if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { continue } elseif {$next_token_type == "case"} { set state "case" continue } elseif {$next_token_type == "default"} { set state "default" continue } elseif {$next_token_type == "leftbrace"} { set state "inside-braces" incr seen_braces 1 continue } elseif {$next_token_type == "rightbrace"} { set state "after-rightbrace" continue } elseif {$next_token_type == "break" || $next_token_type == "continue" || $next_token_type == "return"} { set state "wait-for-semicolon" continue } else { set state "wait-for-break" continue } } } elseif {$state == "inside-braces"} { if {$next_token_type == "rightbrace"} { incr seen_braces -1 if {$seen_braces == 0} { set state "wait-for-break" continue } } elseif {$next_token_type == "leftbrace"} { incr seen_braces 1 } continue } elseif {$state == "after-rightbrace-preprocessor"} { if {$next_token_type == "newline"} { set state "after-rightbrace" } } elseif {$state == "after-rightbrace"} { if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { continue } elseif {$next_token_type == "case"} { set state "case" continue } elseif {$next_token_type == "default"} { set state "default" continue } elseif {$next_token_type == "rightbrace"} { lappend switch_ends [lindex $next_token 1] break } elseif {[string first "pp_" $next_token_type] == 0} { set state "after-rightbrace-preprocessor" } else { report $fileName [lindex $next_token 1] "There should be 'case' or 'default' (state $state)" } } elseif {$state == "case-blocks-end-preprocessor"} { if {$next_token_type == "newline"} { set state "case-blocks-end" } } elseif {$state == "case-blocks-end"} { if {$next_token_type == "ccomment" || $next_token_type == "space" || $next_token_type == "newline"} { continue } elseif {$next_token_type == "rightbrace"} { lappend switch_ends [lindex $next_token 1] break } elseif {[string first "pp_" $next_token_type] == 0} { set state "case-blocks-end-preprocessor" } else { report $fileName [lindex $next_token 1] "Missing break, continue or FALLTHRU comment before rightbrace (state $state)" } } else { report $fileName [lindex $next_token 1] "Unknown state: $state" } } } } } }