Skip to content

Commit dc6b02b

Browse files
committed
Change how keyword expression argments are encoded
Previously arguments were additional properties at the top level of the keyword expression object (siblings of the `0` property). Now they are packed into a single property value keyed by `1`. This brings keyword expressions semantics closer to function semantics (both now have a single argument), and will help make the upcoming generalized keyword expression syntax sugar more sensible.
1 parent 1778e16 commit dc6b02b

36 files changed

+913
-624
lines changed

README.md

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ git clone [email protected]:mkantor/please-lang-prototype.git
99
cd please-lang-prototype
1010
npm install
1111
npm run build
12-
echo '{@runtime, context => :context.program.start_time}' | ./please --output-format=json
12+
echo '{@runtime, { context => :context.program.start_time }}' | ./please --output-format=json
1313
```
1414

1515
There are more example programs in [`./examples`](./examples).
@@ -178,10 +178,11 @@ expressions_. Most of the interesting stuff that Please does involves evaluating
178178
keyword expressions.
179179

180180
Under the hood, keyword expressions are modeled as objects. For example, `:foo`
181-
desugars to `{ @lookup, key: foo }`. All such expressions have a key `0`
182-
referring to a value that is an `@`-prefixed atom (the keyword). Keywords
183-
include `@apply`, `@check`, `@function`, `@if`, `@index`, `@lookup`, `@panic`,
184-
and `@runtime`.
181+
desugars to `{ @lookup, { key: foo } }`. All such expressions have a property
182+
named `0` referring to a value that is an `@`-prefixed atom (the keyword). Most
183+
keyword expressions also require a property named `1` to pass an argument to the
184+
expression. Keywords include `@apply`, `@check`, `@function`, `@if`, `@index`,
185+
`@lookup`, `@panic`, and `@runtime`.
185186

186187
Currently only `@function`, `@lookup`, `@index`, and `@apply` have syntax
187188
sugars.
@@ -210,7 +211,7 @@ function from other programming languages, except there can be any number of
210211
`@runtime` expressions in a given program. Here's an example:
211212

212213
```
213-
{@runtime, context => :context.program.start_time}
214+
{@runtime, { context => :context.program.start_time }}
214215
```
215216

216217
Unsurprisingly, this program outputs the current time when run.
@@ -249,7 +250,7 @@ Take this example `plz` program:
249250
{
250251
language: Please
251252
message: :atom.prepend("Welcome to ")(:language)
252-
now: {@runtime, context => :context.program.start_time}
253+
now: {@runtime, { context => :context.program.start_time }}
253254
}
254255
```
255256

@@ -260,39 +261,57 @@ It desugars to the following `plo` program:
260261
language: Please
261262
message: {
262263
0: @apply
263-
function: {
264-
0: @apply
264+
1: {
265265
function: {
266-
0: @index
267-
object: {
268-
0: @lookup
269-
key: atom
266+
0: @apply
267+
1: {
268+
function: {
269+
0: @index
270+
1: {
271+
object: {
272+
0: @lookup
273+
1: {
274+
key: atom
275+
}
276+
}
277+
query: {
278+
0: prepend
279+
}
280+
}
281+
}
282+
argument: "Welcome to "
270283
}
271-
query: {
272-
0: prepend
284+
}
285+
argument: {
286+
0: @lookup
287+
1: {
288+
key: language
273289
}
274290
}
275-
argument: "Welcome to "
276-
}
277-
argument: {
278-
0: @lookup
279-
key: language
280291
}
281292
}
282293
now: {
283294
0: @runtime
284295
1: {
285-
0: @function
286-
parameter: context
287-
body: {
288-
0: @index
289-
object: {
290-
0: @lookup
291-
key: context
292-
}
293-
query: {
294-
0: program
295-
1: start_time
296+
0: {
297+
0: @function
298+
1: {
299+
parameter: context
300+
body: {
301+
0: @index
302+
1: {
303+
object: {
304+
0: @lookup
305+
1: {
306+
key: context
307+
}
308+
}
309+
query: {
310+
0: program
311+
1: start_time
312+
}
313+
}
314+
}
296315
}
297316
}
298317
}
@@ -308,18 +327,26 @@ Which in turn compiles to the following `plt` program:
308327
message: "Welcome to Please"
309328
now: {
310329
0: @runtime
311-
function: {
312-
0: @function
313-
parameter: context
314-
body: {
315-
0: @index
316-
object: {
317-
0: @lookup
318-
key: context
319-
}
320-
query: {
321-
0: program
322-
1: start_time
330+
1: {
331+
function: {
332+
0: @function
333+
1: {
334+
parameter: context
335+
body: {
336+
0: @index
337+
1: {
338+
object: {
339+
0: @lookup
340+
1: {
341+
key: context
342+
}
343+
}
344+
query: {
345+
0: program
346+
1: start_time
347+
}
348+
}
349+
}
323350
}
324351
}
325352
}
@@ -333,7 +360,7 @@ Which produces the following runtime output:
333360
{
334361
language: Please
335362
message: "Welcome to Please"
336-
now: "2025-02-14T18:45:14.168Z"
363+
now: "2025-05-13T22:11:56.804Z"
337364
}
338365
```
339366

examples/fibonacci.plz

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
11
{
22
fibonacci: n => {
33
@if
4-
condition: :n < 2
5-
then: :n
6-
else: :fibonacci(:n - 1) + :fibonacci(:n - 2)
4+
{
5+
condition: :n < 2
6+
then: :n
7+
else: :fibonacci(:n - 1) + :fibonacci(:n - 2)
8+
}
79
}
810

911
input: {
1012
@runtime
11-
context => :context.arguments.lookup(input)
13+
{ context => :context.arguments.lookup(input) }
1214
}
1315

1416
output: :input match {
1517
none: _ => "missing input argument"
1618
some: input => {
1719
@if
18-
condition: :natural_number.is(:input)
19-
then: :fibonacci(:input)
20-
else: "input must be a natural number"
20+
{
21+
condition: :natural_number.is(:input)
22+
then: :fibonacci(:input)
23+
else: "input must be a natural number"
24+
}
2125
}
2226
}
2327
}.output

examples/kitchen-sink.plz

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
add_one: :integer.add(1)
99
three: :add_one(:two)
1010
function: x => { value: :x }
11-
conditional_value: :function({ @if, :sky_is_blue, :two, :three })
12-
side_effect: { @runtime, context => :context.log("this goes to stderr") }
11+
conditional_value: :function({ @if, { :sky_is_blue, :two, :three } })
12+
side_effect: { @runtime, { context => :context.log("this goes to stderr") } }
1313
}

examples/lookup-environment-variable.plz

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
*/
55
{
66
@runtime
7-
context =>
8-
:context.arguments.lookup(variable) match {
9-
none: {}
10-
some: :context.environment.lookup >> :match({
7+
{
8+
context =>
9+
:context.arguments.lookup(variable) match {
1110
none: {}
12-
some: :identity
13-
})
14-
}
11+
some: :context.environment.lookup >> :match({
12+
none: {}
13+
some: :identity
14+
})
15+
}
16+
}
1517
}

0 commit comments

Comments
 (0)