/vm/regexp.go

http://github.com/feyeleanor/RubyGoLightly · Go · 97 lines · 80 code · 14 blank · 3 comment · 11 complexity · e26987f868fb6b0d1525a82f56d371e8 MD5 · raw file

  1. import (
  2. "pcre";
  3. "tr";
  4. )
  5. // Loosely based on http://vcs.pcre.org/viewvc/code/trunk/pcredemo.c
  6. // Translate this to use Go's stdlib regexp package
  7. func TrRegexp_new(vm *RubyVM, pattern *string, options int) RubyObject {
  8. r := Regexp{type: TR_T_Regexp, class: vm.classes[TR_T_Regexp], ivars: make(map[string] RubyObject)};
  9. error *string;
  10. erroffset int;
  11. r.re = pcre_compile(
  12. pattern, /* the pattern */
  13. options, /* default options */
  14. &error, /* for error message */
  15. &erroffset, /* for error offset */
  16. nil); /* use default character tables */
  17. if (r.re == nil) {
  18. TrRegex_free(vm, r);
  19. vm.throw_reason = TR_THROW_EXCEPTION;
  20. vm.throw_value = TrException_new(vm, vm.cRegexpError, tr_sprintf(vm, "compilation failed at offset %d: %s", erroffset, error));
  21. return TR_UNDEF;
  22. }
  23. return r;
  24. }
  25. func TrRegexp_compile(vm *RubyVM, self, pattern *RubyObject) RubyObject {
  26. if !pattern.(String) && !pattern.(Symbol) {
  27. vm.throw_reason = TR_THROW_EXCEPTION;
  28. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + pattern));
  29. return TR_UNDEF;
  30. }
  31. return TrRegexp_new(vm, pattern.ptr, 0);
  32. }
  33. #define OVECCOUNT 30 /* should be a multiple of 3 */
  34. func TrRegexp_match(vm *RubyVM, self, str *RubyObject) RubyObject {
  35. if !self.(Regexp) {
  36. vm.throw_reason = TR_THROW_EXCEPTION;
  37. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected Regexp"));
  38. return TR_UNDEF;
  39. }
  40. if !str.(String) && !str.(Symbol) {
  41. vm.throw_reason = TR_THROW_EXCEPTION;
  42. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + str));
  43. return TR_UNDEF;
  44. }
  45. r := TrRegexp *(self);
  46. subject := str.ptr;
  47. rc int;
  48. ovector [OVECCOUNT]int;
  49. rc = pcre_exec(
  50. r.re, /* the compiled pattern */
  51. NULL, /* no extra data - we didn't study the pattern */
  52. subject, /* the subject string */
  53. str.len, /* the length of the subject */
  54. 0, /* start at offset 0 in the subject */
  55. 0, /* default options */
  56. ovector, /* output vector for substring information */
  57. OVECCOUNT); /* number of elements in the output vector */
  58. if (rc < 0) return TR_NIL;
  59. if (rc == 0) {
  60. rc = OVECCOUNT/3;
  61. vm.throw_reason = TR_THROW_EXCEPTION;
  62. vm.throw_value = TrException_new(vm, vm.cRegexpError, tr_sprintf(vm, "Too many matches, only %d supported for now", rc - 1));
  63. return TR_UNDEF;
  64. }
  65. // TODO should create a MatchData object
  66. data := vm.newArray();
  67. i int;
  68. for (i = 0; i < rc; i++) {
  69. substring_start := subject + ovector[2*i];
  70. substring_length := ovector[2*i+1] - ovector[2*i];
  71. data.Push(TrString_new(vm, substring_start, substring_length));
  72. }
  73. return data;
  74. }
  75. func TrRegex_free(vm *RubyVM, self *RubyObject) {
  76. r := TrRegexp *(self);
  77. pcre_free(r.re);
  78. }
  79. func TrRegexp_init(vm *RubyVM) {
  80. c := vm.classes[TR_T_Regexp] = Object_const_set(vm, vm.self, TrSymbol_new(vm, Regexp), newClass(vm, TrSymbol_new(vm, Regexp), vm.classes[TR_T_Object]));
  81. Object_add_singleton_method(vm, c, TrSymbol_new(vm, "new"), newMethod(vm, (TrFunc *)TrRegexp_compile, TR_NIL, 1));
  82. c.add_method(vm, TrSymbol_new(vm, "match"), newMethod(vm, (TrFunc *)TrRegexp_match, TR_NIL, 1));
  83. }