mirror of
https://git.acl.cool/al/pages.git
synced 2025-12-16 12:31:18 -05:00
Compare commits
4 commits
18b0b14e25
...
594b9ae2d2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
594b9ae2d2 | ||
|
|
808ebfdfa2 | ||
|
|
53154ec9b7 | ||
|
|
64acf09214 |
9 changed files with 91 additions and 94 deletions
|
|
@ -17,7 +17,7 @@ section.</p>
|
||||||
the character doesn't cause a parsing issue. For example, whitespace
|
the character doesn't cause a parsing issue. For example, whitespace
|
||||||
tokens are not allowed in variable names.</p>
|
tokens are not allowed in variable names.</p>
|
||||||
<p>Some examples of assigning variables:</p>
|
<p>Some examples of assigning variables:</p>
|
||||||
<pre class="gp1"><code>var x: i32; // x is an uninitialized 32-bit signed integer
|
<pre class="language-gp1"><code>var x: i32; // x is an uninitialized 32-bit signed integer
|
||||||
var y <- x; // this won't work, because x has no value
|
var y <- x; // this won't work, because x has no value
|
||||||
x <- 7;
|
x <- 7;
|
||||||
var y <- x; // this time it works, because x is now 7
|
var y <- x; // this time it works, because x is now 7
|
||||||
|
|
@ -25,12 +25,12 @@ var y <- x; // this time it works, because x is now 7
|
||||||
con a: f64 <- 99.8; // a is immutable
|
con a: f64 <- 99.8; // a is immutable
|
||||||
a <- 44.12; // this doesn't work, because con variables cannot be reassigned</code></pre>
|
a <- 44.12; // this doesn't work, because con variables cannot be reassigned</code></pre>
|
||||||
<p>The following lines are equivalent,</p>
|
<p>The following lines are equivalent,</p>
|
||||||
<pre class="gp1"><code>con a <- f64(7.2);
|
<pre class="language-gp1"><code>con a <- f64(7.2);
|
||||||
con a: f64 <- 7.2;
|
con a: f64 <- 7.2;
|
||||||
con a <- 7.2; // 7.2 is implicitly of type f64
|
con a <- 7.2; // 7.2 is implicitly of type f64
|
||||||
con a <- 7.2D; // With an explicit type suffix</code></pre>
|
con a <- 7.2D; // With an explicit type suffix</code></pre>
|
||||||
<p>as are these.</p>
|
<p>as are these.</p>
|
||||||
<pre class="gp1"><code>var c: f32 <- 9;
|
<pre class="language-gp1"><code>var c: f32 <- 9;
|
||||||
var c <- f32(9);
|
var c <- f32(9);
|
||||||
var c: f32 <- f32(9);
|
var c: f32 <- f32(9);
|
||||||
var c <- 9F;</code></pre>
|
var c <- 9F;</code></pre>
|
||||||
|
|
@ -68,7 +68,7 @@ Numeric operators are as one expects from C, with the addition of
|
||||||
<code>**</code> as a power operator.</p>
|
<code>**</code> as a power operator.</p>
|
||||||
<p>Numeric literals have an implicit type, or the type can be specified
|
<p>Numeric literals have an implicit type, or the type can be specified
|
||||||
by a case-insensitive suffix. For example:</p>
|
by a case-insensitive suffix. For example:</p>
|
||||||
<pre class="gp1"><code>var i1 <- 1234; // implicitly i32
|
<pre class="language-gp1"><code>var i1 <- 1234; // implicitly i32
|
||||||
var f1 <- 1234.5; // implicitly f64
|
var f1 <- 1234.5; // implicitly f64
|
||||||
|
|
||||||
var i3 <- 1234L; // i64
|
var i3 <- 1234L; // i64
|
||||||
|
|
@ -150,7 +150,7 @@ value can be used as a literal in this fasion.</p>
|
||||||
double-quoted, e.g. <code>"Hello, World."</code>.</p>
|
double-quoted, e.g. <code>"Hello, World."</code>.</p>
|
||||||
<h3 id="arrays">Arrays</h3>
|
<h3 id="arrays">Arrays</h3>
|
||||||
<p>GP1 supports typical array operations.</p>
|
<p>GP1 supports typical array operations.</p>
|
||||||
<pre class="gp1"><code>var tuples : (int, int)[]; // declare array of tuples
|
<pre class="language-gp1"><code>var tuples : (int, int)[]; // declare array of tuples
|
||||||
var strings : string[]; // declare array of strings
|
var strings : string[]; // declare array of strings
|
||||||
|
|
||||||
var array <- i32[n]; // declare and allocate array of n elements
|
var array <- i32[n]; // declare and allocate array of n elements
|
||||||
|
|
@ -161,7 +161,7 @@ con nums <- {1, 2, 3}; // immutable array of i32
|
||||||
<p>Use the <code>length</code> property to access the number of elements
|
<p>Use the <code>length</code> property to access the number of elements
|
||||||
in an allocated array. Attempting to access <code>length</code> of an
|
in an allocated array. Attempting to access <code>length</code> of an
|
||||||
unallocated array is an exception.</p>
|
unallocated array is an exception.</p>
|
||||||
<pre class="gp1"><code>
|
<pre class="language-gp1"><code>
|
||||||
var colors <- {"Red", "White", "Blue"}; // allocate array
|
var colors <- {"Red", "White", "Blue"}; // allocate array
|
||||||
|
|
||||||
var count <- colors.length; // count is usize(3)
|
var count <- colors.length; // count is usize(3)
|
||||||
|
|
@ -170,7 +170,7 @@ var count <- colors.length; // count is usize(3)
|
||||||
Negative values wrap from the end (-1 is the last element). An exception
|
Negative values wrap from the end (-1 is the last element). An exception
|
||||||
occurs if the value is too big, i.e.no modulo operation is
|
occurs if the value is too big, i.e.no modulo operation is
|
||||||
performed.</p>
|
performed.</p>
|
||||||
<pre class="gp1"><code>var w <- {1, 2, 3, 4, 5, 6, 7};
|
<pre class="language-gp1"><code>var w <- {1, 2, 3, 4, 5, 6, 7};
|
||||||
|
|
||||||
w[0] // first element, 1
|
w[0] // first element, 1
|
||||||
w[-1] // last element, 7
|
w[-1] // last element, 7
|
||||||
|
|
@ -191,7 +191,7 @@ i.e.<code>(u128(4), "2").1</code> would be <code>"2"</code>.</p>
|
||||||
identical to that of .NET 5 and very similar to that of gawk.</p>
|
identical to that of .NET 5 and very similar to that of gawk.</p>
|
||||||
<h2 id="named-functions">Named Functions</h2>
|
<h2 id="named-functions">Named Functions</h2>
|
||||||
<p>Some examples of defining named functions:</p>
|
<p>Some examples of defining named functions:</p>
|
||||||
<pre class="gp1"><code>fn sum(a: f32, b: f32): f32 { a + b } // takes parameters and returns an f32
|
<pre class="language-gp1"><code>fn sum(a: f32, b: f32): f32 { a + b } // takes parameters and returns an f32
|
||||||
|
|
||||||
fn twice_println(s: string) { // takes parameters and implicitly returns ()
|
fn twice_println(s: string) { // takes parameters and implicitly returns ()
|
||||||
println("${s}\n${s}");
|
println("${s}\n${s}");
|
||||||
|
|
@ -210,13 +210,13 @@ ordered from left to right in the function definition that is
|
||||||
unassigned. With regard to the <code>join_println</code> function
|
unassigned. With regard to the <code>join_println</code> function
|
||||||
defined above, this means that all of the following are valid and behave
|
defined above, this means that all of the following are valid and behave
|
||||||
identically.</p>
|
identically.</p>
|
||||||
<pre class="gp1"><code>join_println(a <- "Hello,", b <- "World.");
|
<pre class="language-gp1"><code>join_println(a <- "Hello,", b <- "World.");
|
||||||
join_println(b <- "World.", a <- "Hello,");
|
join_println(b <- "World.", a <- "Hello,");
|
||||||
join_println(b <- "World.", "Hello,");
|
join_println(b <- "World.", "Hello,");
|
||||||
join_println("Hello,", "World.");</code></pre>
|
join_println("Hello,", "World.");</code></pre>
|
||||||
<p>Function names may be overloaded. For example,
|
<p>Function names may be overloaded. For example,
|
||||||
<code>join_println</code> could be additionally defined as</p>
|
<code>join_println</code> could be additionally defined as</p>
|
||||||
<pre class="gp1"><code>fn join_println(a: string, b: string, sep: string) {
|
<pre class="language-gp1"><code>fn join_println(a: string, b: string, sep: string) {
|
||||||
println("${a}${sep}${b}");
|
println("${a}${sep}${b}");
|
||||||
}</code></pre>
|
}</code></pre>
|
||||||
<p>and then both <code>join_println("Hello,", "World.", " ")</code> and
|
<p>and then both <code>join_println("Hello,", "World.", " ")</code> and
|
||||||
|
|
@ -226,7 +226,7 @@ be familar with this pattern from functional languages like F#, wherein
|
||||||
a wrapper function is often used to guard an inner recursive function
|
a wrapper function is often used to guard an inner recursive function
|
||||||
(GP1 permits both single and mutual recursion in functions). For
|
(GP1 permits both single and mutual recursion in functions). For
|
||||||
example:</p>
|
example:</p>
|
||||||
<pre class="gp1"><code>fn factorial(n: u256): u256 {
|
<pre class="language-gp1"><code>fn factorial(n: u256): u256 {
|
||||||
fn aux(n: u256, accumulator: u256): u256 {
|
fn aux(n: u256, accumulator: u256): u256 {
|
||||||
match n > 1 {
|
match n > 1 {
|
||||||
true => aux(n - 1, accumulator * n),
|
true => aux(n - 1, accumulator * n),
|
||||||
|
|
@ -242,7 +242,7 @@ syntax used in this example, refer to <em>Control Flow</em>.</p>
|
||||||
<p>Closures behave as one would expect in GP1, exactly like they do in
|
<p>Closures behave as one would expect in GP1, exactly like they do in
|
||||||
most other programming languages that feature them. Closures look like
|
most other programming languages that feature them. Closures look like
|
||||||
this:</p>
|
this:</p>
|
||||||
<pre class="gp1"><code>var x: u32 <- 8;
|
<pre class="language-gp1"><code>var x: u32 <- 8;
|
||||||
|
|
||||||
var foo <- { y, z => x * y * z}; // foo is a closure; its type is fn<u32 | u32>
|
var foo <- { y, z => x * y * z}; // foo is a closure; its type is fn<u32 | u32>
|
||||||
assert(foo(3, 11) == (8 * 3 * 11)); // true
|
assert(foo(3, 11) == (8 * 3 * 11)); // true
|
||||||
|
|
@ -268,7 +268,7 @@ sign is enclosed by them.</p>
|
||||||
<p>Lambdas are nearly identical to closures, but they don't close over
|
<p>Lambdas are nearly identical to closures, but they don't close over
|
||||||
their environment, and they use the <code>-></code> symbol in place
|
their environment, and they use the <code>-></code> symbol in place
|
||||||
of <code>=></code>. A few examples of lambdas:</p>
|
of <code>=></code>. A few examples of lambdas:</p>
|
||||||
<pre class="gp1"><code>con x: u32 <- 4; // this line is totally irrelevant
|
<pre class="language-gp1"><code>con x: u32 <- 4; // this line is totally irrelevant
|
||||||
|
|
||||||
con square <- { x -> x * x }; // this in not valid, because the type of the function is not known
|
con square <- { x -> x * x }; // this in not valid, because the type of the function is not known
|
||||||
con square <- { x: u32 -> x * x }; // this if fine, because the type is specified in the lambda
|
con square <- { x: u32 -> x * x }; // this if fine, because the type is specified in the lambda
|
||||||
|
|
@ -281,20 +281,20 @@ there is a separate syntax for function types. Given the function
|
||||||
<code>fn sum(a: f64, b: f64): f64 { a + b }</code> the function type is
|
<code>fn sum(a: f64, b: f64): f64 { a + b }</code> the function type is
|
||||||
expressed <code>fn<f64 f64 | f64></code>, meaning a function that
|
expressed <code>fn<f64 f64 | f64></code>, meaning a function that
|
||||||
accepts two f64 values and returns an f64. Therefore,</p>
|
accepts two f64 values and returns an f64. Therefore,</p>
|
||||||
<pre class="gp1"><code>fn sum(a: f64, b: f64): f64 { a + b } </code></pre>
|
<pre class="language-gp1"><code>fn sum(a: f64, b: f64): f64 { a + b } </code></pre>
|
||||||
<pre class="gp1"><code>con sum: fn<f64 f64 | f64> <- { a, b -> a + b };</code></pre>
|
<pre class="language-gp1"><code>con sum: fn<f64 f64 | f64> <- { a, b -> a + b };</code></pre>
|
||||||
<pre class="gp1"><code>con sum <- { a: f64, b: f64 -> a + b };</code></pre>
|
<pre class="language-gp1"><code>con sum <- { a: f64, b: f64 -> a + b };</code></pre>
|
||||||
<p>are all equivalent ways of binding a function of type
|
<p>are all equivalent ways of binding a function of type
|
||||||
<code>fn<f64 f64 | f64></code> to the constant <code>sum</code>.
|
<code>fn<f64 f64 | f64></code> to the constant <code>sum</code>.
|
||||||
Here's an example of how to express a function type for a function
|
Here's an example of how to express a function type for a function
|
||||||
argument.</p>
|
argument.</p>
|
||||||
<pre class="gp1"><code>fn apply_op(a: i32, b: i32, op: fn<i32 i32 | i32>): i32 {
|
<pre class="language-gp1"><code>fn apply_op(a: i32, b: i32, op: fn<i32 i32 | i32>): i32 {
|
||||||
op(a, b)
|
op(a, b)
|
||||||
}</code></pre>
|
}</code></pre>
|
||||||
<h3 id="function-type-inference">Function Type Inference</h3>
|
<h3 id="function-type-inference">Function Type Inference</h3>
|
||||||
<p>The above example provides an explicit type for the argument
|
<p>The above example provides an explicit type for the argument
|
||||||
<code>op</code>. You could safely rewrite this as</p>
|
<code>op</code>. You could safely rewrite this as</p>
|
||||||
<pre class="gp1"><code>fn apply_op(a: i32, b: i32, op: fn): i32 {
|
<pre class="language-gp1"><code>fn apply_op(a: i32, b: i32, op: fn): i32 {
|
||||||
op(a, b)
|
op(a, b)
|
||||||
}</code></pre>
|
}</code></pre>
|
||||||
<p>because the compiler can safely infer the function type of
|
<p>because the compiler can safely infer the function type of
|
||||||
|
|
@ -306,19 +306,19 @@ is not allowed.</p>
|
||||||
syntax used in this section.</p>
|
syntax used in this section.</p>
|
||||||
<p>Numeric types are automatically coerced into other numeric types as
|
<p>Numeric types are automatically coerced into other numeric types as
|
||||||
long as that coercion is not lossy. For example,</p>
|
long as that coercion is not lossy. For example,</p>
|
||||||
<pre class="gp1"><code>var x: i32 <- 10;
|
<pre class="language-gp1"><code>var x: i32 <- 10;
|
||||||
var y: i64 <- x;</code></pre>
|
var y: i64 <- x;</code></pre>
|
||||||
<p>is perfectly legal (the 32-bit value fits nicely in the 64-bit
|
<p>is perfectly legal (the 32-bit value fits nicely in the 64-bit
|
||||||
variable). However, automatic coercion doesn't work if it would be
|
variable). However, automatic coercion doesn't work if it would be
|
||||||
lossy, so</p>
|
lossy, so</p>
|
||||||
<pre class="gp1"><code>var x: i64 <- 10;
|
<pre class="language-gp1"><code>var x: i64 <- 10;
|
||||||
var y: i32 <- x;</code></pre>
|
var y: i32 <- x;</code></pre>
|
||||||
<p>doesn't work. This holds for numeric literals as well.
|
<p>doesn't work. This holds for numeric literals as well.
|
||||||
Unsurprisingly, <code>var x: i32 <- 3.14</code> wouldn't compile. The
|
Unsurprisingly, <code>var x: i32 <- 3.14</code> wouldn't compile. The
|
||||||
floating point value can't be automatically coerced to an integer type.
|
floating point value can't be automatically coerced to an integer type.
|
||||||
So what does work? Casting via the target type's pseudo-constructor
|
So what does work? Casting via the target type's pseudo-constructor
|
||||||
works.</p>
|
works.</p>
|
||||||
<pre class="gp1"><code>con x: f64 <- 1234.5; // okay because the literal can represent any floating point type
|
<pre class="language-gp1"><code>con x: f64 <- 1234.5; // okay because the literal can represent any floating point type
|
||||||
con y: f64 <- f16(1234.5); // also okay, because any f16 can be losslessly coerced to an f64
|
con y: f64 <- f16(1234.5); // also okay, because any f16 can be losslessly coerced to an f64
|
||||||
con z: i32 <- i32(x); // also okay; uses the i32 pseudo-constructor to 'cast' x to a 32-bit integer
|
con z: i32 <- i32(x); // also okay; uses the i32 pseudo-constructor to 'cast' x to a 32-bit integer
|
||||||
|
|
||||||
|
|
@ -346,7 +346,7 @@ type of the function is not an integer, GP1 assumes an exit code of
|
||||||
<code>usize(0)</code> and returns that to the operating system.</p>
|
<code>usize(0)</code> and returns that to the operating system.</p>
|
||||||
<p>The following program prints Hello, World. and exits with an error
|
<p>The following program prints Hello, World. and exits with an error
|
||||||
code.</p>
|
code.</p>
|
||||||
<pre class="gp1"><code>entry main(): usize {
|
<pre class="language-gp1"><code>entry main(): usize {
|
||||||
hello_world();
|
hello_world();
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
@ -358,9 +358,9 @@ fn hello_world() {
|
||||||
keyword that makes it the entry point. The entry function may also be
|
keyword that makes it the entry point. The entry function may also be
|
||||||
implicit. If one is not defined explicitly, the entire file is treated
|
implicit. If one is not defined explicitly, the entire file is treated
|
||||||
as being inside an entry function. Therefore,</p>
|
as being inside an entry function. Therefore,</p>
|
||||||
<pre class="gp1"><code>println("Hello, World.");</code></pre>
|
<pre class="language-gp1"><code>println("Hello, World.");</code></pre>
|
||||||
<p>is a valid and complete program identical to</p>
|
<p>is a valid and complete program identical to</p>
|
||||||
<pre class="gp1"><code>entry main(): usize {
|
<pre class="language-gp1"><code>entry main(): usize {
|
||||||
println("Hello, World.");
|
println("Hello, World.");
|
||||||
}</code></pre>
|
}</code></pre>
|
||||||
<p>This behavior can lend GP1 a very flexible feeling akin to many
|
<p>This behavior can lend GP1 a very flexible feeling akin to many
|
||||||
|
|
@ -368,7 +368,7 @@ scripting languages.</p>
|
||||||
<p>In a program where there is an entry-point specified, only
|
<p>In a program where there is an entry-point specified, only
|
||||||
expressions made within that function will be evaluated. This means that
|
expressions made within that function will be evaluated. This means that
|
||||||
the following program does NOT print anything to the console.</p>
|
the following program does NOT print anything to the console.</p>
|
||||||
<pre class="gp1"><code>entry main(): usize {
|
<pre class="language-gp1"><code>entry main(): usize {
|
||||||
con x: usize <- 7;
|
con x: usize <- 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -383,7 +383,7 @@ structure, in two variants: <code>match</code> and
|
||||||
<code>*expr*</code> are expressions and <code>pattern*</code> are
|
<code>*expr*</code> are expressions and <code>pattern*</code> are
|
||||||
pattern matching options (refer to <em>Pattern Matching</em> for more
|
pattern matching options (refer to <em>Pattern Matching</em> for more
|
||||||
info).</p>
|
info).</p>
|
||||||
<pre class="gp1"><code>match expr {
|
<pre class="language-gp1"><code>match expr {
|
||||||
pattern1 => arm_expr1,
|
pattern1 => arm_expr1,
|
||||||
pattern2 => arm_expr2,
|
pattern2 => arm_expr2,
|
||||||
_ => arm_expr3,
|
_ => arm_expr3,
|
||||||
|
|
@ -394,7 +394,7 @@ expression executes all arms that match the pattern. Both flavors return
|
||||||
their last executed expression.</p>
|
their last executed expression.</p>
|
||||||
<p>The <code>when</code> keyword may be used in a given match arm to
|
<p>The <code>when</code> keyword may be used in a given match arm to
|
||||||
further restrict the conditions of execution, e.g.</p>
|
further restrict the conditions of execution, e.g.</p>
|
||||||
<pre class="gp1"><code>con fs <- 43;
|
<pre class="language-gp1"><code>con fs <- 43;
|
||||||
|
|
||||||
con is_even <- match fs {
|
con is_even <- match fs {
|
||||||
n when n % 2 == 0 => " is "
|
n when n % 2 == 0 => " is "
|
||||||
|
|
@ -412,10 +412,10 @@ print(fs + is_even + "even.")</code></pre>
|
||||||
</ul>
|
</ul>
|
||||||
<p>along with <code>continue</code> and <code>break</code> to help
|
<p>along with <code>continue</code> and <code>break</code> to help
|
||||||
control program flow. All of these are statements.</p>
|
control program flow. All of these are statements.</p>
|
||||||
<pre class="gp1"><code>loop { . . . } // an unconditional loop -- runs forever or until broken</code></pre>
|
<pre class="language-gp1"><code>loop { . . . } // an unconditional loop -- runs forever or until broken</code></pre>
|
||||||
<pre class="gp1"><code>for i in some_iterable { . . . } // loop over anything that is iterable</code></pre>
|
<pre class="language-gp1"><code>for i in some_iterable { . . . } // loop over anything that is iterable</code></pre>
|
||||||
<pre class="gp1"><code>while some_bool { . . . } // classic conditional loop that executes until the predicate is false</code></pre>
|
<pre class="language-gp1"><code>while some_bool { . . . } // classic conditional loop that executes until the predicate is false</code></pre>
|
||||||
<pre class="gp1"><code>do { . . .
|
<pre class="language-gp1"><code>do { . . .
|
||||||
} while some_bool // traditional do/while loop that ensures body executes at least once</code></pre>
|
} while some_bool // traditional do/while loop that ensures body executes at least once</code></pre>
|
||||||
<h2 id="pattern-matching">Pattern Matching</h2>
|
<h2 id="pattern-matching">Pattern Matching</h2>
|
||||||
<p>Pattern matching behaves essentially as it does in SML, with support
|
<p>Pattern matching behaves essentially as it does in SML, with support
|
||||||
|
|
@ -423,7 +423,7 @@ for various sorts of destructuring. It works in normal assignment and in
|
||||||
<code>match</code> arms. It will eventually work in function parameter
|
<code>match</code> arms. It will eventually work in function parameter
|
||||||
assignment, but perhaps not at first.</p>
|
assignment, but perhaps not at first.</p>
|
||||||
<p>For now, some examples.</p>
|
<p>For now, some examples.</p>
|
||||||
<pre class="gp1"><code>a <- ("hello", "world"); // a is a tuple of strings
|
<pre class="language-gp1"><code>a <- ("hello", "world"); // a is a tuple of strings
|
||||||
(b, c) <- a;
|
(b, c) <- a;
|
||||||
|
|
||||||
assert(b == "hello" && c == "world")
|
assert(b == "hello" && c == "world")
|
||||||
|
|
@ -442,24 +442,24 @@ fn u32_list_to_string(l: List<u32>): string { // this is assuming that sq
|
||||||
<h3 id="enums">Enums</h3>
|
<h3 id="enums">Enums</h3>
|
||||||
<p>Enums are pretty powerful in GP1. They can be the typical enumerated
|
<p>Enums are pretty powerful in GP1. They can be the typical enumerated
|
||||||
type you'd expect, like</p>
|
type you'd expect, like</p>
|
||||||
<pre class="gp1"><code>enum Coin { penny, nickle, dime, quarter } // 'vanilla' enum
|
<pre class="language-gp1"><code>enum Coin { penny, nickle, dime, quarter } // 'vanilla' enum
|
||||||
|
|
||||||
var a <- Coin.nickle
|
var a <- Coin.nickle
|
||||||
assert a == Coin.nickle
|
assert a == Coin.nickle
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p>Or an enum can have an implicit field named <code>value</code></p>
|
<p>Or an enum can have an implicit field named <code>value</code></p>
|
||||||
<pre class="gp1"><code>enum Coin: u16 { penny(1), nickle(5), dime(10), quarter(25) }
|
<pre class="language-gp1"><code>enum Coin: u16 { penny(1), nickle(5), dime(10), quarter(25) }
|
||||||
|
|
||||||
var a <- Coin.nickle;
|
var a <- Coin.nickle;
|
||||||
assert(a == Coin.nickle);
|
assert(a == Coin.nickle);
|
||||||
assert(a.value == 5);</code></pre>
|
assert(a.value == 5);</code></pre>
|
||||||
<p>Or an enum can be complex with a user-defined set of fields, like</p>
|
<p>Or an enum can be complex with a user-defined set of fields, like</p>
|
||||||
<pre class="gp1"><code>enum CarModel(make: string, mass: f32, wheelbase: f32) { // enum with multiple fields
|
<pre class="language-gp1"><code>enum CarModel(make: string, mass: f32, wheelbase: f32) { // enum with multiple fields
|
||||||
gt ( "ford", 1581, 2.71018 ),
|
gt ( "ford", 1581, 2.71018 ),
|
||||||
c8_corvette ( "chevy", 1527, 2.72288 )
|
c8_corvette ( "chevy", 1527, 2.72288 )
|
||||||
}</code></pre>
|
}</code></pre>
|
||||||
<p>A field can also have a function type. For example</p>
|
<p>A field can also have a function type. For example</p>
|
||||||
<pre class="gp1"><code>enum CarModel(make: string, mass: f32, wheelbase: f32, gasUsage: fn<f32 | f32>) {
|
<pre class="language-gp1"><code>enum CarModel(make: string, mass: f32, wheelbase: f32, gasUsage: fn<f32 | f32>) {
|
||||||
gt ( "ford", 1581, 2.71018, { miles_traveled -> miles_traveled / 14 } ),
|
gt ( "ford", 1581, 2.71018, { miles_traveled -> miles_traveled / 14 } ),
|
||||||
c8_corvette ( "chevy", 1527, 2.72288, { miles_traveled -> miles_traveled / 19 } )
|
c8_corvette ( "chevy", 1527, 2.72288, { miles_traveled -> miles_traveled / 19 } )
|
||||||
}
|
}
|
||||||
|
|
@ -467,7 +467,7 @@ assert(a.value == 5);</code></pre>
|
||||||
var my_car <- CarModel.c8_corvette;
|
var my_car <- CarModel.c8_corvette;
|
||||||
var gas_used <- my_car.gasUsage(200); // estimate how much gas I'd use on a 200 mile trip</code></pre>
|
var gas_used <- my_car.gasUsage(200); // estimate how much gas I'd use on a 200 mile trip</code></pre>
|
||||||
<p>Equivalence of enums is not influenced by case values, e.g.</p>
|
<p>Equivalence of enums is not influenced by case values, e.g.</p>
|
||||||
<pre class="gp1"><code>enum OneOrAnother: u16 { one(0), another(0) }
|
<pre class="language-gp1"><code>enum OneOrAnother: u16 { one(0), another(0) }
|
||||||
|
|
||||||
con a <- OneOrAnother.one;
|
con a <- OneOrAnother.one;
|
||||||
con b <- OneOrAnother.another;
|
con b <- OneOrAnother.another;
|
||||||
|
|
@ -482,7 +482,7 @@ only value types are allowed for enum fields.</p>
|
||||||
keyword. Fields are defined in the <code>record</code> block and
|
keyword. Fields are defined in the <code>record</code> block and
|
||||||
behavior is defined in the optional <code>impl</code> block.</p>
|
behavior is defined in the optional <code>impl</code> block.</p>
|
||||||
<p>For example,</p>
|
<p>For example,</p>
|
||||||
<pre class="gp1"><code>record Something {
|
<pre class="language-gp1"><code>record Something {
|
||||||
label: i32 // field label followed by some type
|
label: i32 // field label followed by some type
|
||||||
} impl { . . . } // associated functions. This is different than having functions in the fields section because impl functions are not assignable.</code></pre>
|
} impl { . . . } // associated functions. This is different than having functions in the fields section because impl functions are not assignable.</code></pre>
|
||||||
<p>If the record implements some interface, <code>SomeInterface</code>,
|
<p>If the record implements some interface, <code>SomeInterface</code>,
|
||||||
|
|
@ -492,7 +492,7 @@ the <code>impl</code> would be replaced with
|
||||||
functions of the <code>Something</code> record.</p>
|
functions of the <code>Something</code> record.</p>
|
||||||
<h3 id="unions">Unions</h3>
|
<h3 id="unions">Unions</h3>
|
||||||
<p>Unions are the classic discriminated sum type.</p>
|
<p>Unions are the classic discriminated sum type.</p>
|
||||||
<pre class="gp1"><code>union BinaryTree {
|
<pre class="language-gp1"><code>union BinaryTree {
|
||||||
Empty,
|
Empty,
|
||||||
Leaf: i32,
|
Leaf: i32,
|
||||||
Node: (BinaryTree BinaryTree),
|
Node: (BinaryTree BinaryTree),
|
||||||
|
|
@ -502,7 +502,7 @@ functions of the <code>Something</code> record.</p>
|
||||||
section.</p>
|
section.</p>
|
||||||
<p>Type aliasing is provided with the <code>type</code> keyword,
|
<p>Type aliasing is provided with the <code>type</code> keyword,
|
||||||
e.g.</p>
|
e.g.</p>
|
||||||
<pre class="gp1"><code>type TokenStream Sequence<Token>
|
<pre class="language-gp1"><code>type TokenStream Sequence<Token>
|
||||||
type Ast Tree<AbstractNode>
|
type Ast Tree<AbstractNode>
|
||||||
|
|
||||||
fn parse(ts: TokenStream): Ast { . . . }</code></pre>
|
fn parse(ts: TokenStream): Ast { . . . }</code></pre>
|
||||||
|
|
@ -518,7 +518,7 @@ Types</h2>
|
||||||
<code>#</code>, <code>&</code>, and <code>@</code>. These are
|
<code>#</code>, <code>&</code>, and <code>@</code>. These are
|
||||||
immutable reference, mutable reference, and dereference, respectively.
|
immutable reference, mutable reference, and dereference, respectively.
|
||||||
Some examples of referencing/dereferencing values:</p>
|
Some examples of referencing/dereferencing values:</p>
|
||||||
<pre class="gp1"><code>var a <- "core dumped";
|
<pre class="language-gp1"><code>var a <- "core dumped";
|
||||||
var b <- &a; // b is a mutable reference to a
|
var b <- &a; // b is a mutable reference to a
|
||||||
|
|
||||||
assert(a == @b);
|
assert(a == @b);
|
||||||
|
|
@ -539,7 +539,7 @@ assert(@@c == a);
|
||||||
references.</p>
|
references.</p>
|
||||||
<p>The reference operators may be prepended to any type, T, to describe
|
<p>The reference operators may be prepended to any type, T, to describe
|
||||||
the type of a reference to a value of type T, e.g.</p>
|
the type of a reference to a value of type T, e.g.</p>
|
||||||
<pre class="gp1"><code>fn set_through(ref: &string) { // this function takes a mutable reference to a string and returns `()`
|
<pre class="language-gp1"><code>fn set_through(ref: &string) { // this function takes a mutable reference to a string and returns `()`
|
||||||
@ref <- "goodbye";
|
@ref <- "goodbye";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ module type Monad = sig
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
Here we have the usual OCaml signatures for functors, applicative functors, and monads respectively. The only thing of note is that I've written the functions in pipe-last[^pipe-last] style. It's more common to see pipe-first style, which agrees with the usual infix operators, but I don't see any of those around to get offended; do you?
|
Above, we have the usual OCaml signatures for functors, applicative functors, and monads respectively. The only thing of note is that I've written the functions in pipe-last[^pipe-last] style. It's more common to see pipe-first style, which agrees with the usual infix operators, but I don't see any of those around to get offended; do you?
|
||||||
|
|
||||||
```ocaml
|
```ocaml
|
||||||
module ApplicativeOfMonad (M : Monad) :
|
module ApplicativeOfMonad (M : Monad) :
|
||||||
|
|
@ -43,7 +43,7 @@ module FunctorOfMonad (M : Monad) :
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
Each of these accepts an instance of a less general structure and uses only the elements the module provides to implement an instance of the more general structure.
|
Each of these accepts an instance of a less general structure and uses only the elements the module provides to implement an instance of the more general structure. The last one is boring, obviously, being just the composition of the former two, but those are a _little_ interesting.
|
||||||
|
|
||||||
It turns out that there are multiple ways to implement the derivation functors--- also multiple ways to implement a particular monad--- and they don't all behave the same. That makes it hard to predict whether the more-general, derived implementations are the "natural" ones that you expected to get without _ad hoc_ testing, which rather defeats the point of "gratis". On the other hand, the derivations here can be performed pretty mechanically, with little insight, by following the types in much the same way one might mechanically prove an easy proposition.
|
It turns out that there are multiple ways to implement the derivation functors--- also multiple ways to implement a particular monad--- and they don't all behave the same. That makes it hard to predict whether the more-general, derived implementations are the "natural" ones that you expected to get without _ad hoc_ testing, which rather defeats the point of "gratis". On the other hand, the derivations here can be performed pretty mechanically, with little insight, by following the types in much the same way one might mechanically prove an easy proposition.
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ The modules above that seem to have parameters, do; these modules are called "fu
|
||||||
|
|
||||||
A subtlety of the OCaml module system is that if a module is defined with a particular `module type` a.k.a. signature attached, e.g. `module M : S = struct...`, all the types that are abstract in the signature `S` will _also_ be abstract in the module itself. This means that the compiler can't see or be convinced that for some `F (M)` with `type t = M.t` in `F`, `M.t` and `(F (M)).t` are equal. This is because both types are abstract, meaning the underlying type is not available. To fix this, we can explicitly expose the equality by using the `with type` construct. In the above, `Functor with type 'a t = 'a M.t`--- for example--- exposes the equality of the two types, so that functions defined as expecting arguments of `'a t` can accept `'a M.t`, and _vice versa_.
|
A subtlety of the OCaml module system is that if a module is defined with a particular `module type` a.k.a. signature attached, e.g. `module M : S = struct...`, all the types that are abstract in the signature `S` will _also_ be abstract in the module itself. This means that the compiler can't see or be convinced that for some `F (M)` with `type t = M.t` in `F`, `M.t` and `(F (M)).t` are equal. This is because both types are abstract, meaning the underlying type is not available. To fix this, we can explicitly expose the equality by using the `with type` construct. In the above, `Functor with type 'a t = 'a M.t`--- for example--- exposes the equality of the two types, so that functions defined as expecting arguments of `'a t` can accept `'a M.t`, and _vice versa_.
|
||||||
|
|
||||||
[^falsehood]: Unsurprisingly, that's a lie. But isn't it always? You have to buy a monad first.
|
[^falsehood]: Unsurprisingly, that's a lie. Isn't it always? You have to buy a monad first.
|
||||||
|
|
||||||
[^1ml]: See [1ML](https://people.mpi-sws.org/~rossberg/1ml/1ml-jfp-draft.pdf) for an OCaml-like language without this stratification.
|
[^1ml]: See [1ML](https://people.mpi-sws.org/~rossberg/1ml/1ml-jfp-draft.pdf) for an OCaml-like language without this stratification.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
<h1><a href="/resume.pdf" style="text-decoration: none; color: var(--darkest-color)">acl</a>.cool</h1>
|
<h1>
|
||||||
|
<a href="/resume.pdf" style="text-decoration: none; color: var(--darkest-color)">acl</a><a
|
||||||
|
href="https://en.wikipedia.org/wiki/Special:Random"
|
||||||
|
style="text-decoration: none; color: var(--darkest-color)">.</a><a href="https://git.acl.cool/al/pages"
|
||||||
|
style="text-decoration: none; color: var(--darkest-color)">cool</a>
|
||||||
|
</h1>
|
||||||
|
|
||||||
<div id="writings" style="color: var(--lighter-color); line-height: var(--ui-spacing);"></span>
|
<div id="writings" style="color: var(--lighter-color); line-height: var(--ui-spacing);"></span>
|
||||||
|
<p><strong>Welcome! Below are links to things I've made or just enjoy.</strong></p>
|
||||||
<p><strong>Welcome! Below are links to things I've made or just enjoy.</strong></p>
|
|
||||||
1
acl.cool/syntax_wrapper.sh
Symbolic link
1
acl.cool/syntax_wrapper.sh
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../syntax_wrapper.sh
|
||||||
58
build.sh
58
build.sh
|
|
@ -1,6 +1,6 @@
|
||||||
#! /usr/bin/env nix-shell
|
#! /usr/bin/env nix-shell
|
||||||
#! nix-shell -i bash --pure
|
#! nix-shell -i bash --pure
|
||||||
#! nix-shell -p bash harfbuzz soupault woff2 jotdown python3 --pure
|
#! nix-shell -p bash harfbuzz soupault woff2 jotdown python3 recode --pure
|
||||||
|
|
||||||
if ! [[ -d pgvv/ ]]; then
|
if ! [[ -d pgvv/ ]]; then
|
||||||
python3 -m venv pgvv
|
python3 -m venv pgvv
|
||||||
|
|
@ -21,23 +21,8 @@ source ./pgvv/bin/activate
|
||||||
find acl.cool/site/ ytheleus.org/site/ -type f \( -name '*.dj' -o -name '*.html' \) -exec cat {} + >all_chars.txt
|
find acl.cool/site/ ytheleus.org/site/ -type f \( -name '*.dj' -o -name '*.html' \) -exec cat {} + >all_chars.txt
|
||||||
cat common_chars.txt >>all_chars.txt
|
cat common_chars.txt >>all_chars.txt
|
||||||
|
|
||||||
for font in fonts/LiterataTT/LiterataTT-Subhead{Regular,Italic,Bold,BoldItalic}.woff2; do
|
for font in fonts/LiterataTT/LiterataTT-Subhead{Regular,Italic,Medium,MediumItalic,Bold,BoldItalic}.woff2 \
|
||||||
woff2_decompress "$font"
|
fonts/JuliaMono/*{-Light,-Regular,-SemiBold}{,Italic}.woff2; do
|
||||||
ttf_font="${font%.woff2}.ttf"
|
|
||||||
|
|
||||||
subset_ttf="${ttf_font%.ttf}-Subset.ttf"
|
|
||||||
hb-subset "$ttf_font" \
|
|
||||||
--output-file="$subset_ttf" \
|
|
||||||
--text-file=all_chars.txt \
|
|
||||||
--layout-features='*' \
|
|
||||||
--passthrough-tables
|
|
||||||
|
|
||||||
woff2_compress "$subset_ttf"
|
|
||||||
|
|
||||||
rm "$subset_ttf" "$ttf_font"
|
|
||||||
done
|
|
||||||
|
|
||||||
for font in fonts/JuliaMono/*{-Light,-Regular,-SemiBold}{,Italic}.woff2; do
|
|
||||||
woff2_decompress "$font"
|
woff2_decompress "$font"
|
||||||
ttf_font="${font%.woff2}.ttf"
|
ttf_font="${font%.woff2}.ttf"
|
||||||
|
|
||||||
|
|
@ -71,29 +56,20 @@ done
|
||||||
rm css/code.css
|
rm css/code.css
|
||||||
pygmentize -f html -S algol_nu | grep -v 'line-height' >css/code.css
|
pygmentize -f html -S algol_nu | grep -v 'line-height' >css/code.css
|
||||||
|
|
||||||
builtin pushd acl.cool
|
for site in acl.cool ytheleus.org; do
|
||||||
soup_config
|
pushd "$site"
|
||||||
soupault
|
soup_config
|
||||||
NEXT_DIR="serve_$(date +%s)"
|
rm -rf serve/
|
||||||
CUR_DIR=$(find . -maxdepth 1 -type d -regex './serve_[0-9]+')
|
soupault
|
||||||
echo "$PREV_DIR"
|
NEXT_DIR="serve_$(date +%s)"
|
||||||
cp -a serve "$NEXT_DIR"
|
CUR_DIR=$(find . -maxdepth 1 -type d -regex './serve_[0-9]+')
|
||||||
ln -sfn "$NEXT_DIR" serve_
|
echo "$PREV_DIR"
|
||||||
for d in $CUR_DIR; do
|
cp -a serve "$NEXT_DIR"
|
||||||
rm -r $d
|
ln -sfn "$NEXT_DIR" serve_
|
||||||
|
for d in $CUR_DIR; do
|
||||||
|
rm -r $d
|
||||||
|
done
|
||||||
|
popd
|
||||||
done
|
done
|
||||||
popd
|
|
||||||
|
|
||||||
builtin pushd ytheleus.org
|
|
||||||
soup_config
|
|
||||||
soupault
|
|
||||||
NEXT_DIR="serve_$(date +%s)"
|
|
||||||
CUR_DIR=$(find . -maxdepth 1 -type d -regex './serve_[0-9]+')
|
|
||||||
cp -a serve "$NEXT_DIR"
|
|
||||||
ln -sfn "$NEXT_DIR" serve_
|
|
||||||
for d in $CUR_DIR; do
|
|
||||||
rm -r $d
|
|
||||||
done
|
|
||||||
popd
|
|
||||||
|
|
||||||
deactivate
|
deactivate
|
||||||
|
|
|
||||||
|
|
@ -28,28 +28,28 @@
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Subheading';
|
font-family: 'Subheading';
|
||||||
src: url('../assets/fonts/LiterataTT/LiterataTT-SubheadMedium.woff2') format('woff2');
|
src: url('../assets/fonts/LiterataTT/LiterataTT-SubheadMedium-Subset.woff2') format('woff2');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Subheading';
|
font-family: 'Subheading';
|
||||||
src: url('../assets/fonts/LiterataTT/LiterataTT-SubheadMediumItalic.woff2') format('woff2');
|
src: url('../assets/fonts/LiterataTT/LiterataTT-SubheadMediumItalic-Subset.woff2') format('woff2');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Subheading';
|
font-family: 'Subheading';
|
||||||
src: url('../assets/fonts/LiterataTT/LiterataTT-SubheadSemibold.woff2') format('woff2');
|
src: url('../assets/fonts/LiterataTT/LiterataTT-SubheadBold-Subset.woff2') format('woff2');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Subheading';
|
font-family: 'Subheading';
|
||||||
src: url('../assets/fonts/LiterataTT/LiterataTT-SubheadSemiboldItalic.woff2') format('woff2');
|
src: url('../assets/fonts/LiterataTT/LiterataTT-SubheadBoldItalic-Subset.woff2') format('woff2');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +59,7 @@
|
||||||
src: url('../assets/fonts/Alegreya/static/Alegreya-Regular-Subset.woff2') format('woff2');
|
src: url('../assets/fonts/Alegreya/static/Alegreya-Regular-Subset.woff2') format('woff2');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
font-feature-settings: "lnum" 1, "kern" 1, "liga" 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
@ -66,6 +67,7 @@
|
||||||
src: url('../assets/fonts/Alegreya/static/Alegreya-Italic-Subset.woff2') format('woff2');
|
src: url('../assets/fonts/Alegreya/static/Alegreya-Italic-Subset.woff2') format('woff2');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
font-feature-settings: "lnum" 1, "kern" 1, "liga" 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
@ -73,6 +75,7 @@
|
||||||
src: url('../assets/fonts/Alegreya/static/Alegreya-Bold-Subset.woff2') format('woff2');
|
src: url('../assets/fonts/Alegreya/static/Alegreya-Bold-Subset.woff2') format('woff2');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
font-feature-settings: "lnum" 1, "kern" 1, "liga" 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
@ -80,6 +83,7 @@
|
||||||
src: url('../assets/fonts/Alegreya/static/Alegreya-BoldItalic-Subset.woff2') format('woff2');
|
src: url('../assets/fonts/Alegreya/static/Alegreya-BoldItalic-Subset.woff2') format('woff2');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
font-feature-settings: "lnum" 1, "kern" 1, "liga" 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
@ -87,6 +91,7 @@
|
||||||
src: url('../assets/fonts/Alegreya_Sans/AlegreyaSans-Regular-Subset.woff2') format('woff2');
|
src: url('../assets/fonts/Alegreya_Sans/AlegreyaSans-Regular-Subset.woff2') format('woff2');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
font-feature-settings: "lnum" 1, "kern" 1, "liga" 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
@ -94,6 +99,7 @@
|
||||||
src: url('../assets/fonts/Alegreya_Sans/AlegreyaSans-Italic-Subset.woff2') format('woff2');
|
src: url('../assets/fonts/Alegreya_Sans/AlegreyaSans-Italic-Subset.woff2') format('woff2');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
font-feature-settings: "lnum" 1, "kern" 1, "liga" 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
@ -101,6 +107,7 @@
|
||||||
src: url('../assets/fonts/Alegreya_Sans/AlegreyaSans-Bold-Subset.woff2') format('woff2');
|
src: url('../assets/fonts/Alegreya_Sans/AlegreyaSans-Bold-Subset.woff2') format('woff2');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
font-feature-settings: "lnum" 1, "kern" 1, "liga" 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
@ -108,6 +115,7 @@
|
||||||
src: url('../assets/fonts/Alegreya_Sans/AlegreyaSans-BoldItalic-Subset.woff2') format('woff2');
|
src: url('../assets/fonts/Alegreya_Sans/AlegreyaSans-BoldItalic-Subset.woff2') format('woff2');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
font-feature-settings: "lnum" 1, "kern" 1, "liga" 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
|
||||||
|
|
@ -139,4 +139,4 @@ delete_all = true
|
||||||
[widgets.syntax]
|
[widgets.syntax]
|
||||||
widget = "preprocess_element"
|
widget = "preprocess_element"
|
||||||
selector = 'pre code'
|
selector = 'pre code'
|
||||||
command = "pygmentize -l ${ATTR_CLASS##*-} -f html | head -c -13 | awk -F '<pre>' '{print $NF}'"
|
command = "./syntax_wrapper.sh ${ATTR_CLASS##*-}"
|
||||||
|
|
|
||||||
7
syntax_wrapper.sh
Executable file
7
syntax_wrapper.sh
Executable file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#! /usr/bin/env sh
|
||||||
|
|
||||||
|
if [ $# -lt 1 ] || ! pygmentize -L lexers | grep -qw "$1"; then
|
||||||
|
recode ascii..html
|
||||||
|
else
|
||||||
|
pygmentize -l $1 -f html | head -c -13 | awk -F '<pre>' '{print $NF}'
|
||||||
|
fi
|
||||||
1
ytheleus.org/syntax_wrapper.sh
Symbolic link
1
ytheleus.org/syntax_wrapper.sh
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../syntax_wrapper.sh
|
||||||
Loading…
Add table
Add a link
Reference in a new issue