| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| |
| part of intl; |
| |
| /** |
| * A class for holding onto the data for a date so that it can be built |
| * up incrementally. |
| */ |
| class _DateBuilder { |
| // Default the date values to the EPOCH so that there's a valid date |
| // in case the format doesn't set them. |
| int year = 1970, |
| month = 1, |
| day = 1, |
| hour = 0, |
| minute = 0, |
| second = 0, |
| fractionalSecond = 0; |
| bool pm = false; |
| bool utc = false; |
| |
| // Functions that exist just to be closurized so we can pass them to a general |
| // method. |
| void setYear(x) { year = x; } |
| void setMonth(x) { month = x; } |
| void setDay(x) { day = x; } |
| void setHour(x) { hour = x; } |
| void setMinute(x) { minute = x; } |
| void setSecond(x) { second = x; } |
| void setFractionalSecond(x) { fractionalSecond = x; } |
| |
| /** |
| * Return a date built using our values. If no date portion is set, |
| * use the "Epoch" of January 1, 1970. |
| */ |
| DateTime asDate() { |
| // TODO(alanknight): Validate the date, especially for things which |
| // can crash the VM, e.g. large month values. |
| if (debugLogDateCreation) { |
| debugDateCreationLog |
| ..write(" Creating Date from\n") |
| ..write(" UTC: $utc\n") |
| ..write(" year: $year\n") |
| ..write(" month: $month\n") |
| ..write(" day: $day\n") |
| ..write(" pm: $pm\n") |
| ..write(" hour: $hour\n") |
| ..write(" minute: $minute\n") |
| ..write(" second: $second\n") |
| ..write(" fractionalSecond: $fractionalSecond\n"); |
| } |
| var result; |
| if (utc) { |
| result = new DateTime.utc( |
| year, |
| month, |
| day, |
| pm ? hour + 12 : hour, |
| minute, |
| second, |
| fractionalSecond); |
| } else { |
| result = new DateTime( |
| year, |
| month, |
| day, |
| pm ? hour + 12 : hour, |
| minute, |
| second, |
| fractionalSecond); |
| } |
| if (debugLogDateCreation) { |
| debugDateCreationLog |
| ..write("Created $result"); |
| } |
| return result; |
| } |
| } |
| |
| /** |
| * A simple and not particularly general stream class to make parsing |
| * dates from strings simpler. It is general enough to operate on either |
| * lists or strings. |
| */ |
| class _Stream { |
| var contents; |
| int index = 0; |
| |
| _Stream(this.contents); |
| |
| bool atEnd() => index >= contents.length; |
| |
| next() => contents[index++]; |
| |
| /** |
| * Return the next [howMany] items, or as many as there are remaining. |
| * Advance the stream by that many positions. |
| */ |
| read([howMany = 1]) { |
| var result = peek(howMany); |
| index += howMany; |
| return result; |
| } |
| |
| /** |
| * Return the next [howMany] items, or as many as there are remaining. |
| * Does not modify the stream position. |
| */ |
| peek([howMany = 1]) { |
| var result; |
| if (contents is String) { |
| result = contents.substring( |
| index, |
| min(index + howMany, contents.length)); |
| } else { |
| // Assume List |
| result = contents.sublist(index, index + howMany); |
| } |
| return result; |
| } |
| |
| /** Return the remaining contents of the stream */ |
| rest() => peek(contents.length - index); |
| |
| /** |
| * Find the index of the first element for which [f] returns true. |
| * Advances the stream to that position. |
| */ |
| int findIndex(Function f) { |
| while (!atEnd()) { |
| if (f(next())) return index - 1; |
| } |
| return null; |
| } |
| |
| /** |
| * Find the indexes of all the elements for which [f] returns true. |
| * Leaves the stream positioned at the end. |
| */ |
| List findIndexes(Function f) { |
| var results = []; |
| while (!atEnd()) { |
| if (f(next())) results.add(index - 1); |
| } |
| return results; |
| } |
| |
| /** |
| * Assuming that the contents are characters, read as many digits as we |
| * can see and then return the corresponding integer. Advance the stream. |
| */ |
| var digitMatcher = new RegExp(r'\d+'); |
| int nextInteger() { |
| var string = digitMatcher.stringMatch(rest()); |
| if (string == null || string.isEmpty) return null; |
| read(string.length); |
| return int.parse(string); |
| } |
| } |