/vm/string.go

http://github.com/feyeleanor/RubyGoLightly · Go · 183 lines · 158 code · 22 blank · 3 comment · 27 complexity · bb7573de22079d72498df2188209e19b MD5 · raw file

  1. #include <alloca.h>
  2. #include <stdarg.h>
  3. #include <stdio.h>
  4. import (
  5. "bytes";
  6. "fmt";
  7. "tr";
  8. )
  9. // symbol
  10. func TrSymbol_lookup(vm *RubyVM, name string) RubyObject {
  11. return vm.symbols[name] || TR_NIL;
  12. }
  13. func TrSymbol_add(vm *RubyVM, name *string, id *RubyObject) {
  14. vm.symbols[name] = id;
  15. }
  16. func TrSymbol_new(vm *RubyVM, str *string) RubyObject {
  17. id := TrSymbol_lookup(vm, str);
  18. if (!id) {
  19. s := Symbol{type: TR_T_Symbol, class: vm.classes[TR_T_Symbol], ivars: make(map[string] RubyObject), len: strlen(str), ptr: make([]byte, s.len + 1), interned: true};
  20. bytes.Copy(s.ptr, str[0:s.len - 1]);
  21. s.ptr[s.len] = '\0';
  22. id := s;
  23. TrSymbol_add(vm, s.ptr, id);
  24. }
  25. return id;
  26. }
  27. func TrSymbol_to_s(vm *RubyVM, self *RubyObject) RubyObject {
  28. if !self.(String) && !self.(Symbol) {
  29. vm.throw_reason = TR_THROW_EXCEPTION;
  30. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + self));
  31. return TR_UNDEF;
  32. }
  33. return TrString_new(vm, self.ptr, self.len);
  34. }
  35. func TrSymbol_init(vm *RubyVM) {
  36. c := vm.classes[TR_T_Symbol] = Object_const_set(vm, vm.self, TrSymbol_new(vm, Symbol), newClass(vm, TrSymbol_new(vm, Symbol), vm.classes[TR_T_Object]));
  37. c.add_method(vm, TrSymbol_new(vm, "to_s"), newMethod(vm, (TrFunc *)TrSymbol_to_s, TR_NIL, 0));
  38. }
  39. // string
  40. func TrString_to_s(vm *RubyVM, self *RubyObject) RubyObject {
  41. return self;
  42. }
  43. func TrString_size(vm *RubyVM, self) RubyObject {
  44. if !self.(String) && !self.(Symbol) {
  45. vm.throw_reason = TR_THROW_EXCEPTION;
  46. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + self));
  47. return TR_UNDEF;
  48. }
  49. return TR_INT2FIX(self.len);
  50. }
  51. func TrString_new(vm *RubyVM, str *string, len size_t) RubyObject {
  52. s := String{type: TR_T_String, class: vm.classes[TR_T_String], ivars: make(map[string] RubyObject), len: len, ptr: make([]byte, s.len + 1)};
  53. bytes.Copy(s.ptr, str[0:s.len - 1]);
  54. s.ptr[s.len] = '\0';
  55. return s;
  56. }
  57. func TrString_new2(vm *RubyVM, str *string) RubyObject {
  58. return TrString_new(vm, str, strlen(str));
  59. }
  60. func TrString_new3(vm *RubyVM, len size_t) RubyObject {
  61. s := String{type: TR_T_String, class: vm.classes[TR_T_String], ivars: make(map[string] RubyObject), len: len, ptr: make([]byte, s.len + 1)};
  62. s.ptr[s.len] = '\0'
  63. return s;
  64. }
  65. func TrString_add(vm *RubyVM, self, other *RubyObject) RubyObject {
  66. if !self.(String) && !self.(Symbol) {
  67. vm.throw_reason = TR_THROW_EXCEPTION;
  68. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + self));
  69. return TR_UNDEF;
  70. }
  71. if !other.(String) && !other.(Symbol) {
  72. vm.throw_reason = TR_THROW_EXCEPTION;
  73. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + other));
  74. return TR_UNDEF;
  75. }
  76. return tr_sprintf(vm, "%s%s", self.ptr, other.ptr);
  77. }
  78. func TrString_push(vm *RubyVM, self, other *RubyObject) RubyObject {
  79. if !self.(String) && !self.(Symbol) {
  80. vm.throw_reason = TR_THROW_EXCEPTION;
  81. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + self));
  82. return TR_UNDEF;
  83. }
  84. if !other.(String) && !other.(Symbol) {
  85. vm.throw_reason = TR_THROW_EXCEPTION;
  86. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + other));
  87. return TR_UNDEF;
  88. }
  89. orginal_len := self.len;
  90. self.len += other.len;
  91. self.ptr := TR_REALLOC(self.ptr, self.len + 1);
  92. memcpy(self.ptr + original_len, other.ptr, sizeof(char) * other.len);
  93. self.ptr[self.len] = '\0';
  94. return self;
  95. }
  96. func TrString_replace(vm *RubyVM, self, other *RubyObject) RubyObject {
  97. if !self.(String) && !self.(Symbol) {
  98. vm.throw_reason = TR_THROW_EXCEPTION;
  99. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + self));
  100. return TR_UNDEF;
  101. }
  102. if !other.(String) && !other.(Symbol) {
  103. vm.throw_reason = TR_THROW_EXCEPTION;
  104. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + other));
  105. return TR_UNDEF;
  106. }
  107. self.ptr, self.len = other.ptr, other.len;
  108. return self;
  109. }
  110. func TrString_cmp(vm *RubyVM, self, other *RubyObject) RubyObject {
  111. if (!other.(String)) return TR_INT2FIX(-1);
  112. if !self.(String) && !self.(Symbol) {
  113. vm.throw_reason = TR_THROW_EXCEPTION;
  114. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + self));
  115. return TR_UNDEF;
  116. }
  117. return TR_INT2FIX(strcmp(self.ptr, other.ptr));
  118. }
  119. func TrString_substring(vm *RubyVM, self, start, len *RubyObject) RubyObject {
  120. int s = TR_FIX2INT(start);
  121. int l = TR_FIX2INT(len);
  122. if !self.(String) && !self.(Symbol) {
  123. vm.throw_reason = TR_THROW_EXCEPTION;
  124. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + self));
  125. return TR_UNDEF;
  126. }
  127. if s < 0 || (s + l) > self.len { return TR_NIL; }
  128. return TrString_new(vm, self.ptr + s, l);
  129. }
  130. func TrString_to_sym(vm *RubyVM, self *RubyObject) RubyObject {
  131. if !self.(String) && !self.(Symbol) {
  132. vm.throw_reason = TR_THROW_EXCEPTION;
  133. vm.throw_value = TrException_new(vm, vm.cTypeError, TrString_new2(vm, "Expected " + self));
  134. return TR_UNDEF;
  135. }
  136. return TrSymbol_new(vm, self.ptr);
  137. }
  138. // Uses variadic ... parameter which replaces the mechanism used by stdarg.h
  139. func tr_sprintf(vm *RubyVM, fmt *string, args ...) RubyObject {
  140. arg va_list;
  141. va_start(arg, fmt);
  142. len := vsnprintf(NULL, 0, fmt, arg);
  143. char *ptr = alloca(sizeof(char) * len);
  144. va_end(arg);
  145. va_start(arg, fmt);
  146. vsprintf(ptr, fmt, arg);
  147. va_end(arg);
  148. str := TrString_new(vm, ptr, len);
  149. return str;
  150. }
  151. func TrString_init(vm *RubyVM) {
  152. c := vm.classes[TR_T_String] = Object_const_set(vm, vm.self, TrSymbol_new(vm, String), newClass(vm, TrSymbol_new(vm, String), vm.classes[TR_T_Object]));
  153. c.add_method(vm, TrSymbol_new(vm, "to_s"), newMethod(vm, (TrFunc *)TrString_to_s, TR_NIL, 0));
  154. c.add_method(vm, TrSymbol_new(vm, "to_sym"), newMethod(vm, (TrFunc *)TrString_to_sym, TR_NIL, 0));
  155. c.add_method(vm, TrSymbol_new(vm, "size"), newMethod(vm, (TrFunc *)TrString_size, TR_NIL, 0));
  156. c.add_method(vm, TrSymbol_new(vm, "replace"), newMethod(vm, (TrFunc *)TrString_replace, TR_NIL, 1));
  157. c.add_method(vm, TrSymbol_new(vm, "substring"), newMethod(vm, (TrFunc *)ToString_substring, TR_NIL, 2));
  158. c.add_method(vm, TrSymbol_new(vm, "+"), newMethod(vm, (TrFunc *)TrString_add, TR_NIL, 1));
  159. c.add_method(vm, TrSymbol_new(vm, "<<"), newMethod(vm, (TrFunc *)TrString_push, TR_NIL, 1));
  160. c.add_method(vm, TrSymbol_new(vm, "<=>"), newMethod(vm, (TrFunc *)TrString_cmp, TR_NIL, 1));
  161. }