Appearance
Reading a Line
A line in Tilde is a sentence about a figure. Nothing in it is a keyword of the language: line, parallel and through mean what definitions say they mean. So reading a line means working out which definitions it is made of. Tilde does that the way you would read it aloud — from left to right.
Left to right
Tilde takes the longest definition that matches from the start of the line. What that gives back becomes the subject of whatever comes next:
line m
point p at 1 1
line l parallel m through pThe last line reads as make a line l parallel to m, and it passes through p. line l only makes a line; parallel m is said about the line it made, and so is through p, because each gives back the line it was said about. Nothing defines line l parallel m as a whole — it is line l, then … parallel m. The same works on lines that already exist:
l parallel m through pThis is why a constraint gives back its subject: so that the next one in the sentence is about the same thing.
The longest match wins
If two definitions could start the line, the one that takes more of it is used. That is how you replace a reading with your own:
define line (n: new Line) parallel (m: Line) => Line:
line n
n parallel m
return nWith this in your file, line l parallel m uses it, rather than line l and then … parallel m.
If the longest one does not fit — say yours takes a circle, and m is a line — Tilde falls back to the next shorter reading instead of giving up.
When the start does not lead anywhere
Sometimes no reading from the first word makes sense:
print 1 + 2print 1 is a complete sentence, but nothing can follow it with + 2. So Tilde tries from a later word: 1 + 2 reads, gives 3, and print 3 is what the line means. A definition that takes nothing is used the same way:
define greeting => Text:
return "hello"
print greetingA line that already reads from the start is never re-read this way.
= takes everything after it
= binds more loosely than anything else (see How tightly things bind below), so whatever comes after it is worked out first:
scalar k = 2 + 3 -- k is 5
point p = (3, 4) on l -- p is that point, and it is on lRead strictly left to right, the first would add 3 to scalar k = 2. Because = binds loosest, Tilde reads 2 + 3 first instead.
= hands back its right side, so equalities chain the way they do in maths:
a = b = c -- a = b, and b = cHow tightly things bind
A definition can say how tightly it holds what is next to it, with a number after what it gives back — higher holds tighter:
define (a: Scalar) * (b: Scalar) => Scalar at 7:
define (a: Scalar) + (b: Scalar) => Scalar at 6:Everything that says nothing is at 5. When a line could be grouped more than one way, Tilde never reads a looser definition as sitting inside a tighter one. So arithmetic reads as it does in any book — 2 + 3 * 4 is 2 + (3 * 4), which is 14 — and equal ones still go left to right: 10 - 2 - 3 is 5.
A definition matched as a whole is never split up by this. If you define (a) * (b) + (c) * (d) yourself, a * b + c * d uses yours, because it is the longest match.
Use brackets to say otherwise: (2 + 3) * 4 is 20.
Brackets
Brackets say what goes together when left to right is not what you mean:
line l through (1, 2) (3, 4)
print 2 + (3 * 4)What is inside a bracket is worked out first and stands in for it.
Where it lands decides what it is
Two definitions can share their words and differ only in what they give back. A pair of numbers, say, could be a point (x, y) — the prelude's reading — or, if you add one, a line in slope-intercept form (m, k):
define (m: Scalar) , (k: Scalar) => Line:
line l
return lTilde does not guess between them: the place a pair lands decides.
line k through (1, 2) (3, 4) -- through wants points: two points
l parallel (2, 1) -- parallel wants a line: the lineWhen a line can mean two things
If nothing around a thing says which it is — it stands alone, or it lands where anything would do, like print — the line is refused rather than guessed at, and nothing in it runs. Name it first (point p = (2, 1)), then use the name.