fix implicit_pattern_rule_prefix.mk

implement ruleTrie for implicit rules
diff --git a/dep.go b/dep.go
index d3d3a62..d215f37 100644
--- a/dep.go
+++ b/dep.go
@@ -17,7 +17,6 @@
 import (
 	"fmt"
 	"path/filepath"
-	"sort"
 	"strings"
 )
 
@@ -45,9 +44,7 @@
 	rules    map[string]*rule
 	ruleVars map[string]Vars
 
-	implicitRules []*rule // pattern=%. no prefix,suffix.
-	iprefixRules  []*rule // pattern=prefix%..  may have suffix
-	isuffixRules  []*rule // pattern=%suffix  no prefix
+	implicitRules *ruleTrie
 
 	suffixRules map[string][]*rule
 	firstRule   *rule
@@ -63,6 +60,70 @@
 	pickExplicitRuleWithoutCmdCnt int
 }
 
+type ruleTrieEntry struct {
+	rule   *rule
+	suffix string
+}
+
+type ruleTrie struct {
+	rules    []ruleTrieEntry
+	children map[byte]*ruleTrie
+}
+
+func newRuleTrie() *ruleTrie {
+	return &ruleTrie{
+		children: make(map[byte]*ruleTrie),
+	}
+}
+
+func (rt *ruleTrie) add(name string, r *rule) {
+	logf("rule trie: add %q %v %s", name, r.outputPatterns[0], r)
+	if name == "" || name[0] == '%' {
+		logf("rule trie: add entry %q %v %s", name, r.outputPatterns[0], r)
+		rt.rules = append(rt.rules, ruleTrieEntry{
+			rule:   r,
+			suffix: name,
+		})
+		return
+	}
+	c, found := rt.children[name[0]]
+	if !found {
+		c = newRuleTrie()
+		rt.children[name[0]] = c
+	}
+	c.add(name[1:], r)
+}
+
+func (rt *ruleTrie) lookup(name string) []*rule {
+	logf("rule trie: lookup %q", name)
+	if rt == nil {
+		return nil
+	}
+	var rules []*rule
+	for _, entry := range rt.rules {
+		if (entry.suffix == "" && name == "") || strings.HasSuffix(name, entry.suffix[1:]) {
+			rules = append(rules, entry.rule)
+		}
+	}
+	if name == "" {
+		return rules
+	}
+	rules = append(rules, rt.children[name[0]].lookup(name[1:])...)
+	logf("rule trie: lookup %q => %v", name, rules)
+	return rules
+}
+
+func (rt *ruleTrie) size() int {
+	if rt == nil {
+		return 0
+	}
+	size := len(rt.rules)
+	for _, c := range rt.children {
+		size += c.size()
+	}
+	return size
+}
+
 func replaceSuffix(s string, newsuf string) string {
 	// TODO: Factor out the logic around suffix rules and use
 	// it from substitution references.
@@ -81,55 +142,6 @@
 	return exists(target)
 }
 
-func (db *depBuilder) PickImplicitRules(output string) []*rule {
-	var rules []*rule
-	i := sort.Search(len(db.iprefixRules), func(i int) bool {
-		prefix := db.iprefixRules[i].outputPatterns[0].prefix
-		if strings.HasPrefix(output, prefix) {
-			return true
-		}
-		return prefix >= output
-	})
-	if i < len(db.iprefixRules) {
-		for ; i < len(db.iprefixRules); i++ {
-			rule := db.iprefixRules[i]
-			if !strings.HasPrefix(output, rule.outputPatterns[0].prefix) {
-				break
-			}
-			if db.canPickImplicitRule(rule, output) {
-				rules = append(rules, rule)
-			}
-		}
-	}
-
-	i = sort.Search(len(db.isuffixRules), func(i int) bool {
-		suffix := db.isuffixRules[i].outputPatterns[0].suffix
-		if strings.HasSuffix(output, suffix) {
-			return true
-		}
-		return reverse(suffix) >= reverse(output)
-	})
-	if i < len(db.isuffixRules) {
-		for ; i < len(db.isuffixRules); i++ {
-			rule := db.isuffixRules[i]
-			if !strings.HasSuffix(output, rule.outputPatterns[0].suffix) {
-				break
-			}
-			if db.canPickImplicitRule(rule, output) {
-				rules = append(rules, rule)
-			}
-		}
-	}
-	for _, rule := range db.implicitRules {
-		if db.canPickImplicitRule(rule, output) {
-			rules = append(rules, rule)
-		}
-	}
-	// TODO(ukai): which implicit rules is selected?
-	// longest match? last defined?
-	return rules
-}
-
 func (db *depBuilder) canPickImplicitRule(r *rule, output string) bool {
 	outputPattern := r.outputPatterns[0]
 	if !outputPattern.match(output) {
@@ -179,7 +191,14 @@
 		db.pickExplicitRuleWithoutCmdCnt++
 	}
 
-	for _, irule := range db.PickImplicitRules(output) {
+	irules := db.implicitRules.lookup(output)
+	for i := len(irules) - 1; i >= 0; i-- {
+		irule := irules[i]
+		if !db.canPickImplicitRule(irule, output) {
+			logf("ignore implicit rule %q %s", output, irule)
+			continue
+		}
+		logf("pick implicit rule %q => %q %s", output, irule.outputPatterns, irule)
 		db.pickImplicitRuleCnt++
 		if r != nil {
 			ir := &rule{}
@@ -438,13 +457,7 @@
 		ir := &rule{}
 		*ir = *r
 		ir.outputPatterns = []pattern{outputPattern}
-		if outputPattern.prefix != "" {
-			db.iprefixRules = append(db.iprefixRules, ir)
-		} else if outputPattern.suffix != "" {
-			db.isuffixRules = append(db.isuffixRules, ir)
-		} else {
-			db.implicitRules = append(db.implicitRules, ir)
-		}
+		db.implicitRules.add(outputPattern.String(), ir)
 	}
 }
 
@@ -465,14 +478,6 @@
 		}
 	}
 
-	// reverse to the last implicit rules should be selected.
-	// testcase/implicit_pattern_rule.mk
-	reverseImplicitRules(db.implicitRules)
-	reverseImplicitRules(db.iprefixRules)
-	reverseImplicitRules(db.isuffixRules)
-
-	sort.Stable(byPrefix(db.iprefixRules))
-	sort.Stable(bySuffix(db.isuffixRules))
 	return nil
 }
 
@@ -513,12 +518,13 @@
 
 func newDepBuilder(er *evalResult, vars Vars) (*depBuilder, error) {
 	db := &depBuilder{
-		rules:       make(map[string]*rule),
-		ruleVars:    er.ruleVars,
-		suffixRules: make(map[string][]*rule),
-		vars:        vars,
-		done:        make(map[string]*DepNode),
-		phony:       make(map[string]bool),
+		rules:         make(map[string]*rule),
+		ruleVars:      er.ruleVars,
+		implicitRules: newRuleTrie(),
+		suffixRules:   make(map[string][]*rule),
+		vars:          vars,
+		done:          make(map[string]*DepNode),
+		phony:         make(map[string]bool),
 	}
 
 	err := db.populateRules(er)
@@ -544,7 +550,7 @@
 
 	logStats("%d variables", len(db.vars))
 	logStats("%d explicit rules", len(db.rules))
-	logStats("%d implicit rules", len(db.implicitRules))
+	logStats("%d implicit rules", db.implicitRules.size())
 	logStats("%d suffix rules", len(db.suffixRules))
 
 	var nodes []*DepNode
diff --git a/testcase/implicit_pattern_rule_prefix.mk b/testcase/implicit_pattern_rule_prefix.mk
index 8ed95b2..6df648c 100644
--- a/testcase/implicit_pattern_rule_prefix.mk
+++ b/testcase/implicit_pattern_rule_prefix.mk
@@ -1,5 +1,3 @@
-# TODO(go): Fix
-
 MAKEVER:=$(shell make --version | ruby -n0e 'puts $$_[/Make (\d)/,1]')
 
 test: abcd