Skip to content

Commit

Permalink
add in, contains, and MembershipTestable
Browse files Browse the repository at this point in the history
Add an `in` operator that tests membership as in many other languages
(e.g., Python, Kotlin, Rust). The operator combination `!in` works
because `!` now has an infix mode as long as its followed by `in`,
`is_now` or `is_a`.

A new class can support `in` by implementing the `MembershipTestable`
interface, which has a single `contains` method. The method is
required to return a `Boolean`.

Rename `List.has_element` and `Range.has_element` to `List.contains`
and `Range.contains`. Add `Array.contains`, `Map.contains` (an alias
for `Map.has_key`), and `Set.contains`.

Change sets to be non-indexable. The former indexing operation on a
set is better expressed using `in`. Mutable sets no longer have an
operator form for assignment; `MutableSet.add` or `MutableSet.remove`
must be used, instead.

While we're at it, add `Set.add`, rename `MutableMap.delete` to
`MutableMap.remove`, and rename `MutableSet.delete` to
`MutableSet.remove`.
  • Loading branch information
mflatt committed Jan 19, 2025
1 parent 383c8d5 commit a01383c
Show file tree
Hide file tree
Showing 66 changed files with 1,148 additions and 444 deletions.
12 changes: 10 additions & 2 deletions demo.rhm
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ def yep_nums :: List.of(Int) = nums
// `[]` on a list accesses by a 0-based index
nums[1]

// `in` searches a list
3 in nums
"hi" in ["hi", "bye"]

block:
// `use_dynamic` because `also_nums` is not declared to be a list
use_dynamic
Expand All @@ -235,6 +239,7 @@ def yep_nums_a :: Array.now_of(Int): nums_a
nums_a[1]
nums_a[2] := 30
nums_a[2]
30 in nums_a

// `later_of` doesn't check immediately, but checks on read/write
def really_nums_a :: Array.later_of(Int): nums_a
Expand All @@ -254,6 +259,9 @@ map
// `[]` on a map find the value for a key
map[17]

// `in` checks for a key in a map
17 in map

// `Map` is also bound as a constructor function, in which case
// it expects 2-argument lists for the keys and values
def also_map = Map([1, "one"], [2, "two"])
Expand All @@ -280,8 +288,8 @@ mut_map[2]
// using `{}` without `:` creates a set instead of a map
def a_set = {1, 3, 5, 7, 9}

// `[]` on a set checks whether something is in a set
if a_set[1] && !a_set[2]
// `in` on a set checks whether something is in a set
if 1 in a_set && 2 !in a_set
| "ok"
| error("no way!")

Expand Down
10 changes: 5 additions & 5 deletions rhombus-gui-lib/rhombus/gui/private/event.rhm
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ class MouseEvent():
~timestamp: timestamp :: Int = 0):
super(rkt.make_object(gui.#{mouse-event%},
convert_kind(kind),
down[#'left], down[#'middle], down[#'right],
#'left in down, #'middle in down, #'right in down,
x, y,
down[#'shift], down[#'control], down[#'meta], down[#'alt],
#'shift in down, #'control in down, #'meta in down, #'alt in down,
timestamp,
down[#'caps], down[#'mod3], down[#'mod4], down[#'mod5]))()
#'caps in down, #'mod3 in down, #'mod4 in down, #'mod5 in down))()

property kind:
unconvert_kind(rkt.send handle.#{get-event-type}())
Expand Down Expand Up @@ -161,10 +161,10 @@ class KeyEvent():
match code
| _ :: Char: code
| ~else: convert_key(code),
down[#'shift], down[#'control], down[#'meta], down[#'alt],
#'shift in down, #'control in down, #'meta in down, #'alt in down,
x, y,
timestamp,
down[#'caps], down[#'mod3], down[#'mod4], down[#'mod5],
#'caps in down, #'mod3 in down, #'mod4 in down, #'mod5 in down,
use_altgr && #true)
rkt.send evt.#{set-key-release-code}(release_code)
when other_caps_code | rkt.send evt.#{set-other-caps-key-code}(other_caps_code)
Expand Down
4 changes: 2 additions & 2 deletions rhombus-lib/info.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@

(define license '(Apache-2.0 OR MIT))

;; keep in sync with runtime version at "rhombus/private/amalgam/info.rkt"
(define version "0.32")
;; keep in sync with runtime version at "rhombus/private/amalgam/version.rkt"
(define version "0.33")
11 changes: 7 additions & 4 deletions rhombus-lib/rhombus/private/amalgam/annotation.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -548,13 +548,16 @@
(lambda () (order-quote equivalence))
'()
'macro
(lambda (form tail)
(lambda (form tail [mode 'normal])
(syntax-parse tail
[(op . (~var t (:annotation-seq #'is_a)))
(values
(syntax-parse #'t.parsed
[c-parsed::annotation-predicate-form
#`(c-parsed.predicate #,form)]
(let ([r #`(c-parsed.predicate #,form)])
(if (eq? mode 'invert)
#`(not #,r)
r))]
[c-parsed::annotation-binding-form
#:with arg-parsed::binding-form #'c-parsed.binding
#:with arg-impl::binding-impl #'(arg-parsed.infoer-id () arg-parsed.data)
Expand All @@ -564,8 +567,8 @@
(arg-info.matcher-id val-in
arg-info.data
if/blocked
#t
#f))])
#,(eq? mode 'normal)
#,(not (eq? mode 'normal))))])
#'t.tail)]))
'none))

Expand Down
46 changes: 41 additions & 5 deletions rhombus-lib/rhombus/private/amalgam/arithmetic.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"flonum-key.rkt"
"fixnum-key.rkt"
"rhombus-primitive.rkt"
"order.rkt"
"order-primitive.rkt")

(provide (for-spaces (#f
Expand Down Expand Up @@ -53,6 +54,9 @@
get-fixnum-static-infos
get-flonum-static-infos)))

(module+ parse-not
(provide (for-syntax set-parse-not!)))

(define-static-info-getter get-number-static-infos
;; comparison actually requires real numbers, but we want to
;; propagate a comparison operation from things like `+`, and
Expand Down Expand Up @@ -130,8 +134,38 @@
#:order integer_division
#:static-infos #,(get-real-static-infos))

(define-prefix ! not
#:order logical_negation)
(begin-for-syntax
(define parse-not void)
(define (set-parse-not! proc) (set! parse-not proc)))

(define-values-for-syntax (not-expr-prefix not-repet-prefix)
(prefix not
#:order logical_negation))
(define-values-for-syntax (not-expr-infix not-repet-infix)
(values
(expression-infix-operator
(lambda () (order-quote equivalence))
'()
'macro
(lambda (form1 tail)
(parse-not form1 tail #f))
'left)
(repetition-infix-operator
(lambda () (order-quote member_access))
'()
'macro
(lambda (form1 tail)
(parse-not form1 tail #t))
'left)))

(define-syntax !
(expression-prefix+infix-operator
not-expr-prefix
not-expr-infix))
(define-repetition-syntax !
(repetition-prefix+infix-operator
not-repet-prefix
not-repet-infix))

(define-infix && and
#:order logical_conjunction)
Expand Down Expand Up @@ -198,17 +232,19 @@

(define-syntax (define-eql-infix stx)
(syntax-parse stx
[(_ name racket-name)
[(_ name racket-name option ...)
#'(define-infix name racket-name
#:order equivalence)]))
#:order equivalence
option ...)]))

(define (not-equal-always? a b)
(not (equal-always? a b)))

(define-eql-infix == equal-always?)
(define-eql-infix != not-equal-always?)
(define-eql-infix === eq?)
(define-eql-infix is_now equal?)
(define-eql-infix is_now equal?
#:negatable)
(define-eql-infix is_same_number_or_object eqv?)

(void (set-primitive-who! 'fl+ '+))
Expand Down
7 changes: 7 additions & 0 deletions rhombus-lib/rhombus/private/amalgam/array.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"call-result-key.rkt"
"index-result-key.rkt"
"sequence-constructor-key.rkt"
"contains-key.rkt"
"composite.rkt"
"op-literal.rkt"
"reducer.rkt"
Expand Down Expand Up @@ -44,6 +45,7 @@
#:constructor-arity -1
#:instance-static-info ((#%index-get Array.get)
(#%index-set Array.set)
(#%contains Array.contains)
(#%append Array.append)
(#%sequence-constructor Array.to_sequence/optimize))
#:existing
Expand All @@ -60,6 +62,7 @@
(length
get
set
contains
append
copy
copy_from
Expand Down Expand Up @@ -222,6 +225,10 @@
#:primitive (vector-set!)
(vector-set! v i x))

(define/method (Array.contains v i [eql equal-always?])
#:primitive (vector-member)
(and (vector-member i v eql) #t))

(define (check-array who v)
(unless (vector? v)
(raise-annotation-failure who v "Array")))
Expand Down
6 changes: 4 additions & 2 deletions rhombus-lib/rhombus/private/amalgam/class-able.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
[(set) (class-desc-index-set-method-id super)]
[(append) (class-desc-append-method-id super)]
[(compare) (class-desc-compare-method-id super)]
[else (error "unknown able")]))))
[(contains) (class-desc-contains-method-id super)]
[else (error "unknown able" which)]))))

;; gets public or private id, whatever is available to supply arity info in case
;; it's not overridden
Expand Down Expand Up @@ -98,5 +99,6 @@
[(set) (class-desc-index-set-method-id super)]
[(append) (class-desc-append-method-id super)]
[(compare) (class-desc-compare-method-id super)]
[else (error "unknown able")])]))]
[(contains) (class-desc-contains-method-id super)]
[else (error "unknown able" which)])]))]
[else #'#f]))
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"index-key.rkt"
"append-key.rkt"
"compare-key.rkt"
"contains-key.rkt"
"values-key.rkt"
(submod "function-parse.rkt" for-build)
(only-in "function-arity.rkt"
Expand All @@ -26,7 +27,8 @@
maybe-ref-statinfo-id+id
maybe-set-statinfo-id+id
maybe-append-statinfo-id+id
maybe-compare-statinfo-id+id)
maybe-compare-statinfo-id+id
maybe-contains-statinfo-id+id)
#:do [(define-values (proc predicate? count annot-str static-infos)
(cond
[(attribute ret.converter)
Expand Down Expand Up @@ -188,7 +190,8 @@
;; boxed identifier means "checked" for `#%append`
#:box-id? (syntax-e #'checked-append?))
#,@(gen-bounce #'maybe-compare-statinfo-id+id #'#%compare #f
#:box-id? (syntax-e #'checked-compare?)))]))
#:box-id? (syntax-e #'checked-compare?))
#,@(gen-bounce #'maybe-contains-statinfo-id+id #'#%contains #f))]))

(define-for-syntax (de-method-arity arity)
(datum->syntax #f
Expand Down
10 changes: 8 additions & 2 deletions rhombus-lib/rhombus/private/amalgam/class-method.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"index-key.rkt"
"append-key.rkt"
"compare-key.rkt"
"contains-key.rkt"
"static-info.rkt"
"indirect-static-info-key.rkt"
(submod "dot.rkt" for-dot-provider)
Expand Down Expand Up @@ -413,6 +414,7 @@
index-set-statinfo-indirect-stx setable?
append-statinfo-indirect-stx appendable?
compare-statinfo-indirect-stx comparable?
contains-statinfo-indirect-stx container?
super-call-statinfo-indirect-id
#:checked-append? [checked-append? #t]
#:checked-compare? [checked-compare? #t])
Expand Down Expand Up @@ -468,7 +470,10 @@
[op (in-list ops)])
#`(#,op #,(or (let ([a (hash-ref addeds name #f)])
(and a (added-method-rhs-id a)))
(box (added-method-rhs-id added))))))])]))))
(box (added-method-rhs-id added))))))])])
#,(and container?
(eq? 'contains (syntax-e (added-method-id added)))
#`[#,contains-statinfo-indirect-stx #,(added-method-rhs-id added)]))))

;; may need to add info for inherited `call`, etc.:
(define (add-able which statinfo-indirect-stx able? key defs abstract-args
Expand Down Expand Up @@ -504,7 +509,8 @@
;; boxed means "checked" for `#%append`:
#:box-id? checked-append?)]
[defs (add-able 'compare_to compare-statinfo-indirect-stx comparable? #'#%compare defs #'(val)
#:const '#:method)])
#:const '#:method)]
[defs (add-able 'contains contains-statinfo-indirect-stx container? #'#%contains defs #'(val))])
defs))

(define-for-syntax (build-method-result-expression method-result)
Expand Down
5 changes: 3 additions & 2 deletions rhombus-lib/rhombus/private/amalgam/class-parse.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
dots ; list of symbols for dot syntax
dot-provider ; #f or compile-time identifier
static-infos ; syntax object for additional instance static-infos
flags)) ; 'call (=> public `call` is Callable), 'get, 'set, 'append, 'compare; others specific to class/interface/veneer
flags)) ; 'call (=> public `call` is Callable), 'get, 'set, 'append, 'compare, 'contains; others specific to class/interface/veneer

(struct class-desc objects-desc
;; `flags` from `objects-desc` can include 'authentic, 'prefab, 'no-recon
Expand All @@ -90,7 +90,8 @@
index-method-id ; for `get`
index-set-method-id ; for `set`
append-method-id ; for `append`
compare-method-id ; for `compare`
compare-method-id ; for `compare`
contains-method-id ; for `contains`
indirect-call-method-id ; #f or identifier for `call`
prefab-guard-id))

Expand Down
1 change: 1 addition & 0 deletions rhombus-lib/rhombus/private/amalgam/class-primitive.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@
#f ; not mutable indexable
#f ; not appendable
#f ; not comparable
#f ; not container
#f ; not callable (again)
#f ; not prefab
)))))
Expand Down
6 changes: 6 additions & 0 deletions rhombus-lib/rhombus/private/amalgam/class-static-info.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
(able-statinfo-indirect-id 'append super interfaces name-id intro))
(define compare-statinfo-indirect-id
(able-statinfo-indirect-id 'compare super interfaces name-id intro))
(define contains-statinfo-indirect-id
(able-statinfo-indirect-id 'contains super interfaces name-id intro))

(define super-call-statinfo-indirect-id
(able-super-statinfo-indirect-id 'call super interfaces))
Expand Down Expand Up @@ -74,6 +76,9 @@
#'())
#,@(if compare-statinfo-indirect-id
#`((#%indirect-static-info #,compare-statinfo-indirect-id))
#'())
#,@(if contains-statinfo-indirect-id
#`((#%indirect-static-info #,contains-statinfo-indirect-id))
#'())))

(define indirect-static-infos
Expand All @@ -88,6 +93,7 @@
index-set-statinfo-indirect-id
append-statinfo-indirect-id
compare-statinfo-indirect-id
contains-statinfo-indirect-id

super-call-statinfo-indirect-id

Expand Down
Loading

0 comments on commit a01383c

Please sign in to comment.