Skip to content

Commit

Permalink
Add Clojure
Browse files Browse the repository at this point in the history
  • Loading branch information
Steffan153 committed Feb 20, 2024
1 parent e2bd0e5 commit c4bc094
Show file tree
Hide file tree
Showing 6 changed files with 518 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules
dist
src/frontend/grammar.ts
*.test.md.ts
.DS_Store
187 changes: 187 additions & 0 deletions src/languages/clojure/clojure.test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# Clojure

## Printing

```polygolf
$a <- 1;
$b <- "x";
println $a;
print $a;
println $b;
print $b;
```

```clj nogolf
(def a 1)(def b"x")(prn a)(pr a)(println b)(print b)
```

## Ops emit

```polygolf
$a:-100..100 <- 0;
$b:Text <- "xy";
$c <- (0==0);
$d <- (list "q" "r" "s");
% Boolean
and $c $c;
or $c $c;
not $c;
% Unary Arithmetic
~ $a;
- $a;
abs $a;
% Binary Arithmetic
$a + 2;
$a - 2;
$a * 2;
$a div 2;
$a ^ 2;
$a mod 2;
$a & 2;
$a | 2;
$a ~ 2;
max $a 2;
min $a 2;
% Comparison
$a << 2;
$a >> 2;
$a < 2;
$a <= 2;
$a == 2;
$a != 2;
$a >= 2;
$a > 2;
% Parity
is_even $a;
is_odd $a;
% Text Encoding
at[codepoint] "abc" 1;
ord[codepoint] "g";
ord_at[codepoint] "ijk" 1;
char[codepoint] 99;
slice[codepoint] "abcdefg" 2 3;
slice[codepoint] "abcdefg" 0 3;
"a" == "b";
"a" != "b";
% Other
at[Table] (table (1 => 2)) 1;
at[List] $d 1;
at_back[List] $d -2;
at_back[List] $d -1;
size[List] $d;
join $d "_";
sorted $d;
concat[Text] $b "xyz";
int_to_dec 5;
int_to_hex 7;
dec_to_int "5";
split "xyz" "y";
reversed[codepoint] $b;
reversed[List] $d;
repeat $b 3;
right_align "he" 7;
int_to_hex_aligned 31 7;
replace "abcbd" "b" "e";
```

```clj nogolf
(def a 0)(def b"xy")(def c(= 0 0))(def d["q""r""s"])(and c c)(or c c)(not c)(bit-not a)(- a)(abs a)(+ 2 a)(- a 2)(* 2 a)(quot a 2)(int(Math/pow a 2))(rem a 2)(bit-and 2 a)(bit-or 2 a)(bit-xor 2 a)(max 2 a)(min 2 a)(bit-shift-left a 2)(bit-shift-right a 2)(< a 2)(<= a 2)(= a 2)(not= a 2)(>= a 2)(> a 2)(even? a)(odd? a)(int(nth"abc"1))(int(nth"g"0))(int(nth"ijk"1))(str(char 99))(subs"abcdefg"2 5)(subs"abcdefg"0 3)(="a""b")(not="a""b")({1 2}1)(nth d 1)(nth d(-(count d)2))(last d)(count d)(clojure.string/join"_"d)(sort d)(str b"xyz")(str 5)(format"%x"7)(read-string"5")(.split"xyz""y")(clojure.string/reverse b)(reverse d)(apply str(repeat 3 b))(format"%7s""he")(format"%07x"31)(clojure.string/replace"abcbd""b""e")
```

## Looping

```polygolf
for $i 0 31 {
println ((1 + $i) + ($i * $i));
};
```

```clj nogolf
(dotimes[i 31](prn(+ 1 i(* i i))))
```

```polygolf
$a:-10..10 <- -4;
for $i $a ($a+6) {
println $i;
};
```

```clj nogolf
(def a -4)(doseq[i(range a(+ 6 a))](prn i))
```

```polygolf
for 5 {
print "x";
};
```

```clj nogolf
(dotimes[_ 5](print"x"))
```

```polygolf
while (> 1 0) {
println 5;
$x <- 1;
};
```

```clj nogolf
(while(> 1 0)(prn 5)(def x 1))
```

## Argv

```polygolf
println (at[argv] 5);
```

```clj nogolf
(println(nth *command-line-args* 5))
```

```polygolf
for_argv $x 100 {
println $x;
};
```

```clj nogolf
(doseq[x *command-line-args*](println x))
```

## Block in if statement

```polygolf
if (> 1 0) {
$x <- 1;
print $x;
} {
$y <- 2;
println $y;
};
```

```clj nogolf
(if(> 1 0)(do(def x 1)(pr x))(do(def y 2)(prn y)))
```

## implicitlyConvertConcatArg

```polygolf
(.. "he" (int_to_dec 11) "o");
```

```clj implicitlyConvertConcatArg
(str"he"11"o")
```
112 changes: 112 additions & 0 deletions src/languages/clojure/emit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { EmitError, emitIntLiteral, emitTextFactory } from "../../common/emit";
import { isInt, type IR } from "../../IR";
import { type TokenTree } from "../../common/Language";

const emitClojureText = emitTextFactory({
'"TEXT"': { "\\": `\\\\`, "\n": `\\n`, "\r": `\\r`, '"': `\\"` },
});

export default function emitProgram(program: IR.Node): TokenTree {
function emitMultiNode(BaseNode: IR.Node, blockNeedsDo = false): TokenTree {
const children = BaseNode.kind === "Block" ? BaseNode.children : [BaseNode];
if (BaseNode.kind === "Block" && blockNeedsDo) {
return ["(", "do", children.map((x) => emit(x)), ")"];
}
return children.map((x) => emit(x));
}

/**
* Emits the expression.
* @param expr The expression to be emited.
* @returns Token tree corresponding to the expression.
*/
function emit(e: IR.Node): TokenTree {
switch (e.kind) {
case "Block":
return emitMultiNode(e);
case "While":
return ["(", "while", emit(e.condition), emitMultiNode(e.body), ")"];
case "ForEach":
return [
"(",
"doseq",
"[",
emit(e.variable),
emit(e.collection),
"]",
emitMultiNode(e.body),
")",
];
case "ForRange": {
const varName = e.variable === undefined ? "_" : emit(e.variable);
return isInt(0n)(e.start) && isInt(1n)(e.increment)
? [
"(",
"dotimes",
"[",
varName,
emit(e.end),
"]",
emitMultiNode(e.body),
")",
]
: [
"(",
"doseq",
"[",
varName,
"(",
"range",
emit(e.start),
emit(e.end),
isInt(1n)(e.increment) ? [] : emit(e.increment),
")",
"]",
emitMultiNode(e.body),
")",
];
}
case "If":
// TODO: use when when no alternate and multiple statements
return [
"(",
"if",
emit(e.condition),
emitMultiNode(e.consequent, true),
e.alternate === undefined ? [] : emitMultiNode(e.alternate, true),
")",
];
case "Assignment":
return ["(", "def", emit(e.variable), emit(e.expr), ")"];
case "Identifier":
return e.name;
case "Text":
return emitClojureText(e.value);
case "Integer":
return emitIntLiteral(e, {
10: ["", ""],
16: ["0x", ""],
36: ["36r", ""],
});
case "FunctionCall":
return ["(", emit(e.func), e.args.map((x) => emit(x)), ")"];
case "ConditionalOp":
return [
"(",
"if",
emit(e.condition),
emit(e.consequent),
emit(e.alternate),
")",
];
case "List":
return ["[", e.exprs.map((x) => emit(x)), "]"];
case "Table":
return ["{", e.kvPairs.map((x) => [emit(x.key), emit(x.value)]), "}"];
default:
throw new EmitError(e);
}
}

return emitMultiNode(program);
}
Loading

0 comments on commit c4bc094

Please sign in to comment.