• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kjs
 

kjs

  • kjs
regexp_object.cpp
1 // -*- c-basic-offset: 2 -*-
2 /*
3  * This file is part of the KDE libraries
4  * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
5  * Copyright (C) 2003 Apple Computer, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  *
21  */
22 
23 #include <stdio.h>
24 
25 #include "value.h"
26 #include "object.h"
27 #include "types.h"
28 #include "interpreter.h"
29 #include "operations.h"
30 #include "internal.h"
31 #include "regexp.h"
32 #include "regexp_object.h"
33 #include "error_object.h"
34 #include "lookup.h"
35 
36 using namespace KJS;
37 
38 // ------------------------------ RegExpPrototypeImp ---------------------------
39 
40 // ECMA 15.9.4
41 
42 const ClassInfo RegExpPrototypeImp::info = {"RegExp", 0, 0, 0};
43 
44 RegExpPrototypeImp::RegExpPrototypeImp(ExecState *exec,
45  ObjectPrototypeImp *objProto,
46  FunctionPrototypeImp *funcProto)
47  : ObjectImp(objProto)
48 {
49  Value protect(this);
50  setInternalValue(String(""));
51 
52  // The constructor will be added later in RegExpObject's constructor (?)
53 
54  static const Identifier execPropertyName("exec");
55  putDirect(execPropertyName,
56  new RegExpProtoFuncImp(exec,funcProto,RegExpProtoFuncImp::Exec, 0, execPropertyName), DontEnum);
57  static const Identifier testPropertyName("test");
58  putDirect(testPropertyName,
59  new RegExpProtoFuncImp(exec,funcProto,RegExpProtoFuncImp::Test, 0, testPropertyName), DontEnum);
60  putDirect(toStringPropertyName,
61  new RegExpProtoFuncImp(exec,funcProto,RegExpProtoFuncImp::ToString, 0, toStringPropertyName), DontEnum);
62  static const Identifier compilePropertyName("compile");
63  putDirect(compilePropertyName,
64  new RegExpProtoFuncImp(exec,funcProto,RegExpProtoFuncImp::Compile, 1, compilePropertyName), DontEnum);
65 }
66 
67 // ------------------------------ RegExpProtoFuncImp ---------------------------
68 
69 RegExpProtoFuncImp::RegExpProtoFuncImp(ExecState * /*exec*/, FunctionPrototypeImp *funcProto,
70  int i, int len, const Identifier &_ident)
71  : InternalFunctionImp(funcProto), id(i)
72 {
73  Value protect(this);
74  putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
75  ident = _ident;
76 }
77 
78 bool RegExpProtoFuncImp::implementsCall() const
79 {
80  return true;
81 }
82 
83 Value RegExpProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
84 {
85  if (!thisObj.inherits(&RegExpImp::info)) {
86  if (thisObj.inherits(&RegExpPrototypeImp::info)) {
87  switch (id) {
88  case ToString: return String("//"); // FireFox returns /(?:)/
89  }
90  }
91  Object err = Error::create(exec,TypeError);
92  exec->setException(err);
93  return err;
94  }
95 
96  RegExpImp *reimp = static_cast<RegExpImp*>(thisObj.imp());
97  RegExp *re = reimp->regExp();
98  String s;
99  UString str;
100  switch (id) {
101  case Exec: // 15.10.6.2
102  case Test:
103  {
104  s = args[0].toString(exec);
105  int length = s.value().size();
106 
107  // Get values from the last time (in case of /g)
108  Value lastIndex = thisObj.get(exec,"lastIndex");
109  int i = lastIndex.isValid() ? lastIndex.toInt32(exec) : 0;
110  bool globalFlag = thisObj.get(exec,"global").toBoolean(exec);
111  if (!globalFlag)
112  i = 0;
113  if (i < 0 || i > length) {
114  thisObj.put(exec,"lastIndex", Number(0), DontDelete | DontEnum);
115  if (id == Test)
116  return Boolean(false);
117  else
118  return Null();
119  }
120  RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalInterpreter()->builtinRegExp().imp());
121  int **ovector = regExpObj->registerRegexp( re, s.value() );
122 
123  re->prepareMatch(s.value());
124  str = re->match(s.value(), i, 0L, ovector);
125  re->doneMatch();
126  regExpObj->setSubPatterns(re->subPatterns());
127 
128  if (id == Test)
129  return Boolean(!str.isNull());
130 
131  if (str.isNull()) // no match
132  {
133  if (globalFlag)
134  thisObj.put(exec,"lastIndex",Number(0), DontDelete | DontEnum);
135  return Null();
136  }
137  else // success
138  {
139  if (globalFlag)
140  thisObj.put(exec,"lastIndex",Number( (*ovector)[1] ), DontDelete | DontEnum);
141  return regExpObj->arrayOfMatches(exec,str);
142  }
143  }
144  break;
145  case ToString:
146  s = thisObj.get(exec,"source").toString(exec);
147  str = "/";
148  str += s.value();
149  str += "/";
150  if (thisObj.get(exec,"global").toBoolean(exec)) {
151  str += "g";
152  }
153  if (thisObj.get(exec,"ignoreCase").toBoolean(exec)) {
154  str += "i";
155  }
156  if (thisObj.get(exec,"multiline").toBoolean(exec)) {
157  str += "m";
158  }
159  return String(str);
160  case Compile: {
161  RegExp* newEngine = RegExpObjectImp::makeEngine(exec, args[0].toString(exec), args[1]);
162  if (!newEngine)
163  return exec->exception();
164  reimp->setRegExp(newEngine);
165  return Value(reimp);
166  }
167  }
168 
169 
170  return Undefined();
171 }
172 
173 // ------------------------------ RegExpImp ------------------------------------
174 
175 const ClassInfo RegExpImp::info = {"RegExp", 0, 0, 0};
176 
177 RegExpImp::RegExpImp(RegExpPrototypeImp *regexpProto)
178  : ObjectImp(regexpProto), reg(0L)
179 {
180 }
181 
182 RegExpImp::~RegExpImp()
183 {
184  delete reg;
185 }
186 
187 void RegExpImp::setRegExp(RegExp *r)
188 {
189  delete reg;
190  reg = r;
191 
192  Object protect(this);//Protect self from GC (we are allocating a StringImp, and may be new)
193  putDirect("global", (r->flags() & RegExp::Global) ? BooleanImp::staticTrue : BooleanImp::staticFalse,
194  DontDelete | ReadOnly | DontEnum);
195  putDirect("ignoreCase", (r->flags() & RegExp::IgnoreCase) ? BooleanImp::staticTrue : BooleanImp::staticFalse,
196  DontDelete | ReadOnly | DontEnum);
197  putDirect("multiline", (r->flags() & RegExp::Multiline) ? BooleanImp::staticTrue : BooleanImp::staticFalse,
198  DontDelete | ReadOnly | DontEnum);
199 
200  putDirect("source", new StringImp(r->pattern()), DontDelete | ReadOnly | DontEnum);
201  putDirect("lastIndex", NumberImp::zero(), DontDelete | DontEnum);
202 }
203 
204 // ------------------------------ RegExpObjectImp ------------------------------
205 
206 RegExpObjectImp::RegExpObjectImp(ExecState * /*exec*/,
207  FunctionPrototypeImp *funcProto,
208  RegExpPrototypeImp *regProto)
209 
210  : InternalFunctionImp(funcProto), lastOvector(0L), lastNrSubPatterns(0)
211 {
212  Value protect(this);
213  // ECMA 15.10.5.1 RegExp.prototype
214  putDirect(prototypePropertyName, regProto, DontEnum|DontDelete|ReadOnly);
215 
216  // no. of arguments for constructor
217  putDirect(lengthPropertyName, NumberImp::two(), ReadOnly|DontDelete|DontEnum);
218 }
219 
220 RegExpObjectImp::~RegExpObjectImp()
221 {
222  delete [] lastOvector;
223 }
224 
225 int **RegExpObjectImp::registerRegexp( const RegExp* re, const UString& s )
226 {
227  lastString = s;
228  delete [] lastOvector;
229  lastOvector = 0;
230  lastNrSubPatterns = re->subPatterns();
231  return &lastOvector;
232 }
233 
234 Object RegExpObjectImp::arrayOfMatches(ExecState *exec, const UString &result) const
235 {
236  List list;
237  // The returned array contains 'result' as first item, followed by the list of matches
238  list.append(String(result));
239  if ( lastOvector )
240  for ( unsigned int i = 1 ; i < lastNrSubPatterns + 1 ; ++i )
241  {
242  UString substring = lastString.substr( lastOvector[2*i], lastOvector[2*i+1] - lastOvector[2*i] );
243  list.append(String(substring));
244  }
245  Object arr = exec->lexicalInterpreter()->builtinArray().construct(exec, list);
246  arr.put(exec, "index", Number(lastOvector[0]));
247  arr.put(exec, "input", String(lastString));
248  return arr;
249 }
250 
251 Value RegExpObjectImp::get(ExecState *exec, const Identifier &p) const
252 {
253  UString s = p.ustring();
254  if (s[0] == '$' && lastOvector)
255  {
256  bool ok;
257  unsigned long i = s.substr(1).toULong(&ok);
258  if (ok)
259  {
260  if (i < lastNrSubPatterns + 1)
261  {
262  UString substring = lastString.substr( lastOvector[2*i], lastOvector[2*i+1] - lastOvector[2*i] );
263  return String(substring);
264  }
265  return String("");
266  }
267  }
268  return InternalFunctionImp::get(exec, p);
269 }
270 
271 bool RegExpObjectImp::hasProperty(ExecState *exec, const Identifier &p) const
272 {
273  UString s = p.ustring();
274  if (s[0] == '$' && lastOvector) {
275  bool ok;
276  (void)s.substr(1).toULong(&ok);
277  if (ok)
278  return true;
279  }
280 
281  return InternalFunctionImp::hasProperty(exec, p);
282 }
283 
284 bool RegExpObjectImp::implementsConstruct() const
285 {
286  return true;
287 }
288 
289 RegExp* RegExpObjectImp::makeEngine(ExecState *exec, const UString &p, const Value &flagsInput)
290 {
291  UString flags = flagsInput.type() == UndefinedType ? UString("") : flagsInput.toString(exec);
292 
293  // Check for validity of flags
294  for (int pos = 0; pos < flags.size(); ++pos) {
295  switch (flags[pos].unicode()) {
296  case 'g':
297  case 'i':
298  case 'm':
299  break;
300  default: {
301  Object err = Error::create(exec, SyntaxError,
302  "Invalid regular expression flags");
303  exec->setException(err);
304  return 0;
305  }
306  }
307  }
308 
309  bool global = (flags.find("g") >= 0);
310  bool ignoreCase = (flags.find("i") >= 0);
311  bool multiline = (flags.find("m") >= 0);
312 
313  int reflags = RegExp::None;
314  if (global)
315  reflags |= RegExp::Global;
316  if (ignoreCase)
317  reflags |= RegExp::IgnoreCase;
318  if (multiline)
319  reflags |= RegExp::Multiline;
320 
321  RegExp *re = new RegExp(p, reflags);
322  if (!re->isValid()) {
323  Object err = Error::create(exec, SyntaxError,
324  "Invalid regular expression");
325  exec->setException(err);
326  delete re;
327  return 0;
328  }
329  return re;
330 }
331 
332 // ECMA 15.10.4
333 Object RegExpObjectImp::construct(ExecState *exec, const List &args)
334 {
335  UString p;
336  if (args.isEmpty()) {
337  p = "";
338  } else {
339  Value a0 = args[0];
340  if (a0.isA(ObjectType) && a0.toObject(exec).inherits(&RegExpImp::info)) {
341  // It's a regexp. Check that no flags were passed.
342  if (args.size() > 1 && args[1].type() != UndefinedType) {
343  Object err = Error::create(exec,TypeError);
344  exec->setException(err);
345  return err;
346  }
347  RegExpImp *rimp = static_cast<RegExpImp*>(Object::dynamicCast(a0).imp());
348  p = rimp->regExp()->pattern();
349  } else {
350  p = a0.toString(exec);
351  }
352  }
353 
354  RegExp* re = makeEngine(exec, p, args[1]);
355  if (!re)
356  return exec->exception().toObject(exec);
357 
358  RegExpPrototypeImp *proto = static_cast<RegExpPrototypeImp*>(exec->lexicalInterpreter()->builtinRegExpPrototype().imp());
359  RegExpImp *dat = new RegExpImp(proto);
360  Object obj(dat); // protect from GC
361  dat->setRegExp(re);
362 
363  return obj;
364 }
365 
366 bool RegExpObjectImp::implementsCall() const
367 {
368  return true;
369 }
370 
371 // ECMA 15.10.3
372 Value RegExpObjectImp::call(ExecState *exec, Object &/*thisObj*/,
373  const List &args)
374 {
375  // TODO: handle RegExp argument case (15.10.3.1)
376 
377  return construct(exec, args);
378 }
KJS::Boolean
Represents an primitive Boolean value.
Definition: value.h:317
KJS::ExecState
Represents the current state of script execution.
Definition: interpreter.h:439
KJS::ExecState::lexicalInterpreter
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope's global object.
Definition: interpreter.cpp:395
KJS::FunctionPrototypeImp
The initial value of Function.prototype (and thus all objects created with the Function constructor)
Definition: function_object.h:35
KJS::Identifier
Represents an Identifier for a Javascript object.
Definition: identifier.h:32
KJS::Identifier::ustring
const UString & ustring() const
returns a UString of the identifier
Definition: identifier.h:52
KJS::InternalFunctionImp
Base class for all function objects.
Definition: function.h:41
KJS::Interpreter::builtinRegExp
Object builtinRegExp() const
Returns the builtin "RegExp" object.
Definition: interpreter.cpp:209
KJS::Interpreter::builtinRegExpPrototype
Object builtinRegExpPrototype() const
Returns the builtin "RegExp.prototype" object.
Definition: interpreter.cpp:254
KJS::Interpreter::builtinArray
Object builtinArray() const
Returns the builtin "Array" object.
Definition: interpreter.cpp:184
KJS::List
Native list type.
Definition: list.h:48
KJS::List::append
void append(const Value &val)
Append an object to the end of the list.
Definition: list.h:66
KJS::List::isEmpty
bool isEmpty() const
Definition: list.h:86
KJS::List::size
int size() const
Definition: list.h:90
KJS::Null
Represents an primitive Null value.
Definition: value.h:295
KJS::Number
Represents an primitive Number value.
Definition: value.h:368
KJS::Object
Represents an Object.
Definition: object.h:82
KJS::Object::construct
Object construct(ExecState *exec, const List &args)
Creates a new object based on this object.
Definition: object.h:697
KJS::Object::put
void put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr=None)
Sets the specified property.
Definition: object.h:670
KJS::Object::get
Value get(ExecState *exec, const Identifier &propertyName) const
Retrieves the specified property from the object.
Definition: object.h:664
KJS::String
Represents an primitive String value.
Definition: value.h:341
KJS::UString
Unicode string class.
Definition: ustring.h:190
KJS::UString::toULong
unsigned long toULong(bool *ok, bool tolerateEmptyString) const
Attempts an conversion to an unsigned long integer.
Definition: ustring.cpp:686
KJS::UString::find
int find(const UString &f, int pos=0) const
Definition: ustring.cpp:799
KJS::UString::isNull
bool isNull() const
Definition: ustring.h:344
KJS::UString::size
int size() const
Definition: ustring.h:360
KJS::UString::substr
UString substr(int pos=0, int len=-1) const
Definition: ustring.cpp:869
KJS::Undefined
Represents an primitive Undefined value.
Definition: value.h:270
KJS::Value
Value objects are act as wrappers ("smart pointers") around ValueImp objects and their descendents.
Definition: value.h:168
KJS::Value::toString
UString toString(ExecState *exec) const
Performs the ToString type conversion operation on this value (ECMA 9.8)
Definition: value.h:247
KJS::Value::isA
bool isA(Type t) const
Checks whether or not the value is of a particular tpye.
Definition: value.h:204
KJS::Value::toObject
Object toObject(ExecState *exec) const
Performs the ToObject type conversion operation on this value (ECMA 9.9)
Definition: object.h:359
KJS::Value::toInt32
int toInt32(ExecState *exec) const
Performs the ToInt32 type conversion operation on this value (ECMA 9.5)
Definition: value.h:232
KJS::Value::toBoolean
bool toBoolean(ExecState *exec) const
Performs the ToBoolean type conversion operation on this value (ECMA 9.2)
Definition: value.h:217
KJS::Value::isValid
bool isValid() const
Returns whether or not this is a valid value.
Definition: value.h:182
KJS::Value::type
Type type() const
Returns the type of value.
Definition: value.h:196
KJS::ClassInfo
Class Information.
Definition: object.h:59

kjs

Skip menu "kjs"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kjs

Skip menu "kjs"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kjs by doxygen 1.9.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |