aboutsummaryrefslogtreecommitdiff
path: root/src/lang/PredicateEncoder.java
blob: 7ba64981127f04a19f33a9cac1e9bd275b5a955b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package com.googlecode.prolog_cafe.lang;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/**
 * The <code>PredicateEncoder</code> class contains static methods for encoding predicate names.<br>
 * The predicate with <code>hoge:f/n</code> is encoded to <code>hoge.PRED_f_n</code>, where
 * <code>hoge</code> is package name,
 * <code>f</code> is predicate name, and 
 * <code>n</code> is arity.<br>
 *
 * When encoding a predicate name, we apply the following rules:<br>
 *<ul>
 *<li>The alphanumeric characters
 * &ldquo;<code>a</code>&rdquo; through &ldquo;<code>z</code>&rdquo;, 
 * &ldquo;<code>A</code>&rdquo; through &ldquo;<code>Z</code>&rdquo; and 
 * &ldquo;<code>0</code>&rdquo; through &ldquo;<code>9</code>&rdquo; remain the same.
 *<li>The special characters &ldquo;<code>_</code>&rdquo; and &ldquo;<code>$</code>&rdquo; remain the same.
 *<li>All other characters are first converted into a list of character codes. 
 * Then each character code is represented by the 5-character string &ldquo;<code>$XYZW</code>&rdquo;, 
 * where <code>XYZW</code> is the four-digit hexadecimal representation of the character code.
 *</ul>
 *
 * For example,
 * a predicate with <code>hoge:(=..)/2</code> is encoded to <code>hoge.PRED_$003D$002E$002E_2</code>.
 *
 * @author Mutsunori Banbara (banbara@kobe-u.ac.jp)
 * @author Naoyuki Tamura (tamura@kobe-u.ac.jp)
 * @version 1.1
 */
public class PredicateEncoder {

    /**
     * Returns a string representation of class for
     * the predicate with the given arguments.
     * @param pkg package name
     * @param functor predicate name
     * @param arity predicate arity
     * @return a string representation of class for
     * the predicate that corresponds to <code>pkg:functor/arity</code>.
     */
    public static String encode(String pkg, String functor, int arity) {
	String x = functor;
	Pattern p = Pattern.compile("([^a-zA-Z0-9_'$'])");
	Matcher m = p.matcher(x);
	StringBuffer sb = new StringBuffer();
	boolean result = m.find();
	while (result) {
	    //	    m.appendReplacement(sb, String.format("\\$%2X", (int)(m.group().charAt(0))));
	    m.appendReplacement(sb, String.format("\\$%04X", (int)(m.group().charAt(0))));
	    result = m.find();
	}
	m.appendTail(sb);
	x = sb.toString();
	return pkg + ".PRED_" + x + "_" + arity;
    }

    public static String decodeFunctor(String className) {
      // Remove the Java package name, if present.
      int dot = className.lastIndexOf('.');
      if (0 < dot)
        className = className.substring(dot + 1);

      // Trim the common PRED_ prefix.
      if (className.startsWith("PRED_"))
        className = className.substring("PRED_".length());

      // Drop the arity from the end.
      int us = className.lastIndexOf('_');
      if (0 < us)
        className = className.substring(0, us);

      Pattern p = Pattern.compile("\\$([0-9A-F]{4})");
      Matcher m = p.matcher(className);
      StringBuffer r = new StringBuffer();
      while (m.find()) {
        char c = (char) Integer.parseInt(m.group());
        m.appendReplacement(r, Character.toString(c));
      }
      m.appendTail(r);
      return r.toString();
    }

    /**
     * Returns a <code>java.lang.Class</code> object associated with the predicate
     * class with the given arguments.
     * @param pkg package name
     * @param functor predicate name
     * @param arity predicate arity
     * @return a <code>java.lang.Class</code> object associated with the predicate
     * class that corresponds to <code>pkg:functor/arity</code>
     * if exists, otherwise <code>null</code>.
     * @deprecated As of Prolog Cafe 1.1, replaced by {@link PrologClassLoader#loadPredicateClass(String,String,int,boolean)};
     */
    public static Class getClass(String pkg, String functor, int arity) {
	String className = PredicateEncoder.encode(pkg, functor, arity);
	Class clazz = null;
	try {
	    clazz = Class.forName(className);
	} catch (ClassNotFoundException e) {}
	return clazz;
    }

    /**
     * Check whether the predicate class for the given arguments is defined.
     * @param pkg package name
     * @param functor predicate name
     * @param arity predicate arity
     * @return <code>true</code> if the predicate <code>pkg:functor/arity</code>
     * is defined, otherwise <code>false</code>.
     * @deprecated As of Prolog Cafe 1.1, replaced by {@link PrologClassLoader#definedPredicate(String,String,int)};
     */
    public static boolean defined(String pkg, String functor, int arity) {
	Class clazz = PredicateEncoder.getClass(pkg, functor, arity);
	return clazz != null;
    }

    public static void main(String argv[]) {
	String p = argv[0];
	String f = argv[1];
	int n = (Integer.valueOf(argv[2])).intValue();
	System.out.println(p + ":" + f + "/" + n);
	System.out.println(PredicateEncoder.encode(p,f,n));
	System.out.println(PredicateEncoder.defined(p,f,n));
    }
}