guicho271828 / trivia

Pattern Matcher Compatible with Optima
Other
334 stars 22 forks source link

Fix the compilation for read-time `structure-object` literal #49

Closed dfmorrison closed 8 years ago

dfmorrison commented 8 years ago

My apologies if there is a mailing list or some such that's better suited than this for asking questions: I looked but failed to find one.

Anyway, I looked in the documentation, and failed to find an answer to this; my apologies if it's there and I just missed it.

When comparing constants what sort of equality is used? The following would seem to imply equal is being used:

CL-USER> (trivia:match "Foo"
           ("foo" :lower)
           ("FOO" :upper)
           ("Foo" :title))
:TITLE

So does this:

CL-USER> (trivia:match 1
           (1.0 :equalp)
           (1 :equal-or-eql))
:EQUAL-OR-EQL

(Note that in this implementation (CCL):

CL-USER> (list (equal 1 1.0) (equalp 1 1.0))
(NIL T)

)

But this seems to imply equalp is being used instead:

CL-USER> (trivia:match #(1 2 3)
           (#(1 2 3) t))
T

As does this:

CL-USER> (trivia:match #S(FROB :BLAH 1 :BLECH 2)
           (#S(FROB :BLAH 1 :BLECH 2) t))
T

Does it depend on the types involved? Of the thing being matched or of the pattern? And, if so, in which cases are what being used? Of, if it's something else, what, please? Or am I just confused, which is perfectly plausible.

guicho271828 commented 8 years ago

Fair point, this should be further clarified and improved. I will also add some documentation.

Short answer:

Your confusion is somewhat due to my lazyness: The current handling of read-time constant of structure-object is not properly implemented. The implementation is here.

For matching against structure-object, use the structure pattern such as (structure frob :blah 1 :blech 2) (or in shorthand, (frob :blah 1 :blech 2)) for the consistent behavior: Numbers and characters are compared by eql.

Long answer:

The comparison criteria in trivia is not identical to either equal nor equalp. The philosophy in trivia follows:

Your last example matches against a read-time constant #S(FROB :BLAH 1 :BLECH 2). If trivia applied eq/eql/equal to this comparison, It does not make sense because you can't generate the same (by eq/eql/equal) instance of FROB in run time. Same thing applies to #(1 2 3): you can't generate the same instance in run-time. Note that for structure-object and array, equal uses eq.

(trivia:match obj
    (#(1 2 3) t))
    ;; ^^^^^ this array is instantiated in read-time and
    ;;  you cant generate the same instance by `eq` 

Thus, read-time literals of vector which have appeared in the patterns are converted into vector patterns, and the matcher descends into the contents. Elements are compared by eql.

(trivia:match obj
    ((vector 1 2 3) t))
    ;; ^^^^^ compiled into vector pattern

However, currently, read-time literals of structure-object are not converted into structure patterns and instead I abused equalp pattern. This makes some comparisons done by = and char-equal. Thus, for a consistent behavior which always uses eql, write structure pattern, not the read-time literals #S(...).

(trivia:match obj
    (#S(FROB :BLAH 1 :BLECH 2) t))
;; current compilation
(trivia:match obj
    ((equalp #S(FROB :BLAH 1 :BLECH 2)) t))

;; ideal compilation
(trivia:match obj
    ((structure FROB :BLAH 1 :BLECH 2) t))
guicho271828 commented 8 years ago

Hi, it's fixed now. Closing.

guicho271828 commented 8 years ago

I mean the read-time structure-object literals are converted into structure patterns.