blob: ec7cf27bb935048562401fc203e8a5d07c992999 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(https://fxbug.dev/84961): Fix null safety and remove this language version.
// @dart=2.9
class BasicGnParser {
List<String> imports;
Map<String, dynamic> assignedVariables;
List<String> parseErrors;
BasicGnParser(List gnJson) {
imports = [];
assignedVariables = {};
parseErrors = [];
_parse(gnJson);
}
static String parseIdentifier(Map el) {
if (el['type'] != 'IDENTIFIER') {
throw UnsupportedError('Element must be of type IDENTIFIER: $el');
}
return el['value'];
}
static String parseLiteral(Map el) {
if (el['type'] != 'LITERAL') {
throw UnsupportedError('Element must be of type LITERAL: $el');
}
var value = el['value'];
// remove leading and trailing quotes, faster than regex:
int start = 0, end = value.length;
if (end > 0 && (value[start] == '\'' || value[start] == '"')) {
start++;
}
if ((end - start) > 0 &&
(value[end - 1] == '\'' || value[end - 1] == '"')) {
end--;
}
return value.substring(start, end);
}
static List<String> parseListOfLiterals(Map listEl) {
if (listEl['type'] != 'LIST') {
throw UnsupportedError('Element must be of type LIST: $listEl');
}
List<String> result = [];
for (var el in listEl['child']) {
result.add(parseLiteral(el));
}
return result;
}
static dynamic parseLiterals(Map el) {
String type = el['type'];
if (type != 'LITERAL' && type != 'LIST') {
throw UnsupportedError('Element must be of type LITERAL or LIST: $el');
}
if (type == 'LITERAL') {
return parseLiteral(el);
} else {
return parseListOfLiterals(el);
}
}
void _parseAssigment(Map el) {
if (el['type'] != 'BINARY') {
throw UnsupportedError('Element must be of type BINARY: $el');
}
String id = parseIdentifier(el['child'][0]);
dynamic value = parseLiterals(el['child'][1]);
bool append = el['value'] == '+=';
if (append) {
dynamic previous = assignedVariables[id] ?? [];
if (previous is! List) {
previous = [previous];
}
if (value is List) {
previous.addAll(List<String>.from(value));
} else {
previous.add(value);
}
value = previous;
}
assignedVariables[id] = value;
}
void _parseFunction(Map el) {
if (el['type'] != 'FUNCTION') {
throw UnsupportedError('Element must be of type FUNCTION: $el');
}
if (el['value'] != 'import') {
// silently ignore functions that are not import
return;
}
dynamic value = parseLiterals(el['child'][0]);
if (value is List<String>) {
imports.addAll(value);
} else {
imports.add(value);
}
}
void _parse(List gnJson) {
for (Map<String, dynamic> el in gnJson) {
try {
switch (el['type']) {
case 'BINARY':
_parseAssigment(el);
break;
case 'FUNCTION':
_parseFunction(el);
break;
default: // ignore
}
// ignore: avoid_catching_errors
} on UnsupportedError catch (ex) {
parseErrors.add(ex.message);
}
}
}
}