prog.go

  1// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
  2//
  3// This program is free software; you can redistribute it and/or
  4// modify it under the terms of The BSD 3-Clause License
  5// that can be found in the LICENSE file.
  6
  7package uritemplate
  8
  9import (
 10	"bytes"
 11	"strconv"
 12)
 13
 14type progOpcode uint16
 15
 16const (
 17	// match
 18	opRune progOpcode = iota
 19	opRuneClass
 20	opLineBegin
 21	opLineEnd
 22	// capture
 23	opCapStart
 24	opCapEnd
 25	// stack
 26	opSplit
 27	opJmp
 28	opJmpIfNotDefined
 29	opJmpIfNotEmpty
 30	opJmpIfNotFirst
 31	// result
 32	opEnd
 33	// fake
 34	opNoop
 35	opcodeMax
 36)
 37
 38var opcodeNames = []string{
 39	// match
 40	"opRune",
 41	"opRuneClass",
 42	"opLineBegin",
 43	"opLineEnd",
 44	// capture
 45	"opCapStart",
 46	"opCapEnd",
 47	// stack
 48	"opSplit",
 49	"opJmp",
 50	"opJmpIfNotDefined",
 51	"opJmpIfNotEmpty",
 52	"opJmpIfNotFirst",
 53	// result
 54	"opEnd",
 55}
 56
 57func (code progOpcode) String() string {
 58	if code >= opcodeMax {
 59		return ""
 60	}
 61	return opcodeNames[code]
 62}
 63
 64type progOp struct {
 65	code progOpcode
 66	r    rune
 67	rc   runeClass
 68	i    uint32
 69
 70	name string
 71}
 72
 73func dumpProgOp(b *bytes.Buffer, op *progOp) {
 74	b.WriteString(op.code.String())
 75	switch op.code {
 76	case opRune:
 77		b.WriteString("(")
 78		b.WriteString(strconv.QuoteToASCII(string(op.r)))
 79		b.WriteString(")")
 80	case opRuneClass:
 81		b.WriteString("(")
 82		b.WriteString(op.rc.String())
 83		b.WriteString(")")
 84	case opCapStart, opCapEnd:
 85		b.WriteString("(")
 86		b.WriteString(strconv.QuoteToASCII(op.name))
 87		b.WriteString(")")
 88	case opSplit:
 89		b.WriteString(" -> ")
 90		b.WriteString(strconv.FormatInt(int64(op.i), 10))
 91	case opJmp, opJmpIfNotFirst:
 92		b.WriteString(" -> ")
 93		b.WriteString(strconv.FormatInt(int64(op.i), 10))
 94	case opJmpIfNotDefined, opJmpIfNotEmpty:
 95		b.WriteString("(")
 96		b.WriteString(strconv.QuoteToASCII(op.name))
 97		b.WriteString(")")
 98		b.WriteString(" -> ")
 99		b.WriteString(strconv.FormatInt(int64(op.i), 10))
100	}
101}
102
103type prog struct {
104	op     []progOp
105	numCap int
106}
107
108func dumpProg(b *bytes.Buffer, prog *prog, pc uint32) {
109	for i := range prog.op {
110		op := prog.op[i]
111
112		pos := strconv.Itoa(i)
113		if uint32(i) == pc {
114			pos = "*" + pos
115		}
116		b.WriteString("    "[len(pos):])
117		b.WriteString(pos)
118
119		b.WriteByte('\t')
120		dumpProgOp(b, &op)
121
122		b.WriteByte('\n')
123	}
124}
125
126func (p *prog) String() string {
127	b := bytes.Buffer{}
128	dumpProg(&b, p, 0)
129	return b.String()
130}