1 /*
  2  *  Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
  3  *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  *  This code is free software; you can redistribute it and/or modify it
  6  *  under the terms of the GNU General Public License version 2 only, as
  7  *  published by the Free Software Foundation.  Oracle designates this
  8  *  particular file as subject to the "Classpath" exception as provided
  9  *  by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  *  This code is distributed in the hope that it will be useful, but WITHOUT
 12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  *  version 2 for more details (a copy is included in the LICENSE file that
 15  *  accompanied this code).
 16  *
 17  *  You should have received a copy of the GNU General Public License version
 18  *  2 along with this work; if not, write to the Free Software Foundation,
 19  *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  *  or visit www.oracle.com if you need additional information or have any
 23  *  questions.
 24  *
 25  */
 26 package jdk.internal.jextract.impl;
 27 
 28 import jdk.incubator.jextract.Declaration;
 29 import jdk.internal.clang.Cursor;
 30 import jdk.internal.clang.CursorKind;
 31 import jdk.internal.clang.Diagnostic;
 32 import jdk.internal.clang.Index;
 33 import jdk.internal.clang.LibClang;
 34 import jdk.internal.clang.SourceLocation;
 35 import jdk.internal.clang.SourceRange;
 36 import jdk.internal.clang.TranslationUnit;
 37 
 38 import java.nio.file.Path;
 39 import java.util.ArrayList;
 40 import java.util.Collection;
 41 import java.util.List;
 42 import java.util.Optional;
 43 
 44 public class Parser {
 45     private final TreeMaker treeMaker;
 46 
 47     public Parser() {
 48         this.treeMaker = new TreeMaker();
 49     }
 50 
 51     public Declaration.Scoped parse(Path path, Collection<String> args) {
 52         final Index index = LibClang.createIndex(false);
 53 
 54         TranslationUnit tu = index.parse(path.toString(),
 55             d -> {
 56                 if (d.severity() > Diagnostic.CXDiagnostic_Warning) {
 57                     throw new ClangException(d.toString());
 58                 }
 59             },
 60             true, args.toArray(new String[0]));
 61 
 62         MacroParserImpl macroParser = MacroParserImpl.make(treeMaker, tu, args);
 63 
 64         List<Declaration> decls = new ArrayList<>();
 65         Cursor tuCursor = tu.getCursor();
 66         tuCursor.children().
 67             forEach(c -> {
 68                 SourceLocation loc = c.getSourceLocation();
 69                 if (loc == null) {
 70                     return;
 71                 }
 72 
 73                 SourceLocation.Location src = loc.getFileLocation();
 74                 if (src == null) {
 75                     return;
 76                 }
 77 
 78 
 79                 if (c.isDeclaration()) {
 80                     if (c.kind() == CursorKind.UnexposedDecl ||
 81                         c.kind() == CursorKind.Namespace) {
 82                         c.children().map(treeMaker::createTree)
 83                                 .filter(t -> t != null)
 84                                 .forEach(decls::add);
 85                     } else {
 86                         Declaration decl = treeMaker.createTree(c);
 87                         if (decl != null) {
 88                             decls.add(decl);
 89                         }
 90                     }
 91                 } else if (isMacro(c) && src.path() != null) {
 92                     SourceRange range = c.getExtent();
 93                     String[] tokens = c.getTranslationUnit().tokens(range);
 94                     Optional<Declaration.Constant> constant = macroParser.parseConstant(treeMaker.toPos(c), c.spelling(), tokens);
 95                     if (constant.isPresent()) {
 96                         decls.add(constant.get());
 97                     }
 98                 }
 99             });
100 
101         decls.addAll(macroParser.macroTable.reparseConstants());
102         Declaration.Scoped rv = treeMaker.createHeader(tuCursor, decls);
103         treeMaker.freeze();
104         index.close();
105         return rv;
106     }
107 
108     private boolean isMacro(Cursor c) {
109         return c.isPreprocessing() && c.kind() == CursorKind.MacroDefinition;
110     }
111 }