Example #1
0
// newIdentCmd produces a command containing a single identifier node.
func newIdentCmd(identifier string, pos parse.Pos) *parse.CommandNode {
	return &parse.CommandNode{
		NodeType: parse.NodeCommand,
		Args:     []parse.Node{parse.NewIdentifier(identifier).SetPos(pos)},
	}
}
Example #2
0
// newIdentCmd produces a command containing a single identifier node.
func newIdentCmd(identifier string) *parse.CommandNode {
	return &parse.CommandNode{
		NodeType: parse.NodeCommand,
		Args:     []parse.Node{parse.NewIdentifier(identifier)},
	}
}
Example #3
0
// ReplaceTranslatableBlocks replaces begintrans/endtrans blocks
// with an equivalent action using the translation function named
// by fn.
func ReplaceTranslatableBlocks(tr *parse.Tree, fn string) error {
	var err error
	WalkTree(tr, func(n, p parse.Node) {
		if err != nil {
			return
		}
		if IsPseudoFunction(n, BeginTranslatableBlock) {
			list, ok := p.(*parse.ListNode)
			if !ok {
				loc, ctx := tr.ErrorContext(n)
				err = fmt.Errorf("%s:%s:%s not in ListNode (%T)", loc, ctx, BeginTranslatableBlock, p)
				return
			}
			cmd := &parse.CommandNode{
				NodeType: parse.NodeCommand,
				Pos:      n.Position(),
			}
			pipe := &parse.PipeNode{
				NodeType: parse.NodePipe,
				Pos:      n.Position(),
				Cmds:     []*parse.CommandNode{cmd},
			}
			repl := &parse.ActionNode{
				NodeType: parse.NodeAction,
				Pos:      n.Position(),
				Pipe:     pipe,
			}
			if repl != nil {
			}
			pos := -1
			for ii, v := range list.Nodes {
				if v == n {
					pos = ii
					break
				}
			}
			var pipes []parse.Node
			var buf bytes.Buffer
			endPos := -1
		Nodes:
			for ii, v := range list.Nodes[pos+1:] {
				switch x := v.(type) {
				case *parse.TextNode:
					buf.Write(x.Text)
				case *parse.ActionNode:
					if IsPseudoFunction(x, EndTranslatableBlock) {
						endPos = ii
						break Nodes
					}
					if len(x.Pipe.Decl) > 0 {
						loc, ctx := tr.ErrorContext(n)
						err = fmt.Errorf("%s:%s:%s translatable block can't contain a pipe with declaractions", loc, ctx, v)
					}
					buf.WriteString("%v")
					pipes = append(pipes, x.Pipe)
				default:
					loc, ctx := tr.ErrorContext(n)
					err = fmt.Errorf("%s translatable block can't contain %T %s", loc, v, ctx)
					return
				}
			}
			if buf.Len() > 0 {
				text := buf.String()
				quoted := strconv.Quote(text)
				innerPipe := &parse.PipeNode{
					NodeType: parse.NodePipe,
					Pos:      n.Position(),
					Cmds: []*parse.CommandNode{
						&parse.CommandNode{
							NodeType: parse.NodeCommand,
							Pos:      n.Position(),
							Args: []parse.Node{parse.NewIdentifier(fn), &parse.StringNode{
								NodeType: parse.NodeString,
								Pos:      n.Position(),
								Quoted:   quoted,
								Text:     text,
							}},
						},
					},
				}
				cmd.Args = append(cmd.Args, parse.NewIdentifier("printf"), innerPipe)
				cmd.Args = append(cmd.Args, pipes...)
			}
			nodes := list.Nodes[:pos]
			nodes = append(nodes, repl)
			nodes = append(nodes, list.Nodes[endPos+pos+1:]...)
			list.Nodes = nodes
		}
	})
	return err
}
Example #4
0
/**
hackNode 对模板中 template/import 的目标模板重新命名.
规则:
	没有扩展名当作内嵌模板,	反之当作文件模板.
	目标名称变更为绝对路径名.
	所有 template 用 import 替换.	格式为:
	import "from" "target" args...

参数:
	t     模板.
	names 所有使用的模板需要检查是否已经载入.
	from  来源模板名. 绝对路径.
	node  待 hack 的原始 parse.Node.

返回:
	是否有错误发生的错误.
*/
func hackNode(t *Template, names map[string]bool, from string,
	list *parse.ListNode, i int, node parse.Node) error {

	var (
		pipe   *parse.PipeNode
		args   []parse.Node
		target *parse.StringNode
	)
	rootdir := t.RootDir()

	switch n := node.(type) {
	default:
		return nil
	case *parse.ListNode:
		for i, node := range n.Nodes {
			err := hackNode(t, names, from, n, i, node)
			if err != nil {
				return err
			}
		}
		return nil
	case *parse.TemplateNode:

		args = make([]parse.Node, 3)

		args[0] = parse.NewIdentifier("import").SetPos(n.Pos)

		// from, 保存调用者
		args[1] = &parse.StringNode{
			NodeType: parse.NodeString,
			Pos:      n.Position(), // 伪造
			Quoted:   strconv.Quote(from),
			Text:     from,
		}

		// target, 重建目标
		args[2] = &parse.StringNode{
			NodeType: parse.NodeString,
			Pos:      n.Position(), // 伪造
			Quoted:   strconv.Quote(n.Name),
			Text:     n.Name,
		}

		// 复制其它参数
		pipe = n.Pipe
		if pipe != nil &&
			len(pipe.Cmds) != 0 &&
			pipe.Cmds[0].NodeType == parse.NodeCommand {

			for _, arg := range pipe.Cmds[0].Args {
				args = append(args, arg)
			}
		} else {
			if pipe == nil {
				pipe = &parse.PipeNode{
					NodeType: parse.NodePipe,
					Pos:      n.Position(), // 伪造
					Line:     n.Line,
					Cmds: []*parse.CommandNode{
						&parse.CommandNode{
							NodeType: parse.NodeCommand,
							Pos:      n.Position(),
						},
					},
				}
			}
		}

		pipe.Cmds[0].Args = args

		// 改成 ActionNode
		list.Nodes[i] = &parse.ActionNode{
			NodeType: parse.NodeAction,
			Pos:      n.Pos,
			Line:     n.Line,
			Pipe:     pipe,
		}

	case *parse.ActionNode:

		pipe = n.Pipe

		if pipe == nil ||
			len(pipe.Decl) != 0 ||
			len(pipe.Cmds) == 0 ||
			pipe.Cmds[0].NodeType != parse.NodeCommand ||
			len(pipe.Cmds[0].Args) == 0 ||
			pipe.Cmds[0].Args[0].Type() != parse.NodeIdentifier ||
			pipe.Cmds[0].Args[0].String() != "import" {

			return nil
		}

		args = make([]parse.Node, len(pipe.Cmds[0].Args)+1)
		args[0] = pipe.Cmds[0].Args[0]

		// from, 增加调用者来源
		args[1] = &parse.StringNode{
			NodeType: parse.NodeString,
			Pos:      args[0].Position(), // 伪造
			Quoted:   strconv.Quote(from),
			Text:     from,
		}
		// 复制其它参数
		for i, arg := range pipe.Cmds[0].Args {
			if i != 0 {
				args[i+1] = arg
			}
		}
		pipe.Cmds[0].Args = args
	}

	// 处理目标模板 args[2], 有可能是变量.
	target, _ = args[2].(*parse.StringNode)
	if target == nil {
		return nil
	}

	// 计算目标路径
	name := relToURI(rootdir, absPath(from), target.Text)
	if name == "" {
		return fmt.Errorf(
			"template: is invalid on define %q", target.Text)
	}

	// 判断文件模板是否载入
	if path.Ext(name) != "" &&
		!t.base.Lookup(name).IsValid() {

		names[name] = true
	}

	target.Text = name
	target.Quoted = strconv.Quote(name)

	return nil
}