github.com/goplus/llgo@v0.8.3/xtool/clang/parser/parse.go (about) 1 /* 2 * Copyright (c) 2022 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package parser 18 19 import ( 20 "bytes" 21 "os" 22 "os/exec" 23 "strings" 24 25 "github.com/goplus/llgo/xtool/clang/ast" 26 jsoniter "github.com/json-iterator/go" 27 ) 28 29 type Mode uint 30 31 // ----------------------------------------------------------------------------- 32 33 type ParseError struct { 34 Err error 35 Stderr []byte 36 } 37 38 func (p *ParseError) Error() string { 39 if len(p.Stderr) > 0 { 40 return string(p.Stderr) 41 } 42 return p.Err.Error() 43 } 44 45 // ----------------------------------------------------------------------------- 46 47 type Config struct { 48 Json *[]byte 49 Flags []string 50 Stderr bool 51 } 52 53 func DumpAST(filename string, conf *Config) (result []byte, warning []byte, err error) { 54 if conf == nil { 55 conf = new(Config) 56 } 57 skiperr := strings.HasSuffix(filename, "vfprintf.c.i") 58 stdout := NewPagedWriter() 59 stderr := new(bytes.Buffer) 60 args := []string{"-Xclang", "-ast-dump=json", "-fsyntax-only", filename} 61 if len(conf.Flags) != 0 { 62 args = append(conf.Flags, args...) 63 } 64 cmd := exec.Command("clang", args...) 65 cmd.Stdin = os.Stdin 66 cmd.Stdout = stdout 67 if conf.Stderr && !skiperr { 68 cmd.Stderr = os.Stderr 69 } else { 70 cmd.Stderr = stderr 71 } 72 err = cmd.Run() 73 errmsg := stderr.Bytes() 74 if err != nil && !skiperr { 75 return nil, nil, &ParseError{Err: err, Stderr: errmsg} 76 } 77 return stdout.Bytes(), errmsg, nil 78 } 79 80 // ----------------------------------------------------------------------------- 81 82 var json = jsoniter.ConfigCompatibleWithStandardLibrary 83 84 func ParseFileEx(filename string, mode Mode, conf *Config) (file *ast.Node, warning []byte, err error) { 85 out, warning, err := DumpAST(filename, conf) 86 if err != nil { 87 return 88 } 89 if conf != nil && conf.Json != nil { 90 *conf.Json = out 91 } 92 file = new(ast.Node) 93 err = json.Unmarshal(out, file) 94 if err != nil { 95 err = &ParseError{Err: err} 96 } 97 return 98 } 99 100 func ParseFile(filename string, mode Mode) (file *ast.Node, warning []byte, err error) { 101 return ParseFileEx(filename, mode, nil) 102 } 103 104 // -----------------------------------------------------------------------------