diff --git a/code/modules/nano/_JSON.dm b/code/modules/json/json.dm similarity index 62% rename from code/modules/nano/_JSON.dm rename to code/modules/json/json.dm index 29c18b246b6..df6a6a4661c 100644 --- a/code/modules/nano/_JSON.dm +++ b/code/modules/json/json.dm @@ -1,17 +1,12 @@ -/* -n_Json v11.3.21 -*/ - -proc - json2list(json) - var/static/json_reader/_jsonr = new() - return _jsonr.ReadObject(_jsonr.ScanJson(json)) - - list2json(list/L) - var/static/json_writer/_jsonw = new() - return _jsonw.write(L) - - list2json_usecache(list/L) - var/static/json_writer/_jsonw = new() - _jsonw.use_cache = 1 - return _jsonw.write(L) +proc/json2list(json) + var/static/json_reader/_jsonr = new() + return _jsonr.ReadObject(_jsonr.ScanJson(json)) + +proc/list2json(list/L) + var/static/json_writer/_jsonw = new() + return _jsonw.write(L) + +proc/list2json_usecache(list/L) + var/static/json_writer/_jsonw = new() + _jsonw.use_cache = 1 + return _jsonw.write(L) \ No newline at end of file diff --git a/code/modules/json/json_reader.dm b/code/modules/json/json_reader.dm new file mode 100644 index 00000000000..39289201de1 --- /dev/null +++ b/code/modules/json/json_reader.dm @@ -0,0 +1,187 @@ +json_reader/var/list/string = list("'", "\"") +json_reader/var/list/symbols = list("{", "}", "\[", "]", ":", "\"", "'", ",") +json_reader/var/list/sequences = list("b" = 8, "t" = 9, "n" = 10, "f" = 12, "r" = 13) +json_reader/var/list/tokens +json_reader/var/json +json_reader/var/i = 1 + + +json_reader/proc/ScanJson(json) + src.json = json + . = new/list() + src.i = 1 + while(src.i <= lentext(json)) + var/char = get_char() + if(is_whitespace(char)) + i++ + continue + if(string.Find(char)) + . += read_string(char) + else if(symbols.Find(char)) + . += new/json_token/symbol(char) + else if(is_digit(char)) + . += read_number() + else + . += read_word() + i++ + . += new/json_token/eof() + +json_reader/proc/read_word() + var/val = "" + while(i <= lentext(json)) + var/char = get_char() + if(is_whitespace(char) || symbols.Find(char)) + i-- // let scanner handle this character + return new/json_token/word(val) + val += char + i++ + +json_reader/proc/read_string(delim) + var/escape = FALSE + var/val = "" + while(++i <= lentext(json)) + var/char = get_char() + if(escape) + switch(char) + if("\\", "'", "\"", "/", "u") + val += char + else + // TODO: support octal, hex, unicode sequences + ASSERT(sequences.Find(char)) + val += ascii2text(sequences[char]) + else + if(char == delim) + return new/json_token/text(val) + else if(char == "\\") + escape = TRUE + else + val += char + CRASH("Unterminated string.") + +json_reader/proc/read_number() + var/val = "" + var/char = get_char() + while(is_digit(char) || char == "." || lowertext(char) == "e") + val += char + i++ + char = get_char() + i-- // allow scanner to read the first non-number character + return new/json_token/number(text2num(val)) + +json_reader/proc/check_char() + ASSERT(args.Find(get_char())) + +json_reader/proc/get_char() + return copytext(json, i, i+1) + +json_reader/proc/is_whitespace(char) + return char == " " || char == "\t" || char == "\n" || text2ascii(char) == 13 + +json_reader/proc/is_digit(char) + var/c = text2ascii(char) + return 48 <= c && c <= 57 || char == "+" || char == "-" + + +json_reader/proc/ReadObject(list/tokens) + src.tokens = tokens + . = new/list() + i = 1 + read_token("{", /json_token/symbol) + while(i <= tokens.len) + var/json_token/K = get_token() + check_type(/json_token/word, /json_token/text) + next_token() + read_token(":", /json_token/symbol) + + .[K.value] = read_value() + + var/json_token/S = get_token() + check_type(/json_token/symbol) + switch(S.value) + if(",") + next_token() + continue + if("}") + next_token() + return + else + die() + +json_reader/proc/get_token() + return tokens[i] + +json_reader/proc/next_token() + return tokens[++i] + +json_reader/proc/read_token(val, type) + var/json_token/T = get_token() + if(!(T.value == val && istype(T, type))) + CRASH("Expected '[val]', found '[T.value]'.") + next_token() + return T + +json_reader/proc/check_type(...) + var/json_token/T = get_token() + for(var/type in args) + if(istype(T, type)) + return + CRASH("Bad token type: [T.type].") + +json_reader/proc/check_value(...) + var/json_token/T = get_token() + ASSERT(args.Find(T.value)) + +json_reader/proc/read_key() + var/char = get_char() + if(char == "\"" || char == "'") + return read_string(char) + +json_reader/proc/read_value() + var/json_token/T = get_token() + switch(T.type) + if(/json_token/text, /json_token/number) + next_token() + return T.value + if(/json_token/word) + next_token() + switch(T.value) + if("true") + return TRUE + if("false") + return FALSE + if("null") + return null + if(/json_token/symbol) + switch(T.value) + if("\[") + return read_array() + if("{") + return ReadObject(tokens.Copy(i)) + die() + +json_reader/proc/read_array() + read_token("\[", /json_token/symbol) + . = new/list() + var/list/L = . + while(i <= tokens.len) + // Avoid using Add() or += in case a list is returned. + L.len++ + L[L.len] = read_value() + var/json_token/T = get_token() + check_type(/json_token/symbol) + switch(T.value) + if(",") + next_token() + continue + if("]") + next_token() + return + else + die() + next_token() + CRASH("Unterminated array.") + + +json_reader/proc/die(json_token/T) + if(!T) T = get_token() + CRASH("Unexpected token: [T.value].") \ No newline at end of file diff --git a/code/modules/json/json_token.dm b/code/modules/json/json_token.dm new file mode 100644 index 00000000000..7344e91b52c --- /dev/null +++ b/code/modules/json/json_token.dm @@ -0,0 +1,9 @@ +json_token/var/value +json_token/New(v) + src.value = v + +json_token/text +json_token/number +json_token/word +json_token/symbol +json_token/eof \ No newline at end of file diff --git a/code/modules/json/json_writer.dm b/code/modules/json/json_writer.dm new file mode 100644 index 00000000000..3bec70424f2 --- /dev/null +++ b/code/modules/json/json_writer.dm @@ -0,0 +1,54 @@ +json_writer/var/use_cache = 0 +json_writer/proc/WriteObject(list/L) + if(use_cache && L["__json_cache"]) + return L["__json_cache"] + + . = "{" + var/i = 1 + for(var/k in L) + var/val = L[k] + . += {"\"[k]\":[write(val)]"} + if(i++ < L.len) + . += "," + . += "}" + +json_writer/proc/write(val) + if(isnum(val)) + return num2text(val) + else if(isnull(val)) + return "null" + else if(istype(val, /list)) + if(is_associative(val)) + return WriteObject(val) + else + return write_array(val) + else + . += write_string("[val]") + +json_writer/proc/write_array(list/L) + . = "\[" + for(var/i = 1 to L.len) + . += write(L[i]) + if(i < L.len) + . += "," + . += "]" + +json_writer/proc/write_string(txt) + var/static/list/json_escape = list("\\" = "\\\\", "\"" = "\\\"", "\n" = "\\n") + for(var/targ in json_escape) + var/start = 1 + while(start <= lentext(txt)) + var/i = findtext(txt, targ, start) + if(!i) + break + var/lrep = length(json_escape[targ]) + txt = copytext(txt, 1, i) + json_escape[targ] + copytext(txt, i + length(targ)) + start = i + lrep + + return {""[txt]""} + +json_writer/proc/is_associative(list/L) + for(var/key in L) + // if the key is a list that means it's actually an array of lists (stupid Byond...) + if(!isnum(key) && !isnull(L[key]) && !istype(key, /list)) + return TRUE \ No newline at end of file diff --git a/code/modules/nano/JSON Reader.dm b/code/modules/nano/JSON Reader.dm deleted file mode 100644 index 638ff937a3f..00000000000 --- a/code/modules/nano/JSON Reader.dm +++ /dev/null @@ -1,205 +0,0 @@ -json_token - var - value - New(v) - src.value = v - text - number - word - symbol - eof - -json_reader - var - list - string = list("'", "\"") - symbols = list("{", "}", "\[", "]", ":", "\"", "'", ",") - sequences = list("b" = 8, "t" = 9, "n" = 10, "f" = 12, "r" = 13) - tokens - json - i = 1 - - - proc - // scanner - ScanJson(json) - src.json = json - . = new/list() - src.i = 1 - while(src.i <= lentext(json)) - var/char = get_char() - if(is_whitespace(char)) - i++ - continue - if(string.Find(char)) - . += read_string(char) - else if(symbols.Find(char)) - . += new/json_token/symbol(char) - else if(is_digit(char)) - . += read_number() - else - . += read_word() - i++ - . += new/json_token/eof() - - read_word() - var/val = "" - while(i <= lentext(json)) - var/char = get_char() - if(is_whitespace(char) || symbols.Find(char)) - i-- // let scanner handle this character - return new/json_token/word(val) - val += char - i++ - - read_string(delim) - var - escape = FALSE - val = "" - while(++i <= lentext(json)) - var/char = get_char() - if(escape) - switch(char) - if("\\", "'", "\"", "/", "u") - val += char - else - // TODO: support octal, hex, unicode sequences - ASSERT(sequences.Find(char)) - val += ascii2text(sequences[char]) - else - if(char == delim) - return new/json_token/text(val) - else if(char == "\\") - escape = TRUE - else - val += char - CRASH("Unterminated string.") - - read_number() - var/val = "" - var/char = get_char() - while(is_digit(char) || char == "." || lowertext(char) == "e") - val += char - i++ - char = get_char() - i-- // allow scanner to read the first non-number character - return new/json_token/number(text2num(val)) - - check_char() - ASSERT(args.Find(get_char())) - - get_char() - return copytext(json, i, i+1) - - is_whitespace(char) - return char == " " || char == "\t" || char == "\n" || text2ascii(char) == 13 - - is_digit(char) - var/c = text2ascii(char) - return 48 <= c && c <= 57 || char == "+" || char == "-" - - - // parser - ReadObject(list/tokens) - src.tokens = tokens - . = new/list() - i = 1 - read_token("{", /json_token/symbol) - while(i <= tokens.len) - var/json_token/K = get_token() - check_type(/json_token/word, /json_token/text) - next_token() - read_token(":", /json_token/symbol) - - .[K.value] = read_value() - - var/json_token/S = get_token() - check_type(/json_token/symbol) - switch(S.value) - if(",") - next_token() - continue - if("}") - next_token() - return - else - die() - - get_token() - return tokens[i] - - next_token() - return tokens[++i] - - read_token(val, type) - var/json_token/T = get_token() - if(!(T.value == val && istype(T, type))) - CRASH("Expected '[val]', found '[T.value]'.") - next_token() - return T - - check_type(...) - var/json_token/T = get_token() - for(var/type in args) - if(istype(T, type)) - return - CRASH("Bad token type: [T.type].") - - check_value(...) - var/json_token/T = get_token() - ASSERT(args.Find(T.value)) - - read_key() - var/char = get_char() - if(char == "\"" || char == "'") - return read_string(char) - - read_value() - var/json_token/T = get_token() - switch(T.type) - if(/json_token/text, /json_token/number) - next_token() - return T.value - if(/json_token/word) - next_token() - switch(T.value) - if("true") - return TRUE - if("false") - return FALSE - if("null") - return null - if(/json_token/symbol) - switch(T.value) - if("\[") - return read_array() - if("{") - return ReadObject(tokens.Copy(i)) - die() - - read_array() - read_token("\[", /json_token/symbol) - . = new/list() - var/list/L = . - while(i <= tokens.len) - // Avoid using Add() or += in case a list is returned. - L.len++ - L[L.len] = read_value() - var/json_token/T = get_token() - check_type(/json_token/symbol) - switch(T.value) - if(",") - next_token() - continue - if("]") - next_token() - return - else - die() - next_token() - CRASH("Unterminated array.") - - - die(json_token/T) - if(!T) T = get_token() - CRASH("Unexpected token: [T.value].") \ No newline at end of file diff --git a/code/modules/nano/JSON Writer.dm b/code/modules/nano/JSON Writer.dm deleted file mode 100644 index 787357fb760..00000000000 --- a/code/modules/nano/JSON Writer.dm +++ /dev/null @@ -1,58 +0,0 @@ -json_writer - var - use_cache = 0 - - proc - WriteObject(list/L) - if(use_cache && L["__json_cache"]) - return L["__json_cache"] - - . = "{" - var/i = 1 - for(var/k in L) - var/val = L[k] - . += {"\"[k]\":[write(val)]"} - if(i++ < L.len) - . += "," - . += "}" - - write(val) - if(isnum(val)) - return num2text(val) - else if(isnull(val)) - return "null" - else if(istype(val, /list)) - if(is_associative(val)) - return WriteObject(val) - else - return write_array(val) - else - . += write_string("[val]") - - write_array(list/L) - . = "\[" - for(var/i = 1 to L.len) - . += write(L[i]) - if(i < L.len) - . += "," - . += "]" - - write_string(txt) - var/static/list/json_escape = list("\\" = "\\\\", "\"" = "\\\"", "\n" = "\\n") - for(var/targ in json_escape) - var/start = 1 - while(start <= lentext(txt)) - var/i = findtext(txt, targ, start) - if(!i) - break - var/lrep = length(json_escape[targ]) - txt = copytext(txt, 1, i) + json_escape[targ] + copytext(txt, i + length(targ)) - start = i + lrep - - return {""[txt]""} - - is_associative(list/L) - for(var/key in L) - // if the key is a list that means it's actually an array of lists (stupid Byond...) - if(!isnum(key) && !isnull(L[key]) && !istype(key, /list)) - return TRUE diff --git a/tgstation.dme b/tgstation.dme index 136681471c6..e52af2041d8 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1351,8 +1351,10 @@ #include "code\modules\mob\new_player\new_player.dm" #include "code\modules\mob\new_player\poll.dm" #include "code\modules\mob\new_player\preferences_setup.dm" -#include "code\modules\mob\new_player\sprite_accessories.dm" -#include "code\modules\nano\external.dm" +#include "code\modules\mob\new_player\sprite_accessories.dm" +#include "code\modules\nano\nanoexternal.dm" +#include "code\modules\nano\nanomanager.dm" +#include "code\modules\nano\nanomapgen.dm" #include "code\modules\nano\nanoui.dm" #include "code\modules\nano\subsystem.dm" #include "code\modules\nano\interaction\admin.dm"