// tools/hako_check/rules/rule_top_level_local.hako — HC018: Top-level local in prelude // Detects top-level `local` statements (outside of methods/boxes), which are cleanup omissions. static box RuleTopLevelLocalBox { method apply(text, path, out) { if text == null { return 0 } local lines = me._split_lines(text) local i = 0 local in_box = 0 local in_method = 0 local brace_depth = 0 while i < lines.size() { local ln = lines.get(i) local trimmed = me._trim(ln) // Track context: are we inside a box or method? if trimmed.indexOf("box ") == 0 || trimmed.indexOf("static box ") == 0 { in_box = 1 } if in_box == 1 && (trimmed.indexOf("method ") >= 0 || trimmed.indexOf("birth(") >= 0) { in_method = 1 } // Track brace depth local j = 0 while j < trimmed.length() { local ch = trimmed.substring(j, j+1) if ch == "{" { brace_depth = brace_depth + 1 } if ch == "}" { brace_depth = brace_depth - 1 if brace_depth == 0 { in_method = 0 in_box = 0 } } j = j + 1 } // Check for top-level local (not inside method, not a comment) if trimmed.indexOf("local ") == 0 { if in_method == 0 && me._is_comment(trimmed) == 0 { out.push("[HC018] top-level local declaration (not allowed): " + path + ":" + me._itoa(i+1)) } } i = i + 1 } return out.size() } _trim(s) { if s == null { return "" } local start = 0 local end = s.length() // Trim leading whitespace while start < end { local ch = s.substring(start, start+1) if ch == " " || ch == "\t" { start = start + 1 } else { break } } // Trim trailing whitespace while end > start { local ch = s.substring(end-1, end) if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" { end = end - 1 } else { break } } return s.substring(start, end) } _is_comment(s) { if s == null { return 0 } local trimmed = me._trim(s) if trimmed.indexOf("//") == 0 { return 1 } return 0 } _split_lines(s) { local arr = new ArrayBox() if s == null { return arr } local n = s.length() local last = 0 local i = 0 loop(i < n) { local ch = s.substring(i, i+1) if ch == "\n" { arr.push(s.substring(last, i)) last = i + 1 } i = i + 1 } if last <= n { arr.push(s.substring(last)) } return arr } _itoa(n) { local v = 0 + n if v == 0 { return "0" } local out = "" local digits = "0123456789" local tmp = "" while v > 0 { local d = v % 10 tmp = digits.substring(d, d+1) + tmp v = v / 10 } out = tmp return out } } static box RuleTopLevelLocalMain { method main(args) { return 0 } }