diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm
index 0b0b8991aa1..b46e5401528 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[++new_args.len] = 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++