PageRenderTime 34ms CodeModel.GetById 18ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 1ms

/vm/regexp.go

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