@@[target("rust")]

// Ruby syntax skipper — Frame-generated state machine.
// Ruby has # line comments, "..." / '...' strings,
// and %Q{} / %q[] / %w() / etc. percent literals.
//
// Helpers used:
//   skip_simple_string, skip_ruby_percent_literal
// Inline: skip_comment, find_line_end, balanced_paren_end

@@system RubySyntaxSkipperFsm {
    interface:
        do_skip_comment()
        do_skip_string()
        do_find_line_end()
        do_balanced_paren_end()

    machine:
        $Init {
            do_skip_comment() { -> $SkipComment }
            do_skip_string() { -> $SkipString }
            do_find_line_end() { -> $FindLineEnd }
            do_balanced_paren_end() { -> $BalancedParenEnd }
        }

        $SkipComment {
            $>() {
                // Ruby: # line comment only
                if self.pos < self.end && self.bytes[self.pos] == b'#' {
                    let mut j = self.pos + 1;
                    while j < self.end && self.bytes[j] != b'\n' {
                        j += 1;
                    }
                    self.result_pos = j;
                    self.success = 1;
                    return
                }
                self.success = 0;
            }
        }

        $SkipString {
            $>() {
                // Percent literals (must check before simple strings — % prefix)
                if let Some(j) = skip_ruby_percent_literal(&self.bytes, self.pos, self.end) {
                    self.result_pos = j;
                    self.success = 1;
                    return
                }
                // Simple string via shared helper (handles both ' and ")
                if let Some(j) = skip_simple_string(&self.bytes, self.pos, self.end) {
                    self.result_pos = j;
                    self.success = 1;
                    return
                }
                self.success = 0;
            }
        }

        $FindLineEnd {
            $>() {
                let end = self.end;
                let bytes = &self.bytes;
                let mut j = self.pos;
                let mut in_string: u8 = 0;

                while j < end {
                    let b = bytes[j];
                    if b == b'\n' { break; }

                    // Inside string
                    if in_string != 0 {
                        if b == b'\\' { j += 2; continue; }
                        if b == in_string { in_string = 0; }
                        j += 1;
                        continue;
                    }

                    // Terminators
                    if b == b'#' { break; }

                    // String starts
                    if b == b'\'' || b == b'"' {
                        in_string = b;
                        j += 1;
                        continue;
                    }

                    j += 1;
                }
                self.result_pos = j;
            }
        }

        $BalancedParenEnd {
            $>() {
                let end = self.end;
                let bytes = &self.bytes;
                let mut i = self.pos;
                if i >= end || bytes[i] != b'(' {
                    self.success = 0;
                    return
                }
                let mut depth: i32 = 0;
                let mut in_string: u8 = 0;

                while i < end {
                    let b = bytes[i];

                    // Inside string
                    if in_string != 0 {
                        if b == b'\\' { i += 2; continue; }
                        if b == in_string { in_string = 0; }
                        i += 1;
                        continue;
                    }

                    if b == b'\'' || b == b'"' { in_string = b; i += 1; }
                    else if b == b'(' { depth += 1; i += 1; }
                    else if b == b')' {
                        depth -= 1; i += 1;
                        if depth == 0 { self.result_pos = i; self.success = 1; return }
                    } else { i += 1; }
                }
                self.success = 0;
            }
        }

    domain:
        bytes: Vec<u8> = Vec::new()
        pos: usize = 0
        end: usize = 0
        result_pos: usize = 0
        success: usize = 1
}
