summaryrefslogtreecommitdiff
path: root/redo/zwinconstgen.go
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2014-07-11 23:34:39 -0400
committerPietro Gagliardi <[email protected]>2014-07-11 23:34:39 -0400
commitc55386f9295fa5c16763a2a428e8e63eba1e7c53 (patch)
tree760b04a7ede6aeec4cd990b7cc5e5e9e1218eb5a /redo/zwinconstgen.go
parent06c2f1b0517a96f5d8cb2ad22125c121618834f5 (diff)
Added function generation to zwinconstgen.go. cgo uses DWARF to get function parameters, so we'll just specify them manually ourselves; see funcnames_windows.go.
Diffstat (limited to 'redo/zwinconstgen.go')
-rw-r--r--redo/zwinconstgen.go127
1 files changed, 119 insertions, 8 deletions
diff --git a/redo/zwinconstgen.go b/redo/zwinconstgen.go
index 39253f8..07c5959 100644
--- a/redo/zwinconstgen.go
+++ b/redo/zwinconstgen.go
@@ -22,7 +22,7 @@ func getPackage(path string) (pkg *ast.Package) {
filter := func(i os.FileInfo) bool {
return strings.HasSuffix(i.Name(), "_windows.go")
}
- pkgs, err := parser.ParseDir(fileset, path, filter, parser.AllErrors)
+ pkgs, err := parser.ParseDir(fileset, path, filter, parser.AllErrors | parser.ParseComments)
if err != nil {
panic(err)
}
@@ -57,8 +57,6 @@ func (w *walker) Visit(node ast.Node) ast.Visitor {
unknown[n.Name] = struct{}{}
}
}
- case *ast.Comment: // function?
- // TODO
}
return w
}
@@ -72,7 +70,99 @@ func gatherNames(pkg *ast.Package) {
for _, d := range f.Decls {
ast.Walk(&walker{desired}, d)
}
+ for _, c := range f.Comments {
+ for _, cc := range c.List {
+ readComment(cc)
+ }
+ }
+ }
+}
+
+var funcs []string
+var dlls = map[string]struct{}{}
+
+// parse comments of the form "// wfunc dll Name argtypes {ret[,noerr]|void}"
+// TODO clean this up
+func readComment(c *ast.Comment) {
+ words := strings.Split(c.Text, " ")[1:] // strip leading //
+ if len(words) <= 0 || words[0] != "wfunc" {
+ return
+ }
+ dll := words[1]
+ dlls[dll] = struct{}{}
+ name := words[2]
+ args := make([]string, 0, len(words))
+ for i := 3; i < len(words) - 1; i++ {
+ args = append(args, words[i])
+ }
+ ret := words[len(words) - 1]
+
+ funcs = append(funcs, fmt.Sprintf("var fv_%s = %s.NewProc(%q)", name, dll, name))
+
+ r1 := "r1"
+ err := "err"
+ assign := ":="
+
+ r := rune('a')
+ argspec := ""
+ for _, t := range args {
+ argspec += fmt.Sprintf("%c %s, ", r, t)
+ r++
+ }
+ retspec := ""
+ if ret != "void" {
+ r := strings.Split(ret, ",")
+ retspec = "(" + r[0]
+ if len(r) > 1 && r[1] == "noerr" {
+ err = "_"
+ } else {
+ retspec += ", error"
+ }
+ retspec += ")"
+ } else {
+ r1 = "_"
+ err = "_"
+ assign = "="
+ }
+ funcs = append(funcs, fmt.Sprintf("func f_%s(%s) %s {", name, argspec, retspec))
+
+ call := fmt.Sprintf("\t%s, _, %s %s fv_%s.Call(", r1, err, assign, name)
+ r = rune('a')
+ for _, t := range args {
+ call += "uintptr("
+ if t[0] == '*' {
+ call += "unsafe.Pointer("
+ }
+ call += fmt.Sprintf("%c", r)
+ if t[0] == '*' {
+ call += ")"
+ }
+ call += "), "
+ r++
+ }
+ call += ")"
+ funcs = append(funcs, call)
+
+ if ret != "void" {
+ r := strings.Split(ret, ",")
+ retspec = "return (" + r[0] + ")("
+ if r[0][0] == '*' {
+ retspec += "unsafe.Pointer("
+ }
+ retspec += "r1"
+ if r[0][0] == '*' {
+ retspec += ")"
+ }
+ retspec += ")"
+ if len(r) > 1 && r[1] == "noerr" {
+ // do nothing
+ } else {
+ retspec += ", err"
+ }
+ funcs = append(funcs, retspec)
}
+
+ funcs = append(funcs, "}")
}
// for backwards compatibiilty reasons, Windows defines GetWindowLongPtr()/SetWindowLongPtr() as a macro which expands to GetWindowLong()/SetWindowLong() on 32-bit systems
@@ -82,10 +172,6 @@ var gwlpNames = map[string]string{
"amd64": "etWindowLongPtrW",
}
-func writeLine(f *os.File, line string) {
- fmt.Fprintf(f, "%s\n", line)
-}
-
const outTemplate = `package main
import (
"fmt"
@@ -108,7 +194,7 @@ import (
// #include <commctrl.h>
// #include <stdint.h>
{{range .Consts}}// uintptr_t {{.}} = (uintptr_t) ({{noprefix .}});
-{{end}}import "C"
+{{end}}import "C" // notice the lack of newline in the template
// MinGW will generate handle pointers as pointers to some structure type under some conditions I don't fully understand; here's full overrides
var handleOverrides = []string{
"HWND",
@@ -148,8 +234,16 @@ func winName(t reflect.Type) string {
func main() {
buf := new(bytes.Buffer)
fmt.Fprintln(buf, "package ui")
+ fmt.Fprintln(buf, "import (")
+ fmt.Fprintln(buf, "\t\"syscall\"")
+ fmt.Fprintln(buf, "\t\"unsafe\"")
+ fmt.Fprintln(buf, ")")
+
+ // constants
{{range .Consts}} fmt.Fprintf(buf, "const %s = %d\n", {{printf "%q" .}}, C.{{.}})
{{end}}
+
+ // structures
var t reflect.Type
{{range .Structs}} t = reflect.TypeOf(C.{{noprefix .}}{})
fmt.Fprintf(buf, "type %s struct {\n", {{printf "%q" .}})
@@ -166,6 +260,14 @@ func main() {
fmt.Fprintf(buf, "type t_LPARAM %s\n", winName(reflect.TypeOf(C.LPARAM(0))))
fmt.Fprintf(buf, "type t_LRESULT %s\n", winName(reflect.TypeOf(C.LRESULT(0))))
+ // functions
+{{range .Funcs}} fmt.Fprintf(buf, "%s\n", {{printf "%q" .}})
+{{end}}
+
+ // DLLs
+{{range .DLLs}} fmt.Fprintf(buf, "var %s = syscall.NewLazyDLL(%q)\n", {{printf "%q" .}}, {{printf "%s.dll" . | printf "%q"}})
+{{end}}
+
// and finally done
res, err := format.Source(buf.Bytes())
if err != nil { panic(err.Error() + "\n" + string(buf.Bytes())) }
@@ -176,6 +278,8 @@ func main() {
type templateArgs struct {
Consts []string
Structs []string
+ Funcs []string
+ DLLs []string
}
var templateFuncs = template.FuncMap{
@@ -213,6 +317,7 @@ func main() {
// keep sorted for git
consts := make([]string, 0, len(unknown))
structs := make([]string, 0, len(unknown))
+ sorteddlls := make([]string, 0, len(dlls))
for ident, _ := range unknown {
if strings.HasPrefix(ident, "s_") {
structs = append(structs, ident)
@@ -220,8 +325,12 @@ func main() {
}
consts = append(consts, ident)
}
+ for dll, _ := range dlls {
+ sorteddlls = append(sorteddlls, dll)
+ }
sort.Strings(consts)
sort.Strings(structs)
+ sort.Strings(sorteddlls)
// thanks to james4k in irc.freenode.net/#go-nuts
tmpdir, err := ioutil.TempDir("", "windowsconstgen")
@@ -238,6 +347,8 @@ func main() {
err = t.Execute(f, &templateArgs{
Consts: consts,
Structs: structs,
+ Funcs: funcs,
+ DLLs: sorteddlls,
})
if err != nil {
panic(err)