| // 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); |
| } |
| } |
| } |
| } |