You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
typesetting/xenomorph/xenomorph/pointer.rkt

122 lines
5.4 KiB
Racket

6 years ago
#lang debug racket/base
(require "helper.rkt"
"number.rkt"
racket/dict
racket/class
6 years ago
racket/promise
sugar/unstable/dict)
6 years ago
(provide (all-defined-out))
6 years ago
#|
approximates
https://github.com/mbutterick/restructure/blob/master/src/Pointer.coffee
|#
6 years ago
(define (find-top-parent parent)
6 years ago
(cond
6 years ago
[(dict-ref parent 'parent #f) => find-top-parent]
[else parent]))
6 years ago
6 years ago
(define (resolve-pointer type val)
6 years ago
(cond
[type (values type val)]
[(xvoid-pointer? val) (values (xvoid-pointer-type val) (xvoid-pointer-value val))]
[else (raise-argument-error 'Pointer:size "VoidPointer" val)]))
6 years ago
(define xpointer%
6 years ago
(class xenobase%
(super-new)
(init-field [(@offset-type offset-type)]
[(@type type)]
[(@pointer-relative-to pointer-relative-to)]
[(@allow-null? allow-null?)]
[(@null-value null-value)]
[(@pointer-lazy? pointer-lazy?)])
6 years ago
(define/augment (x:decode port parent)
(define offset (send @offset-type x:decode port parent))
6 years ago
(cond
[(and @allow-null? (= offset @null-value)) #f] ; handle null pointers
6 years ago
[else
(define relative (+ (case @pointer-relative-to
6 years ago
[(local) (dict-ref parent '_startOffset)]
6 years ago
[(immediate) (- (pos port) (send @offset-type x:size))]
6 years ago
[(parent) (dict-ref (dict-ref parent 'parent) '_startOffset)]
[(global) (or (dict-ref (find-top-parent parent) '_startOffset) 0)]
[else (error 'unknown-pointer-style)])))
(define ptr (+ offset relative))
(cond
6 years ago
[@type (define (decode-value)
(define orig-pos (pos port))
(pos port ptr)
(begin0
6 years ago
(send @type x:decode port parent)
6 years ago
(pos port orig-pos)))
(if @pointer-lazy? (delay (decode-value)) (decode-value))]
6 years ago
[else ptr])]))
6 years ago
(define/augment (x:encode val-in port [parent #f])
6 years ago
(unless parent ; todo: furnish default pointer context? adapt from Struct?
(raise-argument-error 'xpointer-encode "valid pointer context" parent))
6 years ago
(cond
[val-in
(define new-parent (case @pointer-relative-to
6 years ago
[(local immediate) parent]
[(parent) (dict-ref parent 'parent)]
[(global) (find-top-parent parent)]
[else (error 'unknown-pointer-style)]))
(define relative (+ (case @pointer-relative-to
6 years ago
[(local parent) (dict-ref new-parent 'startOffset)]
6 years ago
[(immediate) (+ (pos port) (send @offset-type x:size val-in parent))]
6 years ago
[(global) 0])))
6 years ago
(send @offset-type x:encode (- (dict-ref new-parent 'pointerOffset) relative) port)
6 years ago
(define-values (type val) (resolve-pointer @type val-in))
(dict-update! new-parent 'pointers
(λ (ptrs) (append ptrs (list (mhasheq 'type type 'val val 'parent parent)))))
(dict-set! new-parent 'pointerOffset
6 years ago
(+ (dict-ref new-parent 'pointerOffset) (send type x:size val parent)))]
[else (send @offset-type x:encode @null-value port)]))
6 years ago
(define/augment (x:size [val-in #f] [parent #f])
(define new-parent (case @pointer-relative-to
6 years ago
[(local immediate) parent]
[(parent) (dict-ref parent 'parent)]
[(global) (find-top-parent parent)]
[else (error 'unknown-pointer-style)]))
(define-values (type val) (resolve-pointer @type val-in))
(when (and val new-parent)
(dict-set! new-parent 'pointerSize
(and (dict-ref new-parent 'pointerSize #f)
6 years ago
(+ (dict-ref new-parent 'pointerSize) (send type x:size val new-parent)))))
(send @offset-type x:size))))
6 years ago
6 years ago
(define (+xpointer [offset-arg #f] [type-arg #f]
#:offset-type [offset-kwarg #f]
#:type [type-kwarg #f]
#:relative-to [pointer-relative-to 'local]
#:lazy [pointer-lazy? #f]
6 years ago
#:allow-null [allow-null? #t]
6 years ago
#:null [null-value 0]
#:pre-encode [pre-proc #f]
#:post-decode [post-proc #f])
(define valid-pointer-relatives '(local immediate parent global))
(unless (memq pointer-relative-to valid-pointer-relatives)
(raise-argument-error '+xpointer (format "~v" valid-pointer-relatives) pointer-relative-to))
6 years ago
(define type-in (or type-arg type-kwarg uint8))
(new (generate-subclass xpointer% pre-proc post-proc)
[offset-type (or offset-arg offset-kwarg uint8)]
[type (case type-in [(void) #f][else type-in])]
[pointer-relative-to pointer-relative-to]
[pointer-lazy? pointer-lazy?]
[allow-null? allow-null?]
[null-value null-value]))
6 years ago
;; A pointer whose type is determined at decode time
6 years ago
(define xvoid-pointer% (class xenobase%
(super-new)
(init-field type value)))
(define (+xvoid-pointer . args) (apply make-object xvoid-pointer% args))
(define (xvoid-pointer? x) (is-a? x xvoid-pointer%))
(define (xvoid-pointer-type x) (get-field type x))
(define (xvoid-pointer-value x) (get-field value x))