diff options
Diffstat (limited to 'src/pkg/regexp/syntax/compile.go')
-rw-r--r-- | src/pkg/regexp/syntax/compile.go | 289 |
1 files changed, 0 insertions, 289 deletions
diff --git a/src/pkg/regexp/syntax/compile.go b/src/pkg/regexp/syntax/compile.go deleted file mode 100644 index 95f6f1569..000000000 --- a/src/pkg/regexp/syntax/compile.go +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syntax - -import "unicode" - -// A patchList is a list of instruction pointers that need to be filled in (patched). -// Because the pointers haven't been filled in yet, we can reuse their storage -// to hold the list. It's kind of sleazy, but works well in practice. -// See http://swtch.com/~rsc/regexp/regexp1.html for inspiration. -// -// These aren't really pointers: they're integers, so we can reinterpret them -// this way without using package unsafe. A value l denotes -// p.inst[l>>1].Out (l&1==0) or .Arg (l&1==1). -// l == 0 denotes the empty list, okay because we start every program -// with a fail instruction, so we'll never want to point at its output link. -type patchList uint32 - -func (l patchList) next(p *Prog) patchList { - i := &p.Inst[l>>1] - if l&1 == 0 { - return patchList(i.Out) - } - return patchList(i.Arg) -} - -func (l patchList) patch(p *Prog, val uint32) { - for l != 0 { - i := &p.Inst[l>>1] - if l&1 == 0 { - l = patchList(i.Out) - i.Out = val - } else { - l = patchList(i.Arg) - i.Arg = val - } - } -} - -func (l1 patchList) append(p *Prog, l2 patchList) patchList { - if l1 == 0 { - return l2 - } - if l2 == 0 { - return l1 - } - - last := l1 - for { - next := last.next(p) - if next == 0 { - break - } - last = next - } - - i := &p.Inst[last>>1] - if last&1 == 0 { - i.Out = uint32(l2) - } else { - i.Arg = uint32(l2) - } - return l1 -} - -// A frag represents a compiled program fragment. -type frag struct { - i uint32 // index of first instruction - out patchList // where to record end instruction -} - -type compiler struct { - p *Prog -} - -// Compile compiles the regexp into a program to be executed. -// The regexp should have been simplified already (returned from re.Simplify). -func Compile(re *Regexp) (*Prog, error) { - var c compiler - c.init() - f := c.compile(re) - f.out.patch(c.p, c.inst(InstMatch).i) - c.p.Start = int(f.i) - return c.p, nil -} - -func (c *compiler) init() { - c.p = new(Prog) - c.p.NumCap = 2 // implicit ( and ) for whole match $0 - c.inst(InstFail) -} - -var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune} -var anyRune = []rune{0, unicode.MaxRune} - -func (c *compiler) compile(re *Regexp) frag { - switch re.Op { - case OpNoMatch: - return c.fail() - case OpEmptyMatch: - return c.nop() - case OpLiteral: - if len(re.Rune) == 0 { - return c.nop() - } - var f frag - for j := range re.Rune { - f1 := c.rune(re.Rune[j:j+1], re.Flags) - if j == 0 { - f = f1 - } else { - f = c.cat(f, f1) - } - } - return f - case OpCharClass: - return c.rune(re.Rune, re.Flags) - case OpAnyCharNotNL: - return c.rune(anyRuneNotNL, 0) - case OpAnyChar: - return c.rune(anyRune, 0) - case OpBeginLine: - return c.empty(EmptyBeginLine) - case OpEndLine: - return c.empty(EmptyEndLine) - case OpBeginText: - return c.empty(EmptyBeginText) - case OpEndText: - return c.empty(EmptyEndText) - case OpWordBoundary: - return c.empty(EmptyWordBoundary) - case OpNoWordBoundary: - return c.empty(EmptyNoWordBoundary) - case OpCapture: - bra := c.cap(uint32(re.Cap << 1)) - sub := c.compile(re.Sub[0]) - ket := c.cap(uint32(re.Cap<<1 | 1)) - return c.cat(c.cat(bra, sub), ket) - case OpStar: - return c.star(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0) - case OpPlus: - return c.plus(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0) - case OpQuest: - return c.quest(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0) - case OpConcat: - if len(re.Sub) == 0 { - return c.nop() - } - var f frag - for i, sub := range re.Sub { - if i == 0 { - f = c.compile(sub) - } else { - f = c.cat(f, c.compile(sub)) - } - } - return f - case OpAlternate: - var f frag - for _, sub := range re.Sub { - f = c.alt(f, c.compile(sub)) - } - return f - } - panic("regexp: unhandled case in compile") -} - -func (c *compiler) inst(op InstOp) frag { - // TODO: impose length limit - f := frag{i: uint32(len(c.p.Inst))} - c.p.Inst = append(c.p.Inst, Inst{Op: op}) - return f -} - -func (c *compiler) nop() frag { - f := c.inst(InstNop) - f.out = patchList(f.i << 1) - return f -} - -func (c *compiler) fail() frag { - return frag{} -} - -func (c *compiler) cap(arg uint32) frag { - f := c.inst(InstCapture) - f.out = patchList(f.i << 1) - c.p.Inst[f.i].Arg = arg - - if c.p.NumCap < int(arg)+1 { - c.p.NumCap = int(arg) + 1 - } - return f -} - -func (c *compiler) cat(f1, f2 frag) frag { - // concat of failure is failure - if f1.i == 0 || f2.i == 0 { - return frag{} - } - - // TODO: elide nop - - f1.out.patch(c.p, f2.i) - return frag{f1.i, f2.out} -} - -func (c *compiler) alt(f1, f2 frag) frag { - // alt of failure is other - if f1.i == 0 { - return f2 - } - if f2.i == 0 { - return f1 - } - - f := c.inst(InstAlt) - i := &c.p.Inst[f.i] - i.Out = f1.i - i.Arg = f2.i - f.out = f1.out.append(c.p, f2.out) - return f -} - -func (c *compiler) quest(f1 frag, nongreedy bool) frag { - f := c.inst(InstAlt) - i := &c.p.Inst[f.i] - if nongreedy { - i.Arg = f1.i - f.out = patchList(f.i << 1) - } else { - i.Out = f1.i - f.out = patchList(f.i<<1 | 1) - } - f.out = f.out.append(c.p, f1.out) - return f -} - -func (c *compiler) star(f1 frag, nongreedy bool) frag { - f := c.inst(InstAlt) - i := &c.p.Inst[f.i] - if nongreedy { - i.Arg = f1.i - f.out = patchList(f.i << 1) - } else { - i.Out = f1.i - f.out = patchList(f.i<<1 | 1) - } - f1.out.patch(c.p, f.i) - return f -} - -func (c *compiler) plus(f1 frag, nongreedy bool) frag { - return frag{f1.i, c.star(f1, nongreedy).out} -} - -func (c *compiler) empty(op EmptyOp) frag { - f := c.inst(InstEmptyWidth) - c.p.Inst[f.i].Arg = uint32(op) - f.out = patchList(f.i << 1) - return f -} - -func (c *compiler) rune(r []rune, flags Flags) frag { - f := c.inst(InstRune) - i := &c.p.Inst[f.i] - i.Rune = r - flags &= FoldCase // only relevant flag is FoldCase - if len(r) != 1 || unicode.SimpleFold(r[0]) == r[0] { - // and sometimes not even that - flags &^= FoldCase - } - i.Arg = uint32(flags) - f.out = patchList(f.i << 1) - - // Special cases for exec machine. - switch { - case flags&FoldCase == 0 && (len(r) == 1 || len(r) == 2 && r[0] == r[1]): - i.Op = InstRune1 - case len(r) == 2 && r[0] == 0 && r[1] == unicode.MaxRune: - i.Op = InstRuneAny - case len(r) == 4 && r[0] == 0 && r[1] == '\n'-1 && r[2] == '\n'+1 && r[3] == unicode.MaxRune: - i.Op = InstRuneAnyNotNL - } - - return f -} |