From 59097a99ea6f4260480c36dc2fc9a534b38769dc Mon Sep 17 00:00:00 2001 From: Tastyfish Date: Fri, 8 Apr 2016 18:07:03 -0400 Subject: [PATCH 1/2] Allows update to set to vars of vars, call procs in arbitrary expressions, procs of vars --- code/modules/admin/verbs/SDQL2/SDQL_2.dm | 139 +++++++++++------- .../admin/verbs/SDQL2/SDQL_2_parser.dm | 34 +++-- 2 files changed, 108 insertions(+), 65 deletions(-) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 0b0b8991aa1..8ba551ae4f3 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -84,22 +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) - for(var/v in call_list) - var/list/arguments[0] - for(var/list/arg in args_list) - arguments += SDQL_expression(d, arg) - - if(copytext(v, 1, 8) == "global.") // Global proc. - spawn() - call("/proc/[copytext(v, 8)]")(arglist(arguments)) - else if(d) - if(hascall(d, v)) - spawn() - call(d, v)(arglist(arguments)) // Spawn in case the function sleeps. + SDQL_var(d, query_tree["call"][1], source = d) if("delete") for(var/datum/d in objs) @@ -130,25 +116,26 @@ if("set" in query_tree) var/list/set_list = query_tree["set"] for(var/datum/d in objs) - var/list/vals = list() - for(var/v in set_list) - if(v in d.vars) - vals += v - vals[v] = SDQL_expression(d, set_list[v]) + for(var/list/sets in set_list) + var/datum/temp = d + var/i = 0 + for(var/v in sets) + if(++i == sets.len) + if(istype(temp, /turf) && (v == "x" || v == "y" || v == "z")) + continue + if(istype(temp.vars[v], /datum/admins)) + continue + temp.vars[v] = SDQL_expression(d, set_list[sets]) + break + if(temp.vars.Find(v) && (istype(temp.vars[v], /datum) || istype(temp.vars[v], /client)) && !istype(temp.vars[v], /datum/admins)) + temp = temp.vars[v] + else + break - if(istype(d, /turf)) - for(var/v in vals) - if(v == "x" || v == "y" || v == "z") - continue - - d.vars[v] = vals[v] - - else - for(var/v in vals) - d.vars[v] = vals[v] catch(var/exception/e) - to_chat(usr, "A runtime error has occured during the execution of your query and your query has been aborted.") - to_chat(usr, "[e]") + to_chat(usr, "An exception has occured during the execution of your query and your query has been aborted.") + to_chat(usr, " [e.name]") + to_chat(usr, " at: [e.file]:[e.line]") /proc/SDQL_parse(list/query_list) var/datum/SDQL_parser/parser = new() @@ -191,7 +178,7 @@ /proc/SDQL_testout(list/query_tree, indent = 0) var/spaces = "" for(var/s = 0, s < indent, s++) - spaces += " " + spaces += "    " for(var/item in query_tree) if(istype(item, /list)) @@ -205,12 +192,12 @@ if(!isnum(item) && query_tree[item]) if(istype(query_tree[item], /list)) - to_chat(usr, "[spaces] (") + to_chat(usr, "[spaces]    (") SDQL_testout(query_tree[item], indent + 2) - to_chat(usr, "[spaces] )") + to_chat(usr, "[spaces]    )") else - to_chat(usr, "[spaces] [query_tree[item]]") + to_chat(usr, "[spaces]    [query_tree[item]]") /proc/SDQL_from_objs(list/tree) if("world" in tree) @@ -368,25 +355,21 @@ val += SDQL_expression(object, expression_list) 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] == "src") - v = object - else if(expression[start] == "usr") - v = usr - else if(expression[start] == "marked") - if(usr.client && usr.client.holder && usr.client.holder.marked_datum) - v = usr.client.holder.marked_datum - else - return null - else if(expression[start] == "\[" && start < expression.len) + + 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 + + if(expression[start] == "\[" && long) if(lowertext(copytext(expression[start + 1], 1, 3)) != "0x") to_chat(usr, "Invalid ref syntax: [expression[start + 1]]") return null @@ -395,13 +378,57 @@ to_chat(usr, "Invalid ref: [expression[start + 1]]") return null start++ - else - return null - if(start < expression.len && expression[start + 1] == ".") - return SDQL_var(v, expression[start + 2]) - else - return v + else if((!long || expression[start + 1] == "." || 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 = 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 // World is mostly a token, really. + else + return null + + else if(object == world) + 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(world, "Invalid list index: [index]") + return null + return L[index] + + return v + +/proc/SDQL_function(var/datum/object, var/procname, var/list/arguments, source) + 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)) /proc/SDQL2_tokenize(query_text) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm index b1b2c28e276..5aa2aa0dc93 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm @@ -207,12 +207,10 @@ //call_query: 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]] 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) node += "call" node["call"] = func - node["args"] = arguments if(tokenl(i) != "on") return i @@ -317,15 +315,17 @@ //assignment: '=' expression - assignment(i, list/node) + assignment(var/i, var/list/node, var/list/assignment_list = list()) + assignment_list += token(i) - node += token(i) + if(token(i + 1) == ".") + i = assignment(i + 2, node, assignment_list) - if(token(i + 1) == "=") - var/varname = token(i) - node[varname] = list() + else if(token(i + 1) == "=") + var/exp_list = list() + node[assignment_list] = exp_list - i = expression(i + 2, node[varname]) + i = expression(i + 2, exp_list) else parse_error("Assignment expected, but no = found") @@ -349,6 +349,22 @@ 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) == "\[") // list index + 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++ From a298ca044aab0c5ff19bb14ce87fe397201dce41 Mon Sep 17 00:00:00 2001 From: Tastyfish Date: Mon, 11 Apr 2016 16:29:20 -0400 Subject: [PATCH 2/2] Fixes function call with lists --- code/modules/admin/verbs/SDQL2/SDQL_2.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 8ba551ae4f3..b46e5401528 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -422,7 +422,7 @@ /proc/SDQL_function(var/datum/object, var/procname, var/list/arguments, source) var/list/new_args = list() for(var/arg in arguments) - new_args += SDQL_expression(source, arg) + new_args[++new_args.len] = SDQL_expression(source, arg) if (object == world) // Global proc. procname = "/proc/[procname]"