Skip to content
This repository has been archived by the owner on Mar 8, 2020. It is now read-only.

Commit

Permalink
Merge pull request #90 from dennwc/gen_header
Browse files Browse the repository at this point in the history
Change the way how libuast header is generated
  • Loading branch information
juanjux authored Sep 28, 2018
2 parents abe42a5 + 789185c commit e5e66e0
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 53 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ before_install:
script:
- make vendor
- make package-all
- ls -l ./build
- make test

deploy:
Expand Down
30 changes: 10 additions & 20 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,14 @@ HOSTOS:=$(shell go env GOHOSTOS)

SRC_DIR=./src
DEPS_C = $(SRC_DIR)/*.h $(SRC_DIR)/*.c
DEPS_GO = $(SRC_DIR)/*.go vendor
DEPS_GO = $(SRC_DIR)/*.go gen_header.go vendor

BUILD_MODE=-buildmode=c-shared
GO_BUILD=go build
CC_WIN64=x86_64-w64-mingw32-gcc
CC_WIN32=i686-w64-mingw32-gcc

ifeq ("$(HOSTOS)", 'windows')
CP_HEADERS=copy $(SRC_DIR)/uast.h

else
CP_HEADERS=cp $(SRC_DIR)/uast.h

endif
GEN_HEADER=go run gen_header.go -o

OUT_NAME=libuast
OUT_HEADER=$(OUT_NAME).h
Expand Down Expand Up @@ -51,34 +45,30 @@ vendor: Gopkg.*

build: build-$(HOSTOS)

build-linux: $(DEPS_C) $(DEPS_GO) cut.sh
build-linux: $(DEPS_C) $(DEPS_GO)
mkdir -p $(OUT_LINUX) && \
GOOS=linux GOARCH=amd64 $(GO_BUILD) $(BUILD_MODE) -o=$(OUT_LINUX)/$(OUT_NAME).so $(SRC_DIR)/ && \
./cut.sh $(OUT_LINUX)/$(OUT_HEADER) && \
$(CP_HEADERS) $(OUT_LINUX)/
$(GEN_HEADER) $(OUT_LINUX)/$(OUT_HEADER)

build-darwin: $(DEPS_C) $(DEPS_GO) cut.sh
build-darwin: $(DEPS_C) $(DEPS_GO)
mkdir -p $(OUT_OSX) && \
GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 $(GO_BUILD) $(BUILD_MODE) -o=$(OUT_OSX)/$(OUT_NAME).so $(SRC_DIR)/ && \
./cut.sh $(OUT_OSX)/$(OUT_HEADER) && \
$(CP_HEADERS) $(OUT_OSX)/
$(GEN_HEADER) $(OUT_OSX)/$(OUT_HEADER)


ifneq ("$(HOSTOS)", "windows")
build-windows: $(DEPS_C) $(DEPS_GO) cut.sh
build-windows: $(DEPS_C) $(DEPS_GO)
mkdir -p $(OUT_WINDOWS)
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=$(CC_WIN64) $(GO_BUILD) $(BUILD_MODE) -o=$(OUT_WINDOWS)/$(OUT_NAME).dll $(SRC_DIR)/
./cut.sh $(OUT_WINDOWS)/$(OUT_HEADER)
$(CP_HEADERS) $(OUT_WINDOWS)/
$(GEN_HEADER) $(OUT_WINDOWS)/$(OUT_HEADER)

else
build-windows: $(DEPS_C) $(DEPS_GO) cut.sh
build-windows: $(DEPS_C) $(DEPS_GO)
mkdir -p $(OUT_WINDOWS)
set GOOS=windows
set GOARCH=amd64
$(GO_BUILD) $(BUILD_MODE) -o=$(OUT_WINDOWS)\\$(OUT_NAME).dll $(SRC_DIR)/
bash cut.sh $(OUT_WINDOWS)\\$(OUT_HEADER)
$(CP_HEADERS) $(OUT_WINDOWS)\\
$(GEN_HEADER) $(OUT_WINDOWS)\\$(OUT_HEADER)

endif

Expand Down
33 changes: 0 additions & 33 deletions cut.sh

This file was deleted.

145 changes: 145 additions & 0 deletions gen_header.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package main

import (
"bytes"
"flag"
"fmt"
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"os"
"strings"
)

var (
outFile = flag.String("o", "libuast.h", "output file")
)

func main() {
flag.Parse()
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

func run() error {
src, err := ioutil.ReadFile("./src/api.go")
if err != nil {
return err
}
fs := token.NewFileSet()
tree, err := parser.ParseFile(fs, "api.go", src, parser.ParseComments)
if err != nil {
return err
}
buf := new(bytes.Buffer)
buf.WriteString(`
#ifdef __cplusplus
extern "C" {
#endif
`)
for _, dec := range tree.Decls {
fnc, ok := dec.(*ast.FuncDecl)
if !ok {
continue
}
doc := fnc.Doc.Text()
pref := "export " + fnc.Name.Name
if !strings.Contains(doc, pref) {
continue
}
buf.WriteString("\n")
for _, c := range fnc.Doc.List {
if strings.HasPrefix(c.Text, "//"+pref) {
continue
}
buf.WriteString(c.Text + "\n")
}
if err = writeCSignature(buf, fnc); err != nil {
return err
}
}
buf.WriteString(`
#ifdef __cplusplus
}
#endif
`)
return writeHeader(buf.Bytes())
}

func writeCSignature(buf *bytes.Buffer, fnc *ast.FuncDecl) error {
typ := fnc.Type
buf.WriteString("extern ")
if typ.Results != nil && len(typ.Results.List) != 0 {
if err := writeCType(buf, typ.Results.List[0].Type); err != nil {
return err
}
} else {
buf.WriteString("void")
}
buf.WriteString(" ")
buf.WriteString(fnc.Name.Name)
buf.WriteString("(")
for i, p := range fnc.Type.Params.List {
if i != 0 {
buf.WriteString(", ")
}
for j, name := range p.Names {
if j != 0 {
buf.WriteString(", ")
}
if err := writeCType(buf, p.Type); err != nil {
return err
}
buf.WriteString(" ")
buf.WriteString(name.Name)
}
}
buf.WriteString(");\n")
return nil
}

func writeCType(buf *bytes.Buffer, typ ast.Expr) error {
switch typ := typ.(type) {
case *ast.Ident:
buf.WriteString(typ.Name)
case *ast.StarExpr:
if err := writeCType(buf, typ.X); err != nil {
return err
}
buf.WriteString("*")
case *ast.SelectorExpr:
pkg, ok := typ.X.(*ast.Ident)
if !ok {
return fmt.Errorf("unknown package: %T", typ.X)
}
switch pkg.Name {
default:
return fmt.Errorf("unknown package: %v", pkg.Name)
case "unsafe":
if typ.Sel.Name != "Pointer" {
return fmt.Errorf("unknown unsafe type: %v", typ.Sel.Name)
}
buf.WriteString("void*")
return nil
case "C":
}
if err := writeCType(buf, typ.Sel); err != nil {
return err
}
default:
return fmt.Errorf("unsupported type: %T", typ)
}
return nil
}

func writeHeader(data []byte) error {
hdr, err := ioutil.ReadFile("./src/uast.h")
if err != nil {
return err
}
hdr = bytes.Replace(hdr, []byte("/*GO-HEADER*/"), data, 1)
return ioutil.WriteFile(*outFile, hdr, 0644)
}
3 changes: 3 additions & 0 deletions src/uast.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>

#define UAST_HASH_SIZE 32

Expand Down Expand Up @@ -142,4 +143,6 @@ static NodeHandle UastLoad(const Uast *src, NodeHandle n, const Uast *dst) {
return 0;
}

/*GO-HEADER*/

#endif // UAST_H_

0 comments on commit e5e66e0

Please sign in to comment.