#
# $Id: encode.icn,v 1.3 2006-07-10 13:43:32 rparlett Exp $
#
# This file is in the public domain.
#
# Author: Robert Parlett (parlett@dial.pipex.com)
#
package lang
import util
# Together with decode.icn, these functions provide a way to encode
# and decode arbitrary objects to and from strings. Class instances
# are handled specially, in that the instance must define how it is
# to be encoded/decoded by implementing the methods in {ClassCoding}.
# The {SelectiveClassCoding} class provides a flexible implementation of these
# methods, allowing selected member variables to be saved using
# independent tags. This allows the class to change considerably and
# still be backward-compatible with old encodings.
#
# @example
# @ import lang
# @ ...
# @ obj := ... any object ...
# @ s := lang::encode(obj)
# @ # s is now a string representation of obj
# @ obj2 := lang::decode(s)
# @ # now obj and obj2 should have the same value
#
#
# Return a string, being the encoded representation of the given object.
#
procedure encode(o)
local e
e := Encode()
e.encode(o)
return e.get_string()
end
#
# This class is used to encode arbitrary objects into strings.
#
# Classes to be encoded must subclass ClassCoding, which allows specification
# of how to encode a class instance.
#
class Encode : Object(
tag_count,
seen,
string_buff
)
method get_string()
return string_buff.get_string("|")
end
method encode_string(s)
local buff
static printable
initial
printable := ::cset(&ascii[33:128]) -- '|\\'
buff := StringBuff()
s ? {
repeat {
buff.add(::tab(::many(printable)))
if ::pos(0) then
return buff.get_string()
buff.add("\\" || ::right(::ord(::move(1)), 3, "0"))
}
}
end
method encode_record(o)
line_out(lang::get_name(o))
line_out(*o)
seen[o] := (tag_count +:= 1)
every encode(!o)
end
method encode(o)
local im, ty, i, pairs
if i := \seen[o] then {
line_out(i)
return
}
ty := lang::get_type(o)
line_out(ty)
case ty of {
"class" :
encode_class(o)
"record" :
encode_record(o)
"procedure" :
line_out(lang::get_name(o))
"null" :
&null
"string" :
line_out(encode_string(o))
"cset" :
line_out(encode_string(string(o)))
"integer" |
"real" :
line_out(string(o))
"set" |
"list" : {
line_out(*o)
seen[o] := (tag_count +:= 1)
every encode(!o)
}
"table" : {
seen[o] := (tag_count +:= 1)
encode(o[[]])
pairs := ::sort(o)
line_out(*pairs)
every encode(!!pairs)
}
default :
&null
}
end
method line_out(s)
string_buff.add(s)
end
method encode_class(o)
local cname, t, m, e
cname := lang::get_class_name(o) | ::stop("invalid class name")
line_out(cname)
seen[o] := (tag_count +:= 1)
o.pre_encode()
o.encode_obj(self)
end
initially()
tag_count := 0
seen := ::table()
string_buff := StringBuff()
end
This page produced by UniDoc on 2021/04/15 @ 23:59:43.