Skip to content

Commit 85b6a2c

Browse files
committed
Add Python target to website
Update website copy, playground, highlighter, and formatter to include Python as a compilation target alongside JavaScript, Ruby, and SQL. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent f738fe2 commit 85b6a2c

9 files changed

Lines changed: 221 additions & 24 deletions

File tree

web/public/styles/pages/home.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,11 @@ body.light-theme .js-badge {
324324
color: #ef4444;
325325
}
326326

327+
.python-badge {
328+
background: rgba(52, 152, 219, 0.2);
329+
color: #3498db;
330+
}
331+
327332
.sql-badge {
328333
background: rgba(59, 130, 246, 0.2);
329334
color: #3b82f6;

web/src/layouts/Layout.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ interface Props {
77
88
const {
99
title = 'Elo — An expression language',
10-
description = 'A simple, well-designed, portable, and safe data expression language that compiles to JavaScript, Ruby, and SQL.',
10+
description = 'A simple, well-designed, portable, and safe data expression language that compiles to JavaScript, Ruby, Python, and SQL.',
1111
activeNav = 'home'
1212
} = Astro.props;
1313

web/src/pages/index.astro

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const url = (path: string) => `${base}${path}`;
2020
</div>
2121
<h1>The Elo Language</h1>
2222
<p class="tagline">A simple, well-designed, portable, and safe data expression language</p>
23-
<p class="subtitle">Elo compiles to JavaScript, Ruby, and SQL. Built for No-Code tools where non-technical users need to manipulate data easily and safely.</p>
23+
<p class="subtitle">Elo compiles to JavaScript, Ruby, Python, and SQL. Built for No-Code tools where non-technical users need to manipulate data easily and safely.</p>
2424
<div class="cta-buttons">
2525
<a href={url('/try')} class="cta-button">Try it now</a>
2626
<a href={url('/reference#get-started')} class="cta-button cta-secondary">Get started</a>
@@ -34,9 +34,9 @@ const url = (path: string) => `${base}${path}`;
3434
<p>A pure data language: everything is a value, no reference semantics, no <code>new</code>. One equality operator that just works. Designed to be safe for non-technical users.</p>
3535
</div>
3636
<div class="feature-card">
37-
<div class="feature-icon">3x</div>
37+
<div class="feature-icon">4x</div>
3838
<h3>Truly Portable</h3>
39-
<p>One expression compiles to semantically equivalent JavaScript, Ruby, and SQL. Frontend, backend, and database all speak the same data language.</p>
39+
<p>One expression compiles to semantically equivalent JavaScript, Ruby, Python, and SQL. Frontend, backend, and database all speak the same data language.</p>
4040
</div>
4141
<div class="feature-card">
4242
<div class="feature-icon">{`{}`}</div>
@@ -85,7 +85,7 @@ in
8585
</div>
8686
<div class="unique-explain">
8787
<h4>Functional &amp; Portable</h4>
88-
<p>Pipeline operators, lambdas, and a comprehensive <a href={url('/stdlib')}>standard library</a>. Write once, compile to JavaScript, Ruby, and SQL—same semantics everywhere.</p>
88+
<p>Pipeline operators, lambdas, and a comprehensive <a href={url('/stdlib')}>standard library</a>. Write once, compile to JavaScript, Ruby, Python, and SQL—same semantics everywhere.</p>
8989
</div>
9090
</div>
9191

@@ -122,7 +122,7 @@ in
122122
</section>
123123

124124
<section class="targets-section">
125-
<h2>One Expression, Three Targets</h2>
125+
<h2>One Expression, Four Targets</h2>
126126
<p class="targets-intro">Elo compiles to idiomatic code in each target language</p>
127127

128128
<div class="targets-demo">
@@ -139,6 +139,10 @@ in
139139
<span class="lang-badge ruby-badge">Ruby</span>
140140
<pre>2 ** 10 > 1000 && Date.today >= Date.today.beginning_of_year</pre>
141141
</div>
142+
<div class="target-card">
143+
<span class="lang-badge python-badge">Python</span>
144+
<pre>2 ** 10 > 1000 and date.today() >= _elo_start_of_year(datetime.now())</pre>
145+
</div>
142146
<div class="target-card">
143147
<span class="lang-badge sql-badge">SQL</span>
144148
<pre>POWER(2, 10) > 1000 AND CURRENT_DATE >= DATE_TRUNC('year', CURRENT_DATE)</pre>

web/src/pages/learn.astro

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const url = (path: string) => `${base}${path}`;
4141
<header class="page-header">
4242
<h1>Learn Elo</h1>
4343
<p class="page-intro">
44-
Elo is an expression language that compiles to JavaScript, Ruby, and SQL.
44+
Elo is an expression language that compiles to JavaScript, Ruby, Python, and SQL.
4545
Think of it as an extended calculator: you write expressions, Elo gives you results.
4646
Let's explore what makes Elo special.
4747
</p>
@@ -81,7 +81,7 @@ in
8181
This checks if an input email belongs to a company domain. The <code>_</code> is input data.
8282
</p>
8383
<p class="lesson-tip">
84-
<strong>Write once, run anywhere:</strong> These expressions compile to JavaScript, Ruby, and SQL.
84+
<strong>Write once, run anywhere:</strong> These expressions compile to JavaScript, Ruby, Python, and SQL.
8585
The same logic works in your browser, on your server, or in your database.
8686
</p>
8787
</section>
@@ -457,7 +457,7 @@ in
457457
let you define schemas that validate structure and coerce values to the right types.
458458
</p>
459459
<p class="lesson-tip">
460-
<strong>Note:</strong> Type definitions compile to JavaScript and Ruby only. SQL is not supported.
460+
<strong>Note:</strong> Type definitions compile to JavaScript, Ruby, and Python only. SQL is not supported.
461461
</p>
462462

463463
<h3>Type Coercion</h3>
@@ -542,7 +542,7 @@ in &#123; name: 'Alice', age: '30' &#125; |> Person</pre>
542542
and make your assumptions explicit. Use guards to reason confidently about your code.
543543
</p>
544544
<p class="lesson-tip">
545-
<strong>Note:</strong> Guards compile to JavaScript and Ruby only. SQL is not supported.
545+
<strong>Note:</strong> Guards compile to JavaScript, Ruby, and Python only. SQL is not supported.
546546
</p>
547547

548548
<h3>Simple Guards</h3>
@@ -901,7 +901,7 @@ in
901901
If any validation fails, an error is thrown immediately.
902902
</p>
903903
<p class="lesson-tip">
904-
<strong>Note:</strong> Type definitions compile to JavaScript and Ruby only.
904+
<strong>Note:</strong> Type definitions compile to JavaScript, Ruby, and Python only.
905905
</p>
906906
</section>
907907

@@ -995,7 +995,7 @@ in
995995
</li>
996996
</ul>
997997
<p class="lesson-closing">
998-
Remember: Elo compiles to JavaScript, Ruby, and SQL. Write once, run anywhere.
998+
Remember: Elo compiles to JavaScript, Ruby, Python, and SQL. Write once, run anywhere.
999999
<br>Happy coding!
10001000
</p>
10011001
</section>

web/src/pages/reference.astro

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import Footer from '../components/Footer.astro';
3939
<h1>The Elo Language</h1>
4040
<p class="page-intro">
4141
Elo is a small expression language that compiles to <strong>JavaScript</strong>,
42-
<strong>Ruby</strong>, and <strong>SQL</strong>. Write once, run anywhere.
42+
<strong>Ruby</strong>, <strong>Python</strong>, and <strong>SQL</strong>. Write once, run anywhere.
4343
</p>
4444
</header>
4545

@@ -279,7 +279,7 @@ import Footer from '../components/Footer.astro';
279279
<pre class="language-elo">let double = fn( x ~> x * 2 ) in double(5)</pre>
280280
<p class="example-desc">Bind a lambda to a name, then call it. Returns 10.</p>
281281
</div>
282-
<p class="note"><strong>Note:</strong> Lambdas compile to JavaScript and Ruby only. SQL does not support function expressions.</p>
282+
<p class="note"><strong>Note:</strong> Lambdas compile to JavaScript, Ruby, and Python only. SQL does not support function expressions.</p>
283283
</section>
284284

285285
<section class="doc-section" id="variables">
@@ -421,7 +421,7 @@ import Footer from '../components/Footer.astro';
421421
<section class="doc-section" id="data-schemas">
422422
<h2>Data Schemas</h2>
423423
<p>Data schemas let you validate and transform complex data structures like JSON. Define schemas using uppercase <code>let</code> bindings with <a href="#type-selectors">type selectors</a>, then apply them with the pipe operator.</p>
424-
<p class="note"><strong>Note:</strong> Data schemas compile to JavaScript and Ruby only. SQL is not supported.</p>
424+
<p class="note"><strong>Note:</strong> Data schemas compile to JavaScript, Ruby, and Python only. SQL is not supported.</p>
425425

426426
<h3>Basic Types</h3>
427427
<p>All <a href="#type-selectors">type selectors</a> can be used as schema types: <code>Int</code>, <code>Float</code>, <code>Bool</code>, <code>String</code>, <code>Null</code>, <code>Date</code>, <code>Datetime</code>, <code>Duration</code>, <code>Data</code>. Use <code>.</code> (dot) for any value.</p>
@@ -649,7 +649,7 @@ elo -e "&#123;name: 'test'&#125;" -o elo</code></pre>
649649
<pre class="language-elo">5 |> guard(x | x > 0)</pre>
650650
<p class="example-desc">Creates a lambda that validates its input. Returns the value if valid.</p>
651651
</div>
652-
<p class="note"><strong>Note:</strong> Guards compile to JavaScript and Ruby only. Use <code>--strip-guards</code> to remove guards in production builds.</p>
652+
<p class="note"><strong>Note:</strong> Guards compile to JavaScript, Ruby, and Python only. Use <code>--strip-guards</code> to remove guards in production builds.</p>
653653
</section>
654654

655655
<section class="doc-section" id="get-started">
@@ -665,7 +665,7 @@ elo -e "&#123;name: 'test'&#125;" -o elo</code></pre>
665665
<p>This gives you two commands:</p>
666666
<ul>
667667
<li><code>elo</code> — Evaluate Elo expressions and see results immediately</li>
668-
<li><code>eloc</code> — Compile Elo to JavaScript, Ruby, or SQL</li>
668+
<li><code>eloc</code> — Compile Elo to JavaScript, Ruby, Python, or SQL</li>
669669
</ul>
670670

671671
<h3>Quick Examples</h3>
@@ -699,11 +699,12 @@ import &#123; DateTime, Duration &#125; from 'luxon';
699699
const double = compile('_ * 2', &#123; runtime: &#123; DateTime, Duration &#125; &#125;);
700700
double(21); // => 42</pre>
701701
<h3>Lower-Level API</h3>
702-
<pre class="language-js">import &#123; parse, compileToJavaScript, compileToRuby, compileToSQL &#125; from '@enspirit/elo';
702+
<pre class="language-js">import &#123; parse, compileToJavaScript, compileToRuby, compileToPython, compileToSQL &#125; from '@enspirit/elo';
703703

704704
const ast = parse('2 + 3 * 4');
705705
compileToJavaScript(ast); // => "2 + 3 * 4"
706706
compileToRuby(ast); // => "2 + 3 * 4"
707+
compileToPython(ast); // => "2 + 3 * 4"
707708
compileToSQL(ast); // => "2 + 3 * 4"</pre>
708709
</section>
709710

@@ -741,13 +742,16 @@ eloc -e "2 + 3 * 4" -t ruby
741742
# Compile to SQL
742743
eloc -e "2 + 3 * 4" -t sql
743744

745+
# Compile to Python
746+
eloc -e "2 + 3 * 4" -t python
747+
744748
# Include runtime prelude
745749
eloc -e "NOW + PT2H" -t ruby -p</pre>
746750
<table class="type-table">
747751
<thead><tr><th>Option</th><th>Description</th></tr></thead>
748752
<tbody>
749753
<tr><td><code>-e, --expression</code></td><td>Expression to compile</td></tr>
750-
<tr><td><code>-t, --target</code></td><td>Target: <code>js</code>, <code>ruby</code>, <code>sql</code></td></tr>
754+
<tr><td><code>-t, --target</code></td><td>Target: <code>js</code>, <code>ruby</code>, <code>python</code>, <code>sql</code></td></tr>
751755
<tr><td><code>-p, --prelude</code></td><td>Include runtime imports</td></tr>
752756
<tr><td><code>--strip-guards</code></td><td>Remove guard/check assertions</td></tr>
753757
<tr><td><code>-f, --file</code></td><td>Output to file</td></tr>

web/src/pages/try.astro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ import Layout from '../layouts/Layout.astro';
116116
<option value="javascript">JavaScript</option>
117117
<option value="ruby">Ruby</option>
118118
<option value="sql">SQL</option>
119+
<option value="python">Python</option>
119120
</select>
120121
<div class="flow-actions">
121122
<button

web/src/scripts/controllers/playground_controller.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,22 @@ import {
1111
compileToJavaScript,
1212
compileToJavaScriptWithMeta,
1313
compileToSQL,
14+
compileToPython,
1415
getPrelude,
1516
defaultFormats,
1617
getFormat
1718
} from '@enspirit/elo';
1819
import type { PreludeTarget } from '@enspirit/elo';
1920
import { elo } from '../codemirror/elo-language';
2021
import { eloDarkTheme, eloLightTheme } from '../codemirror/elo-theme';
21-
import { highlightJS, highlightRuby, highlightSQL } from '../highlighter';
22+
import { highlightJS, highlightRuby, highlightSQL, highlightPython } from '../highlighter';
2223
import { formatCode } from '../formatters';
2324

2425
// Make luxon DateTime and Duration available globally for eval (used by compiled IIFE helpers)
2526
(window as any).DateTime = DateTime;
2627
(window as any).Duration = Duration;
2728

28-
type TargetLanguage = 'ruby' | 'javascript' | 'sql';
29+
type TargetLanguage = 'ruby' | 'javascript' | 'sql' | 'python';
2930

3031
const STORAGE_KEY = 'elo-playground-code';
3132

@@ -453,7 +454,7 @@ export default class PlaygroundController extends Controller {
453454
// Build final output with optional prelude
454455
let finalOutput = formattedOutput;
455456
if (includePrelude) {
456-
const preludeTarget: PreludeTarget = language === 'javascript' ? 'javascript' : language as PreludeTarget;
457+
const preludeTarget: PreludeTarget = language as PreludeTarget;
457458
const prelude = getPrelude(preludeTarget);
458459
if (prelude) {
459460
finalOutput = `${prelude}\n\n${formattedOutput}`;
@@ -540,7 +541,8 @@ export default class PlaygroundController extends Controller {
540541
const extensions: Record<TargetLanguage, string> = {
541542
javascript: 'js',
542543
ruby: 'rb',
543-
sql: 'sql'
544+
sql: 'sql',
545+
python: 'py'
544546
};
545547

546548
const blob = new Blob([this.currentOutput], { type: 'text/plain' });
@@ -571,6 +573,8 @@ export default class PlaygroundController extends Controller {
571573
return compileToJavaScript(ast);
572574
case 'sql':
573575
return compileToSQL(ast);
576+
case 'python':
577+
return compileToPython(ast);
574578
default:
575579
return '';
576580
}
@@ -584,6 +588,8 @@ export default class PlaygroundController extends Controller {
584588
return highlightRuby(code);
585589
case 'sql':
586590
return highlightSQL(code);
591+
case 'python':
592+
return highlightPython(code);
587593
default:
588594
return code;
589595
}

web/src/scripts/formatters.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,16 @@ export function formatRuby(code: string): string {
115115
/**
116116
* Format code based on language
117117
*/
118-
export async function formatCode(code: string, language: 'javascript' | 'ruby' | 'sql'): Promise<string> {
118+
export async function formatCode(code: string, language: 'javascript' | 'ruby' | 'sql' | 'python'): Promise<string> {
119119
switch (language) {
120120
case 'javascript':
121121
return formatJS(code);
122122
case 'sql':
123123
return formatSQL(code);
124124
case 'ruby':
125125
return formatRuby(code);
126+
case 'python':
127+
return code;
126128
default:
127129
return code;
128130
}

0 commit comments

Comments
 (0)