From 3156b3c5e6dc6f7418929bf874f4d6f19ee0d46a Mon Sep 17 00:00:00 2001 From: kevinz000 Date: Thu, 16 Mar 2017 00:24:10 -0700 Subject: [PATCH] [READY]More SDQL stuff from /vg/ (#24970) * sdql3 * wups --- code/modules/admin/verbs/SDQL2/SDQL_2.dm | 117 ++++++++-------- .../admin/verbs/SDQL2/SDQL_2_parser.dm | 131 +++++++++--------- 2 files changed, 126 insertions(+), 122 deletions(-) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 2147157dd72..b666467c7a3 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -71,15 +71,8 @@ var/list/objs = list() for(var/type in select_types) - var/char = copytext(type, 1, 2) - - if(char == "/" || char == "*") - for(var/from in from_objs) - objs += SDQL_get_all(type, from) - CHECK_TICK - - else if(char == "'" || char == "\"") - objs += locate(copytext(type, 2, length(type))) + objs += SDQL_get_all(type, from_objs) + CHECK_TICK if("where" in query_tree) var/objs_temp = objs @@ -91,19 +84,8 @@ switch(query_tree[1]) if("call") - var/list/call_list = query_tree["call"] - var/list/args_list = query_tree["args"] - for(var/datum/d in objs) - var/list/new_args = list() - for(var/a in args_list) - new_args += SDQL_expression(d,a) - for(var/v in call_list) - if(copytext(v,1,8) == "global.") - v = "/proc/[copytext(v,8)]" - SDQL_callproc_global(v,new_args) - else - SDQL_callproc(d, v, new_args) + SDQL_var(d, query_tree["call"][1], source = d) CHECK_TICK if("delete") @@ -231,30 +213,15 @@ /proc/SDQL_from_objs(list/tree) if("world" in tree) - return list(world) - - var/list/out = list() - - for(var/type in tree) - var/char = copytext(type, 1, 2) - - if(char == "/") - out += SDQL_get_all(type, world) - - else if(char == "'" || char == "\"") - out += locate(copytext(type, 2, length(type))) - - return out - + return world + return SDQL_expression(world, tree) /proc/SDQL_get_all(type, location) var/list/out = list() - if(type == "*") - for(var/datum/d in location) - out += d - - return out +// If only a single object got returned, wrap it into a list so the for loops run on it. + if(!islist(location) && location != world) + location = list(location) type = text2path(type) var/typecache = typecacheof(type) @@ -394,21 +361,32 @@ else if(expression[i] == "\[") var/list/expressions_list = expression[++i] - var/list/val2 = list() + val = list() for(var/list/expression_list in expressions_list) - val2[++val2.len] = SDQL_expression(object, expression_list) - val = val2 + var/result = SDQL_expression(object, expression_list) + var/assoc + if(expressions_list[expression_list] != null) + assoc = SDQL_expression(object, expressions_list[expression_list]) + if(assoc != null) + // Need to insert the key like this to prevent duplicate keys fucking up. + var/list/dummy = list() + dummy[result] = assoc + result = dummy + val += result else - val = SDQL_var(object, expression, i) + val = SDQL_var(object, expression, i, object) i = expression.len return list("val" = val, "i" = i) -/proc/SDQL_var(datum/object, list/expression, start = 1) +/proc/SDQL_var(datum/object, list/expression, start = 1, source) var/v - if(expression[start] in object.vars) - v = object.vars[expression[start]] - else if(expression[start] == "{" && start < expression.len) + var/static/list/exclude = list("usr", "src", "marked", "global") + var/long = start < expression.len + if(object == world && long && expression[start + 1] == ".") + to_chat(usr, "Sorry, but global variables are not supported at the moment.") + return null + else if(expression [start] == "{" && long) if(lowertext(copytext(expression[start + 1], 1, 3)) != "0x") to_chat(usr, "Invalid pointer syntax: [expression[start + 1]]") return null @@ -417,28 +395,55 @@ to_chat(usr, "Invalid pointer: [expression[start + 1]]") return null start++ - else + else if((!long || expression[start + 1] == ".") && (expression[start] in object.vars)) + v = object.vars[expression[start]] + else if(long && expression[start + 1] == ":" && hascall(object, expression[start])) + v = expression[start] + else if(!long || expression[start + 1] == ".") switch(expression[start]) if("usr") v = usr if("src") - v = object + v = source if("marked") if(usr.client && usr.client.holder && usr.client.holder.marked_datum) v = usr.client.holder.marked_datum else return null + if("global") + v = world else return null - if(start < expression.len && expression[start + 1] == ".") - return SDQL_var(v, expression[start + 2]) - else - return v + else if(object == world) // Shitty ass hack kill me. + v = expression[start] + if(long) + if(expression[start + 1] == ".") + return SDQL_var(v, expression[start + 2], source = source) + else if(expression[start + 1] == ":") + return SDQL_function(object, v, expression[start + 2], source) + else if(expression[start + 1] == "\[" && islist(v)) + var/list/L = v + var/index = SDQL_expression(source, expression[start + 2]) + if(isnum(index) && (!IsInteger(index) || L.len < index)) + to_chat(usr, "Invalid list index: [index]") + return null + return L[index] + return v + +/proc/SDQL_function(var/datum/object, var/procname, var/list/arguments, source) + set waitfor = FALSE + var/list/new_args = list() + for(var/arg in arguments) + new_args += SDQL_expression(source, arg) + if(object == world) // Global proc. + procname = "/proc/[procname]" + return call(procname)(arglist(new_args)) + return call(object, procname)(arglist(new_args)) // Spawn in case the function sleeps. /proc/SDQL2_tokenize(query_text) var/list/whitespace = list(" ", "\n", "\t") - var/list/single = list("(", ")", ",", "+", "-", ".", ";", "{", "}", "\[", "]") + var/list/single = list("(", ")", ",", "+", "-", ".", ";", "{", "}", "\[", "]", ":") var/list/multi = list( "=" = list("", "="), "<" = list("", "=", ">"), diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm index 3692b9633df..61945f1dde7 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm @@ -116,18 +116,7 @@ i = select_list(i + 1, select) node += "select" node["select"] = select - var/list/from = list() - if(tokenl(i) in list("from", "in")) - i = from_list(i + 1, from) - else - from += "world" - node += "from" - node["from"] = from - if(tokenl(i) == "where") - var/list/where = list() - i = bool_expression(i + 1, where) - node += "where" - node["where"] = where + selectors(i, node) return i //delete_query: 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] @@ -136,18 +125,7 @@ i = select_list(i + 1, select) node += "delete" node["delete"] = select - var/list/from = list() - if(tokenl(i) in list("from", "in")) - i = from_list(i + 1, from) - else - from += "world" - node += "from" - node["from"] = from - if(tokenl(i) == "where") - var/list/where = list() - i = bool_expression(i + 1, where) - node += "where" - node["where"] = where + selectors(i, node) return i //update_query: 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression] @@ -156,52 +134,28 @@ i = select_list(i + 1, select) node += "update" node["update"] = select - var/list/from = list() - if(tokenl(i) in list("from", "in")) - i = from_list(i + 1, from) - else - from += "world" - node += "from" - node["from"] = from if(tokenl(i) != "set") i = parse_error("UPDATE has misplaced SET") var/list/set_assignments = list() i = assignments(i + 1, set_assignments) node += "set" node["set"] = set_assignments - if(tokenl(i) == "where") - var/list/where = list() - i = bool_expression(i + 1, where) - node += "where" - node["where"] = where + selectors(i, node) return i //call_query: 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]] /datum/SDQL_parser/proc/call_query(i, list/node) var/list/func = list() - var/list/arguments = list() - i = call_function(i + 1, func, arguments) + i = variable(i + 1, func) // Yes technically does anything variable() matches but I don't care, if admins fuck up this badly then they shouldn't be allowed near SDQL. node += "call" node["call"] = func - node["args"] = arguments if(tokenl(i) != "on") return i var/list/select = list() i = select_list(i + 1, select) node += "on" node["on"] = select - var/list/from = list() - if(tokenl(i) in list("from", "in")) - i = from_list(i + 1, from) - else - from += "world" - node += "from" - node["from"] = from - if(tokenl(i) == "where") - var/list/where = list() - i = bool_expression(i + 1, where) - node += "where" - node["where"] = where + selectors(i, node) return i //select_list: select_item [',' select_list] @@ -211,13 +165,6 @@ i = select_list(i + 1, node) return i -//from_list: from_item [',' from_list] -/datum/SDQL_parser/proc/from_list(i, list/node) - i = from_item(i, node) - if(token(i) == ",") - i = from_list(i + 1, node) - return i - //assignments: assignment, [',' assignments] /datum/SDQL_parser/proc/assignments(i, list/node) i = assignment(i, node) @@ -236,13 +183,33 @@ i = object_type(i, node) return i +// Standardized method for handling the IN/FROM and WHERE options. +/datum/SDQL_parser/proc/selectors(i, list/node) + while (token(i)) + var/tok = tokenl(i) + if(tok in list("from", "in")) + var/list/from = list() + i = from_item(i + 1, from) + node["from"] = from + continue + if(tok == "where") + var/list/where = list() + i = bool_expression(i + 1, where) + node["where"] = where + continue + parse_error("Expected either FROM, IN or WHERE token, found [token(i)] instead.") + return i + 1 + if(!node.Find("from")) + node["from"] = list("world") + return i + //from_item: 'world' | object_type /datum/SDQL_parser/proc/from_item(i, list/node) if(token(i) == "world") node += "world" i++ else - i = object_type(i, node) + i = expression(i, node) return i //bool_expression: expression [bool_operator bool_expression] @@ -280,6 +247,19 @@ if(token(i + 1) == ".") L += "." i = variable(i + 2, L) + else if(token(i + 1) == "(") // OH BOY PROC + var/list/arguments = list() + i = call_function(i, null, arguments) + L += ":" + L[++L.len] = arguments + else if(token(i + 1) == "\[") + var/list/expression = list() + i = expression(i + 2, expression) + if (token(i) != "]") + parse_error("Missing ] at the end of list access.") + L += "\[" + L[++L.len] = expression + i++ else i++ return i @@ -291,17 +271,36 @@ return i + 1 node += token(i) var/list/expression_list = list() - if(token(i + 1) != "]") + i++ + if(token(i) != "]") var/list/temp_expression_list = list() + var/tok do - i = expression(i + 1, temp_expression_list) - if(token(i) == ",") + tok = token(i) + if(tok == "," || tok == ":") + if(temp_expression_list == null) + parse_error("Found ',' or ':' without expression in an array.") + return i + 1 expression_list[++expression_list.len] = temp_expression_list - temp_expression_list = list() + temp_expression_list = null + if(tok == ":") + temp_expression_list = list() + i = expression(i + 1, temp_expression_list) + expression_list[expression_list[expression_list.len]] = temp_expression_list + temp_expression_list = null + tok = token(i) + if(tok != ",") + if(tok == "]") + break + parse_error("Expected ',' or ']' after array assoc value, but found '[token(i)]'") + return i + i++ + continue + temp_expression_list = list() + i = expression(i, temp_expression_list) while(token(i) && token(i) != "]") - expression_list[++expression_list.len] = temp_expression_list - else - i++ + if(temp_expression_list) + expression_list[++expression_list.len] = temp_expression_list node[++node.len] = expression_list return i + 1