janet-lang / janet

A dynamic language and bytecode vm
https://janet-lang.org
MIT License
3.38k stars 217 forks source link

splicing into structs/tables #1412

Closed reuleaux closed 4 months ago

reuleaux commented 4 months ago

It appears to me that splicing into a struct (or table) should be possible, like so:

(def v true)
(dev x true)
(def blah 'blah)
(def result {
         :v v
         ;(if x ~(:blah ,blah)
        '()
        )
         })

This is not allowed currently:

error: example.janet:61:7: parse error: struct and table literals expect even number of argument

the number of arguments being calculated as 3 here : :v, v, and the if-then-else expression, whereas I think this should be possible: the number of arguments should be counted after splicing them in: this number is even here in any case: if x (is true) as above - then there are four arguments: :v, v, :blah, blah, if not, then the empty list is spliced in, and there are just two arguments in result: :v, v

Note that there are several ways, that I could repair this:

(def result {
         :v v
          :blah (if x blah '())
         })

This makes for 4 arguments of the struct (before splicing): :v, v, :blah, if-then-else ... this is not quite the same, however (in the case of (not x). Another solution: have another one of these splices (that counts as single argument currently):

(def result {
         :v v
         ;(if dry ~(:dry ,dry)
        '()
        )
         ;(if x ~(:blah ,blah)
        '()
        )
         })

This works (currently), with 4 arguments of the result struct being an even number: :v, v, first if-then-else, second if-then-else.

To sum up: I think that the number of arguments of the struct should be calculated / checked as being even after splicing in any bits.

If possible i.e. - I am not that familiar with the code base: if all this information is available at compile/analysis time [?] - it just appears to me that the very first example above should work.

Apparently some kind of argument counting after the splicing in happens already:

(def result {
         :v v
         ;(if dry ~(:dry ,dry)
        '()
        )
         ;(if x ~(:blah ,blah and-more-here)
        '()
        )
         })

this is dismissed:

error: expected even number of arguments to struct constructor, got 7

I am counting: (1) :v, (2) v, (3) :dry, (4) dry, (5) :blah, (6) blah, and (7) 'and-more-here

bakpakin commented 4 months ago

This isn't possible because the source code itself is not representable. If you were to pass this to a macro, what would be passed to the macro? This is an intentional will not fix. Notably, this fails in the parser, not the compiler.

reuleaux commented 4 months ago

OK, thanks for clarifying then at least