Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/parley.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ on:
- 'CodenameOne/src/com/codename1/call/**'
- 'CodenameOne/src/com/codename1/webrtc/**'
- 'Ports/JavaSE/src/com/codename1/impl/javase/webrtc/**'
# The iOS side of WebRTC: the bridge and the builder that decides how
# it compiles (it needs -fobjc-arc for the framework's __weak headers).
# The iOS job is the only place a WebRTC app is compiled for a device.
- 'Ports/iOSPort/nativeSources/CN1WebRTC.m'
- 'maven/build-engine/src/main/java/com/codename1/builders/IPhoneBuilder.java'
- 'CodenameOne/src/com/codename1/io/oidc/**'
- 'CodenameOne/src/com/codename1/io/rest/**'
# The REST client maps its responses through the mapper registry.
Expand Down
2 changes: 1 addition & 1 deletion CodenameOne/src/com/codename1/impl/FileDialogSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public void run() {
d.placeButtonCommands(new Command[]{cancel, open});
Command picked = d.showAtPosition(2, 2, 2, 2, true);
String[] paths = tree.getSelectedPaths();
if (picked == open && paths.length > 0) {
if (picked == open && paths.length > 0) { //NOPMD CompareObjectsWithEquals
deliver(new FileDialogResult(request, paths, -1, null), callback);
} else {
deliver(FileDialogResult.cancelled(request), callback);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7673,9 +7673,16 @@ && conditionCovers(governingKey,

}

// CN1WebRTC.m compiles under either memory model, but the
// WebRTC framework headers it imports declare __weak
// properties, which clang rejects in a file built with
// ARC off ("cannot create __weak reference in file using
// manual reference counting") -- so every WebRTC app
// failed to compile until it was given -fobjc-arc too.
String arcPhaseFixScript =
usesCn1Vision || usesCn1Language || usesCn1Inference
? " arc_sources = ['CN1Vision.m', 'CN1Language.m', 'CN1Inference.m']\n"
|| usesWebRtc
? " arc_sources = ['CN1Vision.m', 'CN1Language.m', 'CN1Inference.m', 'CN1WebRTC.m']\n"
+ " main_target.source_build_phase.files.each do |bf|\n"
+ " ref = bf.file_ref\n"
+ " name = ref && File.basename(ref.path || ref.name || '')\n"
Expand Down
6 changes: 5 additions & 1 deletion maven/dart-runtime/src/main/java/dart/core/DartList.java
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,11 @@ public void sortDefault() {
sort((Funcs.Func2<E, E, Long>) null);
}

public DartIterable<E> reversed() {
/// Dart's `List.reversed`. Not named `reversed()`: Java 21 added
/// `List.reversed()` returning a `List`, and Android's platform jar (API 35+)
/// carries it, so a method of that name returning an `Iterable` fails to
/// compile in every generated Android project.
public DartIterable<E> reversedIterable() {
DartList<E> self = this;
return DartIterable.wrap(() -> new java.util.Iterator<E>() {
// Dart's ListIterator: the length at creation, checked on every step, so
Expand Down
152 changes: 135 additions & 17 deletions maven/dart-runtime/src/main/java/dart/core/DateTime.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,128 @@ public static DateTime utc(long year, long month, long day, long hour, long minu
}

/// Dart's own grammar for DateTime.parse: an ISO 8601 date, an optional time
/// after `T` or a space, an optional fraction, and an optional `Z` or offset.
private static final java.util.regex.Pattern ISO = java.util.regex.Pattern.compile(
"^([+-]?\\d{4,6})-?(\\d\\d)-?(\\d\\d)(?:[ T](\\d\\d)(?::?(\\d\\d)(?::?(\\d\\d)(?:[.,](\\d+))?)?)?"
+ "( ?[zZ]| ?([-+])(\\d\\d)(?::?(\\d\\d))?)?)?$");
/// after `T` or a space, an optional fraction, and an optional `Z` or offset --
/// as a regular expression,
/// `^([+-]?\d{4,6})-?(\d\d)-?(\d\d)(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d+))?)?)?( ?[zZ]| ?([-+])(\d\d)(?::?(\d\d))?)?)?$`.
///
/// Matched by hand rather than with a regex engine: `java.util.regex` does not
/// exist on ParparVM, and `com.codename1.util.regex` would add its whole engine
/// to every Flutter app for one date format. Answers the expression's eleven
/// groups (index 0 unused, an unmatched group null), or null for no match.
/// `DateTimeIsoGrammarTest` holds it to the expression above.
static String[] isoGroups(String s) {
// Only the year's length needs backtracking: \d{4,6} is greedy and the
// month may follow it with no separator. Everything after the year is
// deterministic -- every optional part starts with a character nothing
// else could consume at that point.
int start = s.length() > 0 && (s.charAt(0) == '+' || s.charAt(0) == '-') ? 1 : 0;
for (int len = 6; len >= 4; len--) {
String[] g = isoAfterYear(s, start, len);
if (g != null) {
return g;
}
}
return null;
}

private static String[] isoAfterYear(String s, int start, int yearDigits) {
int n = s.length();
int i = start + yearDigits;
if (!digits(s, start, yearDigits)) {
return null;
}
String[] g = new String[12];
g[1] = s.substring(0, i);
if (i < n && s.charAt(i) == '-') {
i++;
}
if (!digits(s, i, 2)) {
return null;
}
g[2] = s.substring(i, i + 2);
i += 2;
if (i < n && s.charAt(i) == '-') {
i++;
}
if (!digits(s, i, 2)) {
return null;
}
g[3] = s.substring(i, i + 2);
i += 2;
if (i == n) {
return g;
}
char sep = s.charAt(i);
if ((sep != ' ' && sep != 'T') || !digits(s, i + 1, 2)) {
return null;
}
g[4] = s.substring(i + 1, i + 3);
i += 3;
int at = colonDigits(s, i);
if (at >= 0) {
g[5] = s.substring(at - 2, at);
i = at;
at = colonDigits(s, i);
if (at >= 0) {
g[6] = s.substring(at - 2, at);
i = at;
if (i < n && (s.charAt(i) == '.' || s.charAt(i) == ',') && digits(s, i + 1, 1)) {
int e = i + 1;
while (e < n && isDigit(s.charAt(e))) {
e++;
}
g[7] = s.substring(i + 1, e);
i = e;
}
}
}
if (i == n) {
return g;
}
int z = i;
if (s.charAt(i) == ' ') {
i++;
}
if (i < n && (s.charAt(i) == 'z' || s.charAt(i) == 'Z')) {
g[8] = s.substring(z, i + 1);
return i + 1 == n ? g : null;
}
if (i >= n || (s.charAt(i) != '+' && s.charAt(i) != '-') || !digits(s, i + 1, 2)) {
return null;
}
g[9] = s.substring(i, i + 1);
g[10] = s.substring(i + 1, i + 3);
int e = colonDigits(s, i + 3);
if (e >= 0) {
g[11] = s.substring(e - 2, e);
} else {
e = i + 3;
}
g[8] = s.substring(z, e);
return e == n ? g : null;
}

/// `:?(\d\d)` at `i`: the index after it, or -1.
private static int colonDigits(String s, int i) {
int j = i < s.length() && s.charAt(i) == ':' ? i + 1 : i;
return digits(s, j, 2) ? j + 2 : -1;
}

private static boolean digits(String s, int from, int count) {
if (from + count > s.length()) {
return false;
}
for (int k = from; k < from + count; k++) {
if (!isDigit(s.charAt(k))) {
return false;
}
}
return true;
}

private static boolean isDigit(char c) {
return c >= '0' && c <= '9';
}

/// `DateTime.parse`: a value with a `Z` or an offset is UTC, anything else local.
public static DateTime parse(String formattedString) {
Expand All @@ -84,19 +202,19 @@ public static DateTime tryParse(String formattedString) {
if (formattedString == null) {
return null;
}
java.util.regex.Matcher m = ISO.matcher(formattedString);
if (!m.matches()) {
String[] g = isoGroups(formattedString);
if (g == null) {
return null;
}
long year = Long.parseLong(m.group(1).startsWith("+") ? m.group(1).substring(1) : m.group(1));
long month = Long.parseLong(m.group(2));
long day = Long.parseLong(m.group(3));
long hour = num(m.group(4));
long minute = num(m.group(5));
long second = num(m.group(6));
long year = Long.parseLong(g[1].startsWith("+") ? g[1].substring(1) : g[1]);
long month = Long.parseLong(g[2]);
long day = Long.parseLong(g[3]);
long hour = num(g[4]);
long minute = num(g[5]);
long second = num(g[6]);
long milli = 0;
long micro = 0;
String frac = m.group(7);
String frac = g[7];
if (frac != null) {
String six = (frac + "000000").substring(0, 6);
long all = Long.parseLong(six);
Expand All @@ -108,13 +226,13 @@ public static DateTime tryParse(String formattedString) {
// A well-formed date outside DateTime's range is still unparseable: tryParse
// answers null (and parse a FormatException), never the constructor's error.
try {
if (m.group(8) == null) {
if (g[8] == null) {
return new DateTime(year, month, day, hour, minute, second, milli, micro);
}
DateTime u = utc(year, month, day, hour, minute, second, milli, micro);
if (m.group(9) != null) {
long offset = num(m.group(10)) * 60 + num(m.group(11));
long sign = m.group(9).equals("-") ? -1 : 1;
if (g[9] != null) {
long offset = num(g[10]) * 60 + num(g[11]);
long sign = g[9].equals("-") ? -1 : 1;
long at = u.epochMicros - sign * offset * 60000000L;
checkMicrosRange(at);
return new DateTime(at, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1723,7 +1723,7 @@ public void reversedThrowsWhenTheListChangesLengthMidLoop() {
grow.add(1L);
grow.add(2L);
assertThrows(ConcurrentModificationError.class, () -> {
for (Long v : grow.reversed()) {
for (Long v : grow.reversedIterable()) {
grow.add(v);
}
});
Expand All @@ -1733,15 +1733,15 @@ public void reversedThrowsWhenTheListChangesLengthMidLoop() {
shrink.add(3L);
// Shrinking used to read past the new end instead.
assertThrows(ConcurrentModificationError.class, () -> {
for (Long v : shrink.reversed()) {
for (Long v : shrink.reversedIterable()) {
shrink.removeLast();
}
});
DartList<Long> same = new DartList<Long>();
same.add(1L);
same.add(2L);
StringBuilder seen = new StringBuilder();
for (Long v : same.reversed()) {
for (Long v : same.reversedIterable()) {
same.set(0, v);
seen.append(v);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package dart.core;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.jupiter.api.Test;

/// `DateTime.isoGroups` matches Dart's DateTime.parse grammar by hand, because the
/// device has no `java.util.regex`. The JVM running this test does, so the hand
/// matcher is held to the expression itself: same match, same eleven groups.
class DateTimeIsoGrammarTest {
private static final Pattern ISO = Pattern.compile(
"^([+-]?\\d{4,6})-?(\\d\\d)-?(\\d\\d)(?:[ T](\\d\\d)(?::?(\\d\\d)(?::?(\\d\\d)(?:[.,](\\d+))?)?)?"
+ "( ?[zZ]| ?([-+])(\\d\\d)(?::?(\\d\\d))?)?)?$");

private static final String[] PIECES = {
"0", "1", "2", "9", "12", "2024", "-", "+", ":", " ", "T", "Z", "z", ".", ",", "x", "01", "30"
};

private static void check(String s) {
Matcher m = ISO.matcher(s);
String[] got = DateTime.isoGroups(s);
if (!m.matches()) {
assertEquals(null, got == null ? null : "matched", s);
return;
}
String[] want = new String[12];
for (int g = 1; g <= 11; g++) {
want[g] = m.group(g);
}
assertArrayEquals(want, got, s);
}

@Test
void knownForms() {
String[] cases = {
"2024-01-15", "20240115", "2024-01-15T10", "2024-01-15T10Z", "2024-01-15 10:30",
"2024-01-15T1030", "2024-01-15T10:30:00", "2024-01-15T103000.5", "2024-01-15T10:30:00,123456789",
"2024-01-15T10:30:00Z", "2024-01-15T10:30:00 z", "2024-01-15T10:30+05:30", "2024-01-15T10:30 -0800",
"2024-01-15T10:30:00-08", "+123456-01-01T00:00:00.5z", "-002024-01-15", "2024012", "202401155",
"2024-1-15", "2024-01-15T", "2024-01-15T10:", "2024-01-15T10:30:00.", "2024-01-15Z",
"2024-01-15T10:30:00Zjunk", "2024-01-15T10+0", "", "x", "+", "1234567-01-01"
};
for (String s : cases) {
check(s);
}
}

@Test
void randomStrings() {
Random r = new Random(42);
for (int i = 0; i < 200000; i++) {
StringBuilder sb = new StringBuilder();
if (r.nextInt(3) == 0) {
sb.append("2024-01-15T10:30");
}
int parts = r.nextInt(8);
for (int p = 0; p < parts; p++) {
sb.append(PIECES[r.nextInt(PIECES.length)]);
}
check(sb.toString());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5922,7 +5922,7 @@ private Out emitMemberGet(Out target, String name, Node posNode, Ctx ctx) {
return new Out(target.code + ".last()", elem);
}
if (name.equals("reversed")) {
return new Out(target.code + ".reversed()", TypeRef.of("Iterable", elem));
return new Out(target.code + ".reversedIterable()", TypeRef.of("Iterable", elem));
}
}
if (tt.is("Map")) {
Expand Down
20 changes: 20 additions & 0 deletions scripts/flutter-bench/baseline/pr/6082.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"pr": 6082,
"rebaseline": {
"javascript": {
"gallery": {
"code_bytes": {
"from": {
"tolerance": {
"value": 0.005
},
"value": 13418004
},
"reason": "JavaScript Flutter bench has not built since #6055 (java.util.regex absent on ParparVM); master's nightly size predates #6055's Dart runtime. This PR restores the build; the +0.59% is that runtime. DateTime is parsed by hand, no regex engine added.",
"runs": 1,
"value": 13497605
}
}
}
}
}
Loading