Ejemplo n.º 1
0
func ExampleFprint() {
	// Parse source file and extract the AST without comments for
	// this function, with position information referring to the
	// file set fset.
	funcAST, fset := parseFunc("example_test.go", "ExampleFprint")

	// Print the function body into buffer buf.
	// The file set is provided to the printer so that it knows
	// about the original source formatting and can add additional
	// line breaks where they were present in the source.
	var buf bytes.Buffer
	printer.Fprint(&buf, fset, funcAST.Body)

	// Remove braces {} enclosing the function body, unindent,
	// and trim leading and trailing white space.
	s := buf.String()
	s = s[1 : len(s)-1]
	s = strings.TrimSpace(strings.Replace(s, "\n\t", "\n", -1))

	// Print the cleaned-up body text to stdout.
	fmt.Println(s)

	// output:
	// funcAST, fset := parseFunc("example_test.go", "ExampleFprint")
	//
	// var buf bytes.Buffer
	// printer.Fprint(&buf, fset, funcAST.Body)
	//
	// s := buf.String()
	// s = s[1 : len(s)-1]
	// s = strings.TrimSpace(strings.Replace(s, "\n\t", "\n", -1))
	//
	// fmt.Println(s)
}
Ejemplo n.º 2
0
func ExampleConvertAST() {
	fset := token.NewFileSet()
	a, _ := parser.ParseFile(fset, "example.sgo", `
	package example

	type LinkedList struct {
		Head	int
		// For SGo: ?*LinkedList
		Tail	*LinkedList
	}
	`, parser.ParseComments)

	info := &types.Info{
		Defs: map[*ast.Ident]types.Object{},
		Uses: map[*ast.Ident]types.Object{},
	}
	cfg := &types.Config{}
	cfg.Check("", fset, []*ast.File{a}, info)

	importer.ConvertAST(a, info, nil)

	printer.Fprint(os.Stdout, fset, a)
	// Output:
	// package example
	//
	// type LinkedList struct {
	// 	Head	int
	// 	// For SGo: ?*LinkedList
	// 	Tail	?*LinkedList
	// }
}
Ejemplo n.º 3
0
Archivo: codegen.go Proyecto: tcard/sgo
func (c *converter) convertReturnStmt(v *ast.ReturnStmt) {
	if v == nil {
		return
	}
	if v.Results.EntangledPos == 1 {
		// return \ err
		resultsLen := c.lastFunc.Results().Len()
		results := make([][]byte, 0, resultsLen)
		for i := 0; i < resultsLen; i++ {
			typ := c.lastFunc.Results().At(i).Type()
			switch underlying := typ.Underlying().(type) {
			case *types.Pointer, *types.Map, *types.Slice, *types.Signature, *types.Interface, *types.Optional:
				results = append(results, []byte("nil"))
			case *types.Struct:
				typ := c.lastFuncAST.Results.List[i].Type
				buf := &bytes.Buffer{}
				printer.Fprint(buf, c.fset, typ)
				results = append(results, append(buf.Bytes(), '{', '}'))
			case *types.Basic:
				info := underlying.Info()
				switch {
				case info&types.IsBoolean != 0:
					results = append(results, []byte("false"))
				case info&types.IsInteger != 0:
					results = append(results, []byte("0"))
				case info&types.IsFloat != 0, info&types.IsComplex != 0:
					results = append(results, []byte("0.0"))
				case info&types.IsString != 0:
					results = append(results, []byte(`""`))
				default:
					results = append(results, []byte("nil"))
				}
			default:
				panic(fmt.Sprintf("unhandled Type %v", typ))
			}
		}
		text := append(bytes.Join(results, []byte(", ")), []byte(", ")...)
		c.putChunks(int(v.Results.Pos())-1, c.src[c.lastChunkEnd:int(v.Pos())-c.base-1+len("return ")], text)
	}
	for _, v := range v.Results.List {
		c.convertExpr(v)
	}
	if v.Results.EntangledPos > 1 {
		// return x, y, z \
		chunk := ", nil"
		if c.lastFunc.Results().Entangled().Type() == types.Typ[types.Bool] {
			chunk = ", true"
		}
		c.putChunks(int(v.Results.End())+1, c.src[c.lastChunkEnd:int(v.Results.End())-c.base-1], []byte(chunk))
	}
}
Ejemplo n.º 4
0
func nodeFmt(node interface{}, fset *token.FileSet) string {
	var buf bytes.Buffer
	printer.Fprint(&buf, fset, node)
	return strings.Replace(strings.TrimSpace(buf.String()), "\n", "\n\t", -1)
}
Ejemplo n.º 5
0
Archivo: codegen.go Proyecto: tcard/sgo
func fileWithAnnotationComments(file *ast.File, fset, oldFset *token.FileSet, src []byte) ([]byte, *ast.File, error) {
	// TODO: So this is an extremely hacky way of doing this. We're going to
	// add the comments directly to the source comments, as text, and then
	// we're going to re-parse it. This is because I tried manipulating the
	// AST, adding the commments there an shifting the nodes' positions, but
	// doing that right is very very convoluted; you need to be tracking all
	// the time where you are, where you _were_, figure out where's a line
	// break, etc. So, well, this will do for now.
	var err error
	var dstChunks [][]byte
	var lastChunkEnd int
	skipNextSpec := false
	addDoc := func(node ast.Node, name *ast.Ident, typ ast.Expr) {
		if typ == nil {
			return
		}
		if name != nil && len(name.Name) > 0 {
			c := name.Name[0]
			if !(c >= 'A' && c <= 'Z') {
				return
			}
		}
		buf := &bytes.Buffer{}
		err = printer.Fprint(buf, token.NewFileSet(), typ)
		if err != nil {
			return
		}
		pos := int(node.Pos()) - oldFset.File(file.Pos()).Base()
		var space []byte
		for i := pos - 1; i >= 0 && (src[i] == ' ' || src[i] == '\t'); i-- {
			space = append([]byte{src[i]}, space...)
		}
		text := append([]byte("// For SGo: "+buf.String()+"\n"), space...)
		dstChunks = append(dstChunks, src[lastChunkEnd:pos], text)
		lastChunkEnd = pos
	}
	var visitor visitorFunc
	visitor = visitorFunc(func(node ast.Node) (w ast.Visitor) {
		var typ ast.Expr
		var name *ast.Ident
		switch node := node.(type) {
		case *ast.FuncDecl:
			typ = node.Type
			name = node.Name
		case *ast.GenDecl:
			if node.Lparen != 0 || node.Tok == token.IMPORT || node.Tok == token.CONST {
				return visitor
			}
			switch spec := node.Specs[0].(type) {
			case *ast.TypeSpec:
				skipNextSpec = true
				typ = spec.Type
				name = spec.Name
			case *ast.ValueSpec:
				skipNextSpec = true
				typ = spec.Type
				if len(spec.Names.List) > 0 {
					name = spec.Names.List[0]
				}
			}
			switch typ.(type) {
			case *ast.InterfaceType, *ast.StructType:
				return visitor
			}
		case *ast.InterfaceType:
			for i := 0; i < len(node.Methods.List); i++ {
				item := node.Methods.List[i]
				if len(item.Names) > 0 {
					name = item.Names[0]
				}
				addDoc(item, name, item.Type)
			}
			return visitor
		case *ast.StructType:
			for i := 0; i < len(node.Fields.List); i++ {
				item := node.Fields.List[i]
				if len(item.Names) > 0 {
					name = item.Names[0]
				}
				addDoc(item, name, item.Type)
			}
			return visitor
		case *ast.TypeSpec:
			if skipNextSpec {
				skipNextSpec = false
				return visitor
			}
			typ = node.Type
			name = node.Name
		case *ast.ValueSpec:
			if skipNextSpec {
				skipNextSpec = false
				return visitor
			}
			typ = node.Type
			if len(node.Names.List) > 0 {
				name = node.Names.List[0]
			}
		default:
			return visitor
		}

		addDoc(node, name, typ)
		return visitor
	})
	ast.Walk(visitor, file)
	if err != nil {
		return nil, nil, err
	}

	dst := append(
		[]byte("// Autogenerated by SGo revision: "+SGoRevision+"\n// DO NOT EDIT!\n\n"),
		bytes.Join(append(dstChunks, src[lastChunkEnd:]), nil)...)
	dstFile, err := parser.ParseFile(fset, file.Name.Name, dst, parser.ParseComments)
	return dst, dstFile, err
}