Skip to content

Instantly share code, notes, and snippets.

@sma
Created January 28, 2024 09:39
Show Gist options
  • Save sma/d45556007f351f1d2b569114d13b1fdf to your computer and use it in GitHub Desktop.
Save sma/d45556007f351f1d2b569114d13b1fdf to your computer and use it in GitHub Desktop.
/// Parses a plist file into a Dart object.
dynamic parsePlist(String plist) {
final tokens = RegExp(r'(\s+|<[!?].*?>)|<(/?\w+)[^>]*>|([^<]*)', dotAll: true)
.allMatches(plist)
.where((match) => match[1] == null)
.map((match) => match[2] != null ? (1, match[2]!) : (2, match[3]!))
.followedBy([(0, '')]).iterator
..moveNext();
bool at(String s) => tokens.current == (1, s) && tokens.moveNext();
bool expect(String s) => at(s) || (throw 'Expected <$s>, got ${tokens.current}');
T andExpect<T>(T Function() f, String s) {
final result = f();
expect(s);
return result;
}
String text() {
final (t, s) = tokens.current;
if (t != 2) throw 'Expected text, got ${tokens.current}';
tokens.moveNext();
return s.replaceAll('&amp;', '&').replaceAll('&lt;', '<');
}
dynamic parse() {
if (at('dict')) {
return andExpect(() => <String, dynamic>{for (; at('key');) andExpect(text, '/key'): parse()}, '/dict');
} else if (at('array')) {
return <dynamic>[for (; !at('/array');) parse()];
} else if (at('string')) {
return at('/string') ? '' : andExpect(text, '/string');
} else {
throw 'Expected dict, array or string, got ${tokens.current}';
}
}
expect('plist');
return andExpect(parse, '/plist');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment