示例#1
0
文件: parse.go 项目: alistanis/st
// OverwriteStructTag overwrites the struct tag completely
func OverwriteStructTag(tag *ast.BasicLit, tagName string, offset *int, data []byte) []byte {
	val := tag.Value
	start := int(tag.Pos()) + *offset - 1
	end := int(tag.End()) + *offset - 1
	length := len(val)
	oldLength := end - start

	// Delete the original tag
	data = DeleteRange(data, start, end)
	var newTag string
	if options.AppendMode == Append {
		oldTag := removeIndex(removeIndex(val, 0), len(val)-2)
		newTag = fmt.Sprintf("`%s:\"%s\" %s`", options.Tag, tagName, oldTag)
	} else {
		newTag = fmt.Sprintf("`%s:\"%s\"`", options.Tag, tagName)
	}

	numSpaces := len(newTag) - oldLength - 1
	var spaces string

	// Can't pass a negative number to strings.Repeat()
	// it will cause a panic because it passes this number directly to make()
	if numSpaces > 0 {
		spaces = strings.Repeat(" ", numSpaces)
	}

	newTag = fmt.Sprintf("%s%s", spaces, newTag)
	localOffset := len(newTag) - length
	*offset += localOffset

	// Insert new tag
	data = Insert(data, []byte(newTag), start)
	return data
}
示例#2
0
func (check *checker) tag(t *ast.BasicLit) string {
	if t != nil {
		if t.Kind == token.STRING {
			if val, err := strconv.Unquote(t.Value); err == nil {
				return val
			}
		}
		check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value)
	}
	return ""
}
示例#3
0
文件: lit.go 项目: kyeongdong/3
// compiles a basic literal, like numbers and strings
func (w *World) compileBasicLit(n *ast.BasicLit) Expr {
	switch n.Kind {
	default:
		panic(err(n.Pos(), "not allowed:", n.Value, "(", typ(n), ")"))
	case token.FLOAT:
		return floatLit(parseFloat(n.Value))
	case token.INT:
		return intLit(parseInt(n.Value))
	case token.STRING:
		return stringLit(n.Value[1 : len(n.Value)-1]) // remove quotes
	}
}
示例#4
0
func (file *File) basicLitToMessage(node *ast.BasicLit) Message {
	if node.Kind != token.STRING {
		panic("only call basicLitToMessage with a string node")
	}
	val, _ := strconv.Unquote(node.Value)
	pos := file.FSet.Position(node.Pos())
	xcomment := file.cmap.Get(node, pos)

	return Message{
		XComment:    xcomment,
		Reference:   []token.Position{pos},
		Flags:       []string{},
		MsgCtxt:     nil,
		MsgID:       val,
		MsgIDPlural: nil,
	}
}
func TestExtractsLiteral(t *testing.T) {
	var root ast.BasicLit
	root.Kind = token.INT
	root.Value = "0"

	replace, fn := ExtractFnFromExpr("t", &root)

	if replace.Fun.(*ast.Ident).Name != "t" {
		t.Fail()
	}

	if fn.Recv != nil {
		t.Fail()
	}

	if fn.Name.Name != "t" {
		t.Fail()
	}

	if len(fn.Body.List) != 1 {
		t.Fail()
	}

	switch x := fn.Body.List[0].(type) {
	case *ast.ReturnStmt:
		if len(x.Results) != 1 {
			t.Fail()
		} else {
			if x.Results[0].(*ast.BasicLit).Kind != token.INT {
				t.Fail()
			}
			if x.Results[0].(*ast.BasicLit).Value != "0" {
				t.Fail()
			}
		}
	default:
		t.Fail()
	}

	printer.Fprint(os.Stdout, token.NewFileSet(), fn)
	printer.Fprint(os.Stdout, token.NewFileSet(), replace)
}
func (rp *rewritePackage) wrapCallExprWithInterpolatedT(basicLit *ast.BasicLit, callExpr *ast.CallExpr, argIndex int) {
	valueWithoutQuotes, _ := strconv.Unquote(basicLit.Value)

	i18nStringInfo, ok := rp.ExtractedStrings[valueWithoutQuotes]
	if !ok && rp.ExtractedStrings != nil {
		rp.wrapExprArgs(callExpr.Args)
		return
	}

	templatedString := common.ConvertToTemplatedString(valueWithoutQuotes)
	basicLit.Value = strconv.Quote(templatedString)

	if rp.ExtractedStrings != nil {
		rp.updateExtractedStrings(i18nStringInfo, templatedString)
	}

	rp.wrapCallExprWithTemplatedT(basicLit, callExpr, argIndex)
}
func (rp *rewritePackage) wrapBasicLitWithTemplatedT(basicLit *ast.BasicLit, args []ast.Expr, callExpr *ast.CallExpr, argIndex int) ast.Expr {
	valueWithoutQuotes, _ := strconv.Unquote(basicLit.Value) //basicLit.Value[1 : len(basicLit.Value)-1]

	_, ok := rp.ExtractedStrings[valueWithoutQuotes]
	if !ok && rp.ExtractedStrings != nil {
		return callExpr
	}

	rp.TotalStrings++
	tIdent := &ast.Ident{Name: "T"}
	argNames := common.GetTemplatedStringArgs(valueWithoutQuotes)

	compositeExpr := []ast.Expr{}
	processedArgsMap := make(map[string]bool)

	for i, argName := range argNames {
		if callExpr, ok := args[argIndex+i+1].(*ast.CallExpr); ok {
			rp.callExprTFunc(callExpr)
		} else if basicLit, ok := args[argIndex+i+1].(*ast.BasicLit); ok {
			args[argIndex+i] = rp.wrapBasicLitWithT(basicLit)
		}

		if processedArgsMap[argName] != true {
			quotedArgName := "\"" + argName + "\""
			basicLit.ValuePos = 0

			valueExpr := args[argIndex+i+1]
			if basicLit, ok := args[argIndex+i+1].(*ast.BasicLit); ok {
				valueExpr = rp.wrapBasicLitWithT(basicLit)
			}

			keyValueExpr := &ast.KeyValueExpr{Key: &ast.BasicLit{Kind: 9, Value: quotedArgName}, Value: valueExpr}
			processedArgsMap[argName] = true
			compositeExpr = append(compositeExpr, keyValueExpr)
		}
	}

	mapInterfaceType := &ast.InterfaceType{Interface: 142, Methods: &ast.FieldList{List: nil, Opening: 1, Closing: 2}, Incomplete: false}
	mapType := &ast.MapType{Map: 131, Key: &ast.Ident{Name: "string"}, Value: mapInterfaceType}
	compositeLit := &ast.CompositeLit{Type: mapType, Elts: compositeExpr}

	return &ast.CallExpr{Fun: tIdent, Args: []ast.Expr{basicLit, compositeLit}}
}
示例#8
0
// Visit browses the AST tree for strings that could be potentially
// replaced by constants.
// A map of existing constants is built as well (-match-constant).
func (v *treeVisitor) Visit(node ast.Node) ast.Visitor {
	if node == nil {
		return v
	}

	// A single case with "ast.BasicLit" would be much easier
	// but then we wouldn't be able to tell in which context
	// the string is defined (could be a constant definition).
	switch t := node.(type) {
	// Scan for constants in an attempt to match strings with existing constants
	case *ast.GenDecl:
		if !v.p.matchConstant {
			return v
		}
		if t.Tok != token.CONST {
			return v
		}

		for _, spec := range t.Specs {
			val := spec.(*ast.ValueSpec)
			for i, str := range val.Values {
				lit, ok := str.(*ast.BasicLit)
				if !ok || !v.isSupported(lit.Kind) {
					continue
				}

				v.addConst(val.Names[i].Name, lit.Value, val.Names[i].Pos())
			}
		}

	// foo := "moo"
	case *ast.AssignStmt:
		for _, rhs := range t.Rhs {
			lit, ok := rhs.(*ast.BasicLit)
			if !ok || !v.isSupported(lit.Kind) {
				continue
			}

			v.addString(lit.Value, rhs.(*ast.BasicLit).Pos())
		}

	// if foo == "moo"
	case *ast.BinaryExpr:
		if t.Op != token.EQL && t.Op != token.NEQ {
			return v
		}

		var lit *ast.BasicLit
		var ok bool

		lit, ok = t.X.(*ast.BasicLit)
		if ok && v.isSupported(lit.Kind) {
			v.addString(lit.Value, lit.Pos())
		}

		lit, ok = t.Y.(*ast.BasicLit)
		if ok && v.isSupported(lit.Kind) {
			v.addString(lit.Value, lit.Pos())
		}

	// case "foo":
	case *ast.CaseClause:
		for _, item := range t.List {
			lit, ok := item.(*ast.BasicLit)
			if ok && v.isSupported(lit.Kind) {
				v.addString(lit.Value, lit.Pos())
			}
		}

	// return "boo"
	case *ast.ReturnStmt:
		for _, item := range t.Results {
			lit, ok := item.(*ast.BasicLit)
			if ok && v.isSupported(lit.Kind) {
				v.addString(lit.Value, lit.Pos())
			}
		}
	}

	return v
}