@@[target("rust")]

// TypeScript syntax skipper — Frame-generated state machine.
// Delegates to shared helpers where possible; inlines template literal awareness.
//
// Helpers used:
//   skip_line_comment, skip_block_comment, skip_template_literal,
//   skip_simple_string
// Inline: find_line_end and balanced_paren_end with template literal awareness

@@system TypeScriptSyntaxSkipperFsm {
    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 {
            $>() {
                if let Some(j) = skip_line_comment(&self.bytes, self.pos, self.end) {
                    self.result_pos = j;
                    self.success = 1;
                    return
                }
                if let Some(j) = skip_block_comment(&self.bytes, self.pos, self.end) {
                    self.result_pos = j;
                    self.success = 1;
                    return
                }
                self.success = 0;
            }
        }

        $SkipString {
            $>() {
                // Template literal via shared helper (must check before simple string)
                if let Some(j) = skip_template_literal(&self.bytes, self.pos, self.end) {
                    self.result_pos = j;
                    self.success = 1;
                    return
                }
                // Simple string via shared helper
                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 {
            $>() {
                // TypeScript-specific: handle template literals during line scanning
                // Cannot use find_line_end_c_like because it doesn't know about backticks
                let end = self.end;
                let bytes = &self.bytes;
                let mut j = self.pos;
                let mut in_string: u8 = 0;
                let mut in_template: u8 = 0;
                let mut template_brace_depth: i32 = 0;

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

                    // Inside template literal
                    if in_template != 0 {
                        if b == b'`' && template_brace_depth == 0 {
                            in_template = 0;
                            j += 1;
                            continue;
                        }
                        if b == b'\\' { j += 2; continue; }
                        if b == b'$' && j + 1 < end && bytes[j + 1] == b'{' {
                            template_brace_depth += 1;
                            j += 2;
                            continue;
                        }
                        if b == b'}' && template_brace_depth > 0 {
                            template_brace_depth -= 1;
                        }
                        j += 1;
                        continue;
                    }

                    // Inside regular 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';' || b == b'}' { break; }
                    if b == b'/' && j + 1 < end && (bytes[j + 1] == b'/' || bytes[j + 1] == b'*') { break; }

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

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

        $BalancedParenEnd {
            $>() {
                // TypeScript-specific: balanced parens respecting template literals
                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;
                let mut in_template: u8 = 0;

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

                    // Inside template literal
                    if in_template != 0 {
                        if b == b'`' { in_template = 0; }
                        if b == b'\\' { i += 2; continue; }
                        i += 1;
                        continue;
                    }

                    // 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'`' { in_template = 1; 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
}
