Skip to content

Commit cd600d6

Browse files
authored
Add a semicolon composition operator & update docs (#111)
* Tidy up a test * Semicolon operator for pipeline-ordered composition * Doc on operators and identifiers * Update syntax docs
1 parent 3303fe2 commit cd600d6

File tree

6 files changed

+140
-33
lines changed

6 files changed

+140
-33
lines changed

docs/operators-and-identifiers.md

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Operators and Identifiers
2+
3+
Eucalypt distinguishes two different types of identifier, *normal*
4+
identifiers, like `x`, `y`, `α`, `א`, `ziggety-zaggety`, `zoom?`, and
5+
*operator identifiers* like `*`, `@`, `&&`, ``, ``, `⊙⊙⊙`, `<>` and
6+
so on.
7+
8+
It is entirely a matter of the component characters which category and
9+
identifier falls into. Normal identifiers contain letters (including
10+
non-ascii characters), numbers, "-", "?", "$". Operator identifiers
11+
contain the usual suspects and anything identified as an operator or
12+
symbol in unicode. Neither can contain ":" or "," or brackets which
13+
are special in eucalypt.
14+
15+
Any sequence of characters at all can be treated as a normal
16+
identifier by surrounding them in single quotes. This is the only use
17+
of single quotes in eucalypt. This can be useful when you want to use
18+
file paths or other external identifiers as block keys for instance:
19+
20+
```eu
21+
22+
home: {
23+
'.bashrc': false
24+
'.emacs.d': false
25+
'notes.txt': true
26+
}
27+
28+
z: home.'notes.txt'
29+
30+
```
31+
32+
## Normal identifiers
33+
34+
Normal operators are brought into scope by declarations and can be
35+
referred to without qualification in their own block or in more
36+
nested blocks:
37+
38+
```eu
39+
40+
x: {
41+
z: 99
42+
foo: z //=> 99
43+
bar: {
44+
y: z //=> 99
45+
}
46+
}
47+
48+
```
49+
50+
They can be accessed from within other blocks using the lookup
51+
operator:
52+
53+
```eu
54+
55+
x: {
56+
z: 99
57+
}
58+
59+
y: x.z //=> 99
60+
```
61+
62+
They can be overridden using generalised lookup:
63+
64+
```eu
65+
66+
z: 99
67+
y: { z: 100 }."z is {z}" //=> "z is 100"
68+
```
69+
70+
They can be shadowed:
71+
72+
```eu
73+
74+
z: 99
75+
y: { z: 100 r: z //=> 100 }
76+
```
77+
78+
But beware trying to access the outer value:
79+
80+
```eu
81+
name: "foo"
82+
x: { name: name } //=> infinite recursion
83+
```
84+
85+
Accessing shadowed values is not yet easily possible unless you can
86+
refer to an enclosing block and use a lookup.
87+
88+
## Operator identifiers
89+
90+
Operator identifiers are more limited than normal identifiers.
91+
92+
They are brought into scope by operator declarations and available
93+
without qualification in their own block and more nested blocks:
94+
95+
```eu
96+
( l -->> r): "{l} shoots arrow at {r}"
97+
98+
x: {
99+
y: 2 -->> 3 //=> "2 shoots arrow at 3"
100+
}
101+
```
102+
103+
...and can be shadowed:
104+
105+
```eu
106+
107+
(l !!! r): l + r
108+
109+
y: {
110+
(l !!! r): l - r
111+
z: 100 !!! 1 //=> 99
112+
}
113+
114+
```
115+
116+
But:
117+
118+
- they cannot be accessed by lookup, so there is no way of forming a
119+
qualified name to access an operator
120+
- they cannot be overridden by generalised lookup

docs/syntax.md

+6-21
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ Eucalypt has two types of names:
4545
- operator names, which are largely symbolic (e.g. `&&&`, ``, `-+-|`,
4646
``) and are used to name operators
4747

48+
See [Operators and Identifiers](operators-and-identifiers.md) for more.
49+
4850
## The block DSL
4951

5052
A **block** is surrounded by curly braces:
@@ -86,31 +88,14 @@ c: 3
8688
So far all these declarations have been **property declarations** which
8789
contains a name and an expression, separated by a colon.
8890

89-
There is no comma separating declarations. Nor are line endings
90-
significant. The following is a block of three **property
91-
declarations**.
91+
Commas are entirely optional for delimiting declarations. Line endings
92+
are not significant. The following is a top-level block of three
93+
**property declarations**.
9294

9395
```eu
9496
a: 1 b: 2 c: 3
9597
```
9698

97-
(The colon is very important.)
98-
99-
!!! note
100-
101-
This is a controversial choice and might change in future. Eucalypt
102-
aims to be minimal and commas would be redundant. Lacking
103-
explicit delimitation makes the parsing slower and closes off
104-
evolutions of the languages in which the comma would no longer be
105-
redundant (as per some recent enhancements in javascript). Another
106-
option would be a "commas are whitespace" approach as per Clojure
107-
but that leads to confusion when commas are sometimes used,
108-
sometimes not, sometimes places in the wrong place with no
109-
objection from the compiler. Leaving them out keeps the
110-
possibility of using them as a tupling operator in future - but
111-
note that they are required for list literals in the expression
112-
DSL.
113-
11499
There are other types of declarations. By specifying a parameter list,
115100
you get a **function declaration**:
116101

@@ -335,4 +320,4 @@ returns that value if they are.
335320
There are no explicit lambda expressions in Eucalypt right now.
336321
For simple cases, expression or string anaphora should do the job.
337322
For more involved cases, you should use a named function declaration.
338-
More features are coming...
323+
See [Anaphora and Lambdas](anaphora-and-lambdas.md) for more.

harness/test/014_numeric_combinators.eu

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# doesn't require prelude; uses builtins only
2-
31
` :suppress
42
(l||r): __OR(l,r)
53
` :suppress
@@ -17,12 +15,9 @@ take(n, l): __IF((n zero?) || (l empty?), [], cons(l head, take(n dec, l tail)))
1715
` :suppress
1816
drop(n, l): __IF((n zero?) || (l empty?), l, drop(n dec, l tail))
1917
` :suppress
20-
repeat-n(n, i): __IF((n zero?), [], cons(i, repeat-n(dec(n), i)))
21-
22-
# TODO: Can't use this until lists are exposed to eu as cons is not
23-
# currently lazy enough
24-
` :suppress
2518
repeat(i): __CONS(i, repeat(i))
19+
` :suppress
20+
repeat-n(n, i): repeat(i) take(n)
2621

2722
ten-fives: repeat-n(10, 5)
2823
ten-hellos: repeat-n(10, "hello")

lib/prelude.eu

+8-2
Original file line numberDiff line numberDiff line change
@@ -398,11 +398,17 @@ const(k, _): k
398398
` "`compose(f,g,x)` - apply function `f` to `g(x)`."
399399
compose(f, g, x): x g f
400400

401-
` { doc: "`(f ∘ g)` - return composition of `f` and `g`"
401+
` { doc: "`(f ∘ g)` - return composition of `f` and `g` (`g` then `f`)"
402402
export: :suppress
403403
associates: :right
404404
precedence: 88 }
405-
(f ∘ g): compose(f,g)
405+
(f ∘ g): compose(f, g)
406+
407+
` { doc: "`(f ; g)` - return composition of `f` then `g`"
408+
export: :suppress
409+
associates: :left
410+
precedence: 88 }
411+
(f ; g): compose(g, f)
406412

407413
` { doc: "(l @ r) - function application operator, for reversing catentation args and eliding parentheses"
408414
export: :suppress

mkdocs.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
site_name: "Eucalypt: liquiYAML"
1+
site_name: "eucalypt"
22
repo_url: https://github.com/curvelogic/eucalypt
33
copyright: "Copyright (C) 2018 Greg Hawkins"
44
docs_dir: docs
@@ -7,6 +7,7 @@ nav:
77
- Getting Started: getting-started.md
88
- Syntax: syntax.md
99
- Command Line: command-line.md
10+
- Operators and Identifiers: operators-and-identifiers.md
1011
- Anaphora and Lambdas: anaphora-and-lambdas.md
1112
- Philosophy: philosophy-lang.md
1213
markdown_extensions:

src/Eucalypt/Syntax/ParseExpr.hs

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ operatorIdentifier =
4545
"operator identifier"
4646
where
4747
opIdentStartChar =
48-
oneOf (".!@£%^&*|></+=-~" :: String) <|>
48+
oneOf (".!@£%^&*|></+=-~;" :: String) <|>
4949
satisfy
5050
(\c ->
5151
(not . isAscii) c && (c /= '') && (isSymbol c || isPunctuation c))
5252
opIdentContinuationChar =
53-
oneOf (".!@£$%^&*|></?+=-~" :: String) <|>
53+
oneOf (".!@£$%^&*|></?+=-~;" :: String) <|>
5454
satisfy (\c -> (not . isAscii) c && (isSymbol c || isPunctuation c))
5555

5656

0 commit comments

Comments
 (0)