#lang typed/racket/base
(require "assemble-structs.rkt"
"collect-jump-targets.rkt"
"../compiler/il-structs.rkt"
"../compiler/expression-structs.rkt"
racket/list)
(provide fracture)
(: fracture ((Listof Statement) -> (values (Listof BasicBlock)
(Listof Symbol))))
(define (fracture stmts)
(let*: ([first-block-label : Symbol (if (and (not (empty? stmts))
(symbol? (first stmts)))
(first stmts)
(make-label 'start))]
[stmts : (Listof Statement) (if (and (not (empty? stmts))
(symbol? (first stmts)))
(rest stmts)
stmts)]
[jump-targets : (Listof Symbol)
(cons first-block-label (collect-general-jump-targets stmts))]
[entry-points : (Listof Symbol)
(cons first-block-label (collect-entry-points stmts))])
(let: loop : (values (Listof BasicBlock) (Listof Symbol))
([name : Symbol first-block-label]
[acc : (Listof UnlabeledStatement) '()]
[basic-blocks : (Listof BasicBlock) '()]
[stmts : (Listof Statement) stmts]
[last-stmt-goto? : Boolean #f])
(cond
[(null? stmts)
(values (reverse (cons (make-BasicBlock name (reverse acc))
basic-blocks))
entry-points)]
[else
(let: ([first-stmt : Statement (car stmts)])
(: do-on-label (Symbol -> (values (Listof BasicBlock) (Listof Symbol))))
(define (do-on-label label-name)
(cond
[(member label-name jump-targets)
(loop label-name
'()
(cons (make-BasicBlock
name
(if last-stmt-goto?
(reverse acc)
(reverse (append `(,(make-GotoStatement (make-Label label-name)))
acc))))
basic-blocks)
(cdr stmts)
last-stmt-goto?)]
[else
(loop name
acc
basic-blocks
(cdr stmts)
last-stmt-goto?)]))
(cond
[(symbol? first-stmt)
(do-on-label first-stmt)]
[(LinkedLabel? first-stmt)
(do-on-label (LinkedLabel-label first-stmt))]
[else
(loop name
(cons first-stmt acc)
basic-blocks
(cdr stmts)
(GotoStatement? (car stmts)))]))]))))