📄 lispformat.java
字号:
package gnu.kawa.functions;import gnu.text.*;import gnu.lists.*;import java.text.Format;import java.text.FieldPosition;import java.text.ParseException;import java.io.Writer;import gnu.math.*;import gnu.mapping.OutPort;/** A representation of a parsed Common Lisp-style format. */public class LispFormat extends CompoundFormat{ public static final String paramFromList = "<from list>"; public static final String paramFromCount = "<from count>"; public static final String paramUnspecified = "<unspecified>"; public LispFormat(char[] format, int offset, int length) throws ParseException { super(null, 0); // The index in spec of the most recent ~{, ~(, ~{ or ~[. int start_nesting = -1; int choices_seen = 0; // Number of "~;" seen. StringBuffer litbuf = new StringBuffer(100); java.util.Stack stack = new java.util.Stack(); int limit = offset + length; int i = offset; for (;;) { if ((i >= limit || format[i] == '~') && litbuf.length() > 0) { stack.push(new LiteralFormat(litbuf)); litbuf.setLength(0); } if (i >= limit) break; char ch = format[i++]; if (ch != '~') { litbuf.append(ch); continue; } int speci = stack.size(); ch = format[i++]; for (;;) { if (ch == '#') { stack.push(paramFromCount); ch = format[i++]; } else if (ch == 'v' || ch == 'V') { stack.push(paramFromList); ch = format[i++]; } else if (ch == '-' || Character.digit(ch, 10) >= 0) { boolean neg = (ch == '-'); if (neg) ch = format[i++]; int val = 0; int start = i; for (;;) { int dig = Character.digit(ch, 10); if (dig < 0) break; val = 10 * val + dig; ch = format[i++]; } stack.push(i - start < 8 ? IntNum.make(neg ? - val : val) : IntNum.valueOf(format, start, i-start, 10, neg)); } else if (ch == '\'') { stack.push(Char.make(format[i++])); ch = format[i++]; } else if (ch == ',') { stack.push(paramUnspecified); } else break; if (ch != ',') break; ch = format[i++]; } boolean seenColon = false; boolean seenAt = false; for (;;) { if (ch == ':') seenColon = true; else if (ch == '@') seenAt = true; else break; ch = format[i++]; } ch = Character.toUpperCase(ch); int numParams = stack.size() - speci; Format fmt; int minWidth, padChar, charVal, param1, param2, param3, count; switch (ch) { case 'R': case 'D': case 'O': case 'B': case 'X': int argstart = speci; int base; if (ch == 'R') base = getParam(stack, argstart++); else if (ch == 'D') base = 10; else if (ch == 'O') base = 8; else if (ch == 'X') base = 16; else base = 2; minWidth = getParam(stack, argstart); padChar = getParam(stack, argstart+1); int commaChar = getParam(stack, argstart+2); int commaInterval = getParam(stack, argstart+3); int flags = 0; if (seenColon) flags |= IntegerFormat.SHOW_GROUPS; if (seenAt) flags |= IntegerFormat.SHOW_PLUS; fmt = IntegerFormat.getInstance(base, minWidth, padChar, commaChar, commaInterval, flags); break; case 'P': fmt = LispPluralFormat.getInstance(seenColon, seenAt); break; case 'E': case 'F': case 'G': case '$': LispRealFormat dfmt = new LispRealFormat(); dfmt.op = ch; dfmt.arg1 = getParam(stack, speci); dfmt.arg2 = getParam(stack, speci+1); dfmt.arg3 = getParam(stack, speci+2); dfmt.arg4 = getParam(stack, speci+3); if (ch != '$') { dfmt.arg5 = getParam(stack, speci+4); if (ch == 'E' || ch == 'G') { dfmt.arg6 = getParam(stack, speci+5); dfmt.arg7 = getParam(stack, speci+6); } } dfmt.showPlus = seenAt; dfmt.internalPad = seenColon; if (dfmt.argsUsed == 0) fmt = dfmt.resolve(null, 0); else fmt = dfmt; break; case 'A': case 'S': case 'W': case 'Y': // SRFI-48 "yuppify" (pretty-print) // We don't distinguish between ~S and ~W. FIXME. fmt = ObjectFormat.getInstance(ch != 'A'); if (numParams > 0) { minWidth = getParam(stack, speci); int colInc = getParam(stack, speci+1); int minPad = getParam(stack, speci+2); padChar = getParam(stack, speci+3); fmt = new LispObjectFormat((ReportFormat) fmt, minWidth, colInc, minPad, padChar, seenAt ? 0 : 100); } break; case 'C': charVal = numParams > 0 ? getParam(stack, speci) : PARAM_FROM_LIST; fmt = LispCharacterFormat.getInstance(charVal, 1, seenAt, seenColon); break; case '*': fmt = new LispRepositionFormat(getParam(stack, speci), seenColon, seenAt); break; case '(': ch = seenColon ? (seenAt ? 'U' : 'C') : (seenAt ? 'T': 'L'); CaseConvertFormat cfmt = new CaseConvertFormat(null, ch); stack.setSize(speci); stack.push(cfmt); stack.push(IntNum.make(start_nesting)); start_nesting = speci; continue; case ')': if (start_nesting < 0 || ! (stack.elementAt(start_nesting) instanceof CaseConvertFormat)) throw new ParseException("saw ~) without matching ~(", i); cfmt = (CaseConvertFormat) stack.elementAt(start_nesting); cfmt.setBaseFormat(popFormats(stack, start_nesting + 2, speci)); start_nesting = ((IntNum) stack.pop()).intValue(); continue; case '?': LispIterationFormat lfmt = new LispIterationFormat(); lfmt.seenAt = seenAt; lfmt.maxIterations = 1; lfmt.atLeastOnce = true; fmt = lfmt; break; case '{': lfmt = new LispIterationFormat(); lfmt.seenAt = seenAt; lfmt.seenColon = seenColon; lfmt.maxIterations = getParam(stack, speci); stack.setSize(speci); stack.push(lfmt); stack.push(IntNum.make(start_nesting)); start_nesting = speci; continue; case '}': if (start_nesting < 0 || ! (stack.elementAt(start_nesting) instanceof LispIterationFormat)) throw new ParseException("saw ~} without matching ~{", i); lfmt = (LispIterationFormat) stack.elementAt(start_nesting); lfmt.atLeastOnce = seenColon; if (speci > start_nesting + 2) lfmt.body = popFormats(stack, start_nesting + 2, speci); start_nesting = ((IntNum) stack.pop()).intValue(); continue; case '<': LispPrettyFormat pfmt = new LispPrettyFormat(); pfmt.seenAt = seenAt; if (seenColon) { pfmt.prefix = "("; pfmt.suffix = ")"; } else { pfmt.prefix = ""; pfmt.suffix = ""; } stack.setSize(speci); stack.push(pfmt); stack.push(IntNum.make(start_nesting)); stack.push(IntNum.make(choices_seen)); start_nesting = speci; choices_seen = 0; continue; case '>': if (start_nesting < 0 || ! (stack.elementAt(start_nesting) instanceof LispPrettyFormat)) throw new ParseException("saw ~> without matching ~<", i); fmt = popFormats(stack, start_nesting + 3 + choices_seen, speci); stack.push(fmt); pfmt = (LispPrettyFormat) stack.elementAt(start_nesting); pfmt.segments = getFormats(stack, start_nesting + 3, stack.size()); stack.setSize(start_nesting + 3); start_nesting = ((IntNum) stack.pop()).intValue(); start_nesting = ((IntNum) stack.pop()).intValue(); if (seenColon) { // Logical Block for pretty-printing int nsegments = pfmt.segments.length; if (nsegments > 3) throw new ParseException("too many segments in Logical Block format", i); if (nsegments >= 2) { if (! (pfmt.segments[0] instanceof LiteralFormat)) throw new ParseException("prefix segment is not literal", i); pfmt.prefix = ((LiteralFormat) pfmt.segments[0]).content(); pfmt.body = pfmt.segments[1]; } else pfmt.body = pfmt.segments[0]; if (nsegments >=3) { if (! (pfmt.segments[2] instanceof LiteralFormat)) throw new ParseException("suffix segment is not literal", i); pfmt.suffix = ((LiteralFormat) pfmt.segments[2]).content(); } } else // Justification throw new ParseException("not implemented: justfication i.e. ~<...~>", i); continue; case '[': LispChoiceFormat afmt = new LispChoiceFormat(); afmt.param = getParam(stack, speci); if (afmt.param == PARAM_UNSPECIFIED) afmt.param = PARAM_FROM_LIST; if (seenColon) afmt.testBoolean = true; if (seenAt) afmt.skipIfFalse = true; stack.setSize(speci); stack.push(afmt); stack.push(IntNum.make(start_nesting)); stack.push(IntNum.make(choices_seen)); start_nesting = speci; choices_seen = 0; continue; case ';': if (start_nesting >= 0) { if (stack.elementAt(start_nesting) instanceof LispChoiceFormat) { afmt = (LispChoiceFormat) stack.elementAt(start_nesting); if (seenColon) afmt.lastIsDefault = true; fmt = popFormats(stack, start_nesting + 3 + choices_seen, speci); stack.push(fmt); choices_seen++; continue; } else if (stack.elementAt(start_nesting) instanceof LispPrettyFormat) { pfmt = (LispPrettyFormat) stack.elementAt(start_nesting); if (seenAt) pfmt.perLine = true; fmt = popFormats(stack, start_nesting + 3 + choices_seen, speci); stack.push(fmt); choices_seen++; continue; } // else if saw ~< ... } throw new ParseException("saw ~; without matching ~[ or ~<", i); case ']': if (start_nesting < 0 || ! (stack.elementAt(start_nesting) instanceof LispChoiceFormat)) throw new ParseException("saw ~] without matching ~[", i); fmt = popFormats(stack, start_nesting + 3 + choices_seen, speci); stack.push(fmt); afmt = (LispChoiceFormat) stack.elementAt(start_nesting); afmt.choices = getFormats(stack, start_nesting + 3, stack.size()); stack.setSize(start_nesting + 3); choices_seen = ((IntNum) stack.pop()).intValue(); start_nesting = ((IntNum) stack.pop()).intValue(); continue; case '^': param1 = getParam(stack, speci); param2 = getParam(stack, speci+1); param3 = getParam(stack, speci+2); fmt = new LispEscapeFormat(param1, param2, param3); break; case '\n': if (seenAt) litbuf.append(ch); if (! seenColon) { while (i < limit) { ch = format[i++]; if (! Character.isWhitespace(ch)) { i--; break; } } } continue; case '!': fmt = FlushFormat.getInstance(); break; case 'T': param1 = getParam(stack, speci); param2 = getParam(stack, speci+1); param3 = getParam(stack, speci+2); fmt = new LispTabulateFormat(param1, param2, param3, seenAt); break; case '&': param1 = getParam(stack, speci); fmt = new LispFreshlineFormat(param1); break; case 'I': // Indent param1 = getParam(stack, speci); if (param1 == PARAM_UNSPECIFIED) param1 = 0; fmt = LispIndentFormat.getInstance(param1, seenColon); break; case '_': // conditional newline param1 = getParam(stack, speci); if (param1 == PARAM_UNSPECIFIED) param1 = 1; charVal = seenColon && seenAt ? '\n' : ' '; int kind; if (seenAt && seenColon) kind = PrettyWriter.NEWLINE_MANDATORY; else if (seenAt) kind = PrettyWriter.NEWLINE_MISER; else if (seenColon) kind = PrettyWriter.NEWLINE_FILL; else kind = PrettyWriter.NEWLINE_LINEAR; fmt = LispNewlineFormat.getInstance(param1, kind); break; case '~': if (numParams == 0) { litbuf.append(ch); continue; } /* ... otherwise fall through ... */ case '|': count = getParam(stack, speci); if (count == PARAM_UNSPECIFIED) count = 1; // EXTENSION: Allow repeating other characters than '~'. charVal = getParam(stack, speci+1); if (charVal == PARAM_UNSPECIFIED) charVal = ch == '|' ? '\f' : '~'; fmt = LispCharacterFormat.getInstance(charVal, count, false, false); break; case '%': count = getParam(stack, speci); if (count == PARAM_UNSPECIFIED) count = 1; fmt = LispNewlineFormat.getInstance(count, PrettyWriter.NEWLINE_LITERAL); break; default: throw new ParseException("unrecognized format specifier ~"+ch, i); } stack.setSize(speci); stack.push(fmt); } if (i > limit) throw new IndexOutOfBoundsException(); if (start_nesting >= 0) { throw new ParseException("missing ~] or ~}", i); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -