Pastey newget.e
- Posted by slowmaker
Apr 10, 2013
--****
-- == Input Routines
--
-- <>
--
--
namespace stdget
include std/error.e
with trace
include std/io.e
--****
-- === Error Status Constants
-- These are returned from [[:get]] and [[:value]].
public constant
GET_SUCCESS = 0,
GET_EOF = -1,
GET_FAIL = 1,
GET_NOTHING = -2
constant GET_TERMINATOR = 2
constant DIGITS = "0123456789",
HEX_DIGITS = DIGITS & "ABCDEF",
START_NUMERIC = DIGITS & "-+.#"
enum EXACT_LENGTH_REQUIRED, PLACE_LIMIT_IS_MAX
constant IGNORE_PLACE_LIMIT=#3fffffff
constant TRUE = 1
constant NO_CHAR_YET = -2
type natural(integer x)
return x >= 0
end type
type char(integer x)
return x >= -2 and x <= 255
end type
natural input_file -- file to be read from
object input_string -- string to be read from
natural string_next
integer first_ch_offset_this_iteration
char ch=NO_CHAR_YET -- the current character
procedure get_ch()
-- set ch to the next character in the input stream (either string or file)
if sequence(input_string) then
if string_next <= length(input_string) then
ch = input_string[string_next]
string_next += 1
else
ch = GET_EOF
end if
else
ch = getc(input_file)
if ch != GET_EOF then
string_next += 1
end if
end if
end procedure
constant WHITE_SPACE = " \t\n\r"
function skip_blanks()
-- skip white space
-- ch is "live" at entry and exit
integer white_count = 0
while find(ch, WHITE_SPACE) do
get_ch()
white_count += 1
end while
return white_count
end function
function chars_read()
return (string_next-1-first_ch_offset_this_iteration-(ch!=-1))
end function
constant ESCAPE_CHARS = "n'\"t\\reE0",
ESCAPED_CHARS = "\n'\"\t\\\r\e\E\0"
function escape_char(char c)
-- return escape character
natural i
i = find(c, ESCAPE_CHARS)
if i = 0 then
return GET_FAIL
else
return ESCAPED_CHARS[i]
end if
end function
function get_qchar()
-- get a single-quoted character
-- ch is "live" at exit
-- Note: had to beef up the 'c' var type, as the new '\u' and '\U' forms allow
-- the entry of characters with values beyond 255. - slowmaker
atom c, val=-2
get_ch()
c = ch
if ch = '\\' then
get_ch()
c = escape_char(ch)
if c = GET_FAIL then
switch ch do
case 'b' then
get_ch()
val = get_bin_val(8, EXACT_LENGTH_REQUIRED)
case 'x' then
get_ch()
val = get_hex_val(2,EXACT_LENGTH_REQUIRED)
case 'u' then
get_ch()
val = get_hex_val(4,EXACT_LENGTH_REQUIRED)
case 'U' then
get_ch()
val = get_hex_val(8,EXACT_LENGTH_REQUIRED)
end switch
if val < 0 then
return {GET_FAIL, 0}
end if
c = val
end if
elsif ch = '\'' then
return {GET_FAIL, 0}
end if
if val = -2 then -- didn't use the get_xxx_val() funcs, which had live ch on exit
get_ch()
end if
if ch != '\'' then
return {GET_FAIL, 0}
else
get_ch()
return {GET_SUCCESS, c}
end if
end function
function get_heredoc( sequence terminator )
-- In the process of updating get_heredoc() to ignore single leading/trailing
-- crlf's, filter out cr's, and do the indent thing, I uglied up the
-- original get_heredoc(), which was quite clean.
-- My apologies, but hey, it works (maybe...) -- slowmaker
--
sequence text = ""
integer ends_at = 1 - length( terminator )
integer trimcount = 0, trimchar = '_'
get_ch()
if ch = '\r' then
get_ch()
end if
if ch = '\n' then
get_ch()
end if
while ch = trimchar do
trimcount += 1
get_ch()
end while
while ends_at < 1 or not match( terminator, text, ends_at ) do
if ch = GET_EOF then
return { GET_FAIL, 0 }
end if
if ch != '\r' then
text &= ch
ends_at += 1
end if
if trimcount and ch = '\n' then
for i = 1 to trimcount+1 do
get_ch()
if (ch != ' ' and ch != '\t') or ch = GET_EOF then
exit
end if
end for
else
get_ch()
end if
end while
text = head( text, length(text) - length(terminator) )
if length(text) then
if text[$] = '\n' then
text = text[1..$-1]
end if
end if
return { GET_SUCCESS, text }
end function
function get_decimal_integer_val(integer place_limit = 3, integer length_restriction = PLACE_LIMIT_IS_MAX)
-- get value specified by decimal integer characters.
-- underscore allowed, stop on anything that is not decimal integer character or '_'.
-- ch live on return.
-- return integer value if successful
-- otherwise return -1
natural nplaces = 0
integer numeral = -1
atom accumulator = 0
while nplaces < place_limit do
if ch = GET_EOF then
exit
elsif ch !='_' then
numeral = find(ch, DIGITS) - 1
if numeral >=0 then
nplaces += 1
accumulator = accumulator*10 + numeral
else
exit
end if
end if
get_ch()
end while
if nplaces < 1 or (length_restriction = EXACT_LENGTH_REQUIRED and nplaces != place_limit) then
return -1
end if
return accumulator
end function
function get_octal_val(integer place_limit = 3, integer length_restriction = PLACE_LIMIT_IS_MAX)
-- get value specified by octal characters.
-- underscore allowed, stop on anything that is not octal character or '_'.
-- ch live on return.
-- return integer value if successful
-- otherwise return -1
natural nplaces = 0
integer numeral = -1
atom accumulator = 0
while nplaces < place_limit do
if ch = GET_EOF then
exit
elsif ch !='_' then
numeral = find(ch, DIGITS[1..8]) - 1
if numeral >=0 then
nplaces += 1
accumulator = accumulator*8 + numeral
else
exit
end if
end if
get_ch()
end while
if nplaces < 1 or (length_restriction = EXACT_LENGTH_REQUIRED and nplaces != place_limit) then
return -1
end if
return accumulator
end function
function get_hex_val(integer place_limit = 2, integer length_restriction = PLACE_LIMIT_IS_MAX)
-- get value specified by hex characters.
-- underscore allowed, stop on anything that is not hex character or '_'.
-- ch live on return.
-- return integer value if successful
-- otherwise return -1
natural nplaces = 0
integer numeral = -1
atom accumulator = 0
while nplaces < place_limit do
if ch = GET_EOF then
exit
elsif ch !='_' then
numeral = find(ch, HEX_DIGITS) - 1
if numeral < 0 then
-- case insensitive
numeral = find(and_bits(ch, 0b1101_1111), HEX_DIGITS, 10) - 1
end if
if numeral >=0 then
nplaces += 1
accumulator = accumulator*16 + numeral
else
exit
end if
end if
get_ch()
end while
if nplaces < 1 or (length_restriction = EXACT_LENGTH_REQUIRED and nplaces != place_limit) then
return -1
end if
return accumulator
end function
function get_xstring()
-- get a string specified as hex codes, of the form x"hh hh hh"
-- whitespace allowed, hex numerals allowed
-- underscore allowed
sequence text=""
integer char_val
get_ch()
if ch != '"' then
return { GET_FAIL, 0 }
end if
get_ch()
while TRUE do
if ch = GET_EOF then
return { GET_FAIL, 0 }
elsif ch = '"' then
get_ch()
exit
elsif not find(ch, WHITE_SPACE) and ch !='_' then
char_val = get_hex_val()
if char_val < 0 then
return { GET_FAIL, 0 }
else
text &= char_val
end if
else
get_ch()
end if
end while
return { GET_SUCCESS, text }
end function
function get_bin_val(integer place_limit = 8, integer length_restriction = PLACE_LIMIT_IS_MAX )
-- get value specified by binary characters.
-- underscore allowed, stop on anything that is not '0', '1', or '_'.
-- ch live on entry and exit.
-- return integer value if successful
-- otherwise return -1
natural nplaces = 0
integer numeral = -1, accumulator = 0
while nplaces < place_limit do
if ch = GET_EOF then
exit
elsif ch !='_' then
numeral = find(ch, DIGITS[1..2]) - 1
if numeral >=0 then
nplaces += 1
accumulator = accumulator*2 + numeral
else
exit
end if
end if
get_ch()
end while
if nplaces < 1 or (length_restriction = EXACT_LENGTH_REQUIRED and nplaces != place_limit) then
return -1
end if
return accumulator
end function
function get_bstring()
-- get a string specified as binary codes, of the form b"bbbb bbbb bbbb bbbb"
-- whitespace allowed, binary numeral chars allowed
-- underscore allowed
sequence text=""
integer char_val
get_ch()
if ch != '"' then
return { GET_FAIL, 0 }
end if
get_ch()
while TRUE do
if ch = GET_EOF then
return { GET_FAIL, 0 }
elsif ch = '"' then
get_ch()
exit
elsif not find(ch, WHITE_SPACE) and ch !='_' then
char_val = get_bin_val()
if char_val < 0 then
return { GET_FAIL, 0 }
else
text &= char_val
end if
else
get_ch()
end if
end while
return { GET_SUCCESS, text }
end function
function get_string()
-- get a double-quoted character string
-- ch is "live" at exit
sequence text
atom c, val=-2
text = ""
while TRUE do
if val=-2 then -- did NOT get extra char left dangling by get_xxxx_val()'s below
get_ch()
else
val = -2
end if
if ch = GET_EOF or ch = '\n' then
return {GET_FAIL, 0}
elsif ch = '"' then
get_ch()
if length( text ) = 0 then ----------- and ch = '"' then
if ch = '"' then
return get_heredoc( `"""` )
end if
end if
return {GET_SUCCESS, text}
elsif ch = '\\' then
get_ch()
c = escape_char(ch)
if c = GET_FAIL then
switch ch do
case 'b' then
get_ch()
val = get_bin_val(8, EXACT_LENGTH_REQUIRED)
case 'x' then
get_ch()
val = get_hex_val(2,EXACT_LENGTH_REQUIRED)
case 'u' then
get_ch()
val = get_hex_val(4,EXACT_LENGTH_REQUIRED)
case 'U' then
get_ch()
val = get_hex_val(8,EXACT_LENGTH_REQUIRED)
end switch
if val < 0 then
return {GET_FAIL, 0}
end if
c = val
end if
else
c = ch
end if
text = text & c
end while
end function
type plus_or_minus(integer x)
return x = -1 or x = +1
end type
constant GET_IGNORE = GET_NOTHING
function read_comment()
if atom(input_string) then
while ch!='\n' and ch!='\r' and ch!=-1 do
get_ch()
end while
get_ch()
if ch=-1 then
return {GET_EOF, 0}
else
return {GET_IGNORE, 0}
end if
else
for i=string_next to length(input_string) do
ch=input_string[i]
if ch='\n' or ch='\r' then
string_next=i+1
return {GET_IGNORE, 0}
end if
end for
return {GET_EOF, 0}
end if
end function
function read_block_comment()
while ch != -1 do
while ch!='*' and ch!=-1 do
get_ch()
end while
get_ch()
if ch = '/' then
get_ch()
skip_blanks()
return {GET_IGNORE, 0}
end if
end while
return {GET_EOF, 0}
end function
procedure get_num_ch()
while ch = '_' with entry do
entry
get_ch()
end while
end procedure
function get_number()
-- read a number or a comment
-- ch is "live" at entry and exit
plus_or_minus sign, e_sign
natural ndigits
integer hex_digit
atom mantissa, dec, e_mag
sign = +1
mantissa = 0
ndigits = 0
-- process sign
if ch = '-' then
sign = -1
get_ch()
if ch='-' then
return read_comment()
end if
elsif ch = '+' then
get_ch()
end if
-- get mantissa
if ch = '0' then
get_num_ch()
switch ch do
case 'b', 'B' then
--process binary integer and return
get_num_ch()
mantissa = get_bin_val(IGNORE_PLACE_LIMIT)
if mantissa < 0 then
return {GET_FAIL, 0}
else
return {GET_SUCCESS, sign * mantissa}
end if
case 'd', 'D' then
--process decimal integer and return
get_num_ch()
mantissa = get_decimal_integer_val(IGNORE_PLACE_LIMIT)
if mantissa < 0 then
return {GET_FAIL, 0}
else
return {GET_SUCCESS, sign * mantissa}
end if
case 't', 'T' then
--process octal integer and return
get_num_ch()
mantissa = get_octal_val(IGNORE_PLACE_LIMIT)
if mantissa < 0 then
return {GET_FAIL, 0}
else
return {GET_SUCCESS, sign * mantissa}
end if
case 'x', 'X' then
--process hex integer and return
get_num_ch()
mantissa = get_hex_val(IGNORE_PLACE_LIMIT)
if mantissa < 0 then
return {GET_FAIL, 0}
else
return {GET_SUCCESS, sign * mantissa}
end if
end switch
elsif ch = '#' then
-- process hex integer and return
get_num_ch()
mantissa = get_hex_val(IGNORE_PLACE_LIMIT)
if mantissa < 0 then
return {GET_FAIL, 0}
else
return {GET_SUCCESS, sign * mantissa}
end if
end if
-- decimal integer or floating point
while ch >= '0' and ch <= '9' do
ndigits += 1
mantissa = mantissa * 10 + (ch - '0')
get_num_ch()
end while
if ch = '.' then
-- get fraction
get_num_ch()
dec = 10
while ch >= '0' and ch <= '9' do
ndigits += 1
mantissa += (ch - '0') / dec
dec *= 10
get_num_ch()
end while
end if
if ndigits = 0 then
return {GET_FAIL, 0}
end if
mantissa = sign * mantissa
if ch = 'e' or ch = 'E' then
-- get exponent sign
e_sign = +1
e_mag = 0
get_num_ch()
if ch = '-' then
e_sign = -1
get_num_ch()
elsif ch = '+' then
get_num_ch()
end if
-- get exponent magnitude
if ch >= '0' and ch <= '9' then
e_mag = ch - '0'
get_num_ch()
while ch >= '0' and ch <= '9' do
e_mag = e_mag * 10 + ch - '0'
get_num_ch()
end while
else
return {GET_FAIL, 0} -- no exponent
end if
e_mag *= e_sign
if e_mag > 308 then
-- rare case: avoid power() overflow
mantissa *= power(10, 308)
if e_mag > 1000 then
e_mag = 1000
end if
for i = 1 to e_mag - 308 do
mantissa *= 10
end for
else
mantissa *= power(10, e_mag)
end if
end if
return {GET_SUCCESS, mantissa}
end function
integer leading_whitespace
function Get()
-- read a Euphoria data object as a string of characters
-- and return {error_flag, value}
-- Note: ch is "live" at entry and exit of this routine
sequence s, e
integer e1
-- init
skip_blanks()
if ch = -1 then -- string is made of whitespace only
return {GET_EOF, 0}
end if
while 1 do
if find(ch, START_NUMERIC) then
e = get_number()
if e[1] != GET_IGNORE then -- either a number or something illegal was read, so exit: the other goto
return e
end if -- else go read next item, starting at top of loop
skip_blanks()
if ch=-1 or ch='}' then -- '}' is expected only in the "{--\n}" case
return {GET_NOTHING, 0} -- just a comment
end if
elsif ch = '/' then
get_ch()
if ch = '*' then
e = read_block_comment()
if e[1] != GET_IGNORE then
return e
end if
else
return {GET_FAIL, 0}
end if
elsif ch = '{' then
-- process a sequence
s = {}
get_ch()
skip_blanks()
if ch = '}' then -- empty sequence
get_ch()
return {GET_SUCCESS, s} -- empty sequence
end if
while TRUE do -- read: comment(s), element, comment(s), comma and so on till it terminates or errors out
while 1 do -- read zero or more comments and an element
e = Get() -- read next element, using standard function
e1 = e[1]
if e1 = GET_SUCCESS then
s = append(s, e[2])
exit -- element read and added to result
elsif e1 = GET_TERMINATOR then
if ch = '}' then
get_ch()
return {GET_SUCCESS, s}
else
return {GET_FAIL, 0}
end if
elsif e1 != GET_IGNORE then
return e
-- else it was a comment, keep going
elsif ch='}' then
get_ch()
return {GET_SUCCESS, s} -- empty sequence
end if
end while
while 1 do -- now read zero or more post element comments
skip_blanks()
if ch = '}' then
get_ch()
return {GET_SUCCESS, s}
elsif ch = '/' then
get_ch()
if ch = '*' then
e = read_block_comment()
if e[1] != GET_IGNORE then
return {GET_FAIL, 0}
end if
else
return {GET_FAIL, 0}
end if
elsif ch!='-' then
exit
else -- comment starts after item and before comma
e = get_number() -- reads anything starting with '-'
if e[1] != GET_IGNORE then -- it wasn't a comment, this is illegal
return {GET_FAIL, 0}
end if
-- read next comment or , or }
end if
end while
if ch != ',' then
return {GET_FAIL, 0}
end if
get_ch() -- skip comma
end while
elsif ch = '\"' then
return get_string()
elsif ch = '`' then
return get_heredoc("`")
elsif ch = 'x' then
return get_xstring()
elsif ch = 'b' then
return get_bstring()
elsif ch = '\'' then
return get_qchar()
elsif ch = '$' then
get_ch()
skip_blanks()
return {GET_TERMINATOR, 0}
else
return {GET_FAIL, 0}
end if
end while
end function
function get_verbose()
-- read a Euphoria data object as a string of characters
-- and return {error_flag, value, total number of characters, leading whitespace}
-- Note: ch is "live" at entry and exit of this routine.
integer lost_whitespace = 0, no_gap_adjust = 0
-- init
first_ch_offset_this_iteration = string_next-1
if find(ch, WHITE_SPACE) then
lost_whitespace = 1
get_ch()
elsif ch = NO_CHAR_YET then
get_ch()
elsif ch = GET_EOF then
-- do nothing
return {GET_EOF,0,0,0}
else -- object starting immediately after another
no_gap_adjust = 1
end if
leading_whitespace = skip_blanks() + lost_whitespace
return Get() & {chars_read()+lost_whitespace+no_gap_adjust, leading_whitespace}
end function
--****
-- === Answer Types
public constant
GET_SHORT_ANSWER = routine_id("Get"),
GET_LONG_ANSWER = routine_id("get_verbose")
function get_value(object target, integer start_point, integer answer_type)
if answer_type != GET_SHORT_ANSWER and answer_type != GET_LONG_ANSWER then
error:crash("Invalid type of answer, please only use %s (the default) or %s.", {"GET_SHORT_ANSWER", "GET_LONG_ANSWER"})
end if
if atom(target) then -- get()
input_file = target
if start_point then
-- pulled the sum out of the seek call below
-- for debugging purposes
start_point = io:where(target) + start_point
if io:seek(target, start_point) then
error:crash("Initial seek() for get() failed!")
end if
ch = NO_CHAR_YET
end if
string_next = 1
input_string = 0
else
if start_point = 1 then
-- always treat as first call when start point is 1
ch = NO_CHAR_YET
end if
input_string = target
string_next = start_point + (ch != NO_CHAR_YET)
end if
if answer_type = GET_SHORT_ANSWER then
get_ch()
end if
object val = call_func(answer_type, {})
if val[1] = GET_TERMINATOR then
val[1] = GET_FAIL
end if
return val
end function
--****
-- === Routines
--
--**
-- Input, from an open file, a human-readable string of characters representing a Euphoria object.
-- Convert the string into the numeric value of that object.
--
-- Parameters:
-- # ##file## : an integer, the handle to an open file from which to read
-- # ##offset## : an integer, an offset to apply to file position before reading. Defaults to 0.
-- # ##answer## : an integer, either ##GET_SHORT_ANSWER## (the default) or ##GET_LONG_ANSWER##.
--
-- Returns:
-- A **sequence**, of length 2 (##GET_SHORT_ANSWER##) or 4 (##GET_LONG_ANSWER##), made of
--
-- * an integer, the return status. This is any of:
-- ** ##GET_SUCCESS## ~-- object was read successfully
-- ** ##GET_EOF## ~-- end of file before object was read completely
-- ** ##GET_FAIL## ~-- object is not syntactically correct
-- ** ##GET_NOTHING## ~-- nothing was read, even a partial object string, before end of input
-- * an object, the value that was read. This is valid only if return status is ##GET_SUCCESS##.
-- * an integer, the number of characters read. On an error, this is the point at which the
-- error was detected.
-- * an integer, the amount of initial whitespace read before the first active character was found
--
-- Comments:
-- When ##answer## is not specified, or explicitly ##GET_SHORT_ANSWER##, only the first two
-- elements in the returned sequence are actually returned.
--
-- The ##GET_NOTHING## return status will not be returned if ##answer## is ##GET_SHORT_ANSWER##.
--
-- ##get()## can read arbitrarily complicated Euphoria objects. You
-- could have a long sequence of values in braces and separated by
-- commas and comments, e.g. ##{23, {49, 57}, 0.5, -1, 99, 'A', "john"}##.
-- A single call to get() will read in this entire sequence and return its value as a result,
-- as well as complementary information.
--
-- If a nonzero offset is supplied, it is interpreted as an offset to the current file
-- position, and the file will be seek()ed there first.
--
-- ##get()## returns a 2 or 4 element sequence, like ##[[:value]]()## does:
--
-- * a status code (success/error/end of file/no value at all)
-- * the value just read (meaningful only when the status code is ##GET_SUCCESS##)
-- (optionally)
-- * the total number of characters read
-- * the amount of initial whitespace read.
--
-- Using the default value for answer, or setting it to ##GET_SHORT_ANSWER##, returns 2 elements.
-- Setting it to ##GET_LONG_ANSWER## causes 4 elements to be returned.
--
-- Each call to ##get()## picks up where the previous call left off. For instance, a series of 5
-- calls to ##get()## would be needed to read in
--
-- {{{
-- "99 5.2 {1, 2, 3} "Hello" -1"
-- }}}
--
-- On the sixth and any subsequent call to ##get()## you would see a ##GET_EOF## status. If you had
-- something like
--
-- {{{
-- {1, 2, xxx}
-- }}}
--
-- in the input stream you would see a ##GET_FAIL## error status because xxx is not a Euphoria
-- object. And seeing
--
-- {{{
-- -- something\nBut no value
-- }}}
--
-- and the input stream stops right there, you'll receive a status code of ##GET_NOTHING##,
-- because nothing but whitespace or comments was read. If you had opted for a short answer,
-- you'd get ##GET_EOF## instead.
--
-- Multiple "top-level" objects in the input stream must be
-- separated from each other with one or more "whitespace"
-- characters (blank, tab, \r or \n). At the very least, a top
-- level number must be followed by a white space from the following object.
-- Whitespace is not necessary //within// a top-level object. Comments, terminated by either
-- '\n' or '\r', are allowed anywhere inside sequences, and ignored if at the top level.
-- A call to ##get()## will read one entire top-level object, plus possibly one additional
-- (whitespace) character, after a top level number, even though the next object may have an
-- identifiable starting point.
--
-- The combination of ##[[:print]]()## and ##get()## can be used to save a
-- Euphoria object to disk and later read it back. This technique
-- could be used to implement a database as one or more large
-- Euphoria sequences stored in disk files. The sequences could be
-- read into memory, updated and then written back to disk after
-- each series of transactions is complete. Remember to write out
-- a whitespace character (using ##[[:puts]]()##) after each call to ##[[:print]]()##,
-- at least when a top level number was just printed.
--
-- The value returned is not meaningful unless you have a ##GET_SUCCESS## status.
--
-- Example 1:
--
-- -- If he types 77.5, get(0) would return:
-- {GET_SUCCESS, 77.5}
--
-- -- whereas gets(0) would return:
-- "77.5\n"
--
--
-- Example 2:
-- See ##bin\mydata.ex##
--
-- See Also:
-- [[:value]]
public function get(integer file, integer offset=0, integer answer=GET_SHORT_ANSWER)
-- Read the string representation of a Euphoria object
-- from a file. Convert to the value of the object.
-- Return {error_status, value}.
-- Embedded comments inside sequences are now supported.
return get_value(file, offset, answer)
end function
--**
-- Read, from a string, a human-readable string of characters representing a Euphoria object.
-- Convert the string into the numeric value of that object.
--
-- Parameters:
-- # ##st## : a sequence, from which to read text
-- # ##offset## : an integer, the position at which to start reading. Defaults to 1.
-- # ##answer## : an integer, either GET_SHORT_ANSWER (the default) or GET_LONG_ANSWER.
--
-- Returns:
-- A **sequence**, of length 2 (GET_SHORT_ANSWER) or 4 (GET_LONG_ANSWER), made of
--
-- * an integer, the return status. This is any of
-- ** ##GET_SUCCESS## ~-- object was read successfully
-- ** ##GET_EOF## ~-- end of file before object was read completely
-- ** ##GET_FAIL## ~-- object is not syntactically correct
-- ** ##GET_NOTHING## ~-- nothing was read, even a partial object string, before end of input
-- * an object, the value that was read. This is valid only if return status is ##GET_SUCCESS##.
-- * an integer, the number of characters read. On an error, this is the point at which the
-- error was detected.
-- * an integer, the amount of initial whitespace read before the first active character was found
--
-- Comments:
-- When ##answer## is not specified, or explicitly ##GET_SHORT_ANSWER##, only the first two
-- elements in the returned sequence are actually returned.
--
-- This works the same as [[:get]](), but it reads from a string that you supply, rather than
-- from a file or device.
--
-- After reading one valid representation of a Euphoria object, ##value()## will stop reading
-- and ignore any additional characters in the string. For example, "36" and "36P" will
-- both give you ##{GET_SUCCESS, 36}##.
--
-- The function returns ##{return_status, value}## if the answer type is not passed or set to
-- ##GET_SHORT_ANSWER##. If set to ##GET_LONG_ANSWER##, the number of characters read and the
-- amount of leading whitespace are returned in 3rd and 4th position. The ##GET_NOTHING## return
-- status can occur only on a long answer.
--
-- Example 1:
--
-- s = value("12345"}
-- s is {GET_SUCCESS, 12345}
--
--
-- Example 2:
--
-- s = value("{0, 1, -99.9}")
-- -- s is {GET_SUCCESS, {0, 1, -99.9}}
--
--
-- Example 3:
--
-- s = value("+++")
-- -- s is {GET_FAIL, 0}
--
--
-- See Also:
-- [[:get]]
public function value(sequence st, integer start_point=1, integer answer=GET_SHORT_ANSWER)
-- Read the representation of a Euphoria object
-- from a sequence of characters. Convert to the value of the object.
-- Trailing whitespace or comments are not considered.
-- Return {error_status, value}.
-- Embedded comments inside sequence are now supported.
return get_value(st, start_point, answer)
end function
--**
-- Perform a value() operation on a sequence, returning the value on success or
-- the default on failure.
--
-- Parameters:
-- # ##st## : object to retrieve value from.
-- # ##def## : the value returned if ##st## is an atom or ##value(st)## fails.
-- # ##start_point## : an integer, the position in ##st## at which to start
-- getting the value from. Defaults to 1
--
-- Returns:
-- * If ##st##, is an atom then ##def## is returned.
-- * If ##value(st)##, call is a success, then ##value()[2]##, otherwise it will return
-- the parameter #def#.
--
-- Examples:
--
-- object i = defaulted_value("10", 0)
-- -- i is 10
--
-- i = defaulted_value("abc", 39)
-- -- i is 39
--
-- i = defaulted_value(12, 42)
-- -- i is 42
--
-- i = defaulted_value("{1,2}", 42)
-- -- i is {1,2}
--
--
-- See Also:
-- [[:value]]
--
public function defaulted_value(object st, object def, integer start_point=1)
if atom(st) then
return def
end if
object result = get_value(st,start_point, GET_SHORT_ANSWER)
if result[1] = GET_SUCCESS then
return result[2]
end if
return def
end function