Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
G
Guile DNS
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Hugo Hörnquist
Guile DNS
Commits
97de9df8
Commit
97de9df8
authored
May 31, 2022
by
Hugo Hörnquist
Browse files
Options
Downloads
Patches
Plain Diff
Complete rewrite of define-record-type.
parent
9f1fb474
No related branches found
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
dns/internal/object.scm
+96
-59
96 additions, 59 deletions
dns/internal/object.scm
tests/object.scm
+8
-0
8 additions, 0 deletions
tests/object.scm
with
104 additions
and
59 deletions
dns/internal/object.scm
+
96
−
59
View file @
97de9df8
...
@@ -36,68 +36,105 @@
...
@@ -36,68 +36,105 @@
(
list
key
(
serialize
value
)))
(
list
key
(
serialize
value
)))
this
))
this
))
;; Helper procedure for define-record-type macro, which if @var{stx} is a syntax
;; object of a list takes the first argument of it, keeping it a syntax object
(
define
(
unlist
stx
)
(
if
(
list?
(
syntax->datum
stx
))
(
define
(
handle-define*-clause
stx
)
(
->>
stx
syntax->datum
car
(
datum->syntax
stx
))
(
syntax-case
stx
()
stx
))
((
name
default:
default
args
...
)
#'
(
name
default
))
((
name
arg
args
...
)
(
handle-define*-clause
#'
(
name
args
...
)))
(
define
(
mlist->define-field
stx
)
((
name
)
#
'name
)
(
define
l
(
syntax->datum
stx
))
(
name
#
'name
)))
(
cond
((
and
(
list?
l
)
(
memv
default:
l
))
(
define-syntax
build-validator
=>
(
lambda
(
field
)
(
syntax-rules
(
and
or
)
#`
(
#,
(
datum->syntax
stx
(
car
l
))
((
_
variable
(
and
clauses
...
))
(
and
(
build-validator
variable
clauses
)
...
))
#,
(
datum->syntax
stx
(
cadr
field
)))))
((
_
variable
(
or
clauses
...
))
(
or
(
build-validator
variable
clauses
)
...
))
((
list?
l
)
((
_
variable
(
proc
args
...
))
(
proc
variable
args
...
))
(
datum->syntax
stx
(
car
l
)))
((
_
variable
proc
)
(
proc
variable
))))
(
else
stx
)))
;; Given #'(<field-name> type: <validator-body>), expands validator-body to contain <field-name>
;; string x field-spec → <validator syntax>
(
define
(
handle-validator
constructor-name
)
(
define
(
inner
field
)
(
syntax-case
field
()
((
name
type:
validator-body
args
...
)
#`
(
unless
(
build-validator
name
validator-body
)
(
scm-error
'wrong-type-arg
#,
constructor-name
"`~a: ~s' doesn't satisfy `~a'"
(
list
(
quote
name
)
name
(
quote
validator-body
))
(
list
(
quote
name
)
name
))))
((
name
arg
args
...
)
(
inner
#'
(
name
args
...
)))
;; Case when no #:type annotation exists.
;; Should hopefully be optimized away by the compiler
(
_
#'
(
if
#f
#f
))))
inner
)
;; Takes a field from the define-record-type macro, and returns the field name.
;; E.g.
;; (x args ...) ⇒ x
;; x ⇒ x
(
define
(
field-name
stx
)
(
syntax-case
stx
()
((
name
args
...
)
#
'name
)
(
name
#
'name
)))
;; Helper function to use with with-syntax
(
define
(
binding
pattern
fmt
)
(
->>
pattern
syntax->datum
(
format
#f
fmt
)
string->symbol
(
datum->syntax
pattern
)))
(
define-syntax
define-record-type
(
define-syntax
define-record-type
(
lambda
(
stx
)
(
lambda
(
stx
)
(
syntax-case
stx
(
fields
)
(
syntax-case
stx
(
fields
)
((
_
name
(
fields
field
...
))
((
_
type
(
fields
field
...
))
(
with-syntax
((
make-name
(
->>
#
'name
syntax->datum
(
format
#f
"make-~a"
)
(
with-syntax
((
make-<type>
(
binding
#
'type
"make-~a"
))
string->symbol
(
datum->syntax
stx
)))
(
<type>?
(
binding
#
'type
"~a?"
)))
(
name-predicate
(
->>
#
'name
syntax->datum
(
format
#f
"~a?"
)
string->symbol
(
datum->syntax
stx
))))
#`
(
begin
#`
(
begin
;; point
;; construct class
(
define-class
name
()
(
define-class
type
()
#,@
(
map
(
lambda
(
field-name
)
;; needs a pre-expansion since define-class is a macro in itself
(
cond
((
list?
(
syntax->datum
field-name
))
#,@
(
map
field-name
#'
(
field
...
)))
#`
(
#,
(
datum->syntax
field-name
(
car
(
syntax->datum
field-name
)))
init-keyword:
#,
(
->
field-name
syntax->datum
car
symbol->keyword
)
;; construct predicate
init-value:
#,
(
cond
((
memv
default:
(
syntax->datum
field-name
))
(
define
(
<type>?
x
)
=>
(
lambda
(
x
)
(
is-a?
x
type
))
(
datum->syntax
field-name
(
cadr
x
))))
(
else
#f
))))
;; construct public-facing constructor
(
else
(
define*
(
make-<type>
key:
#,@
(
map
handle-define*-clause
#'
(
field
...
)))
#`
(
#,
field-name
#,@
(
map
(
handle-validator
(
symbol->string
(
syntax->datum
#
'make-<type>
)))
init-keyword:
#,
(
->
field-name
syntax->datum
symbol->keyword
)
#'
(
field
...
))
))))
#'
(
field
...
)))
;; bind all values to object
;; point?
(
let
((
return-value
(
make
type
)))
(
define
(
name-predicate
object
)
#,@
(
map
(
lambda
(
g
)
(
is-a?
object
name
))
(
with-syntax
((
f
(
field-name
g
)))
;; make-point
#`
(
slot-set!
return-value
(
quote
#,
(
field-name
g
))
f
)))
(
define*
(
make-name
key:
#,@
(
map
mlist->define-field
#'
(
field
...
)))
#'
(
field
...
))
(
make
name
return-value
))
#,@
(
apply
append
(
map
(
lambda
(
name
)
;; accessors
#`
(
#,
(
->
name
syntax->datum
symbol->keyword
)
#,
name
))
#,@
(
map
(
lambda
(
g
)
(
map
unlist
#'
(
field
...
))))))
;; Supplying the symbol instead of the identifier works here,
#,@
(
map
(
lambda
(
name
)
;; due to how goops' define-method works.
#`
(
define-method
(
#,
name
this
)
#`
(
define-method
(
#,
(
field-name
g
)
(
this
type
))
(
slot-ref
this
(
quote
#,
name
))))
(
slot-ref
this
(
quote
#,
(
field-name
g
)))))
(
map
unlist
#'
(
field
...
)))
#'
(
field
...
))
(
define-method
(
serialize
(
this
name
))
`
(
#,@
(
map
(
lambda
(
name
)
;; pretty printing
#`
(
#,
name
,
(
#,
name
this
)))
(
define-method
(
serialize
(
this
type
))
(
map
unlist
#'
(
field
...
)))))
(
quasiquote
(
define-method
(
write
(
this
name
)
port
)
#,
(
map
(
lambda
(
g
)
(
with-syntax
((
f
(
field-name
g
)))
#`
(
#,
(
field-name
g
)
,
(
serialize
(
f
this
)))))
#'
(
field
...
))))
(
define-method
(
write
(
this
type
)
port
)
((
@
(
ice-9
format
)
format
)
port
"#<~a~:{ ~a=~s~}>"
((
@
(
ice-9
format
)
format
)
port
"#<~a~:{ ~a=~s~}>"
(
class-name
name
)
(
class-name
type
)
(
serialize
this
)))
(
serialize
this
)))))))))
))))))
This diff is collapsed.
Click to expand it.
tests/object.scm
+
8
−
0
View file @
97de9df8
...
@@ -34,3 +34,11 @@
...
@@ -34,3 +34,11 @@
;; This is however explicitly specified
;; This is however explicitly specified
(
test-equal
"Test default value for non-defaulted file with other kv-data"
(
test-equal
"Test default value for non-defaulted file with other kv-data"
#f
(
x
(
make-r4
)))
#f
(
x
(
make-r4
)))
(
catch
'wrong-type-arg
(
lambda
()
(
make-r4
x:
"Hello"
)
(
test-assert
"Type test didn't work"
#f
))
(
lambda
_
(
test-assert
"Type test failed correctly"
#t
)))
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment