Skip to content

Commit

Permalink
Parse non-strings in lists in maps (tgstation#39786)
Browse files Browse the repository at this point in the history
* Parse non-strings in lists in maps

* Fix 'listening' var
  • Loading branch information
SpaceManiac authored and vuonojenmustaturska committed Aug 24, 2018
1 parent 4a10d41 commit 5ffd85b
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 43 deletions.
14 changes: 12 additions & 2 deletions code/__HELPERS/_lists.dm
Original file line number Diff line number Diff line change
Expand Up @@ -489,8 +489,18 @@
return l
. = l.Copy()
for(var/i = 1 to l.len)
if(islist(.[i]))
.[i] = .(.[i])
var/key = .[i]
if(isnum(key))
// numbers cannot ever be associative keys
continue
var/value = .[key]
if(islist(value))
value = deepCopyList(value)
.[key] = value
if(islist(key))
key = deepCopyList(key)
.[i] = key
.[key] = value

//takes an input_key, as text, and the list of keys already used, outputting a replacement key in the format of "[input_key] ([number_of_duplicates])" if it finds a duplicate
//use this for lists of things that might have the same name, like mobs or objects, that you plan on giving to a player as input
Expand Down
92 changes: 51 additions & 41 deletions code/modules/mapping/reader.dm
Original file line number Diff line number Diff line change
Expand Up @@ -409,57 +409,67 @@
//build a list from variables in text form (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7))
//return the filled list
/datum/parsed_map/proc/readlist(text as text, delimiter=",")

var/list/to_return = list()
. = list()
if (!text)
return

var/position
var/old_position = 1

do
//find next delimiter that is not within "..."
while(position != 0)
// find next delimiter that is not within "..."
position = find_next_delimiter_position(text,old_position,delimiter)

//check if this is a simple variable (as in list(var1, var2)) or an associative one (as in list(var1="foo",var2=7))
// check if this is a simple variable (as in list(var1, var2)) or an associative one (as in list(var1="foo",var2=7))
var/equal_position = findtext(text,"=",old_position, position)

var/trim_left = trim_text(copytext(text,old_position,(equal_position ? equal_position : position)),1)//the name of the variable, must trim quotes to build a BYOND compliant associatives list
var/trim_left = trim_text(copytext(text,old_position,(equal_position ? equal_position : position)))
var/left_constant = delimiter == ";" ? trim_left : parse_constant(trim_left)
old_position = position + 1

if(equal_position)//associative var, so do the association
var/trim_right = trim_text(copytext(text,equal_position+1,position))//the content of the variable

//Check for string
if(findtext(trim_right,"\"",1,2))
trim_right = copytext(trim_right,2,findtext(trim_right,"\"",3,0))

//Check for number
else if(isnum(text2num(trim_right)))
trim_right = text2num(trim_right)

//Check for null
else if(trim_right == "null")
trim_right = null

//Check for list
else if(copytext(trim_right,1,5) == "list")
trim_right = readlist(copytext(trim_right,6,length(trim_right)))

//Check for file
else if(copytext(trim_right,1,2) == "'")
trim_right = file(copytext(trim_right,2,length(trim_right)))

//Check for path
else if(ispath(text2path(trim_right)))
trim_right = text2path(trim_right)

to_return[trim_left] = trim_right

else//simple var
to_return[trim_left] = null

while(position != 0)

return to_return
if(equal_position && !isnum(left_constant))
// Associative var, so do the association.
// Note that numbers cannot be keys - the RHS is dropped if so.
var/trim_right = trim_text(copytext(text,equal_position+1,position))
var/right_constant = parse_constant(trim_right)
.[left_constant] = right_constant

else // simple var
. += list(left_constant)

/datum/parsed_map/proc/parse_constant(text)
// number
var/num = text2num(text)
if(isnum(num))
return num

// string
if(findtext(text,"\"",1,2))
return copytext(text,2,findtext(text,"\"",3,0))

// list
if(copytext(text,1,6) == "list(")
return readlist(copytext(text,6,length(text)))

// typepath
var/path = text2path(text)
if(ispath(path))
return path

// file
if(copytext(text,1,2) == "'")
return file(copytext(text,2,length(text)))

// null
if(text == "null")
return null

// not parsed:
// - pops: /obj{name="foo"}
// - new(), newlist(), icon(), matrix(), sound()

// fallback: string
return text

/datum/parsed_map/Destroy()
..()
Expand Down

0 comments on commit 5ffd85b

Please sign in to comment.