From 02fe3e3c823678594da0344515c838d40f3d4d0d Mon Sep 17 00:00:00 2001 From: PanJohnny Date: Sun, 20 Nov 2022 17:23:08 +0100 Subject: [PATCH] Initial commit --- .gitignore | 2 + .idea/.gitignore | 3 + .idea/compiler.xml | 13 ++ .idea/discord.xml | 7 + .idea/encodings.xml | 7 + .idea/jarRepositories.xml | 20 ++ .idea/misc.xml | 18 ++ .idea/uiDesigner.xml | 124 ++++++++++++ .idea/vcs.xml | 6 + README.md | 26 +++ hello.cats | 53 +++++ hello.cats.meow | 1 + pom.xml | 25 +++ src/main/java/com/panjohnny/lang/Main.java | 182 ++++++++++++++++++ .../com/panjohnny/lang/compiled/Compiler.java | 35 ++++ .../com/panjohnny/lang/compiled/Token.java | 47 +++++ .../lang/interpreted/Interpreter.java | 28 +++ .../lang/interpreted/Operations.java | 139 +++++++++++++ .../lang/interpreted/StackProvider.java | 52 +++++ 19 files changed, 788 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/discord.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/vcs.xml create mode 100644 README.md create mode 100644 hello.cats create mode 100644 hello.cats.meow create mode 100644 pom.xml create mode 100644 src/main/java/com/panjohnny/lang/Main.java create mode 100644 src/main/java/com/panjohnny/lang/compiled/Compiler.java create mode 100644 src/main/java/com/panjohnny/lang/compiled/Token.java create mode 100644 src/main/java/com/panjohnny/lang/interpreted/Interpreter.java create mode 100644 src/main/java/com/panjohnny/lang/interpreted/Operations.java create mode 100644 src/main/java/com/panjohnny/lang/interpreted/StackProvider.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..744289d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Project exclude paths +/target/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b3a3b3b --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..8cf359d --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..712ab9d --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..ca29a35 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..aa5c95c --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Weird esoteric cat emoji programming language +*Or: what am I doing with my life* + +Check out hello.cats for hello world and hello.cats.meow for compiled version. Can be downloaded as jar and then used to generate and run code. This language is great, because you can comment everywhere. + +.cats - not compiled + +.cats.meow - compiled + +## Challenge +Open issues with your own code in this language. Best submissions will be added in README. + +## Actions +``` +x++ increment cursor 😺 +x-- decrement cursor 😿 +i++ increment stack index 😽 +i-- decrement stack index πŸ™€ +x**2 power 😻 +sqrt(x) sqrt 😾 +x = 0 cursor set to 0 😼 +if(x > {i--} x {i++}) x = 1 : x = 0 🐈 +if(x==1) {} : {skipTo(😹)} 😸 + 😹 + πŸ’© +``` \ No newline at end of file diff --git a/hello.cats b/hello.cats new file mode 100644 index 0000000..aa2cbda --- /dev/null +++ b/hello.cats @@ -0,0 +1,53 @@ +H - 72 = 8**2 + 8 +😺😺😺😺😺😺😺😺😻 +64 +😺😺😺😺😺😺😺😺 +8 +😽 + +E - 69 = 8**2 + 5 +😺😺😺😺😺😺😺😺😻 +64 +😺😺😺😺😺 +5 +😽 + +L - 76 = 9**2 - 5 +😺😺😺😺😺😺😺😺😺😻 +81 +😿😿😿😿😿 -5 +😽 + +L - 76 = 9**2 - 5 +😺😺😺😺😺😺😺😺😺😻 +81 +😿😿😿😿😿 -5 +😽 + +O - 79 = 9**2 - 2 +😺😺😺😺😺😺😺😺😺😻 +81 +😿😿 -2 +😽 + +SPACE - 32 = 6**2 - 4 +😺😺😺😺😺😺😻 +36 +😿😿😿😿 -4 +😽 + +W - 87 = 9**2 + 6 +😺😺😺😺😺😺😺😺😺😻 +81 +😺😺😺😺😺😺 +6 +😽 + +O - 79 = 9**2 - 2 +😺😺😺😺😺😺😺😺😺😻 +81 +😿😿 -2 +😽 + +R - 82 = 9**2 + 1 +😺😺😺😺😺😺😺😺😺😻 +81 +😺 +1 +😽 + +L - 76 = 9**2 - 5 +😺😺😺😺😺😺😺😺😺😻 +81 +😿😿😿😿😿 -5 +😽 + +D - 69 = 8**2 + 4 +😺😺😺😺😺😺😺😺😻 +64 +😺😺😺😺 +4 \ No newline at end of file diff --git a/hello.cats.meow b/hello.cats.meow new file mode 100644 index 0000000..135017a --- /dev/null +++ b/hello.cats.meow @@ -0,0 +1 @@ +++++++++p++++++++>++++++++p+++++>+++++++++p----->+++++++++p----->+++++++++p-->++++++p---->+++++++++p++++++>+++++++++p-->+++++++++p+>+++++++++p----->++++++++p++++ \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6a94a87 --- /dev/null +++ b/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + + com.panjohnny + CatLang + 1.0-SNAPSHOT + + + org.jetbrains + annotations + 23.0.0 + compile + + + + + 18 + 18 + UTF-8 + + + \ No newline at end of file diff --git a/src/main/java/com/panjohnny/lang/Main.java b/src/main/java/com/panjohnny/lang/Main.java new file mode 100644 index 0000000..d163a75 --- /dev/null +++ b/src/main/java/com/panjohnny/lang/Main.java @@ -0,0 +1,182 @@ +package com.panjohnny.lang; + +import com.panjohnny.lang.compiled.Compiler; +import com.panjohnny.lang.interpreted.Interpreter; +import com.panjohnny.lang.interpreted.Operations; +import com.panjohnny.lang.interpreted.StackProvider; + +import java.io.*; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; + +public class Main { + + public static boolean debug = false; + + public static void main(String[] args) throws IOException { + System.out.println("[PANJOHNNY] Welcome to this utility to do stuff with my eso cat language! Enjoy!"); + System.out.println(); + + if (args.length < 1) { + System.err.println("[(flags)] "); + System.err.println("For flags run with -h (flags are not mandatory)"); + return; + } + + List flags = Arrays.stream(args).filter(s -> s.startsWith("-")).toList(); + + if (flags.contains("-d") || flags.contains("--debug")) { + debug = true; + System.out.println("Ran in debug mode"); + System.out.println(" With " + flags); + } + + if (flags.contains("-h") || flags.contains("--help")) { + System.out.println("Usage: [(flags)] "); + System.out.println("Flags are not mandatory and mode is deducted from file extension."); + System.out.println(" *.cats - compile"); + System.out.println(" *.meow - run"); + System.out.println("Flags:"); + System.out.println(" -h, --help - prints out this help menu"); + System.out.println(" -v, --version - prints out the version"); + System.out.println(" -d, --debug - debugs stuff"); + System.out.println(" Mode flags: - this set of flags changes mode and turns of auto file type detection"); + System.out.println(" -c, --compile - compiles the file as if it was script"); + System.out.println(" -e, --eval - evaluates the file as if it was compiled"); + System.out.println(" -i, --interactive - starts to listen for code that you write and evaluates it on spot"); + System.out.println(" -dc, --decompile - decompiles file"); + } else if (flags.contains("-v") || flags.contains("--version")) { + System.out.println("Version: " + Main.class.getPackage().getImplementationVersion()); + } else if (flags.contains("-c") || flags.contains("--compile")) { + compile(args); + } else if (flags.contains("-e") || flags.contains("--eval")) { + run(args); + } else if (flags.contains("-dc") || flags.contains("--decompile")) { + decompile(args); + } else if (flags.contains("-i") || flags.contains("--interactive")) { + Operations.register(); + System.out.println("Ran in interactive mode"); + + Scanner sc = new Scanner(System.in); + System.out.println("Enter code or EXIT:"); + while (sc.hasNextLine()) { + String s = sc.nextLine(); + if (s.equals("EXIT")) + System.exit(0); + System.out.println(Interpreter.eval(sc.nextLine(), null)); + } + } else { + // AUTO determine + String file = args[args.length - 1]; + + if (file.endsWith(".meow")) + run(args); + else if (file.endsWith(".cats")) + compile(args); + else { + System.err.println("Unknown file type, use -h to see modes"); + System.exit(1); + } + } + } + + private static void compile(String[] args) throws IOException { + File file = getFile(args[args.length - 1]); + if (debug) + System.out.println("Compiling " + file.getAbsolutePath()); + String s = readFile(file); + + String compiled = Compiler.compile(s); + File f = new File("./" + file.getName() + ".meow"); + writeFile(f, compiled); + if (debug) + System.out.println("Compilation finished and saved to: " + f.getAbsolutePath()); + } + + private static void run(String[] args) throws FileNotFoundException { + Operations.register(); + + File file = getFile(args[args.length - 1]); + if (debug) + System.out.println("Executing " + file.getAbsolutePath()); + String s = readFile(file); + + StackProvider sp = Interpreter.run(s, null); + end(sp); + } + + private static void decompile(String[] args) throws IOException { + File file = getFile(args[args.length - 1]); + if (debug) + System.out.println("Executing " + file.getAbsolutePath()); + String s = readFile(file); + + String decompiled = Compiler.decompile(s); + File f = new File("./" + file.getName() + ".cats"); + writeFile(f, decompiled); + if (debug) + System.out.println("Decompiled and saved file to: " + f.getAbsolutePath()); + + } + + private static String readFile(File file) throws FileNotFoundException { + Scanner scanner = new Scanner(file); + StringBuilder sb = new StringBuilder(); + while (scanner.hasNext()) { + sb.append(scanner.next()); + } + + return sb.toString(); + } + + private static File getFile(String path) { + File file = new File(path); + if (!file.exists()) { + file = new File("./" + path); + if (!file.exists()) { + file = new File(".", path); + if (!file.exists()) { + System.err.println("File not found: " + path); + System.exit(1); + } + } + } + + if (file.isDirectory()) { + System.err.println("File is a directory: " + file.getAbsolutePath()); + System.exit(1); + } + + if (!file.canRead()) { + System.err.println("Cannot read file: " + file.getAbsolutePath()); + System.exit(1); + + } + + return file; + } + + private static void writeFile(File file, String s) throws IOException { + if (!file.exists()) + if (!file.createNewFile()) { + System.err.println("Unable to create new file to write to!"); + System.exit(1); + } + BufferedWriter writer = new BufferedWriter(new FileWriter(file)); + writer.write(s); + writer.flush(); + writer.close(); + } + + public static void end(StackProvider provider) { + System.out.println("Program exited with " + provider); + System.out.println("As string: " + provider.asString()); + + if (debug) { + System.out.println("Index: " + provider.index); + System.out.println("Skip hint: " + provider.skipHint); + } + System.exit(0); + } +} \ No newline at end of file diff --git a/src/main/java/com/panjohnny/lang/compiled/Compiler.java b/src/main/java/com/panjohnny/lang/compiled/Compiler.java new file mode 100644 index 0000000..ca7bd9b --- /dev/null +++ b/src/main/java/com/panjohnny/lang/compiled/Compiler.java @@ -0,0 +1,35 @@ +package com.panjohnny.lang.compiled; + +import java.util.List; +import java.util.regex.MatchResult; +import java.util.regex.Pattern; + +public class Compiler { + public static String compile(String source) { + List emojis = Pattern.compile("\\P{M}\\p{M}*+").matcher(source) + .results() + .map(MatchResult::group).toList(); + StringBuilder sb = new StringBuilder(); + for (String emoji : emojis) { + Token tk = Token.fromEmoji(emoji); + if (tk != null) { + sb.append(tk); + } + } + + return sb.toString(); + } + + public static String decompile(String str) { + char[] tokens = str.toCharArray(); + + StringBuilder sb = new StringBuilder(); + for (char s : tokens) { + Token t = Token.fromCode(s + ""); + if (t!=null) + sb.append(t.emoji); + } + + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/panjohnny/lang/compiled/Token.java b/src/main/java/com/panjohnny/lang/compiled/Token.java new file mode 100644 index 0000000..c4c72b2 --- /dev/null +++ b/src/main/java/com/panjohnny/lang/compiled/Token.java @@ -0,0 +1,47 @@ +package com.panjohnny.lang.compiled; + +public enum Token { + INCREMENT("\uD83D\uDE3A", "+"), + DECREMENT("\uD83D\uDE3F", "-"), + RIGHT("\uD83D\uDE3D", ">"), + LEFT("\uD83D\uDE40", "<"), + POW("\uD83D\uDE3B", "p"), + SQRT("\uD83D\uDE3E", "s"), + NIL("\uD83D\uDE3C", "0"), + LOGIC1("\uD83D\uDC08", "("), + LOGIC2("\uD83D\uDE38", ")"), + END_OF_LOGIC("\uD83D\uDE38", "}"), + END("\uD83D\uDCA9", "#"); + + final String emoji; + final String code; + Token(String emoji, String code) { + this.emoji = emoji; + this.code = code; + } + + public static Token fromEmoji(String emoji) { + for (Token token : Token.values()) { + if (token.emoji.equals(emoji)) { + return token; + } + } + + return null; + } + + public static Token fromCode(String code) { + for (Token token : Token.values()) { + if (token.code.equals(code)) { + return token; + } + } + + return null; + } + + @Override + public String toString() { + return code; + } +} diff --git a/src/main/java/com/panjohnny/lang/interpreted/Interpreter.java b/src/main/java/com/panjohnny/lang/interpreted/Interpreter.java new file mode 100644 index 0000000..0cfdcd5 --- /dev/null +++ b/src/main/java/com/panjohnny/lang/interpreted/Interpreter.java @@ -0,0 +1,28 @@ +package com.panjohnny.lang.interpreted; + +import com.panjohnny.lang.compiled.Compiler; +import com.panjohnny.lang.compiled.Token; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.function.Consumer; + +public final class Interpreter { + public static StackProvider run(String inp, @Nullable StackProvider stack) { + if (stack == null) { + stack = new StackProvider(); + } + char[] results = inp.toCharArray(); + for (char s : results) { + Token tk = Token.fromCode(s + ""); + Consumer cons = Operations.OPERATIONS.get(tk); + if (cons != null) + cons.accept(stack); + } + return stack; + } + + public static StackProvider eval(String inp, @Nullable StackProvider stack) { + return run(Compiler.compile(inp), stack); + } +} diff --git a/src/main/java/com/panjohnny/lang/interpreted/Operations.java b/src/main/java/com/panjohnny/lang/interpreted/Operations.java new file mode 100644 index 0000000..a8efcd5 --- /dev/null +++ b/src/main/java/com/panjohnny/lang/interpreted/Operations.java @@ -0,0 +1,139 @@ +package com.panjohnny.lang.interpreted; + +import com.panjohnny.lang.Main; +import com.panjohnny.lang.compiled.Token; + +import java.util.HashMap; +import java.util.function.Consumer; + +public final class Operations { + public static final HashMap> OPERATIONS = new HashMap<>(); + + public static void register() { + // 😺 x++ + OPERATIONS.put(Token.INCREMENT, Operations::increment); + + // 😿 x-- + OPERATIONS.put(Token.DECREMENT, Operations::decrement); + + // 😽 >>> + OPERATIONS.put(Token.RIGHT, Operations::moveRight); + + // πŸ™€ <<< + OPERATIONS.put(Token.LEFT, Operations::moveLeft); + + // 😻 x**2 + OPERATIONS.put(Token.POW, Operations::pow); + + // 😾 sqrt + OPERATIONS.put(Token.SQRT, Operations::sqrt); + + // 😼 x = 0 + OPERATIONS.put(Token.NIL, Operations::zero); + + // 🐈 if(x > {i--} x {i++}) x = 1 : x = 0 + OPERATIONS.put(Token.LOGIC1, Operations::logic); + + // 😸 if(x == 1) {} : {skipTo(😹)} + OPERATIONS.put(Token.LOGIC2, Operations::if1); + + // 😹 + OPERATIONS.put(Token.END_OF_LOGIC, Operations::endOfLogic); + + OPERATIONS.put(Token.END, (stack) -> { + if (stack.skipHint()) + return; + Main.end(stack); + }); + } + + public static void increment(StackProvider stack) { + if (stack.skipHint()) + return; + stack.set(stack.get()+1); + if (Main.debug) + System.out.println("+ (" + stack.get() + ")"); + } + + public static void decrement(StackProvider stack) { + if (stack.skipHint()) + return; + stack.set(stack.get()-1); + if (Main.debug) + System.out.println("- (" + stack.get() + ")"); + } + + public static void moveRight(StackProvider stack) { + if (stack.skipHint()) + return; + stack.moveRight(); + if (Main.debug) + System.out.println("> (" + stack.get() + ")"); + } + + public static void moveLeft(StackProvider stack) { + if (stack.skipHint()) + return; + stack.moveLeft(); + if (Main.debug) + System.out.println("< (" + stack.get() + ")"); + } + + public static void pow(StackProvider stack) { + if (stack.skipHint()) + return; + stack.set(stack.get()*stack.get()); + if (Main.debug) + System.out.println("pow (" + stack.get() + ")"); + } + + public static void sqrt(StackProvider stack) { + if (stack.skipHint()) + return; + stack.set((int)Math.sqrt(stack.get())); + if (Main.debug) + System.out.println("sqrt (" + stack.get() + ")"); + } + + public static void zero(StackProvider stack) { + if (stack.skipHint()) + return; + stack.set(0); + if (Main.debug) + System.out.println("0 (" + stack.get() + ")"); + } + + public static void logic(StackProvider stack) { + if (stack.skipHint()) + return; + // if(x > {i--} x {i++}) x = 1 : x = 0 + + int current = stack.get(); + stack.moveLeft(); + int before = stack.get(); + stack.moveRight(); + if (current > before) + stack.set(1); + else + stack.set(0); + if (Main.debug) + System.out.println("LOGIC1 (" + stack.get() + ")"); + } + + public static void if1(StackProvider stack) { + if (stack.skipHint()) + return; + if (stack.get() != 1) + stack.skipHint+=1; + if (Main.debug) + System.out.println("LOGIC2 (" + stack.get() + ")"); + } + + public static void endOfLogic(StackProvider stack) { + if (!stack.skipHint()) + return; + stack.skipHint-=1; + if (Main.debug) + System.out.println("END_OF_LOGIC (" + stack.get() + ")"); + } +} diff --git a/src/main/java/com/panjohnny/lang/interpreted/StackProvider.java b/src/main/java/com/panjohnny/lang/interpreted/StackProvider.java new file mode 100644 index 0000000..ed806fd --- /dev/null +++ b/src/main/java/com/panjohnny/lang/interpreted/StackProvider.java @@ -0,0 +1,52 @@ +package com.panjohnny.lang.interpreted; + +import java.util.LinkedList; + +public class StackProvider { + LinkedList stack; + public int index = 0; + public int skipHint; + public StackProvider() { + this.stack = new LinkedList<>(); + this.stack.addLast(0); + } + + public void moveLeft() { + index--; + if (index < 0) { + index = stack.size() - 1; + } + } + + public void moveRight() { + index++; + while (index >= stack.size()) { + stack.addLast(0); + } + } + + public void set(int value) { + stack.set(index, value); + } + + public int get() { + return stack.get(index); + } + + @Override + public String toString() { + return stack.toString(); + } + + public boolean skipHint() { + return skipHint > 0; + } + + public String asString() { + StringBuilder sb = new StringBuilder(); + for (int a : stack) { + sb.append((char) a); + } + return sb.toString(); + } +}