SNAPKITTYWEST's picture
push from SNAPKITTYWEST/sovereign-ide
ffc07fb verified
Raw History Blame Contribute Delete
7.6 kB
! Layer 4 β€” Sovereign IDE Incremental Parser (Tree-sitter / GLR)
! Maps to: snapkitty-resonance-isa Abjad VM IR, j-matrix-twin SUBLEQ
MODULE sovereign_parser
USE iso_c_binding
USE sovereign_runtime, ONLY: runtime_panic, str_intern
USE sovereign_text_buffer, ONLY: text_buffer_t, buffer_slice, buffer_length
IMPLICIT NONE
PRIVATE
! ── Token kinds ───────────────────────────────────────────────────────────
INTEGER, PARAMETER :: TOK_EOF = 0
INTEGER, PARAMETER :: TOK_IDENT = 1
INTEGER, PARAMETER :: TOK_NUMBER = 2
INTEGER, PARAMETER :: TOK_STRING = 3
INTEGER, PARAMETER :: TOK_OP = 4
INTEGER, PARAMETER :: TOK_NEWLINE = 5
INTEGER, PARAMETER :: TOK_ERROR = 255
! ── CST node ──────────────────────────────────────────────────────────────
INTEGER, PARAMETER :: MAX_CST_NODES = 2097152
INTEGER, PARAMETER :: MAX_CST_CHILDREN = 16
TYPE :: cst_node_t
INTEGER(C_INT32_T) :: kind = 0 ! grammar symbol ID
INTEGER :: start_byte = 0
INTEGER :: end_byte = 0
INTEGER :: parent = 0
INTEGER :: children(MAX_CST_CHILDREN) = 0
INTEGER :: n_children = 0
LOGICAL :: is_error = .FALSE.
INTEGER :: ir_opcode = 0 ! Abjad VM IR opcode (resonance-isa)
END TYPE cst_node_t
! ── Grammar rule ──────────────────────────────────────────────────────────
INTEGER, PARAMETER :: MAX_RULES = 4096
INTEGER, PARAMETER :: MAX_RHS = 16
TYPE :: grammar_rule_t
INTEGER(C_INT32_T) :: lhs = 0
INTEGER(C_INT32_T) :: rhs(MAX_RHS) = 0
INTEGER :: rhs_len = 0
INTEGER :: action = 0
END TYPE grammar_rule_t
! ── Parse table (GLR) ─────────────────────────────────────────────────────
INTEGER, PARAMETER :: MAX_STATES = 1024
TYPE :: parse_table_t
INTEGER :: rules(MAX_STATES, 256) ! state Γ— lookahead β†’ action
INTEGER :: rule_count = 0
LOGICAL :: worm_sealed = .FALSE. ! bifrost: sealed after grammar load
END TYPE parse_table_t
! ── Parser context ────────────────────────────────────────────────────────
TYPE :: parser_ctx_t
TYPE(cst_node_t) :: nodes(MAX_CST_NODES)
INTEGER :: node_count = 0
INTEGER :: root = 0
TYPE(parse_table_t) :: table
LOGICAL :: dirty = .TRUE.
END TYPE parser_ctx_t
PUBLIC :: parser_init
PUBLIC :: parser_load_grammar
PUBLIC :: parser_parse_full
PUBLIC :: parser_parse_incremental
PUBLIC :: parser_node_text
PUBLIC :: parser_find_node_at
CONTAINS
! ---------------------------------------------------------------------------
SUBROUTINE parser_init(ctx)
TYPE(parser_ctx_t), INTENT(INOUT) :: ctx
ctx%node_count = 0
ctx%root = 0
ctx%dirty = .TRUE.
ctx%table%rule_count = 0
ctx%table%worm_sealed = .FALSE.
ctx%table%rules = 0
WRITE(*,'(A)') '[parser] init'
END SUBROUTINE parser_init
! ---------------------------------------------------------------------------
! Load grammar from file; WORM-seal the table after load
SUBROUTINE parser_load_grammar(ctx, grammar_path)
TYPE(parser_ctx_t), INTENT(INOUT) :: ctx
CHARACTER(LEN=*), INTENT(IN) :: grammar_path
! TODO: read grammar file, build GLR table
! TODO: call bifrost_worm_seal on table after verification
ctx%table%worm_sealed = .TRUE.
WRITE(*,'(A,A)') '[parser] grammar loaded from ', TRIM(grammar_path)
END SUBROUTINE parser_load_grammar
! ---------------------------------------------------------------------------
! Full parse of entire buffer
SUBROUTINE parser_parse_full(ctx, buf)
TYPE(parser_ctx_t), INTENT(INOUT) :: ctx
TYPE(text_buffer_t), INTENT(IN) :: buf
INTEGER :: n
n = buffer_length(buf)
ctx%node_count = 0
ctx%root = glr_parse(ctx, buf, 0, n)
ctx%dirty = .FALSE.
WRITE(*,'(A,I0,A)') '[parser] full parse: ', ctx%node_count, ' nodes'
END SUBROUTINE parser_parse_full
! ---------------------------------------------------------------------------
! Incremental reparse for edit region [edit_start, edit_end)
SUBROUTINE parser_parse_incremental(ctx, buf, edit_start, edit_end)
TYPE(parser_ctx_t), INTENT(INOUT) :: ctx
TYPE(text_buffer_t), INTENT(IN) :: buf
INTEGER, INTENT(IN) :: edit_start, edit_end
! TODO: locate affected subtree, re-enter GLR at boundary
ctx%dirty = .FALSE.
WRITE(*,'(A,I0,A,I0)') '[parser] incremental reparse: ', &
edit_start, ' β†’ ', edit_end
END SUBROUTINE parser_parse_incremental
! ---------------------------------------------------------------------------
SUBROUTINE parser_node_text(ctx, buf, node_idx, text)
TYPE(parser_ctx_t), INTENT(IN) :: ctx
TYPE(text_buffer_t), INTENT(IN) :: buf
INTEGER, INTENT(IN) :: node_idx
CHARACTER(LEN=*), INTENT(OUT) :: text
INTEGER :: s, e
s = ctx%nodes(node_idx)%start_byte
e = ctx%nodes(node_idx)%end_byte
CALL buffer_slice(buf, s, e - s, text)
END SUBROUTINE parser_node_text
! ---------------------------------------------------------------------------
! Find deepest CST node containing byte offset
FUNCTION parser_find_node_at(ctx, offset) RESULT(idx)
TYPE(parser_ctx_t), INTENT(IN) :: ctx
INTEGER, INTENT(IN) :: offset
INTEGER :: idx
idx = find_recursive(ctx, ctx%root, offset)
END FUNCTION parser_find_node_at
! ── Internal GLR skeleton ─────────────────────────────────────────────────
RECURSIVE FUNCTION glr_parse(ctx, buf, start, end_b) RESULT(node_idx)
TYPE(parser_ctx_t), INTENT(INOUT) :: ctx
TYPE(text_buffer_t), INTENT(IN) :: buf
INTEGER, INTENT(IN) :: start, end_b
INTEGER :: node_idx
! TODO: full GLR implementation
! Stub: create a single leaf error node
ctx%node_count = ctx%node_count + 1
node_idx = ctx%node_count
ctx%nodes(node_idx)%start_byte = start
ctx%nodes(node_idx)%end_byte = end_b
ctx%nodes(node_idx)%is_error = .FALSE.
END FUNCTION glr_parse
RECURSIVE FUNCTION find_recursive(ctx, idx, offset) RESULT(found)
TYPE(parser_ctx_t), INTENT(IN) :: ctx
INTEGER, INTENT(IN) :: idx, offset
INTEGER :: found, i, child
found = idx
IF (idx == 0) RETURN
DO i = 1, ctx%nodes(idx)%n_children
child = ctx%nodes(idx)%children(i)
IF (ctx%nodes(child)%start_byte <= offset .AND. &
ctx%nodes(child)%end_byte > offset) THEN
found = find_recursive(ctx, child, offset)
RETURN
END IF
END DO
END FUNCTION find_recursive
END MODULE sovereign_parser