Skip to content

Commit a23c755

Browse files
committed
Enable syntax highlighting with tree-sitter
1 parent 31b79b2 commit a23c755

File tree

11 files changed

+312
-257
lines changed

11 files changed

+312
-257
lines changed

Makefile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
AWK=awk
2+
HUGO=hugo
3+
4+
.PHONY: build
5+
build:
6+
$(HUGO)
7+
make public/*.html
8+
make public/**/*.html
9+
10+
public/%.html: .FORCE
11+
@mv $@ tmp.html
12+
$(AWK) -v outfile=$@ -f scripts/process-code-blocks.awk tmp.html
13+
@rm tmp.html
14+
15+
.PHONY: .FORCE
16+
.FORCE:

content/_index.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ title = 'About'
77

88
## Readable and concise concatenative programming
99

10-
```
10+
```cognate
1111
~~ Fizzbuzz in Cognate
1212
1313
Def Multiple as (Zero? Modulo);
@@ -23,7 +23,7 @@ For each in Range 1 to 100 (Print Fizzbuzz)
2323

2424
Cognate is a project aiming to create a human readable programming language with as little syntax as possible. Where natural language programming usually uses many complex syntax rules, instead Cognate takes them away. What it adds is simple, a way to embed comments into statements.
2525

26-
```
26+
```cognate
2727
~~ Towers of Hanoi in Cognate
2828
2929
Def Move discs as (
@@ -45,7 +45,7 @@ Move 5 discs from "a" via "b" to "c"
4545

4646
As you can see, Cognate ignores words starting with lowercase letters, allowing them to be used to describe functionality and enhance readability. This makes Cognate codebases intuitive and maintainable.
4747

48-
```
48+
```cognate
4949
~~ Square numbers in Cognate
5050
5151
Def Square as (* Twin);
@@ -55,7 +55,7 @@ Print
5555

5656
Cognate is a stack-oriented programming language similar to Forth or Factor, except statements are evaluated right to left. This gives the expressiveness of concatenative programming as well as the readability of prefix notation. Statements can be delimited at arbitrary points, allowing them to read as sentences would in English.
5757

58-
```
58+
```cognate
5959
~~ Prime numbers in Cognate
6060
6161
Def Factor (Zero? Modulo Swap);

content/learn.md

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ Alternatively, you can use the interactive web playground [here](https://cognate
2929
## First Programs
3030

3131

32-
```
32+
```cognate
3333
Print "Hello world!";
3434
```
3535

3636
Fairly simple right? This example calls the `Print` function with one parameter - the string `"Hello world!"`. Now let's do another simple example, adding two numbers.
3737

38-
```
38+
```cognate
3939
Print + 2 3;
4040
```
4141

@@ -45,7 +45,7 @@ Wait what? That isn't how maths works!
4545
Cognate doesn't care how maths works. Where in most programming languages, `+` would be an operator and would be used in the infix position, in Cognate `+` is a function. Like `Print`, the `+` function is called by being written before its arguments like shown above.
4646

4747

48-
```
48+
```cognate
4949
Print - 10 36; ~~ Subtracts 10 from 36
5050
```
5151

@@ -55,7 +55,7 @@ Another thing to note is that the order of parameters for `-` and `/` are backwa
5555

5656
Let's have a more complex example, this subtracts 12 from 15 and then multiplies the result by 2.
5757

58-
```
58+
```cognate
5959
Print * 2 - 12 15;
6060
```
6161

@@ -71,7 +71,7 @@ By now you may have realised that Cognate is evaluating our programs backwards -
7171

7272
Cognate comes with functions to manipulate the stack. The simplest of these is `Twin`, which takes the top element from the stack, and puts it back on again - twice. The below snippet uses `Twin` to square a number by multiplying it by itself.
7373

74-
```
74+
```cognate
7575
Print * Twin 8;
7676
```
7777

@@ -81,14 +81,14 @@ Now we don't want to write this every time we square a number right? So let's cr
8181

8282
Functions in Cognate are defined using `Def` and the name of the function. The function body is put in brackets after this.
8383

84-
```
84+
```cognate
8585
Def Square (* Twin);
8686
Print Square 8;
8787
```
8888

8989
This is great, but it certainly could flow better. Cognate ignores words starting with lowercase letters, allowing them to be used as comments. This lets us write:
9090

91-
```
91+
```cognate
9292
Print the Square of 8;
9393
```
9494

@@ -98,19 +98,19 @@ In this example the readability isn't really improved much, but in more complex
9898
By now you've probably noticed the semicolons. These delimit statements so that Cognate knows what order to evaluate functions in (remember that these are executed backwards). Definitions should also be terminated with semicolons. The stack persists between statements, letting us do things like this.
9999

100100

101-
```
101+
```cognate
102102
8 ; Square ; Print ;
103103
```
104104

105105
or this
106106

107-
```
107+
```cognate
108108
Square 8 ; Print ;
109109
```
110110

111111
or this
112112

113-
```
113+
```cognate
114114
8 ; Print the Square ;
115115
```
116116

@@ -120,14 +120,14 @@ This flexible syntax allows Cognate programs to flow as if written in sentences.
120120

121121
Variables are defined in a fairly similar manner to functions using `Let` and their name. This takes a value from the stack, binding it to this name. Variables are referenced with the same syntax in which functions are called.
122122

123-
```
123+
```cognate
124124
Let X be 4;
125125
Print X;
126126
```
127127

128128
We can use variables to define functions that take named parameters - here's an alternate version of the `Square` function.
129129

130-
```
130+
```cognate
131131
Def Square as (
132132
Let X;
133133
* X X
@@ -136,7 +136,7 @@ Def Square as (
136136

137137
Notice that the last statement before a closing bracket does not need to be terminated with a semicolon. Also there is no return statement, since values are implicitly returned on the stack. This means we can actually define functions that return multiple values, such as the `Twin` function we saw earlier.
138138

139-
```
139+
```cognate
140140
Def Twin as (
141141
Let X;
142142
X X
@@ -148,23 +148,23 @@ Def Twin as (
148148

149149
Like most programming languages, Cognate has if statements and loops and all that jazz. The simplest form of control flow is `When`, which simply executes a block of code if given `True` or not if `False`.
150150

151-
```
151+
```cognate
152152
When == 1 1 (
153153
Print "Who'd have guessed?"
154154
);
155155
```
156156

157157
There is also `Unless` that evaluates the block if given `False`. `While` takes a condition in brackets and evaluates the block of code until the condition is `False`. `Until`, you guessed it, is the opposite of `While` and runs until the condition is `True`.
158158

159-
```
159+
```cognate
160160
While (True) (
161161
Print "This may well print forever"
162162
);
163163
```
164164

165165
What's with the second set of brackets? `When` doesn't have them, so why should `While`? This is because brackets denote blocks! These prevent code being instantly evaluated and instead push a reference onto the stack. Blocks also control variable scopes. We can evaluate a block using the `Do` function - which is how our control flow functions are implemented.
166166

167-
```
167+
```cognate
168168
Do (
169169
Print "Hello from inside a block!"
170170
);
@@ -176,7 +176,7 @@ This explains the syntax for functions: `Def` simply binds a block to a name, mu
176176
Now that this (hopefully) makes some sense, we can finally introduce the `If` statement! `If` is a function that takes three parameters. The first is a boolean, if this is `True` then the second argument is returned. If not, the third argument is returned. We can chain `If`s together to have more complex control flow.
177177

178178

179-
```
179+
```cognate
180180
Print
181181
If == X 1 then "foo"
182182
If == X 2 then "bar"
@@ -185,7 +185,7 @@ Print
185185

186186
We can combine this with `Do` to have conditional code execution.
187187

188-
```
188+
```cognate
189189
Do
190190
If == X 1 then ( Print "foo" )
191191
If == X 2 then ( Print "bar" )
@@ -194,7 +194,7 @@ Do
194194

195195
Now, lets use our knowledge of blocks to define our own control flow function `Thrice`, which should evaluate a block three times in a row. This demonstrates a different use of `Def` in which we bind a block from the stack.
196196

197-
```
197+
```cognate
198198
Def Thrice as (
199199
Def F;
200200
F F F
@@ -207,7 +207,7 @@ Thrice (
207207

208208
A more general version of this function, `Times` can be defined using recursion.
209209

210-
```
210+
```cognate
211211
Def Times (
212212
Let N number of repetitions;
213213
Def F function to repeat;
@@ -221,7 +221,7 @@ Times 5 (
221221

222222
Now you may see a small problem with this. If the user calls `Times` with a non-integer parameter it will loop forever - that won't do at all! We use the `Integer!` function to throw a type error if a decimal is given.
223223

224-
```
224+
```cognate
225225
Def Times (
226226
Let N is Integer! number of repetitions;
227227
Def F function to repeat;
@@ -235,7 +235,7 @@ We could also use the `Block!` function for `F` but we'll already get a type err
235235
The `Times` function is also our first loop. We don't need to define it every time though as it's also in the standard library. Another loop is `While`.
236236

237237

238-
```
238+
```cognate
239239
While (!= "done" Twin Input) (
240240
Print
241241
);
@@ -252,13 +252,13 @@ This loop is most useful in imperative code where intermediary values are passed
252252

253253
In Cognate, lists are generated using - you guessed it - a function. The `List` function takes a block as a parameter. It evaluates this block *in a new stack* and then returns that stack as a list.
254254

255-
```
255+
```cognate
256256
Print List (1 2 3 4 5);
257257
```
258258

259259
This allows Cognate's list creation to be much more flexible than other languages - for example what if we wanted a list of 100 ones?
260260

261-
```
261+
```cognate
262262
Print List ( Times 100 (1) );
263263
```
264264

@@ -268,37 +268,37 @@ The three most fundamental list functions are `Push`, `First`, and `Rest`.
268268
The `Push` function takes a value and a list as parameters, and returns the list with the value *pushed* to it's first element. `First` simply returns the first element of a list. `Rest` returns a list without its first element.
269269

270270

271-
```
271+
```cognate
272272
Let L be Push "foo" to List ( "bar" "baz" );
273273
Print First element of L;
274274
Print Rest of L;
275275
```
276276

277277
`Range` creates a list of numbers from a starting (inclusive) and an ending (exclusive) number. `For` is a higher order function that applied an operation to each element of a list - it is the loop for iterating over lists.
278278

279-
```
279+
```cognate
280280
Def Square as (* Twin);
281281
For each in Range 1 to 20 (Print the Square);
282282
```
283283

284284
`Map` is like `For` but the result of the computation is stored in a new list.
285285

286-
```
286+
```cognate
287287
Let Evens be Map (* 2) over Range 1 to 50;
288288
Print Evens;
289289
```
290290

291291
`Filter` applies a function to each element of a list also. This function should return a boolean - if this is `False` then the function is removed from the returned list.
292292

293-
```
293+
```cognate
294294
Let Even? be (Zero? Modulo 2);
295295
Let Evens be Filter (Even?) over Range 1 to 100;
296296
Print Evens;
297297
```
298298

299299
The functional programmers reading this are likely expecting a Fold or Reduce function next - which applies an operation to a list with an accumulator. However Cognate needs no fold function, as `For` can store intermediary values on the stack, acting like a fold.
300300

301-
```
301+
```cognate
302302
Def Factorial as (
303303
Let N be Integer!;
304304
For each in Range 1 to N (*) from 1;
@@ -316,7 +316,7 @@ While storing state between loop iterations is very useful, in some cases you ju
316316
The `Box` function takes a value and places it in a box. `Unbox` returns the item stored in a box. `Set` takes a box and a value as parameters and mutates the box to hold the value, updating all references to it.
317317

318318

319-
```
319+
```cognate
320320
Let X be Box 1;
321321
Print Unbox X; ~~ prints 1
322322
@@ -326,7 +326,7 @@ Print Unbox X; ~~ prints 2
326326

327327
Boxes aren't limited to mutating variables, they can be used for any value.
328328

329-
```
329+
```cognate
330330
Let L be Map (Box) over Range 1 to 10;
331331
Print L;
332332
@@ -339,7 +339,7 @@ Print L;
339339

340340
While boxes may not seem as ergonomic as mutation in other languages, they are both more flexible than mutable variables and more predictable than implicit references. We can also easily extend mutation, like this:
341341

342-
```
342+
```cognate
343343
Def Box-list as ( Map (Box) );
344344
345345
Def Inplace-map as (
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{{ printf "<!--cognate-->" | safeHTML }}<div class="code"><pre><code>
2+
{{ .Inner | safeHTML }}
3+
</code></pre></div>

public/categories/index.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
<title>Categories on Cognate: Readable and concise concatenative programming</title>
55
<link>https://cognate-lang.github.io/categories/</link>
66
<description>Recent content in Categories on Cognate: Readable and concise concatenative programming</description>
7-
<generator>Hugo -- gohugo.io</generator>
8-
<language>en-us</language><atom:link href="https://cognate-lang.github.io/categories/index.xml" rel="self" type="application/rss+xml" />
7+
<generator>Hugo</generator>
8+
<language>en-us</language>
9+
<atom:link href="https://cognate-lang.github.io/categories/index.xml" rel="self" type="application/rss+xml" />
910
</channel>
1011
</rss>

0 commit comments

Comments
 (0)