-- Copyright 1993-1998, by the Cecil Project -- Department of Computer Science and Engineering, University of Washington -- See the LICENSE file for license information. (--DOC Cecil characters are pretty standard. The `parse_as_int' methods convert digits (such as `'0'' ... `'9'') to integer equivalents. --) -- methods for character objects extend char isa ordered_hashable[char]; -- ascii conversion behavior method from_ascii(i@:int):char { from_ascii(i, { error("not a legal ascii code") }) } method from_ascii(i@:int, if_error:&():char):char { ascii_chars.fetch(i, if_error) } private let ascii_chars:i_vector[char] := new_i_vector_init[char](256, &(i:int){ internal_from_ascii(i) }); private method internal_from_ascii(i@:int):char { prim rtl: "decl int ch := unbox_int i; decl OOP chrOop := box_char ch; return chrOop;" } --DOCSHORT convert between characters and integer ASCII codes method ascii_code(c@:char):int { prim rtl: "decl int code := unbox_char c; decl OOP codeOop := box_int code; return codeOop;" } -- character testing behavior method =(l@:char,r@:char):bool { l.ascii_code = r.ascii_code } method <(l@:char,r@:char):bool { l.ascii_code < r.ascii_code } -- this is an optimization to avoid separate = and < calls: method <=(l@:char,r@:char):bool { l.ascii_code <= r.ascii_code } method is_lower_case(c@:char):bool { c >= 'a' & { c <= 'z' } } method is_upper_case(c@:char):bool { c >= 'A' & { c <= 'Z' } } method is_letter(c@:char):bool { c.is_lower_case | { c.is_upper_case } } method is_digit(c@:char):bool { c >= '0' & { c <= '9' } } method is_digit(c@:char, base:int):bool { if(base = 10, { ^ c.is_digit }); -- a quickie optimization if(base < 10, { ^ c >= '0' & { c <= from_ascii('0'.ascii_code + base) } }); assert(base <= 36, "base too big to handle"); c.is_digit | { let l:char := c.to_lower_case; l >= 'a' & { l <= from_ascii('a'.ascii_code + (base - 10)) } } } method is_hex_digit(c@:char):bool { c.is_digit | { c >= 'a' & { c <= 'f' } | { c >= 'A' & { c <= 'F' } } } } method is_printable(c@:char):bool { c.ascii_code >= 32 & { c.ascii_code < 127 } } -- The hash(@vstring, @int) primitive in specialized.cecil depends on the -- definition of character hashing being c.ascii_code % range. If you -- change this, go fix the primitive to do the right thing. method hash(c@:char, range:int):int { c.ascii_code % range } -- character conversion behavior --DOCSHORT convert to a string of a single character method as_string(c@:char):string { strings!c.ascii_code } private let strings:i_vector[string] := new_i_vector_init[string](256, &(i:int){ new_i_vstring(1, from_ascii(i)) }); method to_lower_case(c@:char):char { if(c.is_upper_case, { from_ascii(c.ascii_code - 'A'.ascii_code + 'a'.ascii_code) }, { c }) } method to_upper_case(c@:char):char { if(c.is_lower_case, { from_ascii(c.ascii_code - 'a'.ascii_code + 'A'.ascii_code) }, { c }) } method parse_as_int(c@:char):int { assert(c.is_digit, "should be a digit"); c.ascii_code - '0'.ascii_code } method parse_as_int(c@:char, base:int):int { if(c.is_digit, { ^ c.parse_as_int }); assert(c.is_digit(base), "should be a digit"); -- c must be a letter c.to_lower_case.ascii_code - 'a'.ascii_code + 10 } method parse_as_int(c@:char, fail@closure:&():int):int { if_false(c.is_digit, { ^ eval(fail) }); c.ascii_code - '0'.ascii_code } method parse_as_int(c@:char, base:int, fail@closure:&():int):int { if(c.is_digit, { ^ c.parse_as_int }); if_false(c.is_digit(base), { ^ eval(fail) }); -- c must be a letter c.to_lower_case.ascii_code - 'a'.ascii_code + 10 } -- printing behavior method print_string(c@:char):string { "'" || as_string(c) || "'" }