diff --git a/code/game/machinery/telecomms/ntsl2.dm b/code/game/machinery/telecomms/ntsl2.dm index ec1e5b923ca..3404a662296 100644 --- a/code/game/machinery/telecomms/ntsl2.dm +++ b/code/game/machinery/telecomms/ntsl2.dm @@ -1,3 +1,4 @@ +GLOBAL_DATUM_INIT(ntsl2_config, /datum/ntsl2_configuration, new()) // Custom Implementations for NTSL2 /* NTSL2 Configuration Datum * This is an abstract handler for the configuration loadout. It's set up like this both for ease of transfering in and out of the UI @@ -58,6 +59,25 @@ // Used to determine what languages are allowable for conversion. Generated during runtime. var/list/valid_languages = list("--DISABLE--") +/datum/ntsl2_configuration/proc/reset() + /* Simple Toggles */ + toggle_activated = initial(toggle_activated) + toggle_jobs = initial(toggle_jobs) + toggle_timecode = initial(toggle_timecode) + // Hack section + toggle_gibberish = initial(toggle_gibberish) + toggle_honk = initial(toggle_honk) + + /* Strings */ + setting_language = initial(setting_language) + + /* Tables */ + regex = list() + + /* Arrays */ + firewall = list() + + /datum/ntsl2_configuration/proc/update_languages() for(var/language in all_languages) var/datum/language/L = all_languages[language] @@ -108,6 +128,12 @@ signal.data["reject"] = TRUE return + // Firewall + // This must happen before anything else modifies the signal ["name"]. + if(islist(firewall) && firewall.len > 0) + if(firewall.Find(signal.data["name"])) + signal.data["reject"] = 1 + // These two stack properly. // Simple job indicator switch. if(toggle_jobs) @@ -152,11 +178,6 @@ new_message = start.Replace(original, replacePattern) signal.data["message"] = new_message - // Firewall - if(islist(firewall) && firewall.len > 0) - if(firewall.Find(signal.data["name"])) - signal.data["reject"] = 1 - // Check the message for forbidden HTML (REMOVE THIS IF YOU START STRIPPING HTML IN REGEX) var/regex/bannedTags = new("(Language conversion disabled.") else setting_language = new_language - to_chat(user, "Messages will now be converted to [new_language].") + to_chat(user, "Messages will now be converted to [new_language].") // Tables if(href_list["create_row"]) - to_chat(world, "NTSL2 create_row || [href_list["table"]]") if(href_list["table"] && href_list["table"] in tables) if(requires_unlock[href_list["table"]] && !source.unlocked) return @@ -205,19 +223,17 @@ if(new_value == null) return vars[href_list["table"]][new_key] = new_value - to_chat(user, "Added row [new_key] -> [new_value].") + to_chat(user, "Added row [new_key] -> [new_value].") if(href_list["delete_row"]) - to_chat(world, "NTSL2 delete_row || [href_list["table"]]") if(href_list["table"] && href_list["table"] in tables) if(requires_unlock[href_list["table"]] && !source.unlocked) return vars[href_list["table"]].Remove(href_list["delete_row"]) - to_chat(user, "Removed row [href_list["delete_row"]] from [href_list["table"]]") + to_chat(user, "Removed row [href_list["delete_row"]] from [href_list["table"]]") // Arrays if(href_list["create_item"]) - to_chat(world, "NTSL2 create_item || [href_list["array"]]") if(href_list["array"] && href_list["array"] in arrays) if(requires_unlock[href_list["array"]] && !source.unlocked) return @@ -225,14 +241,14 @@ if(new_value == null) return vars[href_list["array"]].Add(new_value) + to_chat(user, "Added row [new_value].") if(href_list["delete_item"]) - to_chat(world, "NTSL2 delete_item || [href_list["array"]]") if(href_list["array"] && href_list["array"] in arrays) if(requires_unlock[href_list["array"]] && !source.unlocked) return vars[href_list["array"]].Remove(href_list["delete_item"]) - to_chat(user, "Removed [href_list["delete_item"]] from [href_list["array"]]") + to_chat(user, "Removed [href_list["delete_item"]] from [href_list["array"]]") // Spit out the serialized config to the user if(href_list["save_config"]) diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 7692cd770cb..247914ed436 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -435,12 +435,6 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() var/logs = 0 // number of logs var/totaltraffic = 0 // gigabytes (if > 1024, divide by 1024 -> terrabytes) - // Old NTSL - var/list/memory = list() // stored memory - var/list/rawcode = list() // the code to compile (list of characters) - var/datum/TCS_Compiler/Compiler // the compiler that compiles and runs the code - var/autoruncode = 0 // 1 if the code is set to run every time a signal is picked up - var/encryption = "null" // encryption key: ie "password" var/salt = "null" // encryption salt: ie "123comsat" // would add up to md5("password123comsat") @@ -449,8 +443,6 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() /obj/machinery/telecomms/server/Initialize() ..() - Compiler = new() - Compiler.Holder = src server_radio = new() /obj/machinery/telecomms/server/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) @@ -508,23 +500,10 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() if(GLOB.ntsl2_config) GLOB.ntsl2_config.modify_signal(signal) - //if(Compiler && autoruncode) - // Compiler.Run(signal) // execute the code - var/can_send = relay_information(signal, "/obj/machinery/telecomms/hub") if(!can_send) relay_information(signal, "/obj/machinery/telecomms/broadcaster") - -/obj/machinery/telecomms/server/proc/setcode(var/list/code) - if(istype(code)) - rawcode = code - -/obj/machinery/telecomms/server/proc/compile(mob/user as mob) - if(Compiler) - admin_log(user) - return Compiler.Compile(rawcode) - /obj/machinery/telecomms/server/proc/update_logs() // start deleting the very first log entry if(logs >= 400) @@ -544,16 +523,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() log_entries.Add(log) update_logs() -/obj/machinery/telecomms/server/proc/admin_log(var/mob/mob) - var/msg="[key_name(mob)] has compiled a script to server [src]:" - log_game("NTSL: [msg]") - log_game("NTSL: [rawcode.Join("")]") - src.investigate_log("[msg]
[rawcode.Join("")]", "ntsl") - if(length(rawcode)) // Let's not bother the admins for empty code. - message_admins("[key_name_admin(mob)] has compiled and uploaded a NTSL script to [src.id] (JMP)") - // Simple log entry datum - /datum/comm_log_entry var/parameters = list() // carbon-copy to signal.data[] var/name = "data packet (#)" diff --git a/code/game/machinery/telecomms/traffic_control.dm b/code/game/machinery/telecomms/traffic_control.dm index 45f0817ef55..8979dfeeb75 100644 --- a/code/game/machinery/telecomms/traffic_control.dm +++ b/code/game/machinery/telecomms/traffic_control.dm @@ -1,25 +1,23 @@ /obj/machinery/computer/telecomms/traffic name = "telecommunications traffic control" - var/screen = 0 // the screen number: - var/allservers = 0 // Are all servers being edited at the same time? - var/list/servers = list() // the servers located by the computer - var/mob/editingcode - var/mob/lasteditor - var/obj/machinery/telecomms/server/SelectedServer - - var/compiling_errors = "" - - var/network = "NULL" // the network to probe - var/temp = "" // temporary feedback messages - - var/storedcode = "" // code stored - light_color = LIGHT_COLOR_DARKGREEN req_access = list(access_tcomsat) circuit = /obj/item/circuitboard/comm_traffic + // NTSL2 + var/window_id // mostly used to let the configuration datum update the user's UI + var/unlocked = FALSE + +/obj/machinery/computer/telecomms/traffic/attackby(obj/item/I, mob/user) + if(ismultitool(I)) + unlocked = !unlocked + to_chat(user, "This computer is now [unlocked ? "Unlocked" : "Locked"]. \ +Reopen the UI to see the difference.") + return + . = ..() + /obj/machinery/computer/telecomms/traffic/attack_hand(mob/user) interact(user) @@ -27,154 +25,19 @@ if(stat & (BROKEN|NOPOWER)) return 0 - user.set_machine(src) + if(GLOB.ntsl2_config.valid_languages.len == 1) + GLOB.ntsl2_config.update_languages() // this is silly but it has to be done because ntsl2 inits before languages do - if(!editingcode || editingcode && editingcode.machine != src) - editingcode = user - lasteditor = user - - var/dat = "" - - dat += "
Telecommunications Traffic Control
" - - if(screen == 0) //main menu - dat += "
[temp]
" - dat += "
Current Network: [network]
" - if(servers.len) - dat += "
Detected Telecommunication Servers:" - - dat += "
\[Flush Buffer\]" - - else - dat += "
No servers detected. Scan for servers: \[Scan\]" - - if(screen == 1) //server menu - dat += "
[temp]
" - dat += "
\[Main Menu\] \[Refresh\]
" - dat += "
Current Network: [network]" - if(allservers) - dat += "
Selected Server: All Servers

" - else - dat += "
Selected Server: [SelectedServer.id]

" - dat += "
\[Edit Code\]" - dat += "
Signal Execution: " - if(allservers) - dat += "ALWAYS NEVER" - else - if(SelectedServer.autoruncode) - dat += "ALWAYS" - else - dat += "NEVER" - - if(screen == 2) //code editor - if(editingcode == user) - dat += {"
[temp]
-
- \[Back\] - \[Main Menu\] - \[Refresh\] -
- - - -
- -
- - - Compile - Clear - -
- [compiling_errors] -
- -
- - - - -
- "} - else - dat += {"
[temp]
-
\[Refresh\]
-
- - -
-
- [compiling_errors] -
- "} //anything typed will be overridden anyways by the one who is editing the code - - var/datum/browser/popup = new(user, "traffic_control", "Telecommunication Traffic Control", 700, 500) - //codemirror - popup.add_script("codemirror-compressed", 'nano/codemirror/codemirror-compressed.js') // A custom minified JavaScript file of CodeMirror, with the following plugins: CSS Mode, NTSL Mode, CSS-hint addon, Search addon, Sublime Keymap. - popup.add_stylesheet("codemirror", 'nano/codemirror/codemirror.css') // A CSS sheet containing the basic stylings and formatting information for CodeMirror. - popup.add_stylesheet("lesser-dark", 'nano/codemirror/lesser-dark.css') // A theme for CodeMirror to use, which closely resembles the rest of the NanoUI style. - - popup.set_content(dat) - popup.open() - - temp = "" + var/datum/asset/assets = get_asset_datum(/datum/asset/simple/ntsl2) + assets.send(user) + var/dat = file2text("html/ntsl2/dist/index.html") + if(unlocked) + dat += "\n" + var/datum/browser/ntsl2/nt_browser = new(user, name, "NTSL2", 720, 480, src, GLOB.ntsl2_config.ntsl_serialize()) + nt_browser.set_content(dat) + nt_browser.open() + window_id = nt_browser.window_id /obj/machinery/computer/telecomms/traffic/Topic(href, href_list) if(..()) @@ -184,209 +47,4 @@ if(!istype(user) || !user.client) return 0 - if(user != editingcode) - return 0 - - var/code = href_list["cMirror"] - if(code) - storedcode = code - - var/list/codelist = href_list["cMirrorList"] - if(istext(codelist)) - codelist = json_decode(codelist) - - add_fingerprint(user) - user.set_machine(src) - - if(!allowed(user) && !emagged && !user.can_admin_interact()) - to_chat(user, "Access Denied.") - return 0 - - switch(href_list["choice"]) - if("Compile") - if(!istype(codelist)) - return 0 - if(user != editingcode) - return 0 //only one editor - - if(SelectedServer) - var/obj/machinery/telecomms/server/Server = SelectedServer - Server.setcode(codelist) - - spawn(0) - // Output all the compile-time errors - compiling_errors = "Please wait, compiling..." - updateUsrDialog() - - var/list/compileerrors = Server.compile(user) // then compile the code! - if(!telecomms_check(user)) - return - - if(compileerrors.len) - compiling_errors = "Compile Errors
" - for(var/datum/scriptError/e in compileerrors) - compiling_errors += "\t>[e.message]
" - compiling_errors += "([compileerrors.len] errors)" - - - else - compiling_errors = "TCS compilation successful!
" - compiling_errors += "(0 errors)" - - updateUsrDialog() - if(allservers) - spawn(0) - compiling_errors = "Please wait, compiling..." - updateUsrDialog() - - for(var/obj/machinery/telecomms/server/Server in servers) - Server.setcode(codelist) - var/list/compileerrors = Server.compile(user) - if(!telecomms_check(user)) - return - if(compileerrors.len) - compiling_errors = "Compile Errors
" - for(var/datum/scriptError/e in compileerrors) - compiling_errors += "\t>[e.message]
" - compiling_errors += "([compileerrors.len] errors)" - updateUsrDialog() - return // If there are errors, don't waste time compiling on other servers - compiling_errors = "TCS compilation successful!
" - compiling_errors += "(0 errors)" - updateUsrDialog() - - if("Clear") - if(!telecomms_check(user) || user != editingcode) - return 0 - - if(SelectedServer) - var/obj/machinery/telecomms/server/Server = SelectedServer - Server.memory = list() // clear the memory - - compiling_errors = "Server Memory Cleared!" - storedcode = null - updateUsrDialog() - if(allservers) - for(var/obj/machinery/telecomms/server/Server in servers) - Server.memory = list() // clear the memory - - compiling_errors = "Server Memory Cleared!" - storedcode = null - updateUsrDialog() - - if(href_list["viewserver"]) - screen = 1 - if(href_list["viewserver"] == "all") - allservers = 1 - else - allservers = 0 - for(var/obj/machinery/telecomms/T in servers) - if(T.id == href_list["viewserver"]) - SelectedServer = T - break - - if(href_list["operation"]) - switch(href_list["operation"]) - - if("release") - servers = list() - screen = 0 - - if("mainmenu") - screen = 0 - - if("codeback") - if(allservers || SelectedServer) - screen = 1 - - if("scan") - if(servers.len > 0) - temp = "- FAILED: CANNOT PROBE WHEN BUFFER FULL -" - - else - for(var/obj/machinery/telecomms/server/T in range(25, src)) - if(T.network == network) - servers.Add(T) - - if(!servers.len) - temp = "- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -" - else - temp = "- [servers.len] SERVERS PROBED & BUFFERED -" - - screen = 0 - - if("editcode") - screen = 2 - - if("togglerun") - SelectedServer.autoruncode = !(SelectedServer.autoruncode) - if("runon") - for(var/obj/machinery/telecomms/server/Server in servers) - Server.autoruncode = 1 - if("runoff") - for(var/obj/machinery/telecomms/server/Server in servers) - Server.autoruncode = 0 - - if(href_list["network"]) - - var/newnet = input(user, "Which network do you want to view?", "Comm Monitor", network) as null|text - - if(newnet && canAccess(user)) - if(length(newnet) > 15) - temp = "- FAILED: NETWORK TAG STRING TOO LENGHTLY -" - - else - - network = newnet - screen = 0 - servers = list() - temp = "- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -" - - updateUsrDialog() - -/obj/machinery/computer/telecomms/traffic/attackby(var/obj/item/D as obj, var/mob/user as mob, params) - if(istype(D, /obj/item/screwdriver)) - playsound(get_turf(src), D.usesound, 50, 1) - if(do_after(user, 20 * D.toolspeed, target = src)) - if(src.stat & BROKEN) - to_chat(user, "The broken glass falls out.") - var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) - new /obj/item/shard(loc) - var/obj/item/circuitboard/comm_traffic/M = new /obj/item/circuitboard/comm_traffic( A ) - for(var/obj/C in src) - C.loc = src.loc - A.circuit = M - A.state = 3 - A.icon_state = "3" - A.anchored = 1 - qdel(src) - else - to_chat(user, "You disconnect the monitor.") - var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc ) - var/obj/item/circuitboard/comm_traffic/M = new /obj/item/circuitboard/comm_traffic( A ) - for(var/obj/C in src) - C.loc = src.loc - A.circuit = M - A.state = 4 - A.icon_state = "4" - A.anchored = 1 - qdel(src) - src.updateUsrDialog() - return - -/obj/machinery/computer/telecomms/traffic/emag_act(user as mob) - if(!emagged) - playsound(get_turf(src), 'sound/effects/sparks4.ogg', 75, 1) - emagged = 1 - to_chat(user, "You you disable the security protocols") - -/obj/machinery/computer/telecomms/traffic/proc/canAccess(var/mob/user) - if(issilicon(user) || in_range(user, src)) - return 1 - return 0 - -/obj/machinery/computer/telecomms/traffic/proc/telecomms_check(var/mob/mob) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/telecomms_check() called tick#: [world.time]") - if(mob && istype(mob.machine, /obj/machinery/computer/telecomms/traffic) && in_range(mob.machine, mob) || issilicon(mob) && istype(mob.machine, /obj/machinery/computer/telecomms/traffic)) - return 1 - return 0 + GLOB.ntsl2_config.Topic(user, href_list, window_id, src) \ No newline at end of file diff --git a/code/game/machinery/telecomms/traffic_control_ntsl2.dm b/code/game/machinery/telecomms/traffic_control_ntsl2.dm deleted file mode 100644 index e48b52000f1..00000000000 --- a/code/game/machinery/telecomms/traffic_control_ntsl2.dm +++ /dev/null @@ -1,51 +0,0 @@ -GLOBAL_DATUM_INIT(ntsl2_config, /datum/ntsl2_configuration, new()) -/obj/machinery/computer/telecomms/traffic - name = "telecommunications traffic control" - - light_color = LIGHT_COLOR_DARKGREEN - - req_access = list(access_tcomsat) - circuit = /obj/item/circuitboard/comm_traffic - - // NTSL2 - var/window_id // mostly used to let the configuration datum update the user's UI - var/unlocked = FALSE - -/obj/machinery/computer/telecomms/traffic/attackby(obj/item/I, mob/user) - if(ismultitool(I)) - unlocked = !unlocked - to_chat(user, "This computer is now [unlocked ? "Unlocked" : "Locked"]. \ -Reopen the UI to see the difference.") - return - . = ..() - -/obj/machinery/computer/telecomms/traffic/attack_hand(mob/user) - interact(user) - -/obj/machinery/computer/telecomms/traffic/interact(mob/user) - if(stat & (BROKEN|NOPOWER)) - return 0 - - if(GLOB.ntsl2_config.valid_languages.len == 1) - GLOB.ntsl2_config.update_languages() // this is silly but it has to be done because ntsl2 inits before languages do - - var/datum/asset/assets = get_asset_datum(/datum/asset/simple/ntsl2) - assets.send(user) - - var/dat = file2text("html/ntsl2/dist/index.html") - if(unlocked) - dat += "\n" - var/datum/browser/ntsl2/nt_browser = new(user, name, "NTSL2", 720, 480, src, GLOB.ntsl2_config.ntsl_serialize()) - nt_browser.set_content(dat) - nt_browser.open() - window_id = nt_browser.window_id - -/obj/machinery/computer/telecomms/traffic/Topic(href, href_list) - if(..()) - return 1 - - var/mob/user = usr - if(!istype(user) || !user.client) - return 0 - - GLOB.ntsl2_config.Topic(user, href_list, window_id, src) \ No newline at end of file diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm index 45294f01286..29f78c124c2 100644 --- a/code/game/machinery/transformer.dm +++ b/code/game/machinery/transformer.dm @@ -134,7 +134,7 @@ return // Crossed didn't like people lying down. - if(isobject(AM)) + if(isatom(AM)) AM.loc = src.loc do_transform_mime(AM) else @@ -222,7 +222,7 @@ AM.loc = src.loc irradiate(AM) - else if(isobject(AM)) + else if(isatom(AM)) AM.loc = src.loc scan(AM) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 91c237a0328..d7ce35b6d72 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -721,7 +721,7 @@ var/list/admin_verbs_ticket = list( var/list/Lines = file2list("config/admins.txt") for(var/line in Lines) var/list/splitline = splittext(line, " - ") - if(n_lower(splitline[1]) == ckey) + if(lowertext(splitline[1]) == ckey) if(splitline.len >= 2) rank = ckeyEx(splitline[2]) break diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index cbada74eee1..90b95aa3d1b 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -886,23 +886,20 @@ Traitors and the like can also be revived with the previous role mostly intact. /client/proc/reset_all_tcs() set category = "Admin" - set name = "Reset Telecomms Scripts" - set desc = "Blanks all telecomms scripts from all telecomms servers" + set name = "Reset NTSL2 Configuration" + set desc = "Resets NTSL2 to the default configuration." if(!check_rights(R_ADMIN)) return - var/confirm = alert(src, "You sure you want to blank all NTSL scripts?", "Confirm", "Yes", "No") + var/confirm = alert(src, "You sure you want to reset NTSL2?", "Confirm", "Yes", "No") if(confirm != "Yes") return - for(var/obj/machinery/telecomms/server/S in telecomms_list) - var/datum/TCS_Compiler/C = S.Compiler - S.rawcode = "" - C.Compile("") - log_admin("[key_name(usr)] blanked all telecomms scripts.") - message_admins("[key_name_admin(usr)] blanked all telecomms scripts.") - feedback_add_details("admin_verb","RAT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + GLOB.ntsl2_config.reset() + log_admin("[key_name(usr)] reset NTSL2 scripts.") + message_admins("[key_name_admin(usr)] reset NTSL2 scripts.") + feedback_add_details("admin_verb","RAT2") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/list_ssds() set category = "Admin" diff --git a/code/modules/nano/modules/ert_manager.dm b/code/modules/nano/modules/ert_manager.dm index d954c36ee2d..09e54db366c 100644 --- a/code/modules/nano/modules/ert_manager.dm +++ b/code/modules/nano/modules/ert_manager.dm @@ -66,7 +66,7 @@ slots_list += "paranormal: [paranormal_slots]" if(cyborg_slots > 0) slots_list += "cyborg: [cyborg_slots]" - var slot_text = list_implode(slots_list, ", ") + var/slot_text = jointext(slots_list, ", ") notify_ghosts("An ERT is being dispatched. Open positions: [slot_text]") message_admins("[key_name_admin(usr)] dispatched a [ert_type] ERT. Slots: [slot_text]", 1) log_admin("[key_name(usr)] dispatched a [ert_type] ERT. Slots: [slot_text]") diff --git a/code/modules/scripting/AST/AST Nodes.dm b/code/modules/scripting/AST/AST Nodes.dm deleted file mode 100644 index c8bb3ba9f78..00000000000 --- a/code/modules/scripting/AST/AST Nodes.dm +++ /dev/null @@ -1,129 +0,0 @@ -/* - File: AST Nodes - An abstract syntax tree (AST) is a representation of source code in a computer-friendly format. It is composed of nodes, - each of which represents a certain part of the source code. For example, an node represents an if statement in the - script's source code. Because it is a representation of the source code in memory, it is independent of any specific scripting language. - This allows a script in any language for which a parser exists to be run by the interpreter. - - The AST is produced by an object. It consists of a with an arbitrary amount of statements. These statements are - run in order by an object. A statement may in turn run another block (such as an if statement might if its condition is - met). - - Articles: - - -*/ -/* - Constants: Operator Precedence - OOP_OR - Logical or - OOP_AND - Logical and - OOP_BIT - Bitwise operations - OOP_EQUAL - Equality checks - OOP_COMPARE - Greater than, less then, etc - OOP_ADD - Addition and subtraction - OOP_MULTIPLY - Multiplication and division - OOP_POW - Exponents - OOP_UNARY - Unary Operators - OOP_GROUP - Parentheses -*/ -/var/const/OOP_OR = 1 //|| -/var/const/OOP_AND = OOP_OR + 1 //&& -/var/const/OOP_BIT = OOP_AND + 1 //&, | -/var/const/OOP_EQUAL = OOP_BIT + 1 //==, != -/var/const/OOP_COMPARE = OOP_EQUAL + 1 //>, <, >=, <= -/var/const/OOP_ADD = OOP_COMPARE + 1 //+, - -/var/const/OOP_MULTIPLY= OOP_ADD + 1 //*, /, % -/var/const/OOP_POW = OOP_MULTIPLY + 1 //^ -/var/const/OOP_UNARY = OOP_POW + 1 //! -/var/const/OOP_GROUP = OOP_UNARY + 1 //() - -/* - Class: node -*/ -/datum/node/proc/ToString() - return "[src.type]" -/* - Class: identifier -*/ -/datum/node/identifier - var/id_name - -/datum/node/identifier/New(id) - . = ..() - src.id_name = id - -/datum/node/identifier/ToString() - return id_name - -/* - Class: expression -*/ -/datum/node/expression -/* - Class: operator - See and for subtypes. -*/ -/datum/node/expression/operator - var/datum/node/expression/exp - var/token = "" // Used when giving type mismatches. - var/tmp/name - var/tmp/precedence - -/datum/node/expression/operator/New() - .=..() - if(!src.name) - src.name = "[src.type]" - -/datum/node/expression/operator/ToString() - return "operator: [name]" - -/* - Class: FunctionCall -*/ -/datum/node/expression/FunctionCall - //Function calls can also be expressions or statements. - var/func_name - var/datum/node/identifier/object - var/list/parameters = list() - -/* - Class: literal -*/ -/datum/node/expression/value/literal - var/value - -/datum/node/expression/value/literal/New(value) - . = ..() - src.value = value - -/datum/node/expression/value/literal/ToString() - return src.value - -/* - Class: variable -*/ -/datum/node/expression/value/variable - var/datum/node/object //Either a node/identifier or another node/expression/value/variable which points to the object - var/datum/node/identifier/id - - -/datum/node/expression/value/variable/New(ident) - . = ..() - id = ident - if(istext(id)) - id = new(id) - -/datum/node/expression/value/variable/ToString() - return src.id.ToString() - -/* - Class: reference -*/ -/datum/node/expression/value/reference - var/datum/value - -/datum/node/expression/value/reference/New(value) - . = ..() - src.value = value - -/datum/node/expression/value/reference/ToString() - return "ref: [src.value] ([src.value.type])" \ No newline at end of file diff --git a/code/modules/scripting/AST/Blocks.dm b/code/modules/scripting/AST/Blocks.dm deleted file mode 100644 index 331e49c16fe..00000000000 --- a/code/modules/scripting/AST/Blocks.dm +++ /dev/null @@ -1,45 +0,0 @@ -/* - File: Block Types -*/ -/* - Class: BlockDefinition - An object representing a set of actions to perform independently from the rest of the script. Blocks are basically just - lists of statements to execute which also contain some local variables and methods. Note that since functions are local to a block, - it is possible to have a function definition inside of any type of block (such as in an if statement or another function), - and not just in the global scope as in many languages. -*/ -/datum/node/BlockDefinition - var/list/statements = new - var/list/functions = new - var/list/initial_variables = new - -/* - Proc: SetVar - Defines a permanent variable. The variable will not be deleted when it goes out of scope. - - Notes: - Since all pre-existing temporary variables are deleted, it is not generally desirable to use this proc after the interpreter has been instantiated. - Instead, use . - - See Also: - - -*/ -/datum/node/BlockDefinition/proc/SetVar(name, value) - initial_variables[name] = value - - -/* - Class: GlobalBlock - A block object representing the global scope. -*/ -// -/datum/node/BlockDefinition/GlobalBlock/New() - initial_variables["null"] = null - return ..() - -/* - Class: FunctionBlock - A block representing a function body. -*/ -// -/datum/node/BlockDefinition/FunctionBlock \ No newline at end of file diff --git a/code/modules/scripting/AST/Operators/Binary Operators.dm b/code/modules/scripting/AST/Operators/Binary Operators.dm deleted file mode 100644 index 8781b6dd416..00000000000 --- a/code/modules/scripting/AST/Operators/Binary Operators.dm +++ /dev/null @@ -1,189 +0,0 @@ -/* - File: Binary Operators -*/ -/* - Class: binary - Represents a binary operator in the AST. A binary operator takes two operands (ie x and y) and returns a value. -*/ -/datum/node/expression/operator/binary - var/datum/node/expression/exp2 - -////////// Comparison Operators ////////// -/* - Class: Equal - Returns true if x = y. -*/ -// -/datum/node/expression/operator/binary/Equal - token = "==" - precedence = OOP_EQUAL - -/* -Class: NotEqual -Returns true if x and y aren't equal. -*/ -// -/datum/node/expression/operator/binary/NotEqual - token = "!=" - precedence = OOP_EQUAL - -/* -Class: Greater -Returns true if x > y. -*/ -// -/datum/node/expression/operator/binary/Greater - token = ">" - precedence = OOP_COMPARE - -/* -Class: Less -Returns true if x < y. -*/ -// -/datum/node/expression/operator/binary/Less - token = "<" - precedence = OOP_COMPARE - -/* -Class: GreaterOrEqual -Returns true if x >= y. -*/ -// -/datum/node/expression/operator/binary/GreaterOrEqual - token = ">=" - precedence = OOP_COMPARE - -/* -Class: LessOrEqual -Returns true if x <= y. -*/ -// -/datum/node/expression/operator/binary/LessOrEqual - token = "<=" - precedence = OOP_COMPARE - - -////////// Logical Operators ////////// - -/* -Class: LogicalAnd -Returns true if x and y are true. -*/ -// -/datum/node/expression/operator/binary/LogicalAnd - token = "&&" - precedence = OOP_AND - -/* -Class: LogicalOr -Returns true if x, y, or both are true. -*/ -// -/datum/node/expression/operator/binary/LogicalOr - token = "||" - precedence = OOP_OR - -/* -Class: LogicalXor -Returns true if either x or y but not both are true. -*/ -// -/datum/node/expression/operator/binary/LogicalXor //Not implemented in nS - precedence = OOP_OR - - -////////// Bitwise Operators ////////// - -/* -Class: BitwiseAnd -Performs a bitwise and operation. - -Example: -011 & 110 = 010 -*/ -// -/datum/node/expression/operator/binary/BitwiseAnd - token = "&" - precedence = OOP_BIT - -/* -Class: BitwiseOr -Performs a bitwise or operation. - -Example: -011 | 110 = 111 -*/ -// -/datum/node/expression/operator/binary/BitwiseOr - token = "|" - precedence = OOP_BIT - -/* -Class: BitwiseXor -Performs a bitwise exclusive or operation. - -Example: -011 xor 110 = 101 -*/ -// -/datum/node/expression/operator/binary/BitwiseXor - token = "`" - precedence = OOP_BIT - - -////////// Arithmetic Operators ////////// - -/* -Class: Add -Returns the sum of x and y. -*/ -// -/datum/node/expression/operator/binary/Add - token = "+" - precedence = OOP_ADD - -/* -Class: Subtract -Returns the difference of x and y. -*/ -// -/datum/node/expression/operator/binary/Subtract - token = "-" - precedence = OOP_ADD - -/* -Class: Multiply -Returns the product of x and y. -*/ -// -/datum/node/expression/operator/binary/Multiply - token = "*" - precedence = OOP_MULTIPLY - -/* -Class: Divide -Returns the quotient of x and y. -*/ -// -/datum/node/expression/operator/binary/Divide - token = "/" - precedence = OOP_MULTIPLY - -/* -Class: Power -Returns x raised to the power of y. -*/ -// -/datum/node/expression/operator/binary/Power - token = "^" - precedence = OOP_POW - -/* -Class: Modulo -Returns the remainder of x / y. -*/ -// -/datum/node/expression/operator/binary/Modulo - token = "%" - precedence = OOP_MULTIPLY diff --git a/code/modules/scripting/AST/Operators/Unary Operators.dm b/code/modules/scripting/AST/Operators/Unary Operators.dm deleted file mode 100644 index e7cd4b8489a..00000000000 --- a/code/modules/scripting/AST/Operators/Unary Operators.dm +++ /dev/null @@ -1,51 +0,0 @@ -/* - File: Unary Operators -*/ -/* - Class: unary - Represents a unary operator in the AST. Unary operators take a single operand (referred to as x below) and return a value. -*/ -/datum/node/expression/operator/unary - precedence = OOP_UNARY - -/* - Class: LogicalNot - Returns !x. - - Example: - !true = false and !false = true -*/ -// -/datum/node/expression/operator/unary/LogicalNot - name = "logical not" - -/* - Class: BitwiseNot - Returns the value of a bitwise not operation performed on x. - - Example: - ~10 (decimal 2) = 01 (decimal 1). -*/ -// -/datum/node/expression/operator/unary/BitwiseNot - name = "bitwise not" - -/* - Class: Minus - Returns -x. -*/ -// -/datum/node/expression/operator/unary/Minus - name = "minus" - -/* - Class: group - A special unary operator representing a value in parentheses. -*/ -// -/datum/node/expression/operator/unary/group - precedence = OOP_GROUP - -/datum/node/expression/operator/unary/New(var/datum/node/expression/exp) - src.exp = exp - return ..() diff --git a/code/modules/scripting/AST/Statements.dm b/code/modules/scripting/AST/Statements.dm deleted file mode 100644 index bae9f3de68c..00000000000 --- a/code/modules/scripting/AST/Statements.dm +++ /dev/null @@ -1,110 +0,0 @@ -/* - File: Statement Types -*/ -/* - Class: statement - An object representing a single instruction run by an interpreter. -*/ -/datum/node/statement -/* - Class: FunctionCall - Represents a call to a function. -*/ -// -/datum/node/statement/FunctionCall - var/func_name - var/datum/node/identifier/object - var/list/parameters = new - -/* -Class: FunctionDefinition -Defines a function. -*/ -// -/datum/node/statement/FunctionDefinition - var/func_name - var/list/parameters = new - var/datum/node/BlockDefinition/FunctionBlock/block - -/* -Class: VariableAssignment -Sets a variable in an accessible scope to the given value if one exists, otherwise initializes a new local variable to the given value. - -Notes: -If a variable with the same name exists in a higher block, the value will be assigned to it. If not, -a new variable is created in the current block. To force creation of a new variable, use . - -See Also: -- -*/ -// -/datum/node/statement/VariableAssignment - var/datum/node/identifier/object - var/datum/node/identifier/var_name - var/datum/node/expression/value - -/* -Class: VariableDeclaration -Intializes a local variable to a null value. - -See Also: -- -*/ -// -/datum/node/statement/VariableDeclaration - var/datum/node/identifier/object - var/datum/node/identifier/var_name - -/* -Class: IfStatement -*/ -// -/datum/node/statement/IfStatement - var/skip = 0 - var/datum/node/BlockDefinition/block - var/datum/node/BlockDefinition/else_block //may be null - var/datum/node/expression/cond - var/datum/node/statement/else_if - -/datum/node/statement/IfStatement/ElseIf - -/* -Class: WhileLoop -Loops while a given condition is true. -*/ -// -/datum/node/statement/WhileLoop - var/datum/node/BlockDefinition/block - var/datum/node/expression/cond - -/* -Class: ForLoop -Loops while test is true, initializing a variable, increasing the variable -*/ -/datum/node/statement/ForLoop - var/datum/node/BlockDefinition/block - var/datum/node/expression/test - var/datum/node/expression/init - var/datum/node/expression/increment - -/* -Class: BreakStatement -Ends a loop. -*/ -// -/datum/node/statement/BreakStatement - -/* -Class: ContinueStatement -Skips to the next iteration of a loop. -*/ -// -/datum/node/statement/ContinueStatement - -/* -Class: ReturnStatement -Ends the function and returns a value. -*/ -// -/datum/node/statement/ReturnStatement - var/datum/node/expression/value \ No newline at end of file diff --git a/code/modules/scripting/Errors.dm b/code/modules/scripting/Errors.dm deleted file mode 100644 index 63538c3f18f..00000000000 --- a/code/modules/scripting/Errors.dm +++ /dev/null @@ -1,169 +0,0 @@ -/* - File: Errors -*/ -/* - Class: scriptError - An error scanning or parsing the source code. -*/ -/datum/scriptError -/* - Var: message - A message describing the problem. -*/ - var/message - -/datum/scriptError/New(msg = null) - if(msg)message = msg - -/datum/scriptError/BadToken - message = "Unexpected token: " - var/datum/token/token - -/datum/scriptError/BadToken/New(datum/token/t) - token = t - if(t && t.line) - message = "[t.line]: [message]" - - if(istype(t)) - message += "[t.value]" - - else - message += "[t]" - -/datum/scriptError/InvalidID - parent_type = /datum/scriptError/BadToken - message = "Invalid identifier name: " - -/datum/scriptError/ReservedWord - parent_type = /datum/scriptError/BadToken - message = "Identifer using reserved word: " - -/datum/scriptError/BadNumber - parent_type = /datum/scriptError/BadToken - message = "Bad number: " - -/datum/scriptError/BadReturn - var/datum/token/token - message = "Unexpected return statement outside of a function." - -/datum/scriptError/BadReturn/New(datum/token/t) - src.token = t - -/datum/scriptError/EndOfFile - message = "Unexpected end of file." - -/datum/scriptError/ExpectedToken - message = "Expected: '" - -/datum/scriptError/ExpectedToken/New(id, datum/token/T) - if(T && T.line) - message = "[T.line]: [message]" - - message += "[id]'. " - - if(T) - message += "Found '[T.value]'." - - -/datum/scriptError/UnterminatedComment - message = "Unterminated multi-line comment statement: expected */" - -/datum/scriptError/DuplicateFunction/New(name, datum/token/t) - message = "Function '[name]' defined twice." - -/datum/scriptError/ParameterFunction - message = "You cannot use a function inside a parameter." - -/datum/scriptError/ParameterFunction/New(datum/token/t) - var/line = "?" - if(t) - line = t.line - message = "[line]: [message]" - -/* - Class: runtimeError - An error thrown by the interpreter in running the script. -*/ -/datum/runtimeError - var/name -/* - Var: message - A basic description as to what went wrong. -*/ - var/message - var/datum/stack/stack -/* - Proc: ToString - Returns a description of the error suitable for showing to the user. -*/ -/datum/runtimeError/proc/ToString() - . = "[name]: [message]" - if(!stack.Top()) - return - - . += "\nStack:" - while(stack.Top()) - var/datum/node/statement/FunctionCall/stmt = stack.Pop() - . += "\n\t [stmt.func_name]()" - -/datum/runtimeError/TypeMismatch - name = "TypeMismatchError" - -/datum/runtimeError/TypeMismatch/New(op, a, b) - message = "Type mismatch: '[a]' [op] '[b]'" - -/datum/runtimeError/TypeMismatch/unary/New(op, a) - message = "Type mismatch: [op]'[a]'" - -/datum/runtimeError/TypeMismatch/New(op, a, b) - message = "Type mismatch: '[a]' [op] '[b]'" - -/datum/runtimeError/UnexpectedReturn - name = "UnexpectedReturnError" - message = "Unexpected return statement." - -/datum/runtimeError/UnknownInstruction - name = "UnknownInstructionError" - message = "Unknown instruction type. This may be due to incompatible compiler and interpreter versions or a lack of implementation." - -/datum/runtimeError/UndefinedVariable - name = "UndefinedVariableError" - -/datum/runtimeError/UndefinedVariable/New(variable) - message = "Variable '[variable]' has not been declared." - -/datum/runtimeError/UndefinedFunction - name = "UndefinedFunctionError" - -/datum/runtimeError/UndefinedFunction/New(function) - message = "Function '[function]()' has not been defined." - -/datum/runtimeError/DuplicateVariableDeclaration - name = "DuplicateVariableError" - -/datum/runtimeError/DuplicateVariableDeclaration/New(variable) - message="Variable '[variable]' was already declared." - -/datum/runtimeError/IterationLimitReached - name = "MaxIterationError" - message = "A loop has reached its maximum number of iterations." - -/datum/runtimeError/RecursionLimitReached - name = "MaxRecursionError" - message = "The maximum amount of recursion has been reached." - -/datum/runtimeError/DivisionByZero - name = "DivideByZeroError" - message = "Division by zero attempted." - -/datum/runtimeError/MaxCPU - name = "MaxComputationalUse" - message = "Maximum amount of computational cycles reached (>= 1000)." - -/datum/runtimeError/VectorLimit - name = "VectorSizeOverflow" - message = "Maximum vector size reached" - -/datum/runtimeError/StringLimit - name = "StringSizeOverflow" - message = "Maximum string size reached" diff --git a/code/modules/scripting/Implementations/Telecomms.dm b/code/modules/scripting/Implementations/Telecomms.dm deleted file mode 100644 index a24a9522b38..00000000000 --- a/code/modules/scripting/Implementations/Telecomms.dm +++ /dev/null @@ -1,352 +0,0 @@ -/* --- Traffic Control Scripting Language --- */ - // Nanotrasen TCS Language - Made by Doohl - -/datum/n_Interpreter/TCS_Interpreter - var/datum/TCS_Compiler/Compiler - -/datum/n_Interpreter/TCS_Interpreter/HandleError(datum/runtimeError/e) - Compiler.Holder.add_entry(e.ToString(), "Execution Error") - -/datum/n_Interpreter/TCS_Interpreter/GC() - ..() - Compiler = null - -/datum/TCS_Compiler - var/datum/n_Interpreter/TCS_Interpreter/interpreter - var/obj/machinery/telecomms/server/Holder // the server that is running the code - var/ready = 1 // 1 if ready to run code - - /* -- Set ourselves to Garbage Collect -- */ - -/datum/TCS_Compiler/proc/GC() - Holder = null - if(interpreter) - interpreter.GC() - - -//temp -/datum/TCS_Compiler - var/datum/n_scriptOptions/nS_Options/options - var/datum/n_Scanner/nS_Scanner/scanner - var/list/tokens - var/datum/n_Parser/nS_Parser/parser - var/datum/node/BlockDefinition/GlobalBlock/program - - /* -- Compile a raw block of text -- */ - -/datum/TCS_Compiler/proc/Compile(list/code) - options = new() - scanner = new(code, options) - tokens = scanner.Scan() - parser = new(tokens, options) - program = parser.Parse() - - var/list/returnerrors = list() - - returnerrors += scanner.errors - returnerrors += parser.errors - - if(returnerrors.len) - return returnerrors - - interpreter = new(program) - interpreter.persist = 1 - interpreter.Compiler= src - - return returnerrors - -/* -- Execute the compiled code -- */ - -/datum/TCS_Compiler/proc/Run(var/datum/signal/signal) - if(!ready) - return - - if(!interpreter) - return - - interpreter.container = src - - interpreter.CreateGlobalScope() // Reset the variables. - interpreter.curScope = interpreter.globalScope - - interpreter.SetVar("PI", 3.141592653) // value of pi - interpreter.SetVar("E", 2.718281828) // value of e - interpreter.SetVar("SQURT2", 1.414213562) // value of the square root of 2 - interpreter.SetVar("FALSE", 0) // boolean shortcut to 0 - interpreter.SetVar("false", 0) // boolean shortcut to 0 - interpreter.SetVar("TRUE", 1) // boolean shortcut to 1 - interpreter.SetVar("true", 1) // boolean shortcut to 1 - - interpreter.SetVar("NORTH", NORTH) // NORTH (1) - interpreter.SetVar("SOUTH", SOUTH) // SOUTH (2) - interpreter.SetVar("EAST", EAST) // EAST (4) - interpreter.SetVar("WEST", WEST) // WEST (8) - - // Channel macros - interpreter.SetVar("$common", PUB_FREQ) - interpreter.SetVar("$science", SCI_FREQ) - interpreter.SetVar("$command", COMM_FREQ) - interpreter.SetVar("$medical", MED_FREQ) - interpreter.SetVar("$engineering", ENG_FREQ) - interpreter.SetVar("$security", SEC_FREQ) - interpreter.SetVar("$supply", SUP_FREQ) - interpreter.SetVar("$service", SRV_FREQ) - - // Signal data - - interpreter.SetVar("$content", signal.data["message"]) - interpreter.SetVar("$freq", signal.frequency) - interpreter.SetVar("$source", signal.data["name"]) - interpreter.SetVar("$job", signal.data["job"]) - interpreter.SetVar("$sign", signal) - interpreter.SetVar("$pass", !(signal.data["reject"])) // if the signal isn't rejected, pass = 1; if the signal IS rejected, pass = 0 - - var/datum/language/speaking = signal.data["language"] - if(speaking) - interpreter.SetVar("$language", speaking.name) - else - interpreter.SetVar("$language", "Unknown") - - // Set up the script procs - - /* - -> Send another signal to a server - @format: broadcast(content, frequency, source, job) - - @param content: Message to broadcast - @param frequency: Frequency to broadcast to - @param source: The name of the source you wish to imitate. Must be stored in stored_names list. - @param job: The name of the job. - */ - interpreter.SetProc("broadcast", "tcombroadcast", signal, list("message", "freq", "source", "job")) - - /* - -> Store a value permanently to the server machine (not the actual game hosting machine, the ingame machine) - @format: mem(address, value) - - @param address: The memory address (string index) to store a value to - @param value: The value to store to the memory address - */ - interpreter.SetProc("mem", "mem", signal, list("address", "value")) - - /* - -> Delay code for a given amount of deciseconds - @format: sleep(time) - - @param time: time to sleep in deciseconds (1/10th second) - */ - interpreter.SetProc("sleep", "delay", signal, list("time")) - - /* - -> Replaces a string with another string - @format: replace(string, substring, replacestring) - - @param string: the string to search for substrings (best used with $content$ constant) - @param substring: the substring to search for - @param replacestring: the string to replace the substring with - - */ - interpreter.SetProc("replace", /proc/n_replacetext) - - /* - -> Locates an element/substring inside of a list or string - @format: find(haystack, needle, start = 1, end = 0) - - @param haystack: the container to search - @param needle: the element to search for - @param start: the position to start in - @param end: the position to end in - - */ - interpreter.SetProc("find", /proc/smartfind) - - /* - -> Finds the length of a string or list - @format: length(container) - - @param container: the list or container to measure - - */ - interpreter.SetProc("length", /proc/smartlength) - - /* -- Clone functions, carried from default BYOND procs --- */ - - // vector namespace - interpreter.SetProc("vector", /proc/n_list) - interpreter.SetProc("at", /proc/n_listpos) - interpreter.SetProc("copy", /proc/n_listcopy) - interpreter.SetProc("push_back", /proc/n_listadd) - interpreter.SetProc("remove", /proc/n_listremove) - interpreter.SetProc("cut", /proc/n_listcut) - interpreter.SetProc("swap", /proc/n_listswap) - interpreter.SetProc("insert", /proc/n_listinsert) - - interpreter.SetProc("pick", /proc/n_pick) - interpreter.SetProc("prob", /proc/prob_chance) - interpreter.SetProc("substr", /proc/docopytext) - - interpreter.SetProc("shuffle", /proc/shuffle) - interpreter.SetProc("uniquevector", /proc/uniquelist) - - interpreter.SetProc("text2vector", /proc/n_splittext) - interpreter.SetProc("vector2text", /proc/n_jointext) - - // Donkie~ - // Strings - interpreter.SetProc("lower", /proc/n_lower) - interpreter.SetProc("upper", /proc/n_upper) - interpreter.SetProc("explode", /proc/string_explode) - interpreter.SetProc("implode", /proc/n_jointext) - interpreter.SetProc("repeat", /proc/n_repeat) - interpreter.SetProc("reverse", /proc/reverse_text) - interpreter.SetProc("tonum", /proc/n_str2num) - interpreter.SetProc("capitalize", /proc/capitalize) - interpreter.SetProc("replacetextEx",/proc/n_replacetextEx) - - // Numbers - interpreter.SetProc("tostring", /proc/n_num2str) - interpreter.SetProc("sqrt", /proc/n_sqrt) - interpreter.SetProc("abs", /proc/n_abs) - interpreter.SetProc("floor", /proc/n_floor) - interpreter.SetProc("ceil", /proc/n_ceiling) - interpreter.SetProc("round", /proc/n_round) - interpreter.SetProc("clamp", /proc/n_clamp) - interpreter.SetProc("inrange", /proc/n_isInRange) - interpreter.SetProc("rand", /proc/rand_chance) - interpreter.SetProc("arctan", /proc/Atan2) - interpreter.SetProc("lcm", /proc/n_lcm) - interpreter.SetProc("gcd", /proc/Gcd) - interpreter.SetProc("mean", /proc/Mean) - interpreter.SetProc("root", /proc/n_root) - interpreter.SetProc("sin", /proc/n_sin) - interpreter.SetProc("cos", /proc/n_cos) - interpreter.SetProc("arcsin", /proc/n_asin) - interpreter.SetProc("arccos", /proc/n_acos) - interpreter.SetProc("tan", /proc/n_tan) - interpreter.SetProc("csc", /proc/n_csc) - interpreter.SetProc("cot", /proc/n_cot) - interpreter.SetProc("sec", /proc/n_sec) - interpreter.SetProc("todegrees", /proc/n_toDegrees) - interpreter.SetProc("toradians", /proc/n_toRadians) - interpreter.SetProc("lerp", /proc/Lerp) - interpreter.SetProc("max", /proc/n_max) - interpreter.SetProc("min", /proc/n_min) - - // End of Donkie~ - - // Time - interpreter.SetProc("time", /proc/time) - interpreter.SetProc("timestamp", /proc/gameTimestamp) - - // Run the compiled code - interpreter.Run() - - // Backwards-apply variables onto signal data - /* sanitize EVERYTHING. fucking players can't be trusted with SHIT */ - - /* Okay, so, the original 'sanitizing' code... did fucking nothing. Then PJB fixed it, which means no HTML. - But I like HTML, so back to no sanitizing.*/ - - var/message = interpreter.GetVar("$content") - var/regex/bannedTags = new ("( BYOND code procs -#define SCRIPT_MAX_REPLACEMENTS_ALLOWED 200 -// --- List operations (lists known as vectors in n_script) --- - -// Clone of list() -/proc/n_list() - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/n_list() called tick#: [world.time]") - var/list/returnlist = list() - for(var/e in args) - returnlist.Add(e) - return returnlist - -// Clone of pick() -/proc/n_pick() - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/n_pick() called tick#: [world.time]") - var/list/finalpick = list() - for(var/e in args) - if(isobject(e)) - if(istype(e, /list)) - var/list/sublist = e - for(var/sube in sublist) - finalpick.Add(sube) - continue - finalpick.Add(e) - - return pick(finalpick) - -// Clone of list[] -/proc/n_listpos(var/list/L, var/pos, var/value) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/n_listpos() called tick#: [world.time]") - if(!istype(L, /list)) return - if(isnum(pos)) - if(!value) - if(L.len >= pos && !(pos > L.len)) - return L[pos] - else - if(L.len >= pos && !(pos > L.len)) - L[pos] = value - else if(istext(pos)) - if(!value) - return L[pos] - else - L[pos] = value - -// Clone of list.Copy() -/proc/n_listcopy(var/list/L, var/start, var/end) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/n_listcopy() called tick#: [world.time]") - if(!istype(L, /list)) return - return L.Copy(start, end) - -// Clone of list.Add() -/proc/n_listadd() - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/n_listadd() called tick#: [world.time]") - var/list/chosenlist - var/i = 1 - for(var/e in args) - if(i == 1) - if(isobject(e)) - if(istype(e, /list)) - chosenlist = e - i = 2 - else - if(chosenlist) - chosenlist.Add(e) - -// Clone of list.Remove() -/proc/n_listremove() - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/n_listremove() called tick#: [world.time]") - var/list/chosenlist - var/i = 1 - for(var/e in args) - if(i == 1) - if(isobject(e)) - if(istype(e, /list)) - chosenlist = e - i = 2 - else - if(chosenlist) - chosenlist.Remove(e) - -// Clone of list.len = 0 -/proc/n_listcut(var/list/L, var/start, var/end) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/n_listcut() called tick#: [world.time]") - if(!istype(L, /list)) return - return L.Cut(start, end) - -// Clone of list.Swap() -/proc/n_listswap(var/list/L, var/firstindex, var/secondindex) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/n_listswap() called tick#: [world.time]") - if(!istype(L, /list)) return - if(L.len >= secondindex && L.len >= firstindex) - return L.Swap(firstindex, secondindex) - -// Clone of list.Insert() -/proc/n_listinsert(var/list/L, var/index, var/element) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/n_listinsert() called tick#: [world.time]") - if(!istype(L, /list)) return - return L.Insert(index, element) - -// --- Miscellaneous functions --- - -// Clone of rand() -/proc/rand_chance(var/low = 0, var/high) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/rand_chance() called tick#: [world.time]") - return rand(low, high) - -// Clone of prob() -/proc/prob_chance(var/chance) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/prob_chance() called tick#: [world.time]") - return prob(chance) - -// Merge of list.Find() and findtext() -/proc/smartfind(var/haystack, var/needle, var/start = 1, var/end = 0) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/smartfind() called tick#: [world.time]") - if(haystack && needle) - if(isobject(haystack)) - if(istype(haystack, /list)) - if(length(haystack) >= end && start > 0) - var/list/listhaystack = haystack - return listhaystack.Find(needle, start, end) - - else - if(istext(haystack)) - if(length(haystack) >= end && start > 0) - return findtext(haystack, needle, start, end) - -// Clone of copytext() -/proc/docopytext(var/string, var/start = 1, var/end = 0) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/docopytext() called tick#: [world.time]") - if(istext(string) && isnum(start) && isnum(end)) - if(start > 0) - return copytext(string, start, end) - -// Clone of length() -/proc/smartlength(var/container) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/smartlength() called tick#: [world.time]") - if(container) - if(istype(container, /list) || istext(container)) - return length(container) - return 0 - -// BY DONKIE~ -// String stuff -/proc/n_lower(var/string) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/n_lower() called tick#: [world.time]") - if(istext(string)) - return lowertext(string) - -/proc/n_upper(var/string) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/n_upper() called tick#: [world.time]") - if(istext(string)) - return uppertext(string) - -/proc/time() - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/time() called tick#: [world.time]") - return world.time + (12 HOURS) - -proc/string_explode(var/string, var/separator = "") - //writepanic("[__FILE__].[__LINE__] \\/proc/string_explode() called tick#: [world.time]") - if(istext(string) && (istext(separator) || isnull(separator))) - return splittext(string, separator) - -//Converts a list to a string -/proc/list_implode(var/list/li, var/separator) - if(istype(li) && (istext(separator) || isnull(separator))) - return jointext(li, separator) - -proc/n_repeat(var/string, var/amount) - //writepanic("[__FILE__].[__LINE__] \\/proc/n_repeat() called tick#: [world.time]") - if(istext(string) && isnum(amount)) - var/i - var/newstring = "" - if(length(newstring)*amount >=1000) - return - for(i=0, i<=amount, i++) - if(i>=1000) - break - newstring = newstring + string - - return newstring - -// I don't know if it's neccesary to make my own proc, but I think I have to to be able to check for istext. -proc/n_str2num(var/string) - //writepanic("[__FILE__].[__LINE__] \\/proc/n_str2num() called tick#: [world.time]") - if(istext(string)) - return text2num(string) - -// Clamps N between min and max -/proc/n_clamp(var/num, var/min = 0, var/max = 1) - if(isnum(num) && isnum(min) && isnum(max)) - return Clamp(num, min, max) - -// Number shit -proc/n_num2str(var/num) - //writepanic("[__FILE__].[__LINE__] \\/proc/n_num2str() called tick#: [world.time]") - if(isnum(num)) - return num2text(num) - -// Squareroot -proc/n_sqrt(var/num) - //writepanic("[__FILE__].[__LINE__] \\/proc/n_sqrt() called tick#: [world.time]") - if(isnum(num)) - return sqrt(num) - -// Magnitude of num -proc/n_abs(var/num) - //writepanic("[__FILE__].[__LINE__] \\/proc/n_abs() called tick#: [world.time]") - if(isnum(num)) - return abs(num) - -// Round down -proc/n_floor(var/num) - //writepanic("[__FILE__].[__LINE__] \\/proc/n_floor() called tick#: [world.time]") - if(isnum(num)) - return Floor(num) - -// Round up -proc/n_ceiling(var/num) - //writepanic("[__FILE__].[__LINE__] \\/proc/n_ceil() called tick#: [world.time]") - if(isnum(num)) - return Ceiling(num) - -// Round to nearest integer -proc/n_round(var/num) - //writepanic("[__FILE__].[__LINE__] \\/proc/n_round() called tick#: [world.time]") - if(isnum(num)) - if(num-round(num)<0.5) - return round(num) - return Ceiling(num) - -// END OF BY DONKIE :( - -/proc/n_sin(var/const/x) - if(isnum(x)) - return sin(x) - -/proc/n_cos(var/const/x) - if(isnum(x)) - return cos(x) - -/proc/n_tan(var/const/x) - if(isnum(x)) - return Tan(x) - -/proc/n_csc(var/const/x) - if(isnum(x)) - return Csc(x) - -/proc/n_cot(var/const/x) - if(isnum(x)) - return Cot(x) - -/proc/n_sec(var/const/x) - if(isnum(x)) - return Sec(x) - -/proc/n_asin(var/const/x) - if(isnum(x)) - return arcsin(x) - -/proc/n_acos(var/const/x) - if(isnum(x)) - return arccos(x) - -/proc/n_isInRange(var/const/x, var/const/min, var/const/max) - if(isnum(x) && isnum(min) && isnum(max)) - return IsInRange(x, min, max) - -/proc/n_lcm(var/const/a, var/const/b) - if(isnum(a) && isnum(b)) - return Lcm(a, b) - -/proc/n_root(var/const/n, var/const/x) - if(isnum(n) && isnum(x)) - return Root(n, x) - -/proc/n_toDegrees(var/const/x) - if(isnum(x)) - return ToDegrees(x) - -/proc/n_toRadians(var/const/x) - if(isnum(x)) - return ToRadians(x) - -/proc/n_max(...) - return max(arglist(args)) - -/proc/n_min(...) - return min(arglist(args)) - -/proc/n_log(var/num) - if(isnum(num) && 0 < num) - return log(num) - -/proc/n_replacetext(text, r, with) - return replacetext(text, r, with) - -/proc/n_replacetextEx(text, r, with) - return replacetextEx(text, r, with) - -/proc/n_jointext(list, glue) - return jointext(list, glue) - -/proc/n_splittext(text, delim) - return splittext(text, delim) \ No newline at end of file diff --git a/code/modules/scripting/Interpreter/Evaluation.dm b/code/modules/scripting/Interpreter/Evaluation.dm deleted file mode 100644 index 84c255fe9ad..00000000000 --- a/code/modules/scripting/Interpreter/Evaluation.dm +++ /dev/null @@ -1,203 +0,0 @@ -/proc/isobject(x) - return (istype(x, /datum) || istype(x, /list) || istype(x, /savefile) || istype(x, /client) || (x == world)) - -/datum/n_Interpreter/proc/Eval(datum/node/expression/exp) - if(istype(exp, /datum/node/expression/FunctionCall)) - return RunFunction(exp) - - else if(istype(exp, /datum/node/expression/operator)) - return EvalOperator(exp) - - else if(istype(exp, /datum/node/expression/value/literal)) - var/datum/node/expression/value/literal/lit = exp - return lit.value - - else if(istype(exp, /datum/node/expression/value/reference)) - var/datum/node/expression/value/reference/ref = exp - return ref.value - - else if(istype(exp, /datum/node/expression/value/variable)) - var/datum/node/expression/value/variable/v = exp - if(!v.object) - return Eval(GetVariable(v.id.id_name)) - else - var/datum/D - if(istype(v.object, /datum/node/identifier)) - D = GetVariable(v.object:id_name) - else - D = v.object - - D = Eval(D) - if(!isobject(D)) - return null - - if(!D.vars.Find(v.id.id_name)) - RaiseError(new/datum/runtimeError/UndefinedVariable("[v.object.ToString()].[v.id.id_name]")) - return null - - return Eval(D.vars[v.id.id_name]) - - else if(istype(exp, /datum/node/expression)) - RaiseError(new/datum/runtimeError/UnknownInstruction()) - - else - return exp - -/datum/n_Interpreter/proc/EvalOperator(datum/node/expression/operator/exp) - if(istype(exp, /datum/node/expression/operator/binary)) - var/datum/node/expression/operator/binary/bin = exp - try // This way we can forgo sanity in the actual evaluation (other than divide by 0). - switch(bin.type) - if(/datum/node/expression/operator/binary/Equal) - return Equal(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/NotEqual) - return NotEqual(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/Greater) - return Greater(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/Less) - return Less(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/GreaterOrEqual) - return GreaterOrEqual(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/LessOrEqual) - return LessOrEqual(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/LogicalAnd) - return LogicalAnd(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/LogicalOr) - return LogicalOr(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/LogicalXor) - return LogicalXor(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/BitwiseAnd) - return BitwiseAnd(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/BitwiseOr) - return BitwiseOr(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/BitwiseXor) - return BitwiseXor(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/Add) - return Add(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/Subtract) - return Subtract(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/Multiply) - return Multiply(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/Divide) - return Divide(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/Power) - return Power(Eval(bin.exp), Eval(bin.exp2)) - - if(/datum/node/expression/operator/binary/Modulo) - return Modulo(Eval(bin.exp), Eval(bin.exp2)) - - else - RaiseError(new/datum/runtimeError/UnknownInstruction()) - - catch - RaiseError(new/datum/runtimeError/TypeMismatch(bin.token, Eval(bin.exp), Eval(bin.exp2))) - - else - try - switch(exp.type) - if(/datum/node/expression/operator/unary/Minus) - return Minus(Eval(exp.exp)) - - if(/datum/node/expression/operator/unary/LogicalNot) - return LogicalNot(Eval(exp.exp)) - - if(/datum/node/expression/operator/unary/BitwiseNot) - return BitwiseNot(Eval(exp.exp)) - - if(/datum/node/expression/operator/unary/group) - return Eval(exp.exp) - - else - RaiseError(new/datum/runtimeError/UnknownInstruction()) - catch - RaiseError(new/datum/runtimeError/TypeMismatch/unary(exp.token, Eval(exp.exp))) - -//Binary// -//Comparison operators -/datum/n_Interpreter/proc/Equal(a, b) - return a == b - -/datum/n_Interpreter/proc/NotEqual(a, b) - return a != b //LogicalNot(Equal(a, b)) - -/datum/n_Interpreter/proc/Greater(a, b) - return a > b - -/datum/n_Interpreter/proc/Less(a, b) - return a < b - -/datum/n_Interpreter/proc/GreaterOrEqual(a, b) - return a >= b - -/datum/n_Interpreter/proc/LessOrEqual(a, b) - return a <= b - -//Logical Operators -/datum/n_Interpreter/proc/LogicalAnd(a, b) - return a && b - -/datum/n_Interpreter/proc/LogicalOr(a, b) - return a || b - -/datum/n_Interpreter/proc/LogicalXor(a, b) - return (a || b) && !(a && b) - -//Bitwise Operators -/datum/n_Interpreter/proc/BitwiseAnd(a, b) - return a & b - -/datum/n_Interpreter/proc/BitwiseOr(a, b) - return a | b - -/datum/n_Interpreter/proc/BitwiseXor(a, b) - return a ^ b - -//Arithmetic Operators -/datum/n_Interpreter/proc/Add(a, b) - return a + b - -/datum/n_Interpreter/proc/Subtract(a, b) - return a - b - -/datum/n_Interpreter/proc/Divide(a, b) - if(b == 0) - RaiseError(new/datum/runtimeError/DivisionByZero()) - return null - - return a / b - -/datum/n_Interpreter/proc/Multiply(a, b) - return a * b - -/datum/n_Interpreter/proc/Modulo(a, b) - - return a % b - -/datum/n_Interpreter/proc/Power(a, b) - return a ** b - -//Unary// -/datum/n_Interpreter/proc/Minus(a) - return -a - -/datum/n_Interpreter/proc/LogicalNot(a) - return !a - -/datum/n_Interpreter/proc/BitwiseNot(a) - return ~a diff --git a/code/modules/scripting/Interpreter/Interaction.dm b/code/modules/scripting/Interpreter/Interaction.dm deleted file mode 100644 index ffcf8f716d8..00000000000 --- a/code/modules/scripting/Interpreter/Interaction.dm +++ /dev/null @@ -1,157 +0,0 @@ -/* - File: Interpreter (Public) - Contains methods for interacting with the interpreter. -*/ -/* - Class: n_Interpreter - Procedures allowing for interaction with the script that is being run by the interpreter object. -*/ - -/* - Proc: Load - Loads a 'compiled' script into memory. - - Parameters: - program - A object which represents the script's global scope. -*/ -/datum/n_Interpreter/proc/Load(var/datum/node/BlockDefinition/GlobalBlock/program) - ASSERT(program) - src.program = program - CreateGlobalScope() - alertadmins = 0 // reset admin alerts - -/* -Proc: Run -Runs the script. -*/ -/datum/n_Interpreter/proc/Run() - cur_recursion = 0 // reset recursion - cur_statements = 0 // reset CPU tracking - - ASSERT(src.program) - RunBlock(src.program) - -/* -Proc: SetVar -Defines a global variable for the duration of the next execution of a script. - -Notes: -This differs from in that variables set using this procedure only last for the session, -while those defined from the block object persist if it is ran multiple times. - -See Also: -- -*/ -/datum/n_Interpreter/proc/SetVar(name, value) - if(!istext(name)) - //CRASH("Invalid variable name") - return - - AssignVariable(name, value) - -/* -Proc: SetProc -Defines a procedure to be available to the script. - -Parameters: -name - The name of the procedure as exposed to the script. -path - The typepath of a proc to be called when the function call is read by the interpreter, or, if object is specified, a string representing the procedure's name. -object - (Optional) An object which will the be target of a function call. -params - Only required if object is not null, a list of the names of parameters the proc takes. -*/ -/datum/n_Interpreter/proc/SetProc(name, path, object = null, list/params = null) - if(!istext(name)) - //CRASH("Invalid function name") - return - - if(!object) - globalScope.functions[name] = path - - else - var/datum/node/statement/FunctionDefinition/S = new() - S.func_name = name - S.parameters = params - S.block = new() - S.block.SetVar("src", object) - var/datum/node/expression/FunctionCall/C = new() - C.func_name = path - C.object = new("src") - for(var/p in params) - C.parameters += new/datum/node/expression/value/variable(p) - - var/datum/node/statement/ReturnStatement/R = new() - R.value = C - S.block.statements += R - globalScope.functions[name] = S -/* -Proc: VarExists -Checks whether a global variable with the specified name exists. -*/ -/datum/n_Interpreter/proc/VarExists(name) - return globalScope.variables.Find(name) //convert to 1/0 first? - -/* -Proc: ProcExists -Checks whether a global function with the specified name exists. -*/ -/datum/n_Interpreter/proc/ProcExists(name) - return globalScope.functions.Find(name) - -/* -Proc: GetVar -Returns the value of a global variable in the script. Remember to ensure that the variable exists before calling this procedure. - -See Also: -- -*/ -/datum/n_Interpreter/proc/GetVar(name) - if(!VarExists(name)) - //CRASH("No variable named '[name]'.") - return - var/x = globalScope.variables[name] - return Eval(x) - -/* -Proc: GetCleanVar -Returns the value of a global variable in the script and cleans it (sanitizes). -*/ - -/datum/n_Interpreter/proc/GetCleanVar(name, compare) - var/x = GetVar(name) - if(istext(x) && compare && x != compare) // Was changed - x = sanitize(x) - return x - -/* -Proc: CallProc -Calls a global function defined in the script and, amazingly enough, returns its return value. Remember to ensure that the function -exists before calling this procedure. - -See Also: -- -*/ -/datum/n_Interpreter/proc/CallProc(name, params[]=null) - if(!ProcExists(name)) - //CRASH("No function named '[name]'.") - return - - var/datum/node/statement/FunctionDefinition/func = globalScope.functions[name] - - if(istype(func)) - var/datum/node/statement/FunctionCall/stmt = new - stmt.func_name = func.func_name - stmt.parameters = params - return RunFunction(stmt) - - else - return call(func)(arglist(params)) - //CRASH("Unknown function type '[name]'.") - -/* -Event: HandleError -Called when the interpreter throws a runtime error. - -See Also: -- -*/ -/datum/n_Interpreter/proc/HandleError(var/datum/runtimeError/e) diff --git a/code/modules/scripting/Interpreter/Interpreter.dm b/code/modules/scripting/Interpreter/Interpreter.dm deleted file mode 100644 index c24e9ba5e3a..00000000000 --- a/code/modules/scripting/Interpreter/Interpreter.dm +++ /dev/null @@ -1,380 +0,0 @@ -/* - File: Interpreter (Internal) -*/ -/* - Class: n_Interpreter -*/ -/* - Macros: Status Macros - RETURNING - Indicates that the current function is returning a value. - BREAKING - Indicates that the current loop is being terminated. - CONTINUING - Indicates that the rest of the current iteration of a loop is being skipped. -*/ -#define RETURNING 1 -#define BREAKING 2 -#define CONTINUING 4 - -/datum/n_Interpreter - var/datum/scope/curScope - var/datum/scope/globalScope - - var/datum/node/BlockDefinition/program - var/datum/node/statement/FunctionDefinition/curFunction - var/datum/stack/scopes = new() - var/datum/stack/functions = new() - - var/datum/container // associated container for interpeter -/* - Var: status - A variable indicating that the rest of the current block should be skipped. This may be set to any combination of . -*/ - var/status = 0 - var/returnVal - - var/max_statements = 900 // maximum amount of statements that can be called in one execution. this is to prevent massive crashes and exploitation - var/cur_statements = 0 // current amount of statements called - var/alertadmins = 0 // set to 1 if the admins shouldn't be notified of anymore issues - var/max_iterations = 100 // max number of uninterrupted loops possible - var/max_recursion = 10 // max recursions without returning anything (or completing the code block) - var/cur_recursion = 0 // current amount of recursion -/* - Var: persist - If 0, global variables will be reset after Run() finishes. -*/ - var/persist = 1 - var/paused = 0 - -/* - Constructor: New - Calls with the given parameters. -*/ -/datum/n_Interpreter/New(datum/node/BlockDefinition/GlobalBlock/program = null) - . = ..() - if(program) - Load(program) - -/* - Set ourselves to Garbage Collect -*/ -/datum/n_Interpreter/proc/GC() - ..() - container = null - -/* - Proc: RaiseError - Raises a runtime error. -*/ -/datum/n_Interpreter/proc/RaiseError(datum/runtimeError/e) - e.stack = functions.Copy() - e.stack.Push(curFunction) - src.HandleError(e) - -/datum/n_Interpreter/proc/CreateScope(datum/node/BlockDefinition/B) - var/datum/scope/S = new(B, curScope) - scopes.Push(curScope) - curScope = S - return S - -/datum/n_Interpreter/proc/CreateGlobalScope() - scopes.Clear() - var/datum/scope/S = new(program, null) - globalScope = S - return S - -/* -Proc: AlertAdmins -Alerts the admins of a script that is bad. -*/ -/datum/n_Interpreter/proc/AlertAdmins() - if(container && !alertadmins) - if(istype(container, /datum/TCS_Compiler)) - var/datum/TCS_Compiler/Compiler = container - var/obj/machinery/telecomms/server/Holder = Compiler.Holder - var/message = "Potential crash-inducing NTSL script detected at telecommunications server [Compiler.Holder] ([Holder.x], [Holder.y], [Holder.z])." - - alertadmins = 1 - message_admins(message, 1) -/* -Proc: RunBlock -Runs each statement in a block of code. -*/ -/datum/n_Interpreter/proc/RunBlock(var/datum/node/BlockDefinition/Block, var/datum/scope/scope = null) - var/is_global = istype(Block, /datum/node/BlockDefinition/GlobalBlock) - if(!is_global) - if(scope) - curScope = scope - else - CreateScope(Block) - else - if(!persist) - CreateGlobalScope() - - curScope = globalScope - - if(cur_statements < max_statements) - for(var/datum/node/statement/S in Block.statements) - while(paused) sleep(10) - - cur_statements++ - if(cur_statements >= max_statements) - RaiseError(new/datum/runtimeError/MaxCPU()) - AlertAdmins() - break - - if(istype(S, /datum/node/statement/VariableAssignment)) - var/datum/node/statement/VariableAssignment/stmt = S - var/name = stmt.var_name.id_name - - if(!stmt.object) - // Below we assign the variable first to null if it doesn't already exist. - // This is necessary for assignments like +=, and when the variable is used in a function - // If the variable already exists in a different block, then AssignVariable will automatically use that one. - if(!IsVariableAccessible(name)) - AssignVariable(name, null) - - AssignVariable(name, Eval(stmt.value)) - else - var/datum/D = Eval(GetVariable(stmt.object.id_name)) - if(!D) - return - - D.vars[stmt.var_name.id_name] = Eval(stmt.value) - - else if(istype(S, /datum/node/statement/VariableDeclaration)) - //VariableDeclaration nodes are used to forcibly declare a local variable so that one in a higher scope isn't used by default. - var/datum/node/statement/VariableDeclaration/dec=S - if(!dec.object) - AssignVariable(dec.var_name.id_name, null, curScope) - else - var/datum/D = Eval(GetVariable(dec.object.id_name)) - if(!D) - return - - D.vars[dec.var_name.id_name] = null - - else if(istype(S, /datum/node/statement/FunctionCall)) - RunFunction(S) - - else if(istype(S, /datum/node/statement/FunctionDefinition)) - //do nothing - - else if(istype(S, /datum/node/statement/WhileLoop)) - RunWhile(S) - - else if(istype(S, /datum/node/statement/IfStatement)) - RunIf(S) - - else if(istype(S, /datum/node/statement/ReturnStatement)) - if(!curFunction) - RaiseError(new/datum/runtimeError/UnexpectedReturn()) - continue - - status |= RETURNING - returnVal = Eval(S:value) - break - - else if(istype(S, /datum/node/statement/BreakStatement)) - status |= BREAKING - break - - else if(istype(S, /datum/node/statement/ContinueStatement)) - status |= CONTINUING - break - - else - RaiseError(new/datum/runtimeError/UnknownInstruction()) - - CHECK_TICK - - if(status) - break - - curScope = scopes.Pop() - -/* -Proc: RunFunction -Runs a function block or a proc with the arguments specified in the script. -*/ -/datum/n_Interpreter/proc/RunFunction(var/datum/node/statement/FunctionCall/stmt) - //Note that anywhere /datum/node/statement/FunctionCall/stmt is used so may /datum/node/expression/FunctionCall - - // If recursion gets too high (max 50 nested functions) throw an error - if(cur_recursion >= max_recursion) - AlertAdmins() - RaiseError(new/datum/runtimeError/RecursionLimitReached()) - return 0 - - var/datum/node/statement/FunctionDefinition/def - if(!stmt.object) //A scope's function is being called, stmt.object is null - def = GetFunction(stmt.func_name) - - else if(istype(stmt.object)) //A method of an object exposed as a variable is being called, stmt.object is a /node/identifier - var/O = GetVariable(stmt.object.id_name) //Gets a reference to the object which is the target of the function call. - if(!O) return //Error already thrown in GetVariable() - def = Eval(O) - - if(!def) - return - - cur_recursion++ // add recursion - if(istype(def)) - if(curFunction) functions.Push(curFunction) - var/datum/scope/S = CreateScope(def.block) - - for(var/i = 1 to def.parameters.len) - var/val - if(stmt.parameters.len >= i) - val = stmt.parameters[i] - //else - // unspecified param - AssignVariable(def.parameters[i], new/datum/node/expression/value/literal(Eval(val)), S) - - curFunction = stmt - RunBlock(def.block, S) - - //Handle return value - . = returnVal - status &= ~RETURNING - returnVal = null - curFunction = functions.Pop() - cur_recursion-- - - else - cur_recursion-- - var/list/params = new - for(var/datum/node/expression/P in stmt.parameters) - params += list(Eval(P)) - - if(isobject(def)) //def is an object which is the target of a function call - if(!hascall(def, stmt.func_name)) - RaiseError(new/datum/runtimeError/UndefinedFunction("[stmt.object.id_name].[stmt.func_name]")) - return - - return call(def, stmt.func_name)(arglist(params)) - - else //def is a path to a global proc - return call(def)(arglist(params)) - //else - // RaiseError(new/runtimeError/UnknownInstruction()) - -/* -Proc: RunIf -Checks a condition and runs either the if block or else block. -*/ -/datum/n_Interpreter/proc/RunIf(var/datum/node/statement/IfStatement/stmt) - if(!stmt.skip) - if(Eval(stmt.cond)) - RunBlock(stmt.block) - // Loop through the if else chain and tell them to be skipped. - var/datum/node/statement/IfStatement/i = stmt.else_if - var/fail_safe = 800 - - while(i && fail_safe) - fail_safe -= 1 - i.skip = 1 - i = i.else_if - - else if(stmt.else_block) - RunBlock(stmt.else_block) - - // We don't need to skip you anymore. - stmt.skip = 0 - -/* -Proc: RunWhile -Runs a while loop. -*/ - -/datum/n_Interpreter/proc/RunWhile(var/datum/node/statement/WhileLoop/stmt) - var/i = 1 - while(Eval(stmt.cond) && Iterate(stmt.block, i++)) - continue - - status &= ~BREAKING - -/* -Proc:Iterate -Runs a single iteration of a loop. Returns a value indicating whether or not to continue looping. -*/ - -/datum/n_Interpreter/proc/Iterate(var/datum/node/BlockDefinition/block, count) - RunBlock(block) - if(max_iterations > 0 && count >= max_iterations) - RaiseError(new/datum/runtimeError/IterationLimitReached()) - return 0 - - if(status & (BREAKING|RETURNING)) - return 0 - - status &= ~CONTINUING - return 1 - -/* -Proc: GetFunction -Finds a function in an accessible scope with the given name. Returns a . -*/ - -/datum/n_Interpreter/proc/GetFunction(name) - var/datum/scope/S = curScope - while(S) - if(S.functions.Find(name)) - return S.functions[name] - S = S.parent - - RaiseError(new/datum/runtimeError/UndefinedFunction(name)) - -/* -Proc: GetVariable -Finds a variable in an accessible scope and returns its value. -*/ - -/datum/n_Interpreter/proc/GetVariable(name) - var/datum/scope/S = curScope - while(S) - if(S.variables.Find(name)) - return S.variables[name] - S = S.parent - - RaiseError(new/datum/runtimeError/UndefinedVariable(name)) - -/datum/n_Interpreter/proc/GetVariableScope(name) //needed for when you reassign a variable in a higher scope - var/datum/scope/S = curScope - while(S) - if(S.variables.Find(name)) - return S - - S = S.parent - - -/datum/n_Interpreter/proc/IsVariableAccessible(name) - var/datum/scope/S = curScope - while(S) - if(S.variables.Find(name)) - return TRUE - S = S.parent - - return FALSE - - -/* -Proc: AssignVariable -Assigns a value to a variable in a specific block. - -Parameters: -name - The name of the variable to assign. -value - The value to assign to it. -S - The scope the variable resides in. If it is null, a scope with the variable already existing is found. If no scopes have a variable of the given name, the current scope is used. -*/ - -/datum/n_Interpreter/proc/AssignVariable(name, datum/node/expression/value, var/datum/scope/S = null) - if(!S) S = GetVariableScope(name) - if(!S) S = curScope - if(!S) S = globalScope - - ASSERT(istype(S)) - if(istext(value) || isnum(value) || isnull(value)) value = new/datum/node/expression/value/literal(value) - else if(!istype(value) && isobject(value)) value = new/datum/node/expression/value/reference(value) - //TODO: check for invalid name - S.variables["[name]"] = value - - diff --git a/code/modules/scripting/Interpreter/Scope.dm b/code/modules/scripting/Interpreter/Scope.dm deleted file mode 100644 index 24b3fbf727d..00000000000 --- a/code/modules/scripting/Interpreter/Scope.dm +++ /dev/null @@ -1,16 +0,0 @@ -/* - Class: scope - A runtime instance of a block. Used internally by the interpreter. -*/ -/datum/scope - var/datum/scope/parent = null - var/datum/node/BlockDefinition/block - var/list/functions - var/list/variables - -/datum/scope/New(var/datum/node/BlockDefinition/B, var/datum/scope/parent) - src.block = B - src.parent = parent - src.variables = B.initial_variables.Copy() - src.functions = B.functions.Copy() - . = ..() diff --git a/code/modules/scripting/Options.dm b/code/modules/scripting/Options.dm deleted file mode 100644 index be471756359..00000000000 --- a/code/modules/scripting/Options.dm +++ /dev/null @@ -1,122 +0,0 @@ -/* -File: Options -*/ -// Ascii values of characters -/var/const/ascii_A = 65 -/var/const/ascii_Z = 90 -/var/const/ascii_a = 97 -/var/const/ascii_z = 122 -/var/const/ascii_DOLLAR = 36 // $ -/var/const/ascii_ZERO = 48 -/var/const/ascii_NINE = 57 -/var/const/ascii_UNDERSCORE = 95 // _ - -/* - Class: n_scriptOptions -*/ -/datum/n_scriptOptions/proc/CanStartID(char) //returns true if the character can start a variable, function, or keyword name (by default letters or an underscore) - if(!isnum(char)) - char = text2ascii(char) - - return (char in ascii_A to ascii_Z) || (char in ascii_a to ascii_z) || char == ascii_UNDERSCORE || char == ascii_DOLLAR - -/datum/n_scriptOptions/proc/IsValidIDChar(char) //returns true if the character can be in the body of a variable, function, or keyword name (by default letters, numbers, and underscore) - if(!isnum(char)) - char = text2ascii(char) - - return CanStartID(char) || IsDigit(char) - -/datum/n_scriptOptions/proc/IsDigit(char) - if(!isnum(char)) - char = text2ascii(char) - - return char in ascii_ZERO to ascii_NINE - -/datum/n_scriptOptions/proc/IsValidID(id) //returns true if all the characters in the string are okay to be in an identifier name - if(!CanStartID(id)) //don't need to grab first char in id, since text2ascii does it automatically - return 0 - - var/list/charmap = string2charlist(id) - if(charmap.len == 1) - return 1 - - for(var/i = 2 to charmap.len) - if(!IsValidIDChar(charmap[i])) - return 0 - return 1 - -/* - Class: nS_Options - An implementation of for the n_Script language. -*/ -/datum/n_scriptOptions/nS_Options - var/list/symbols = list( - "(", - ")", - "\[", - "]", - ";", - ",", - "{", - "}" - ) //scanner - Characters that can be in symbols -/* -Var: keywords -An associative list used by the parser to parse keywords. Indices are strings which will trigger the keyword when parsed and the -associated values are types of which the proc will be called. -*/ - var/list/keywords = list( - "if" = /datum/n_Keyword/nS_Keyword/kwIf, - "else" = /datum/n_Keyword/nS_Keyword/kwElse, - "elseif" = /datum/n_Keyword/nS_Keyword/kwElseIf, - "while" = /datum/n_Keyword/nS_Keyword/kwWhile, - "break" = /datum/n_Keyword/nS_Keyword/kwBreak, - "continue" = /datum/n_Keyword/nS_Keyword/kwContinue, - "return" = /datum/n_Keyword/nS_Keyword/kwReturn, - "def" = /datum/n_Keyword/nS_Keyword/kwDef - ) - - var/list/assign_operators = list( - "=" = null, - "&=" = "&", - "|=" = "|", - "`=" = "`", - "+=" = "+", - "-=" = "-", - "*=" = "*", - "/=" = "/", - "^=" = "^", - "%=" = "%" - ) - - var/list/unary_operators = list( - "!" = /datum/node/expression/operator/unary/LogicalNot, - "~" = /datum/node/expression/operator/unary/BitwiseNot, - "-" = /datum/node/expression/operator/unary/Minus - ) - - var/list/binary_operators = list( - "==" = /datum/node/expression/operator/binary/Equal, - "!=" = /datum/node/expression/operator/binary/NotEqual, - ">" = /datum/node/expression/operator/binary/Greater, - "<" = /datum/node/expression/operator/binary/Less, - ">=" = /datum/node/expression/operator/binary/GreaterOrEqual, - "<=" = /datum/node/expression/operator/binary/LessOrEqual, - "&&" = /datum/node/expression/operator/binary/LogicalAnd, - "||" = /datum/node/expression/operator/binary/LogicalOr, - "&" = /datum/node/expression/operator/binary/BitwiseAnd, - "|" = /datum/node/expression/operator/binary/BitwiseOr, - "`" = /datum/node/expression/operator/binary/BitwiseXor, - "+" = /datum/node/expression/operator/binary/Add, - "-" = /datum/node/expression/operator/binary/Subtract, - "*" = /datum/node/expression/operator/binary/Multiply, - "/" = /datum/node/expression/operator/binary/Divide, - "^" = /datum/node/expression/operator/binary/Power, - "%" = /datum/node/expression/operator/binary/Modulo - ) - -/datum/n_scriptOptions/nS_Options/New() - . = ..() - for(var/O in assign_operators + binary_operators + unary_operators) - if(!symbols.Find(O)) - symbols += O \ No newline at end of file diff --git a/code/modules/scripting/Parser/Expressions.dm b/code/modules/scripting/Parser/Expressions.dm deleted file mode 100644 index f0712fc5aa6..00000000000 --- a/code/modules/scripting/Parser/Expressions.dm +++ /dev/null @@ -1,371 +0,0 @@ -/* - File: Expressions - Procedures for parsing expressions. -*/ - -/* - Macros: Expression Macros - OPERATOR - A value indicating the parser currently expects a binary operator. - VALUE - A value indicating the parser currently expects a value. - SHIFT - Tells the parser to push the current operator onto the stack. - REDUCE - Tells the parser to reduce the stack. -*/ -#define OPERATOR 1 -#define VALUE 2 -#define SHIFT 0 -#define REDUCE 1 - -/* - Class: nS_Parser -*/ -/datum/n_Parser/nS_Parser -/* - Var: expecting - A variable which keeps track of whether an operator or value is expected. It should be either or . See - for more information. -*/ - var/expecting = VALUE - -/* - Proc: Precedence - Compares two operators, decides which is higher in the order of operations, and returns or . -*/ -/datum/n_Parser/nS_Parser/proc/Precedence(var/datum/node/expression/operator/top, var/datum/node/expression/operator/input) - if(istype(top)) - top = top.precedence - - if(istype(input)) - - input = input:precedence - - if(top >= input) - return REDUCE - - return SHIFT - -/* - Proc: GetExpression - Takes a token expected to represent a value and returns an node. -*/ -/datum/n_Parser/nS_Parser/proc/GetExpression(var/datum/token/T) - if(!T) - return - - if(istype(T, /datum/node/expression)) - return T - - switch(T.type) - if(/datum/token/word) - return new/datum/node/expression/value/variable(T.value) - - if(/datum/token/accessor) - var/datum/token/accessor/A = T - var/datum/node/expression/value/variable/E// = new(A.member) - var/datum/stack/S = new() - - while(istype(A.object, /datum/token/accessor)) - S.Push(A) - A = A.object - - ASSERT(istext(A.object)) - - while(A) - var/datum/node/expression/value/variable/V = new() - V.id = new(A.member) - if(E) - V.object = E - else - V.object = new/datum/node/identifier(A.object) - - E = V - A = S.Pop() - return E - - if(/datum/token/number, /datum/token/string) - return new/datum/node/expression/value/literal(T.value) - -/* - Proc: GetOperator - Gets a path related to a token or string and returns an instance of the given type. This is used to get an instance of either a binary or unary - operator from a token. - - Parameters: - O - The input value. If this is a token, O is reset to the token's value. - When O is a string and is in L, its associated value is used as the path to instantiate. - type - The desired type of the returned object. - L - The list in which to search for O. - - See Also: - - - - -*/ -/datum/n_Parser/nS_Parser/proc/GetOperator(O, type = /datum/node/expression/operator, L[]) - if(istype(O, type)) - return O //O is already the desired type - - if(istype(O, /datum/token)) - O = O:value //sets O to text - - if(istext(O)) //sets O to path - if(L.Find(O)) - O = L[O] - else - return null - - if(ispath(O)) - O = new O //catches path from last check - - else - return null //Unknown type - - return O - -/* - Proc: GetBinaryOperator - Uses to search for an instance of a binary operator type with which the given string is associated. For example, if - O is set to "+", an node is returned. - - See Also: - - - - -*/ -/datum/n_Parser/nS_Parser/proc/GetBinaryOperator(O) - return GetOperator(O, /datum/node/expression/operator/binary, options.binary_operators) - -/* - Proc: GetUnaryOperator - Uses to search for an instance of a unary operator type with which the given string is associated. For example, if - O is set to "!", a node is returned. - - See Also: - - - - -*/ -/datum/n_Parser/nS_Parser/proc/GetUnaryOperator(O) - return GetOperator(O, /datum/node/expression/operator/unary, options.unary_operators) - -/* - Proc: Reduce - Takes the operator on top of the opr stack and assigns its operand(s). Then this proc pushes the value of that operation to the top - of the val stack. -*/ -/datum/n_Parser/nS_Parser/proc/Reduce(var/datum/stack/opr, var/datum/stack/val) - var/datum/node/expression/operator/O = opr.Pop() - if(!O) - return - - if(!istype(O)) - errors += new/datum/scriptError("Error reducing expression - invalid operator.") - return - - //Take O and assign its operands, popping one or two values from the val stack - //depending on whether O is a binary or unary operator. - if(istype(O, /datum/node/expression/operator/binary)) - var/datum/node/expression/operator/binary/B=O - B.exp2 = val.Pop() - B.exp = val.Pop() - val.Push(B) - - else - O.exp=val.Pop() - val.Push(O) - -/* - Proc: EndOfExpression - Returns true if the current token represents the end of an expression. - - Parameters: - end - A list of values to compare the current token to. -*/ -/datum/n_Parser/nS_Parser/proc/EndOfExpression(end[]) - if(!curToken) - return 1 - if(istype(curToken, /datum/token/symbol) && end.Find(curToken.value)) - return 1 - if(istype(curToken, /datum/token/end) && end.Find(/datum/token/end)) - return 1 - return 0 - -/* - Proc: ParseExpression - Uses the Shunting-yard algorithm to parse expressions. - - Notes: - - When an opening parenthesis is found, then is called to handle it. - - The variable helps distinguish unary operators from binary operators (for cases like the - operator, which can be either). - - Articles: - - - - - - See Also: - - - - - - -*/ - -/datum/n_Parser/nS_Parser/proc/ParseExpression(var/list/end = list(/datum/token/end), list/ErrChars = list("{", "}"), check_functions = 0) - var/datum/stack/opr = new - var/datum/stack/val = new - src.expecting = VALUE - var/loop = 0 - for() - loop++ - if(loop > 800) - errors += new/datum/scriptError("Too many nested tokens.") - return - - if(EndOfExpression(end)) - break - - if(istype(curToken, /datum/token/symbol) && ErrChars.Find(curToken.value)) - errors += new/datum/scriptError/BadToken(curToken) - break - - if(index > tokens.len) //End of File - errors += new/datum/scriptError/EndOfFile() - break - - var/datum/token/ntok - if(index + 1 <= tokens.len) - ntok = tokens[index + 1] - - if(istype(curToken, /datum/token/symbol) && curToken.value == "(") //Parse parentheses expression - if(expecting != VALUE) - errors += new/datum/scriptError/ExpectedToken("operator", curToken) - NextToken() - continue - - val.Push(ParseParenExpression()) - - else if(istype(curToken, /datum/token/symbol)) //Operator found. - var/datum/node/expression/operator/curOperator //Figure out whether it is unary or binary and get a new instance. - if(src.expecting == OPERATOR) - curOperator = GetBinaryOperator(curToken) - if(!curOperator) - errors += new/datum/scriptError/ExpectedToken("operator", curToken) - NextToken() - continue - else - curOperator = GetUnaryOperator(curToken) - if(!curOperator) //given symbol isn't a unary operator - errors += new/datum/scriptError/ExpectedToken("expression", curToken) - NextToken() - continue - - if(opr.Top() && Precedence(opr.Top(), curOperator) == REDUCE) //Check order of operations and reduce if necessary - Reduce(opr, val) - continue - - opr.Push(curOperator) - src.expecting = VALUE - - else if(ntok && ntok.value == "(" && istype(ntok, /datum/token/symbol)\ - && istype(curToken, /datum/token/word)) //Parse function call - - if(!check_functions) - - var/datum/token/preToken = curToken - var/old_expect = src.expecting - var/fex = ParseFunctionExpression() - if(old_expect != VALUE) - errors += new/datum/scriptError/ExpectedToken("operator", preToken) - NextToken() - continue - - val.Push(fex) - else - errors += new/datum/scriptError/ParameterFunction(curToken) - break - - else if(istype(curToken, /datum/token/keyword)) //inline keywords - var/datum/n_Keyword/kw = options.keywords[curToken.value] - kw = new kw(inline=1) - if(kw) - if(!kw.Parse(src)) - return - else - errors += new/datum/scriptError/BadToken(curToken) - - else if(istype(curToken, /datum/token/end)) //semicolon found where it wasn't expected - errors += new/datum/scriptError/BadToken(curToken) - NextToken() - continue - else - if(expecting != VALUE) - errors += new/datum/scriptError/ExpectedToken("operator", curToken) - NextToken() - continue - - val.Push(GetExpression(curToken)) - src.expecting = OPERATOR - - NextToken() - - while(opr.Top()) - Reduce(opr, val) - //Reduce the value stack completely - . = val.Pop() //Return what should be the last value on the stack - - if(val.Top()) // - var/datum/node/N = val.Pop() - errors += new/datum/scriptError("Error parsing expression. Unexpected value left on stack: [N.ToString()].") - return null - -/* - Proc: ParseFunctionExpression - Parses a function call inside of an expression. - - See Also: - - -*/ - -/datum/n_Parser/nS_Parser/proc/ParseFunctionExpression() - var/datum/node/expression/FunctionCall/exp = new - exp.func_name = curToken.value - NextToken() //skip function name - NextToken() //skip open parenthesis, already found - var/loops = 0 - - for() - loops++ - if(loops >= 800) - errors += new/datum/scriptError("Too many nested expressions.") - break - //CRASH("Something TERRIBLE has gone wrong in ParseFunctionExpression ;__;") - - if(istype(curToken, /datum/token/symbol) && curToken.value == ")") - return exp - exp.parameters += ParseParamExpression() - if(errors.len) - return exp - - if(curToken.value == "," && istype(curToken, /datum/token/symbol)) - NextToken() //skip comma - - if(istype(curToken, /datum/token/end)) //Prevents infinite loop... - errors += new/datum/scriptError/ExpectedToken(")") - return exp - -/* - Proc: ParseParenExpression - Parses an expression that ends with a close parenthesis. This is used for parsing expressions inside of parentheses. - - See Also: - - -*/ -/datum/n_Parser/nS_Parser/proc/ParseParenExpression() - if(!CheckToken("(", /datum/token/symbol)) - return - return new/datum/node/expression/operator/unary/group(ParseExpression(list(")"))) - -/* - Proc: ParseParamExpression - Parses an expression that ends with either a comma or close parenthesis. This is used for parsing the parameters passed to a function call. - - See Also: - - -*/ -/datum/n_Parser/nS_Parser/proc/ParseParamExpression(var/check_functions = 0) - var/cf = check_functions - return ParseExpression(list(",", ")"), check_functions = cf) \ No newline at end of file diff --git a/code/modules/scripting/Parser/Keywords.dm b/code/modules/scripting/Parser/Keywords.dm deleted file mode 100644 index cef9a065213..00000000000 --- a/code/modules/scripting/Parser/Keywords.dm +++ /dev/null @@ -1,204 +0,0 @@ -/* - File: Keywords -*/ -var/const/KW_FAIL = 0 //Fatal error; stop parsing entire script. -var/const/KW_PASS = 1 //OK -var/const/KW_ERR = 2 //Non-fatal error, keyword couldn't be handled properly. Ignore keyword but continue on. -var/const/KW_WARN = 3 //Warning - -/* -var/const/Class: n_Keyword -var/const/Represents a special statement in the code triggered by a keyword. -*/ -/datum/n_Keyword -/* - Var: inline - 1 if the keyword is in an expression (e.g. the new keyword in many languages), 0 otherwise (such as the if and else keywords). -*/ - var/inline - -/datum/n_Keyword/New(inline = 0) - src.inline = inline - return ..() - -/* - Proc: Parse - Called when the parser finds a keyword in the code. - - Parameters: - parser - The parser that created this object. You can use the parameter to manipulate the parser in order to add statements and blocks - to its AST. -*/ -/datum/n_Keyword/proc/Parse(var/datum/n_Parser/parser) - return -/* - Class: nS_Keyword - A keyword in n_Script. By default these include return, if, else, while, and def. To enable or disable a keyword, change the - list. - - Behavior: - When a parser is expecting a new statement, and a keyword listed in is found, it will call the keyword's - proc. -*/ -/datum/n_Keyword/nS_Keyword/New(var/inline = 0) - if(inline) - del src - -/datum/n_Keyword/nS_Keyword/kwReturn/Parse(var/datum/n_Parser/nS_Parser/parser) - . = KW_PASS - if(istype(parser.curBlock, /datum/node/BlockDefinition/GlobalBlock)) // Exit out of the program by setting the tokens list size to the same as index. - parser.tokens.len = parser.index - return - - var/datum/node/statement/ReturnStatement/stmt = new - parser.NextToken() //skip 'return' token - stmt.value = parser.ParseExpression() - parser.curBlock.statements += stmt - -/datum/n_Keyword/nS_Keyword/kwIf/Parse(var/datum/n_Parser/nS_Parser/parser) - . = KW_PASS - var/datum/node/statement/IfStatement/stmt = new - parser.NextToken() //skip 'if' token - stmt.cond = parser.ParseParenExpression() - if(!parser.CheckToken(")", /datum/token/symbol)) - return KW_FAIL - - if(!parser.CheckToken("{", /datum/token/symbol, skip=0)) //Token needs to be preserved for parse loop, so skip=0 - return KW_ERR - - parser.curBlock.statements += stmt - stmt.block = new - parser.AddBlock(stmt.block) - -/datum/n_Keyword/nS_Keyword/kwElseIf/Parse(var/datum/n_Parser/nS_Parser/parser) - . = KW_PASS - var/list/L = parser.curBlock.statements - var/datum/node/statement/IfStatement/ifstmt - - if(L && L.len) - ifstmt = L[L.len] //Get the last statement in the current block - - if(!ifstmt || !istype(ifstmt) || ifstmt.else_if) - to_chat(usr, "NTSL: ELSE IF FAILED: [!ifstmt], [!istype(ifstmt)], [!istype(ifstmt) || ifstmt.else_if]")// Usr is unsafe as SHIT but JUST incase I forget this debug line like the fucking asset cache... - - parser.errors += new/datum/scriptError/ExpectedToken("if statement", parser.curToken) - return KW_FAIL - - var/datum/node/statement/IfStatement/ElseIf/stmt = new - parser.NextToken() //skip 'if' token - stmt.cond = parser.ParseParenExpression() - if(!parser.CheckToken(")", /datum/token/symbol)) - return KW_FAIL - - if(!parser.CheckToken("{", /datum/token/symbol, skip = 0)) //Token needs to be preserved for parse loop, so skip=0 - return KW_ERR - - parser.curBlock.statements += stmt - stmt.block = new - ifstmt.else_if = stmt - parser.AddBlock(stmt.block) - -/datum/n_Keyword/nS_Keyword/kwElse/Parse(var/datum/n_Parser/nS_Parser/parser) - . = KW_PASS - var/list/L = parser.curBlock.statements - var/datum/node/statement/IfStatement/stmt - - if(L && L.len) - stmt = L[L.len] //Get the last statement in the current block - - if(!stmt || !istype(stmt) || stmt.else_block) //Ensure that it is an if statement - to_chat(usr, "NTSL: ELSE IF FAILED: [!stmt], [!istype(stmt)], [!istype(stmt) || stmt.else_block]")// Usr is unsafe as SHIT but JUST incase I forget this debug line like the fucking asset cache... - - parser.errors += new/datum/scriptError/ExpectedToken("if statement", parser.curToken) - return KW_FAIL - - parser.NextToken() //skip 'else' token - if(!parser.CheckToken("{", /datum/token/symbol, skip = 0)) - return KW_ERR - - stmt.else_block = new() - parser.AddBlock(stmt.else_block) - -/datum/n_Keyword/nS_Keyword/kwWhile/Parse(var/datum/n_Parser/nS_Parser/parser) - . = KW_PASS - var/datum/node/statement/WhileLoop/stmt = new - parser.NextToken() //skip 'while' token - stmt.cond = parser.ParseParenExpression() - if(!parser.CheckToken(")", /datum/token/symbol)) - return KW_FAIL - - if(!parser.CheckToken("{", /datum/token/symbol, skip=0)) - return KW_ERR - - parser.curBlock.statements += stmt - stmt.block = new - parser.AddBlock(stmt.block) - -/datum/n_Keyword/nS_Keyword/kwBreak/Parse(var/datum/n_Parser/nS_Parser/parser) - . = KW_PASS - if(istype(parser.curBlock, /datum/node/BlockDefinition/GlobalBlock)) - parser.errors += new/datum/scriptError/BadToken(parser.curToken) - . = KW_WARN - - var/datum/node/statement/BreakStatement/stmt = new - parser.NextToken() //skip 'break' token - parser.curBlock.statements += stmt - -/datum/n_Keyword/nS_Keyword/kwContinue/Parse(var/datum/n_Parser/nS_Parser/parser) - . = KW_PASS - if(istype(parser.curBlock, /datum/node/BlockDefinition/GlobalBlock)) - parser.errors += new/datum/scriptError/BadToken(parser.curToken) - . = KW_WARN - - var/datum/node/statement/ContinueStatement/stmt = new - parser.NextToken() //skip 'break' token - parser.curBlock.statements += stmt - -/datum/n_Keyword/nS_Keyword/kwDef/Parse(var/datum/n_Parser/nS_Parser/parser) - . = KW_PASS - var/datum/node/statement/FunctionDefinition/def = new - parser.NextToken() //skip 'def' token - - if(!parser.options.IsValidID(parser.curToken.value)) - parser.errors += new/datum/scriptError/InvalidID(parser.curToken) - return KW_FAIL - - def.func_name = parser.curToken.value - parser.NextToken() - - if(!parser.CheckToken("(", /datum/token/symbol)) - return KW_FAIL - - for() //for now parameters can be separated by whitespace - they don't need a comma in between - if(istype(parser.curToken, /datum/token/symbol)) - switch(parser.curToken.value) - if(",") - parser.NextToken() - if(")") - break - else - parser.errors += new/datum/scriptError/BadToken(parser.curToken) - return KW_ERR - - else if(istype(parser.curToken, /datum/token/word)) - def.parameters += parser.curToken.value - parser.NextToken() - - else - parser.errors += new/datum/scriptError/InvalidID(parser.curToken) - return KW_ERR - - if(!parser.CheckToken(")", /datum/token/symbol)) - return KW_FAIL - - if(istype(parser.curToken, /datum/token/end)) //Function prototype - parser.curBlock.statements += def - - else if(parser.curToken.value == "{" && istype(parser.curToken, /datum/token/symbol)) - def.block = new - parser.curBlock.statements += def - parser.curBlock.functions[def.func_name] = def - parser.AddBlock(def.block) - else - parser.errors += new/datum/scriptError/BadToken(parser.curToken) - return KW_FAIL diff --git a/code/modules/scripting/Parser/Parser.dm b/code/modules/scripting/Parser/Parser.dm deleted file mode 100644 index d9c737e7ea8..00000000000 --- a/code/modules/scripting/Parser/Parser.dm +++ /dev/null @@ -1,205 +0,0 @@ -/* - File: Parser -*/ -/* - Class: n_Parser - An object that reads tokens and produces an AST (abstract syntax tree). -*/ -/datum/n_Parser -/* - Var: index - The parser's current position in the token's list. -*/ - var/index = 1 -/* - Var: tokens - A list of tokens in the source code generated by a scanner. -*/ - var/list/tokens = new -/* - Var: errors - A list of fatal errors found by the parser. If there are any items in this list, then it is not safe to run the returned AST. - - See Also: - - -*/ - var/list/errors = new -/* - Var: warnings - A list of non-fatal problems in the script. -*/ - var/list/warnings = new -/* - Var: curToken - The token at in . -*/ - var/datum/token/curToken - var/datum/stack/blocks = new - var/datum/node/BlockDefinition/GlobalBlock/global_block = new - var/datum/node/BlockDefinition/GlobalBlock/curBlock - -/* - Proc: Parse - Reads the tokens and returns the AST's node. Be sure to populate the tokens list before calling this procedure. -*/ -/datum/n_Parser/proc/Parse() - return -/* - Proc: NextToken - Sets to the next token in the list, or null if there are no more tokens. -*/ -/datum/n_Parser/proc/NextToken() - if(index >= tokens.len) - curToken = null - else - curToken = tokens[++index] - return curToken - -/* - Class: nS_Parser - An implmentation of a parser for n_Script. -*/ -/datum/n_Parser/nS_Parser - var/datum/n_scriptOptions/nS_Options/options -/* - Constructor: New - - Parameters: - tokens - A list of tokens to parse. - options - An object used for configuration. -*/ -/datum/n_Parser/nS_Parser/New(tokens[], var/datum/n_scriptOptions/options) - src.tokens = tokens - src.options = options - curBlock = global_block - return ..() - -/datum/n_Parser/nS_Parser/Parse() - ASSERT(tokens) - for(,src.index <= src.tokens.len, src.index++) - curToken = tokens[index] - switch(curToken.type) - if(/datum/token/keyword) - var/datum/n_Keyword/kw = options.keywords[curToken.value] - kw = new kw() - if(kw) - if(!kw.Parse(src)) - return - - if(/datum/token/word) - var/datum/token/ntok - if(index + 1 > tokens.len) - errors += new/datum/scriptError/BadToken(curToken) - continue - - ntok = tokens[index + 1] - - if(!istype(ntok, /datum/token/symbol)) - errors += new/datum/scriptError/BadToken(ntok) - continue - - if(ntok.value == "(") - ParseFunctionStatement() - - else if(options.assign_operators.Find(ntok.value)) - ParseAssignment() - - else - errors += new/datum/scriptError/BadToken(ntok) - continue - - if(!istype(curToken, /datum/token/end)) - errors += new/datum/scriptError/ExpectedToken(";", curToken) - continue - - if(/datum/token/symbol) - if(curToken.value == "}") - if(!EndBlock()) - errors += new/datum/scriptError/BadToken(curToken) - continue - - else - errors += new/datum/scriptError/BadToken(curToken) - continue - - if(/datum/token/end) - warnings += new/datum/scriptError/BadToken(curToken) - continue - - else - errors += new/datum/scriptError/BadToken(curToken) - return - - return global_block - -/datum/n_Parser/nS_Parser/proc/CheckToken(val, type, err = 1, skip = 1) - if(curToken.value != val || !istype(curToken, type)) - if(err) - errors += new/datum/scriptError/ExpectedToken(val, curToken) - return 0 - if(skip) - NextToken() - - return 1 - -/datum/n_Parser/nS_Parser/proc/AddBlock(var/datum/node/BlockDefinition/B) - blocks.Push(curBlock) - curBlock = B - -/datum/n_Parser/nS_Parser/proc/EndBlock() - if(curBlock == global_block) - return 0 - - curBlock = blocks.Pop() - return 1 - -/datum/n_Parser/nS_Parser/proc/ParseAssignment() - var/name = curToken.value - if(!options.IsValidID(name)) - errors += new/datum/scriptError/InvalidID(curToken) - return - - NextToken() - var/t = options.binary_operators[options.assign_operators[curToken.value]] - var/datum/node/statement/VariableAssignment/stmt = new() - stmt.var_name = new(name) - NextToken() - - if(t) - stmt.value = new t() - stmt.value:exp = new/datum/node/expression/value/variable(stmt.var_name) - stmt.value:exp2 = ParseExpression() - else - stmt.value = ParseExpression() - - curBlock.statements += stmt - -/datum/n_Parser/nS_Parser/proc/ParseFunctionStatement() - if(!istype(curToken, /datum/token/word)) - errors += new/datum/scriptError("Bad identifier in function call.") - return - - var/datum/node/statement/FunctionCall/stmt=new - stmt.func_name = curToken.value - NextToken() //skip function name - if(!CheckToken("(", /datum/token/symbol)) //Check for and skip open parenthesis - return - var/loops = 0 - for() - loops++ - if(loops >= 800) - errors +=new/datum/scriptError("Cannot find ending params.") - return - - if(!curToken) - errors+=new/datum/scriptError/EndOfFile() - return - if(istype(curToken, /datum/token/symbol) && curToken.value == ")") - curBlock.statements += stmt - NextToken() //Skip close parenthesis - return - - var/datum/node/expression/P = ParseParamExpression(check_functions = 1) - stmt.parameters += P - if(istype(curToken, /datum/token/symbol) && curToken.value == ",") - NextToken() diff --git a/code/modules/scripting/Scanner/Scanner.dm b/code/modules/scripting/Scanner/Scanner.dm deleted file mode 100644 index da6a2c04803..00000000000 --- a/code/modules/scripting/Scanner/Scanner.dm +++ /dev/null @@ -1,293 +0,0 @@ -/* - File: Scanner -*/ -/* - Class: n_Scanner - An object responsible for breaking up source code into tokens for use by the parser. -*/ -/datum/n_Scanner - var/list/code -/* - Var: errors - A list of fatal errors found by the scanner. If there are any items in this list, then it is not safe to parse the returned tokens. - - See Also: - - -*/ - var/list/errors = new -/* - Var: warnings - A list of non-fatal problems in the source code found by the scanner. -*/ - var/list/warnings = new - -/* - Proc: LoadCode - Loads source code. -*/ -/datum/n_Scanner/proc/LoadCode(var/list/c) - code=c - -/* - Proc: LoadCodeFromFile - Gets the code from a file and calls . -*/ -/datum/n_Scanner/proc/LoadCodeFromFile(var/f) - LoadCode(file2text(f)) - -/* - Proc: Scan - Runs the scanner and returns the resulting list of tokens. Ensure that has been called first. -*/ -/datum/n_Scanner/proc/Scan() - -/* - Class: nS_Scanner - A scanner implementation for n_Script. -*/ -/datum/n_Scanner/nS_Scanner -/* - Variable: codepos - The scanner's position in the source code. -*/ - var/codepos = 1 - var/line = 1 - var/linepos = 0 //column=codepos-linepos - var/datum/n_scriptOptions/nS_Options/options - - var/commenting = 0 - // 1: single-line - // 2: multi-line -/* - Variable: ignore - A list of characters that are ignored by the scanner. - - Default Value: - Whitespace -*/ - var/list/ignore = list(" ", "\t", "\n") //Don't add tokens for whitespace -/* - Variable: end_stmt - A list of characters that end a statement. Each item may only be one character long. - - Default Value: - Semicolon -*/ - var/list/end_stmt = list(";") -/* - Variable: string_delim - A list of characters that can start and end strings. - - Default Value: - Double and single quotes. -*/ - var/list/string_delim = list("\"", "'") -/* - Variable: delim - A list of characters that denote the start of a new token. This list is automatically populated. -*/ - var/list/delim = new - -/* - Macro: COL - The current column number. -*/ - #define COL codepos-linepos - -/* - Constructor: New - Parameters: - code - The source code to tokenize. - options - An object used to configure the scanner. -*/ -/datum/n_Scanner/nS_Scanner/New(var/list/c, var/datum/n_scriptOptions/nS_Options/options) - . = ..() - ignore += ascii2text(13) //Carriage return - delim += ignore + options.symbols + end_stmt + string_delim - src.options = options - LoadCode(c) - -/datum/n_Scanner/nS_Scanner/Scan() //Creates a list of tokens from source code - var/list/tokens = new - for(, src.codepos <= code.len, src.codepos++) - var/char = code[codepos] - var/nextchar = TCOMMS_SAFE_INDEX(code, codepos + 1) - if(char == "\n") - line++ - linepos = codepos - - if(char in ignore) - continue - - else if(char == "/" && (nextchar == "*" || nextchar == "/")) - ReadComment() - - else if(end_stmt.Find(char)) - tokens += new/datum/token/end(char, line, COL) - - else if(string_delim.Find(char)) - codepos++ //skip string delimiter - tokens += ReadString(char) - - else if(options.CanStartID(char)) - tokens += ReadWord() - - else if(options.IsDigit(char)) - tokens += ReadNumber() - - else if(options.symbols.Find(char)) - tokens += ReadSymbol() - - CHECK_TICK - - codepos = initial(codepos) - line = initial(line) - linepos = initial(linepos) - return tokens - - -/* - Proc: ReadString - Reads a string in the source code into a token. - - Parameters: - start - The character used to start the string. -*/ -/datum/n_Scanner/nS_Scanner/proc/ReadString(start) - var/buf - for(, codepos <= code.len, codepos++)//codepos to length(code)) - var/char = code[codepos] - switch(char) - if("\\") //Backslash (\) encountered in string - codepos++ //Skip next character in string, since it was escaped by a backslash - char = TCOMMS_SAFE_INDEX(code, codepos) - switch(char) - if("\\") //Double backslash - buf += "\\" - if("n") //\n Newline - buf += "\n" - else - if(char == start) //\" Doublequote - buf += start - else //Unknown escaped text - buf += char - if("\n") - . = new/datum/token/string(buf, line, COL) - errors += new/datum/scriptError("Unterminated string. Newline reached.", .) - line++ - linepos = codepos - break - else - if(char == start) //string delimiter found, end string - break - else - buf += char //Just a normal character in a string - if(!.) - return new/datum/token/string(buf, line, COL) - -/* - Proc: ReadWord - Reads characters separated by an item in into a token. -*/ -/datum/n_Scanner/nS_Scanner/proc/ReadWord() - var/char = code[codepos] - var/buf - - while(!delim.Find(char)) - buf += char - if(++codepos > code.len) break - char = code[codepos] - - codepos-- //allow main Scan() proc to read the delimiter - if(options.keywords.Find(buf)) - return new/datum/token/keyword(buf, line, COL) - else - return new/datum/token/word(buf, line, COL) - -/* - Proc: ReadSymbol - Reads a symbol into a token. -*/ -/datum/n_Scanner/nS_Scanner/proc/ReadSymbol() - var/char = code[codepos] - var/buf - - while(options.symbols.Find(buf + char)) - buf += char - if(++codepos > code.len) break - char = code[codepos] - - codepos-- //allow main Scan() proc to read the next character - return new /datum/token/symbol(buf, line, COL) - -/* - Proc: ReadNumber - Reads a number into a token. -*/ -/datum/n_Scanner/nS_Scanner/proc/ReadNumber() - var/char = code[codepos] - var/buf - var/dec = 0 - - while(options.IsDigit(char) || (char == "." && !dec)) - if(char == ".") - dec = 1 - - buf += char - codepos++ - char = TCOMMS_SAFE_INDEX(code, codepos) - - var/datum/token/number/T = new(buf, line, COL) - if(isnull(text2num(buf))) - errors += new/datum/scriptError("Bad number: ", T) - T.value = 0 - - codepos-- //allow main Scan() proc to read the next character - return T - -/* - Proc: ReadComment - Reads a comment and outputs the type of comment -*/ - -/datum/n_Scanner/nS_Scanner/proc/ReadComment() - var/char = code[codepos] - var/nextchar = TCOMMS_SAFE_INDEX(code, codepos + 1) - var/charstring = char + nextchar - var/comm = 1 - // 1: single-line comment - // 2: multi-line comment - var/expectedend = 0 - - if(charstring == "//" || charstring == "/*") - if(charstring == "/*") - comm = 2 // starts a multi-line comment - - while(comm) - if(++codepos > code.len) - break - - if(expectedend) // ending statement expected... - char = code[codepos] - if(char == "/") // ending statement found - beak the comment - comm = 0 - break - - if(comm == 2) - // multi-line comments are broken by ending statements - char = code[codepos] - if(char == "*") - expectedend = 1 - continue - else - char = code[codepos] - if(char == "\n") - comm = 0 - break - - if(expectedend) - expectedend = 0 - - if(comm == 2) - errors += new/datum/scriptError/UnterminatedComment() - diff --git a/code/modules/scripting/Scanner/Tokens.dm b/code/modules/scripting/Scanner/Tokens.dm deleted file mode 100644 index acf7bbbad99..00000000000 --- a/code/modules/scripting/Scanner/Tokens.dm +++ /dev/null @@ -1,40 +0,0 @@ -/* - Class: Token - Represents an entity and position in the source code. -*/ -/datum/token - var/value - var/line - var/column - -/datum/token/New(v, l = 0, c = 0) - value = v - line = l - column = c - -/datum/token/string - -/datum/token/symbol - -/datum/token/word - -/datum/token/keyword - -/datum/token/number/New() - . = ..() - if(!isnum(value)) - value = text2num(value) - ASSERT(!isnull(value)) - -/datum/token/accessor - var/object - var/member - -/datum/token/accessor/New(object, member, l = 0, c = 0) - src.object = object - src.member = member - src.value = "[object].[member]" //for debugging only - src.line = l - src.column = c - -/datum/token/end diff --git a/code/modules/scripting/__defines.dm b/code/modules/scripting/__defines.dm deleted file mode 100644 index 52f30e68fdc..00000000000 --- a/code/modules/scripting/__defines.dm +++ /dev/null @@ -1 +0,0 @@ -#define TCOMMS_SAFE_INDEX(list, index) list.len > index ? list[index] : null diff --git a/paradise.dme b/paradise.dme index b48412ed2f9..7097af81f38 100644 --- a/paradise.dme +++ b/paradise.dme @@ -677,7 +677,7 @@ #include "code\game\machinery\telecomms\presets.dm" #include "code\game\machinery\telecomms\telecomunications.dm" #include "code\game\machinery\telecomms\telemonitor.dm" -#include "code\game\machinery\telecomms\traffic_control_ntsl2.dm" +#include "code\game\machinery\telecomms\traffic_control.dm" #include "code\game\magic\Uristrunes.dm" #include "code\game\mecha\mech_bay.dm" #include "code\game\mecha\mech_fabricator.dm" @@ -2112,25 +2112,6 @@ #include "code\modules\research\xenobiology\xenobio_camera.dm" #include "code\modules\research\xenobiology\xenobiology.dm" #include "code\modules\ruins\ruin_areas.dm" -#include "code\modules\scripting\__defines.dm" -#include "code\modules\scripting\Errors.dm" -#include "code\modules\scripting\Options.dm" -#include "code\modules\scripting\AST\AST Nodes.dm" -#include "code\modules\scripting\AST\Blocks.dm" -#include "code\modules\scripting\AST\Statements.dm" -#include "code\modules\scripting\AST\Operators\Binary Operators.dm" -#include "code\modules\scripting\AST\Operators\Unary Operators.dm" -#include "code\modules\scripting\Implementations\_Logic.dm" -#include "code\modules\scripting\Implementations\Telecomms.dm" -#include "code\modules\scripting\Interpreter\Evaluation.dm" -#include "code\modules\scripting\Interpreter\Interaction.dm" -#include "code\modules\scripting\Interpreter\Interpreter.dm" -#include "code\modules\scripting\Interpreter\Scope.dm" -#include "code\modules\scripting\Parser\Expressions.dm" -#include "code\modules\scripting\Parser\Keywords.dm" -#include "code\modules\scripting\Parser\Parser.dm" -#include "code\modules\scripting\Scanner\Scanner.dm" -#include "code\modules\scripting\Scanner\Tokens.dm" #include "code\modules\security_levels\keycard authentication.dm" #include "code\modules\security_levels\security levels.dm" #include "code\modules\shuttle\assault_pod.dm"