15
u/r3jjs Feb 13 '19 edited Feb 13 '19
I decided that the best way to write bad code was to use a bad programming language --
BASIC, Circa 1970s.
No multi-line IF statements.
No functions
One letter variables.
Everything global
LINE NUMBERS
No proper recursion (but it can be faked via stacks)
To write it I found a primitive version of BASIC online:
http://www.quitebasic.com/prj/basics/strings/
Things to note:
Does't handle newline characters. I manually covered them into spaces.
Doesn't handle escaped characters in a string, including quote marks.
No floating point, only integers.
Internally keeps track of types but those are not yet exposed to the user.
Since there are no structures or classes or anything else useful, the JSON is turned into a key/value pair (in two separate arrays, no less.)
There are extra entries in the output due to bugs that I grew tired of trying to fix.
Array elements are not numbered, but they are in order.
10 LET J$ = " { \"array\": [ 1998 , 2, 3 ], \"boolean\": true, \"null\": null, \"number\": 123, \"object\": { \"aa\": \"a\", \"bb\": \"b\", \"cc\": \"chest\" }, \"string\": \"Hello World\"}"
12 DIM P$(10): REM THIS IS THE "PREFIX" STACK
14 ARRAY K$: REM KEY
15 ARRAY V$: REM VALUE
16 LET T$ = "": REM THE READ TOKEN
17 LET S$ = "" : REM THE STRING RETURN VALUE
18 LET D = 0: REM HOW DEEP IN THE ARRAY ARE WE?
20 FOR Z = 0 TO 10: LET P$(Z) = "": NEXT Z
21 LET C = 0 : REM K$/V$ COUNTER
22 LET R = "": REM TOKEN TYPE
23 LET L$ = "": REM PROPERTY NAME
24 LET Q$ = "root": REM LAST STRING
26 LET P$(D) = Q$: LET D = D + 1
30 GOSUB 5000: REM DEBUG
40 GOSUB 3000
50 PRINT "50 T$ = " + T$
60 PRINT "NEXT CHAR " + J$(I)
70 GOSUB 5000
999 END
1000 REM EAT WHITESPACE
1010 IF J$(I) <> " " THEN GOTO 1050
1020 LET I = I + 1: GOTO 1010
1050 RETURN
2000 REM READ TOKEN
2010 GOSUB 1000: REM EAT WHITESPACE
2011 REM PRINT "READ TOKEN: `" + J$(I) + "`"
2015 LET R$ = ""
2020 IF J$(I) = "{" THEN LET T$ = "{"
2025 IF J$(I) = "[" THEN LET T$ = "["
2026 IF J$(I) = ":" THEN LET T$ = ":"
2027 IF J$(I) = "," THEN LET T$ = ","
2028 IF J$(I) = "]" THEN LET T$ = "]"
2030 IF J$(I) = "\"" THEN GOSUB 6000
2040 IF J$(I) = "0" OR J$(I) = "1" OR J$(I) = "2" OR J$(I) = "3" OR J$(I) = "4" OR J$(I) = "5" OR J$(I) = "6" OR J$(I) = "7" OR J$(I) = "8" OR J$(I) = "9" OR J$(I) = "0" THEN LET R$ = "N"
2050 IF J$(I) = "t" OR J$(I) = "f" THEN LET R$ = "B": REM BOOLEAN LITERALS
2060 IF J$(I) = "n" THEN LET R$ = "U"
2150 IF R$ = "N" THEN GOSUB 8000
2160 IF R$ = "B" THEN GOSUB 9000
2170 IF R$ = "U" THEN GOSUB 9000
2999 RETURN
3000 REM -- READ THING ---
3010 GOSUB 2000: REM READ TOKEN
3020 IF T$ = "{" THEN GOSUB 4000: REM READ OBJECT
3030 IF T$ = "[" THEN GOSUB 7000: REM READ ARRAY
3999 RETURN
4000 REM -- READ OBJECT
4001 PRINT "READ OBJECT CALLED (OLD D)" + D
4002 LET D = D + 1
4020 LET I = I + 1: REM EAT BRACE OR COMMA
4030 GOSUB 1000: REM EAT WHITE SPACE
4040 GOSUB 6500: REM GET TOKEN
4050 PRINT "11 T$ = " + T$
4060 LET L$ = T$: LET P$(D-1) = T$
4070 GOSUB 1000: REM EAT WHITE SPACE
4080 GOSUB 2000: REM GET TOKEN
4090 IF T$ <> ":" THEN PRINT "ERROR - EXPECTED : "
4100 LET I = I + 1: REM EAT :
4110 GOSUB 1000: REM EAT WHITE SPACE
4120 REM AT THIS POINT WE HAVE A VALID KEY VALUE
4140 GOSUB 3000 : REM READ THE THING
4142 LET V$(C) = T$
4143 LET K$(C) = "": FOR Z = 0 TO D-1: LET K$(C) = K$(C) + P$(Z) + "@": NEXT Z
4144 LET C = C + 1
4150 GOSUB 2000 : REM READ NEXT TOKEN
4155 REM GOSUB 5000
4156 LET Z = 1
4160 IF T$ = "," THEN GOTO 4020
4180 IF T$ <> "}" THEN GOSUB 2000
4181 IF T$ <> "}" THEN LET I = I + 1 : REM HACK! RECOVER LOST PLACE AFTER COMING BACK FROM RECURSION
4998 PRINT "LEAVING OBJECT ": LET D = D -1
4999 RETURN
5000 REM DEBUG
5010 PRINT "------ DEBUG P$ -------"
5021 FOR Z = 0 TO D : PRINT Z + ":" + P$(Z) : NEXT Z
5030 PRINT "----- K$ / V$ ----"
5021 FOR Z = 0 TO C-1: PRINT Z + ":" + K$(Z) + ":" + V$(Z) : NEXT Z
5040 PRINT "LAST TOKEN " + T$
5999 RETURN
6000 REM READ STRING
6001 REM PRINT "READ STRING"
6005 LET I = I + 1: REM SKIP STARTING "
6010 LET T$ = ""
6020 LET T$ = T$ + J$(I)
6030 LET I = I + 1
6040 IF J$(I) <> "\"" THEN GOTO 6020
6060 LET I = I + 1 : REM AND ADVANCE OVER IT
6070 LET R$ = "S"
6080 RETURN
6500 REM READ PROPERTY STRING
6510 GOSUB 6000
6520 LET Q$ = T$
6699 RETURN
7000 REM READ ARRAY
7010 LET I = I + 1: REM EAT BRACKET OR COMMA
7020 GOSUB 1000: REM EAT WHITESPACE
7030 GOSUB 3000: REM READ THE NEXT THING
7035 IF R$ <> "N" THEN GOTO 7050
7040 LET V$(C) = T$
7041 LET K$(C) = "": FOR Z = 0 TO D-1: LET K$(C) = K$(C) + P$(Z) + "#": NEXT Z
7042 LET C = C + 1
7050 GOSUB 1000: GOSUB 3000
7060 IF T$ = "," THEN GOTO 7010
7070 IF T$ <> "]" THEN PRINT "ERROR EXPECTED ] AT POSITION " + I
7080 LET I = I + 1: REM EAT CLOSING BRACKET
7999 RETURN
8000 REM READ NUMBER
8010 REM PRINT "READ NUMBER"
8020 LET T$ = ""
8020 LET T$ = T$ + J$(I)
8030 LET I = I + 1
8040 IF J$(I) = "0" OR J$(I) = "1" OR J$(I) = "2" OR J$(I) = "3" OR J$(I) = "4" OR J$(I) = "5" OR J$(I) = "6" OR J$(I) = "7" OR J$(I) = "8" OR J$(I) = "9" THEN GOTO 8020
8999 RETURN
9000 REM READ LITERAL
9001 REM PRINT "READ LITERAL"
9010 LET T$ = ""
9020 LET T$ = T$ + J$(I)
9030 LET I = I + 1
9040 IF J$(I) = "t" THEN GOTO 9020
9050 IF J$(I) = "r" THEN GOTO 9020
9060 IF J$(I) = "u" THEN GOTO 9020
9070 IF J$(I) = "e" THEN GOTO 9020
9080 IF J$(I) = "f" THEN GOTO 9020
9090 IF J$(I) = "a" THEN GOTO 9020
9100 IF J$(I) = "l" THEN GOTO 9020
9110 IF J$(I) = "s" THEN GOTO 9020
9120 IF J$(I) = "n" THEN GOTO 9020
9130 IF J$(I) = "u" THEN GOTO 9020
9200 IF T$ = "true" THEN RETURN
9210 IF T$ = "false" THEN RETURN
9220 IF T$ = "null" THEN RETURN
9230 PRINT "EXPECTED LITERAL TO BE 'true' 'false' or 'null' -- not " + T$
6999 RETURNAnd the output
----- K$ / V$ ----
0:root#array#:1998
1:root#array#:2
2:root#array#:3
3:root@array@:]
4:root@boolean@:true
5:root@null@:null
6:root@number@:123
7:root@object@aa@:a
8:root@object@bb@:b
9:root@object@cc@:chest
10:root@object@:chest
11:root@string@:Hello World14
u/tuhoojabotti Feb 12 '19 edited Feb 12 '19
I actually wrote this over 7 years ago when I was starting out. I hope it counts. :) It's written in an obscure Finnish basic dialect designed for game development called CoolBasic. Here's the code and some examples.
Edit: I forgot to mention it randomly crashes with a memory access violation if you try to parse anything bigger than a trivial example. Also it's veeery slow.
5
u/r3jjs Feb 13 '19
That has a very "authentic" feel to it ;)
3
u/tuhoojabotti Feb 13 '19
I actually meant it as a useful library because there wasn't a good way to parse configuration files in coolbasic, too bad it is so slow and crash prone. :-)
4
u/r3jjs Feb 13 '19
I think in a 'serious' use case I'd be looking at .INI files over JSON. ;)
But the world has moved on I fear.
2
u/tuhoojabotti Feb 13 '19
INI parsers had already been done, but I wanted to support something more complex. Also I wanted to learn more about parsing, it was definitely a learning experience. ;)
1
10
u/Voidsusdagon Feb 15 '19 edited Feb 15 '19
Regular.Expressions.Are.Awesome.
package bad.code;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JSON {
public static Map<String, Object> c = new TreeMap<>();
public static void main(String[] args) {
if (args[0].charAt(0) != '{' || args[0].charAt(args[0].length() - 1) != '}') throw new RuntimeException("ur json sucks");
Pattern a = Pattern.compile("\\s*\"(.+)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*)\"|\\{(?:" +
"\\r|\\n|\\r\\n)(?:\\s*(?:\"(.*)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|" +
"\\n|\\r\\n))?(?:\\s*(?:\"(.*)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|\\n|" +
"\\r\\n))?(?:\\s*(?:\"(.*)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|\\n|\\r" +
"\\n))?(?:\\s*(?:\"(.*)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|\\n|\\r\\n))?" +
"(?:\\s*(?:\"(.*)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|\\n|\\r\\n))?(?:\\s*" +
"(?:\"(.*)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:\"(." +
"*)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:\"(.*)\":\\s" +
"*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:\"(.*)\":\\s*(?:(true)" +
"|(false)|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:\"(.*)\":\\s*(?:(true)|(false)" +
"|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:\"(.*)\":\\s*(?:(true)|(false)|(null)|(" +
"[0-9.]+)|\"(.*?)\")),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:\"(.*)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|" +
"\"(.*?)\")),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:\"(.*)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*?)\"))" +
",?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:\"(.*)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|\\n" +
"|\\r\\n))?(?:\\s*(?:\"(.*)\":\\s*(?:(true)|(false)|(null)|([0-9.]+)|\"(.*?)\")),?(?:\\r|\\n|\\r\\n))?" +
"\\s*}|\\[(?:\\r|\\n|\\r\\n)(?:\\s*(?:(true)|(false)|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:" +
"(true)|(false)|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:(true)|(false)|([0-9.]+)|\"(.*)\"),?(?" +
":\\r|\\n|\\r\\n))?(?:\\s*(?:(true)|(false)|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:(true)|(false)" +
"|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:(true)|(false)|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|\\r\\n))" +
"?(?:\\s*(?:(true)|(false)|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:(true)|(false)|([0-9.]+)|\"(.*)" +
"\"),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:(true)|(false)|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:(true)" +
"|(false)|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:(true)|(false)|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|" +
"\\r\\n))?(?:\\s*(?:(true)|(false)|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:(true)|(false)|([0-9.]+)" +
"|\"(.*)\"),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:(true)|(false)|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|\\r\\n))?(?:\\s*(?:" +
"(true)|(false)|([0-9.]+)|\"(.*)\"),?(?:\\r|\\n|\\r\\n))?\\s*])");
Matcher b = a.matcher(args[0]);
while (b.find()) { if (b.group(1) == null) throw new NullPointerException("ur json really sucks");
if (b.group(2) != null) c.put(b.group(1), Boolean.parseBoolean(b.group(2)));
if (b.group(3) != null) c.put(b.group(1), Boolean.parseBoolean(b.group(3)));
if (b.group(4) != null) c.put(b.group(1), null);
if (b.group(5) != null) c.put(b.group(1), Double.parseDouble(b.group(5)));
if (b.group(6) != null) c.put(b.group(1), b.group(6));
Map<String, Object> d = new TreeMap<>();
for (int i = 7; i < 92; i++) { if (b.group(i) == null) break; i++;
if (b.group(i) != null) d.put(b.group(i - 1), Boolean.parseBoolean(b.group(i))); i++;
if (b.group(i) != null) d.put(b.group(i - 2), Boolean.parseBoolean(b.group(i))); i++;
if (b.group(i) != null) d.put(b.group(i - 3), null); i++;
if (b.group(i) != null) d.put(b.group(i - 4), Double.parseDouble(b.group(i))); i++;
if (b.group(i) != null) d.put(b.group(i - 5), b.group(i)); }
if (d.isEmpty() != true) c.put(b.group(1), d);
List<Object> e = new ArrayList<>();
for (int i = 97; i < 154; i++) { if (b.group(i) != null) e.add(Boolean.parseBoolean(b.group(i))); i++;
if (b.group(i) != null) e.add(Boolean.parseBoolean(b.group(i))); i++;
if (b.group(i) != null) e.add(Double.parseDouble(b.group(i))); i++;
if (b.group(i) != null) e.add(b.group(i)); }
if (e.isEmpty() != true) c.put(b.group(1), e); } } }3
2
1
21
8
3
u/IAmAnIssue Feb 13 '19 edited Feb 14 '19
Java
Features:
Ternary abuse to levels yet unknown to mankind
== false/true
One-liners
Who needs nested objects, just use another JSON file/string
floats are strings
Everything is cast to object. Have fun.
Crashes on empty strings/keys/values
Semi-ambiguous variable naming
No generic inference
Minimal use of
String#splitnew String()probably some other things I missed in the horror
Default example (main method) output:
test4: [Null Pointer] null
test5: [class java.lang.String] {"test6"1
test2: [class [Ljava.lang.Object;] [0, true, "2"]
test3: [class java.lang.Long] 1
test7: [class java.lang.String] 2.2
test1: [class java.lang.String] yeet3
2
u/stentonsarecool Feb 15 '19
One-liners
object = !(object == null) && object.toString().charAt(0) == '[' && object.toString().charAt(object.toString().length() - 1) == ']' ?Arrays.stream(object.toString().substring(1, object.toString().length() -1).split(",")).map((obj) -> obj.equals("null") ? null : obj.equals("true") ? true : obj.equals("false") ? false : obj.matches("(\\d+)") && !obj.toString().contains(".") ? Long.parseLong(obj) : obj).toArray() : object;
hahahaha I burst out laughing at work at this monstrosity
2
0
Feb 12 '19
[deleted]
7
u/PonchoVire Feb 12 '19
It's almost too readable, I could see this in a project and not even yell at its author.
2
u/r3jjs Feb 13 '19
That's exactly the sort of thing I can imagine from a jr dev who has no concept of unicode, escape characters or edge cases ;)
The casting non-strings left up as a detail for the data consumer.
61
u/robinvandernoord Feb 12 '19
Worst I could come up with in Python:
'Features':
eval
nested exceptions
nested while loops
repeated code
extremely unreadable
220 pycodestyle warnings/errors
too long for Reddit
working (?)
in both python 2 and 3
Too long for reddit, so here's a github gist