source: branches/0.19.x/abcl/src/org/armedbear/lisp/LispCharacter.java

Last change on this file was 12513, checked in by ehuelsmann, 15 years ago

Remove 'private' keyword to eliminate the Java requirement

for the compiler to generate synthetic accessors: functions that
don't appear in the source but do appear in the class file.

Patch by: Douglas Miles <dmiles _at_ users.sf.net>

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.0 KB
Line 
1/*
2 * LispCharacter.java
3 *
4 * Copyright (C) 2002-2007 Peter Graves
5 * $Id: LispCharacter.java 12513 2010-03-02 22:35:36Z ehuelsmann $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import static org.armedbear.lisp.Lisp.*;
37import java.util.HashMap;
38import java.util.Map;
39
40public final class LispCharacter extends LispObject
41{
42  public static final LispCharacter[] constants;
43  public static final CharHashMap<LispCharacter> lispChars;
44
45  static
46  {
47    lispChars = new CharHashMap<LispCharacter>(LispCharacter.class,null){
48      public LispCharacter get(char c) {
49        LispCharacter lc = super.get(c);
50        if (lc==null) {
51          lc = new LispCharacter(c);
52          put(c, lc);
53        }
54        return lc;
55      }
56    };
57    constants = lispChars.constants;
58    for (int i = constants.length; i-- > 0;)
59      constants[i] = new LispCharacter((char)i);
60  }
61
62  public final char value;
63  private String name;
64  public static LispCharacter getInstance(char c)
65  {
66    try
67      {
68        return lispChars.get(c);
69      }
70    catch (ArrayIndexOutOfBoundsException e)
71      {
72        return new LispCharacter(c);
73      }
74  }
75
76  // This needs to be public for the compiler.
77  public LispCharacter(char c)
78  {
79    this.value = c;
80  }
81
82  @Override
83  public LispObject typeOf()
84  {
85    if (isStandardChar())
86      return Symbol.STANDARD_CHAR;
87    return Symbol.CHARACTER;
88  }
89
90  @Override
91  public LispObject classOf()
92  {
93    return BuiltInClass.CHARACTER;
94  }
95
96  @Override
97  public LispObject getDescription()
98  {
99    StringBuilder sb = new StringBuilder("character #\\");
100    sb.append(value);
101    sb.append(" char-code #x");
102    sb.append(Integer.toHexString(value));
103    return new SimpleString(sb);
104  }
105
106  @Override
107  public LispObject typep(LispObject type)
108  {
109    if (type == Symbol.CHARACTER)
110      return T;
111    if (type == BuiltInClass.CHARACTER)
112      return T;
113    if (type == Symbol.BASE_CHAR)
114      return T;
115    if (type == Symbol.STANDARD_CHAR)
116      return isStandardChar() ? T : NIL;
117    return super.typep(type);
118  }
119
120  @Override
121  public boolean characterp()
122  {
123    return true;
124  }
125
126  @Override
127  public LispObject STRING()
128  {
129    return new SimpleString(value);
130  }
131
132  boolean isStandardChar()
133  {
134    if (value >= ' ' && value < 127)
135      return true;
136    if (value == '\n')
137      return true;
138    return false;
139  }
140
141  @Override
142  public boolean eql(char c)
143  {
144    return value == c;
145  }
146
147  @Override
148  public boolean eql(LispObject obj)
149  {
150    if (this == obj)
151      return true;
152    if (obj instanceof LispCharacter)
153      {
154        if (value == ((LispCharacter)obj).value)
155          return true;
156      }
157    return false;
158  }
159
160  @Override
161  public boolean equal(LispObject obj)
162  {
163    if (this == obj)
164      return true;
165    if (obj instanceof LispCharacter)
166      {
167        if (value == ((LispCharacter)obj).value)
168          return true;
169      }
170    return false;
171  }
172
173  @Override
174  public boolean equalp(LispObject obj)
175  {
176    if (this == obj)
177      return true;
178    if (obj instanceof LispCharacter)
179      {
180        if (value == ((LispCharacter)obj).value)
181          return true;
182        return LispCharacter.toLowerCase(value) == LispCharacter.toLowerCase(((LispCharacter)obj).value);
183      }
184    return false;
185  }
186
187  public static char getValue(LispObject obj)
188  {       
189          if (obj instanceof LispCharacter)
190        return ((LispCharacter)obj).value;
191      type_error(obj, Symbol.CHARACTER);
192        // Not reached.
193      return 0;
194  }
195
196  public final char getValue()
197  {
198    return value;
199  }
200
201  @Override
202  public Object javaInstance()
203  {
204    return Character.valueOf(value);
205  }
206
207  @Override
208  public Object javaInstance(Class c)
209  {
210    return javaInstance();
211  }
212
213  @Override
214  public int sxhash()
215  {
216    return value;
217  }
218
219  @Override
220  public int psxhash()
221  {
222    return Character.toUpperCase(value);
223  }
224
225  /** See LispObject.getStringValue() */
226  @Override
227  public String getStringValue()
228  {
229    return String.valueOf(value);
230  }
231
232  @Override
233  public final String writeToString()
234  {
235    final LispThread thread = LispThread.currentThread();
236    boolean printReadably = (Symbol.PRINT_READABLY.symbolValue(thread) != NIL);
237    // "Specifically, if *PRINT-READABLY* is true, printing proceeds as if
238    // *PRINT-ESCAPE*, *PRINT-ARRAY*, and *PRINT-GENSYM* were also true,
239    // and as if *PRINT-LENGTH*, *PRINT-LEVEL*, and *PRINT-LINES* were
240    // false."
241    boolean printEscape =
242      printReadably || (Symbol.PRINT_ESCAPE.symbolValue(thread) != NIL);
243    StringBuilder sb = new StringBuilder();
244    if (printEscape)
245      {
246        sb.append("#\\");
247        switch (value)
248          {
249          case 0:
250            sb.append("Null");
251            break;
252          case 7:
253            sb.append("Bell");
254            break;
255          case '\b':
256            sb.append("Backspace");
257            break;
258          case '\t':
259            sb.append("Tab");
260            break;
261          case '\n':
262            sb.append("Newline");
263            break;
264          case '\f':
265            sb.append("Page");
266            break;
267          case '\r':
268            sb.append("Return");
269            break;
270          case 27:
271            sb.append("Escape");
272            break;
273          case 127:
274            sb.append("Rubout");
275            break;
276    default:
277      if (name!=null)
278              sb.append(name);
279      else
280              sb.append(value);
281            break;
282          }
283      }
284    else
285      {
286        sb.append(value);
287      }
288    return sb.toString();
289  }
290
291  // ### character
292  private static final Primitive CHARACTER =
293    new Primitive(Symbol.CHARACTER, "character")
294    {
295      @Override
296      public LispObject execute(LispObject arg)
297      {
298        if (arg instanceof LispCharacter)
299          return arg;
300        if (arg instanceof AbstractString)
301          {
302            if (arg.length() == 1)
303              return ((AbstractString)arg).AREF(0);
304          }
305        else if (arg instanceof Symbol)
306          {
307            String name = ((Symbol)arg).getName();
308            if (name.length() == 1)
309              return LispCharacter.getInstance(name.charAt(0));
310          }
311        return type_error(arg, Symbol.CHARACTER_DESIGNATOR);
312      }
313    };
314
315  // ### whitespacep
316  private static final Primitive WHITESPACEP =
317    new Primitive("whitespacep", PACKAGE_SYS, true)
318    {
319      @Override
320      public LispObject execute(LispObject arg)
321      {
322          return Character.isWhitespace(LispCharacter.getValue(arg)) ? T : NIL;
323      }
324    };
325
326  // ### char-code
327  private static final Primitive CHAR_CODE =
328    new Primitive(Symbol.CHAR_CODE, "character")
329    {
330      @Override
331      public LispObject execute(LispObject arg)
332      {
333          int n = LispCharacter.getValue(arg);
334          return Fixnum.getInstance(n);
335      }
336    };
337
338  // ### char-int
339  private static final Primitive CHAR_INT =
340    new Primitive(Symbol.CHAR_INT, "character")
341    {
342      @Override
343      public LispObject execute(LispObject arg)
344      {
345          int n = LispCharacter.getValue(arg);
346          return Fixnum.getInstance(n);
347      }
348    };
349
350  // ### code-char
351  private static final Primitive CODE_CHAR =
352    new Primitive(Symbol.CODE_CHAR, "code")
353    {
354      @Override
355      public LispObject execute(LispObject arg)
356      {
357          int n = Fixnum.getValue(arg);
358          if (n < CHAR_MAX)
359            return lispChars.get((char)n);
360          else if (n <= Character.MAX_VALUE)
361            return new LispCharacter((char)n);
362              // SBCL signals a type-error here: "not of type (UNSIGNED-BYTE 8)"
363        return NIL;
364      }
365    };
366
367  // ### characterp
368  private static final Primitive CHARACTERP =
369    new Primitive(Symbol.CHARACTERP, "object")
370    {
371      @Override
372      public LispObject execute(LispObject arg)
373      {
374        return arg instanceof LispCharacter ? T : NIL;
375      }
376    };
377
378  // ### both-case-p
379  private static final Primitive BOTH_CASE_P =
380    new Primitive(Symbol.BOTH_CASE_P, "character")
381    {
382      @Override
383      public LispObject execute(LispObject arg)
384      {
385        char c = getValue(arg);
386        if (Character.isLowerCase(c) || Character.isUpperCase(c))
387          return T;
388        return NIL;
389      }
390    };
391
392  // ### lower-case-p
393  private static final Primitive LOWER_CASE_P =
394    new Primitive(Symbol.LOWER_CASE_P, "character")
395    {
396      @Override
397      public LispObject execute(LispObject arg)
398      {
399        return Character.isLowerCase(getValue(arg)) ? T : NIL;
400      }
401    };
402
403  // ### upper-case-p
404  private static final Primitive UPPER_CASE_P =
405    new Primitive(Symbol.UPPER_CASE_P, "character")
406    {
407      @Override
408      public LispObject execute(LispObject arg)
409      {
410        return Character.isUpperCase(getValue(arg)) ? T : NIL;
411      }
412    };
413
414  // ### char-downcase
415  private static final Primitive CHAR_DOWNCASE =
416    new Primitive(Symbol.CHAR_DOWNCASE, "character")
417    {
418      @Override
419      public LispObject execute(LispObject arg)
420      {
421          final char c = LispCharacter.getValue(arg);
422          if (c < 128)
423           return constants[LOWER_CASE_CHARS[c]];
424        return LispCharacter.getInstance(toLowerCase(c));
425      }
426    };
427
428  // ### char-upcase
429  private static final Primitive CHAR_UPCASE =
430    new Primitive(Symbol.CHAR_UPCASE, "character")
431    {
432      @Override
433      public LispObject execute(LispObject arg)
434      {
435        final char c;
436        c = LispCharacter.getValue(arg);
437        if (c < 128)
438          return constants[UPPER_CASE_CHARS[c]];
439        return LispCharacter.getInstance(toUpperCase(c));
440      }
441    };
442
443  // ### digit-char
444  private static final Primitive DIGIT_CHAR =
445    new Primitive(Symbol.DIGIT_CHAR, "weight &optional radix")
446    {
447      @Override
448      public LispObject execute(LispObject arg)
449      {
450          if (arg instanceof Bignum)
451              return NIL;
452
453          int weight = Fixnum.getValue(arg);
454        if (weight < 10)
455          return constants['0'+weight];
456        return NIL;
457      }
458      @Override
459      public LispObject execute(LispObject first, LispObject second)
460
461      {
462        int radix;
463        if (second instanceof Fixnum)
464            radix = ((Fixnum)second).value;
465        else
466            radix = -1;
467       
468        if (radix < 2 || radix > 36)
469          return type_error(second,
470                                 list(Symbol.INTEGER, Fixnum.TWO,
471                                       Fixnum.constants[36]));
472        if (first instanceof Bignum)
473            return NIL;
474        int weight = Fixnum.getValue(first);
475        if (weight >= radix)
476          return NIL;
477        if (weight < 10)
478          return constants['0' + weight];
479        return constants['A' + weight - 10];
480      }
481    };
482
483  // ### digit-char-p char &optional radix => weight
484  private static final Primitive DIGIT_CHAR_P =
485    new Primitive(Symbol.DIGIT_CHAR_P, "char &optional radix")
486    {
487      @Override
488      public LispObject execute(LispObject arg)
489      {
490          final int n = Character.digit(LispCharacter.getValue(arg), 10);
491          return n < 0 ? NIL : Fixnum.getInstance(n);
492      }
493      @Override
494      public LispObject execute(LispObject first, LispObject second)
495
496      {
497        char c;
498            c = LispCharacter.getValue(first);
499        if (second instanceof Fixnum)
500          {
501            int radix = ((Fixnum)second).value;
502            if (radix >= 2 && radix <= 36)
503              {
504                int n = Character.digit(c, radix);
505                return n < 0 ? NIL : Fixnum.constants[n];
506              }
507          }
508        return type_error(second,
509                               list(Symbol.INTEGER, Fixnum.TWO,
510                                     Fixnum.constants[36]));
511      }
512    };
513
514  // ### standard-char-p
515  private static final Primitive STANDARD_CHAR_P =
516    new Primitive(Symbol.STANDARD_CHAR_P, "character")
517    {
518      @Override
519      public LispObject execute(LispObject arg)
520      {
521          return checkCharacter(arg).isStandardChar() ? T : NIL;
522      }
523    };
524
525  // ### graphic-char-p
526  private static final Primitive GRAPHIC_CHAR_P =
527    new Primitive(Symbol.GRAPHIC_CHAR_P, "char")
528    {
529      @Override
530      public LispObject execute(LispObject arg)
531      {
532          char c = LispCharacter.getValue(arg);
533          if (c >= ' ' && c < 127)
534            return T;
535          return Character.isISOControl(c) ? NIL : T;
536      }
537    };
538
539  // ### alpha-char-p
540  private static final Primitive ALPHA_CHAR_P =
541    new Primitive(Symbol.ALPHA_CHAR_P, "character")
542    {
543      @Override
544      public LispObject execute(LispObject arg)
545      {
546          return Character.isLetter(LispCharacter.getValue(arg)) ? T : NIL;
547      }
548    };
549
550  // ### alphanumericp
551  private static final Primitive ALPHANUMERICP =
552    new Primitive(Symbol.ALPHANUMERICP, "character")
553    {
554      @Override
555      public LispObject execute(LispObject arg)
556      {
557          return Character.isLetterOrDigit(LispCharacter.getValue(arg)) ? T : NIL;
558      }
559    };
560
561  public static final int nameToChar(String s)
562  {
563    String lower = s.toLowerCase();
564    LispCharacter lc = namedToChar.get(lower);
565    if (lc!=null) return lc.value;
566    if (lower.equals("null"))
567      return 0;
568    if (lower.equals("bell"))
569      return 7;
570    if (lower.equals("backspace"))
571      return '\b';
572    if (lower.equals("tab"))
573      return '\t';
574    if (lower.equals("linefeed"))
575      return '\n';
576    if (lower.equals("newline"))
577      return '\n';
578    if (lower.equals("page"))
579      return '\f';
580    if (lower.equals("return"))
581      return '\r';
582    if (lower.equals("escape"))
583        return 27;
584    if (lower.equals("space"))
585      return ' ';
586    if (lower.equals("rubout"))
587      return 127;
588    // Unknown.
589    return -1;
590  }
591
592  // ### name-char
593  private static final Primitive NAME_CHAR =
594    new Primitive(Symbol.NAME_CHAR, "name")
595    {
596      @Override
597      public LispObject execute(LispObject arg)
598      {
599        String s = arg.STRING().getStringValue();
600        int n = nameToChar(s);
601        return n >= 0 ? LispCharacter.getInstance((char)n) : NIL;
602      }
603    };
604
605  public static final String charToName(char c)
606  {
607    switch (c)
608      {
609      case 0:
610        return "Null";
611      case 7:
612        return "Bell";
613      case '\b':
614        return "Backspace";
615      case '\t':
616        return "Tab";
617      case '\n':
618        return "Newline";
619      case '\f':
620        return "Page";
621      case '\r':
622        return "Return";
623      case 27:
624        return "Escape";
625      case ' ':
626        return "Space";
627      case 127:
628        return "Rubout";
629      }
630    if (c<0 || c>255) return null;
631    return lispChars.get(c).name;
632  }
633
634  // ### char-name
635  private static final Primitive CHAR_NAME =
636    new Primitive(Symbol.CHAR_NAME, "character")
637    {
638      @Override
639      public LispObject execute(LispObject arg)
640      {
641        String name = charToName(LispCharacter.getValue(arg));
642        return name != null ? new SimpleString(name) : NIL;
643      }
644    };
645
646  public static final char toUpperCase(char c)
647  {
648    if (c < 128)
649      return UPPER_CASE_CHARS[c];
650    return Character.toUpperCase(c);
651  }
652
653  static int maxNamedChar = 0; 
654  static Map<String, LispCharacter> namedToChar = new HashMap<String, LispCharacter>(); 
655 
656  static void setCharNames(int i, String[] string) { 
657    int settingChar = i; 
658    int index = 0; 
659    int stringLen = string.length; 
660    while(stringLen-->0) { 
661      setCharName(settingChar,string[index]); 
662      index++; 
663      settingChar++; 
664    } 
665    if (maxNamedChar<settingChar) maxNamedChar = settingChar; 
666  } 
667 
668  static void setCharName(int settingChar, String string) { 
669    LispCharacter c = lispChars.get((char)settingChar); 
670    c.name = string; 
671    namedToChar.put(string.toLowerCase(), c); 
672  } 
673   
674  static { 
675   new CharNameMaker0(); 
676  } 
677   
678  static class CharNameMaker0{ 
679    { 
680      setCharNames(0,new String[]{"Null", "Soh", "Stx", "Etx", "Eot", "Enq", "Ack", "Bell", "Backspace", "Tab", "Newline", "Vt", "Page", "Return", "So", "Si", "Dle", "Dc1", "Dc2", "Dc3", "Dc4", "Nak", "Syn", "Etb", "Can", "Em", "Sub", "Escape", "Fs", "Gs", "Rs", "Us"}); 
681      setCharNames(128,new String[]{"U0080", "U0081", "U0082", "U0083", "U0084", "U0085", "U0086", "U0087", "U0088", "U0089", "U008a", "U008b", "U008c", "U008d", "U008e", "U008f", "U0090", "U0091", "U0092", "U0093", "U0094", "U0095", "U0096", "U0097", "U0098", "U0099", "U009a", "U009b", "U009c", "U009d", "U009e", "U009f"}); 
682    } 
683  } 
684
685  static final char[] UPPER_CASE_CHARS = new char[128];
686
687  static
688  {
689    for (int i = UPPER_CASE_CHARS.length; i-- > 0;)
690      UPPER_CASE_CHARS[i] = Character.toUpperCase((char)i);
691  }
692
693  public static final char toLowerCase(char c)
694  {
695    if (c < 128)
696      return LOWER_CASE_CHARS[c];
697    return Character.toLowerCase(c);
698  }
699
700  static final char[] LOWER_CASE_CHARS = new char[128];
701
702  static
703  {
704    for (int i = LOWER_CASE_CHARS.length; i-- > 0;)
705      LOWER_CASE_CHARS[i] = Character.toLowerCase((char)i);
706  }
707}
Note: See TracBrowser for help on using the repository browser.