// Copyright 2000-2005 the Contributors, as shown in the revision logs. // Licensed under the Apache Public Source License 2.0 ("the License"). // You may not use this file except in compliance with the License. package org.ibex.js; /** A JavaScript regular expression object */ public class JSRegexp extends JS.Immutable { private static final JS.Method METHOD = new JS.Method(); private boolean global; private GnuRegexp.RE re; private int lastIndex; private JS pattern; private int flags; public JSRegexp(JS arg0, JS arg1) throws JSExn { if(arg0 instanceof JSRegexp) { JSRegexp r = (JSRegexp) arg0; this.global = r.global; this.re = r.re; this.lastIndex = r.lastIndex; this.pattern = r.pattern; this.flags = r.flags; } else { String pattern = JSU.toString(arg0); String sFlags = null; int flags = 0; if(arg1 != null) sFlags = JSU.toString(arg1); if(sFlags == null) sFlags = ""; for(int i=0;i= s.length()) { lastIndex = 0; return null; } GnuRegexp.REMatch match = re.getMatch(s,start); if(global) lastIndex = match == null ? s.length() : match.getEndIndex(); return match == null ? null : matchToExecResult(match,re,s); } case "test": { String s = JSU.toString(args[0]); if (!global) return JSU.B(re.getMatch(s) != null); int start = global ? lastIndex : 0; if(start < 0 || start >= s.length()) { lastIndex = 0; return null; } GnuRegexp.REMatch match = re.getMatch(s,start); lastIndex = match != null ? s.length() : match.getEndIndex(); return JSU.B(match != null); } case "toString": return JSU.S(args[0].coerceToString()); //#end break; } case 2: { //#switch(JSU.str(method)) case "stringMatch": return stringMatch(args[0], args[1]); case "stringSearch": return stringSearch(args[0], args[1]); //#end break; } case 3: { //#switch(JSU.str(method)) case "stringReplace": return stringReplace(args[0], args[1], args[2]); //#end break; } } return super.call(method, args); } public JS get(JS key) throws JSExn { //#switch(JSU.str(key)) case "exec": return METHOD; case "test": return METHOD; case "toString": return METHOD; case "lastIndex": return JSU.N(lastIndex); case "source": return pattern; case "global": return JSU.B(global); case "ignoreCase": return JSU.B(flags & GnuRegexp.RE.REG_ICASE); case "multiline": return JSU.B(flags & GnuRegexp.RE.REG_MULTILINE); //#end return super.get(key); } public void put(JS key, JS value) throws JSExn { if(JSU.isString(key)) { if(JSU.toString(key).equals("lastIndex")) { lastIndex = JSU.toInt(value); return; } } super.put(key,value); } private static JS matchToExecResult(GnuRegexp.REMatch match, GnuRegexp.RE re, String s) { if (match == null) return null; try { JS ret = new JS.Obj(); ret.put(JSU.S("index"), JSU.N(match.getStartIndex())); ret.put(JSU.S("input"), JSU.S(s)); int n = re.getNumSubs(); ret.put(JSU.S("length"), JSU.N(n+1)); ret.put(JSU.ZERO, JSU.S(match.toString())); for(int i=1;i<=n;i++) ret.put(JSU.N(i),JSU.S(match.toString(i))); return ret; } catch (JSExn e) { throw new Error("this should never happen"); } } public String coerceToString() { StringBuffer sb = new StringBuffer(); sb.append('/'); sb.append(pattern); sb.append('/'); if(global) sb.append('g'); if((flags & GnuRegexp.RE.REG_ICASE) != 0) sb.append('i'); if((flags & GnuRegexp.RE.REG_MULTILINE) != 0) sb.append('m'); return sb.toString(); } private static final JS[] execarg = new JS[1]; static JS stringMatch(JS o, JS arg0) throws JSExn { String s = JSU.toString(o); GnuRegexp.RE re; JSRegexp regexp = null; if(arg0 instanceof JSRegexp) { regexp = (JSRegexp) arg0; re = regexp.re; } else { re = newRE(JSU.toString(arg0),0); } if(regexp == null) { GnuRegexp.REMatch match = re.getMatch(s); return matchToExecResult(match,re,s); } try { execarg[0] = o; if(!regexp.global) return regexp.call(JSU.S("exec"), execarg); } finally { execarg[0] = null; } GnuRegexp.REMatch[] matches = re.getAllMatches(s); JSArray ret = new JSArray(matches.length); for(int i=0;i 0 ? matches[matches.length-1].getEndIndex() : s.length(); return ret; } static JS stringSearch(JS o, JS arg0) throws JSExn { String s = JSU.toString(o); GnuRegexp.RE re = arg0 instanceof JSRegexp ? ((JSRegexp)arg0).re : newRE(JSU.toString(arg0),0); GnuRegexp.REMatch match = re.getMatch(s); return match == null ? JSU.N(-1) : JSU.N(match.getStartIndex()); } static JS stringReplace(JS o, JS arg0, JS arg1) throws JSExn { String s = JSU.toString(o); GnuRegexp.RE re; JSFunction replaceFunc = null; String replaceString = null; JSRegexp regexp = null; if(arg0 instanceof JSRegexp) { regexp = (JSRegexp) arg0; re = regexp.re; } else { re = newRE(arg0.toString(),0); } if(arg1 instanceof JSFunction) replaceFunc = (JSFunction) arg1; else replaceString = JSU.toString(arg1); GnuRegexp.REMatch[] matches; if(regexp != null && regexp.global) { matches = re.getAllMatches(s); if(regexp != null) { if(matches.length > 0) regexp.lastIndex = matches[matches.length-1].getEndIndex(); else regexp.lastIndex = s.length(); } } else { GnuRegexp.REMatch match = re.getMatch(s); if(match != null) matches = new GnuRegexp.REMatch[]{ match }; else matches = new GnuRegexp.REMatch[0]; } StringBuffer sb = new StringBuffer(s.length()); int pos = 0; char[] sa = s.toCharArray(); for(int i=0;i= '0' && c2 <= '9') { n = (c - '0') * 10 + (c2 - '0'); i++; } else { n = c - '0'; } if(n > 0) sb.append(match.toString(n)); break; case '$': sb.append('$'); break; case '&': sb.append(match.toString()); break; case '`': sb.append(source.substring(0,match.getStartIndex())); break; case '\'': sb.append(source.substring(match.getEndIndex())); break; default: sb.append('$'); sb.append(c); } } if(i < s.length()) sb.append(s.charAt(i)); return sb.toString(); } static JS stringSplit(JS s_, JS arg0, JS arg1, int nargs) throws JSExn { String s = JSU.toString(s_); int limit = nargs < 2 ? Integer.MAX_VALUE : JSU.toInt(arg1); if(limit < 0) limit = Integer.MAX_VALUE; if(limit == 0) return new JSArray(0); GnuRegexp.RE re = null; JSRegexp regexp = null; String sep = null; JSArray ret = new JSArray(); int p = 0; if(arg0 instanceof JSRegexp) { regexp = (JSRegexp) arg0; re = regexp.re; } else { sep = JSU.toString(arg0); } // special case this for speed. additionally, the code below doesn't properly handle // zero length strings if(sep != null && sep.length()==0) { int len = s.length(); for(int i=0;i