webruby 0.2.5 → 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/webruby.rb +0 -4
- data/lib/webruby/app.rb +4 -0
- data/lib/webruby/rake/files.rake +2 -1
- data/lib/webruby/rake/mruby.rake +1 -1
- data/modules/emscripten/AUTHORS +1 -0
- data/modules/emscripten/ChangeLog +34 -1
- data/modules/emscripten/cmake/Platform/Emscripten.cmake +30 -9
- data/modules/emscripten/emcc +61 -28
- data/modules/emscripten/emrun +15 -11
- data/modules/emscripten/emscripten.py +3 -0
- data/modules/emscripten/src/closure-externs.js +110 -0
- data/modules/emscripten/src/intertyper.js +1 -1
- data/modules/emscripten/src/jsifier.js +7 -21
- data/modules/emscripten/src/library.js +2 -1
- data/modules/emscripten/src/library_browser.js +16 -5
- data/modules/emscripten/src/library_fs.js +3 -1
- data/modules/emscripten/src/library_gl.js +691 -591
- data/modules/emscripten/src/library_glut.js +2 -0
- data/modules/emscripten/src/library_sdl.js +29 -5
- data/modules/emscripten/src/library_uuid.js +140 -0
- data/modules/emscripten/src/modules.js +1 -1
- data/modules/emscripten/src/parseTools.js +29 -19
- data/modules/emscripten/src/postamble.js +3 -4
- data/modules/emscripten/src/preamble.js +17 -1
- data/modules/emscripten/src/relooper/Relooper.cpp +8 -8
- data/modules/emscripten/src/relooper/Relooper.h +5 -5
- data/modules/emscripten/src/relooper/test.txt +2 -2
- data/modules/emscripten/src/runtime.js +1 -1
- data/modules/emscripten/src/settings.js +3 -0
- data/modules/emscripten/src/struct_info.json +12 -0
- data/modules/emscripten/system/include/uuid/uuid.h +35 -0
- data/modules/emscripten/tools/js-optimizer.js +191 -142
- data/modules/emscripten/tools/js_optimizer.py +3 -29
- data/modules/emscripten/tools/shared.py +43 -6
- data/modules/mruby/include/mruby/value.h +3 -2
- data/modules/mruby/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c +5 -9
- data/modules/mruby/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c +3 -5
- data/modules/mruby/mrbgems/mruby-hash-ext/src/hash-ext.c +0 -3
- data/modules/mruby/mrbgems/mruby-numeric-ext/src/numeric_ext.c +0 -1
- data/modules/mruby/mrbgems/mruby-random/src/mt19937ar.c +0 -1
- data/modules/mruby/mrbgems/mruby-range-ext/src/range.c +2 -6
- data/modules/mruby/mrbgems/mruby-sprintf/src/sprintf.c +0 -4
- data/modules/mruby/mrbgems/mruby-string-ext/mrblib/string.rb +22 -0
- data/modules/mruby/mrbgems/mruby-string-ext/src/string.c +2 -2
- data/modules/mruby/mrbgems/mruby-string-ext/test/string.rb +21 -2
- data/modules/mruby/mrbgems/mruby-string-utf8/mrbgem.rake +4 -0
- data/modules/mruby/mrbgems/mruby-string-utf8/src/string.c +297 -0
- data/modules/mruby/mrbgems/mruby-string-utf8/test/string.rb +27 -0
- data/modules/mruby/mrbgems/mruby-struct/src/struct.c +0 -1
- data/modules/mruby/mrblib/init_mrblib.c +0 -3
- data/modules/mruby/src/array.c +22 -8
- data/modules/mruby/src/backtrace.c +12 -9
- data/modules/mruby/src/class.c +3 -3
- data/modules/mruby/src/codegen.c +17 -5
- data/modules/mruby/src/dump.c +5 -6
- data/modules/mruby/src/error.c +0 -2
- data/modules/mruby/src/etc.c +0 -2
- data/modules/mruby/src/gc.c +4 -8
- data/modules/mruby/src/load.c +1 -6
- data/modules/mruby/src/numeric.c +0 -6
- data/modules/mruby/src/object.c +3 -5
- data/modules/mruby/src/parse.y +37 -38
- data/modules/mruby/src/proc.c +8 -1
- data/modules/mruby/src/range.c +3 -7
- data/modules/mruby/src/state.c +0 -1
- data/modules/mruby/src/string.c +2 -17
- data/modules/mruby/src/symbol.c +0 -1
- data/modules/mruby/src/variable.c +3 -22
- data/modules/mruby/src/vm.c +9 -8
- data/modules/mruby/tasks/mrbgem_spec.rake +13 -5
- data/modules/mruby/tasks/mrbgems_test.rake +3 -3
- data/modules/mruby/tasks/mruby_build_commands.rake +2 -2
- data/modules/mruby/tasks/mruby_build_gem.rake +3 -3
- data/modules/mruby/test/init_mrbtest.c +0 -3
- data/modules/mruby/test/t/array.rb +12 -1
- data/modules/mruby/test/t/class.rb +67 -0
- data/modules/mruby/test/t/exception.rb +12 -0
- data/modules/mruby/test/t/kernel.rb +75 -1
- data/modules/mruby/test/t/syntax.rb +115 -0
- data/scripts/gen_require.rb +12 -1
- metadata +8 -2
@@ -24,41 +24,16 @@ import_sig = re.compile('var ([_\w$]+) *=[^;]+;')
|
|
24
24
|
|
25
25
|
class Minifier:
|
26
26
|
'''
|
27
|
-
asm.js minification support. We calculate
|
27
|
+
asm.js minification support. We calculate minification of
|
28
28
|
globals here, then pass that into the parallel js-optimizer.js runners which
|
29
29
|
during registerize perform minification of locals.
|
30
30
|
'''
|
31
31
|
|
32
|
-
def __init__(self, js, js_engine
|
32
|
+
def __init__(self, js, js_engine):
|
33
33
|
self.js = js
|
34
34
|
self.js_engine = js_engine
|
35
|
-
MAX_NAMES = min(MAX_NAMES, 120000)
|
36
|
-
|
37
|
-
# Create list of valid short names
|
38
|
-
|
39
|
-
INVALID_2 = set(['do', 'if', 'in'])
|
40
|
-
INVALID_3 = set(['for', 'new', 'try', 'var', 'env', 'let'])
|
41
|
-
|
42
|
-
self.names = []
|
43
|
-
init_possibles = string.ascii_letters + '_$'
|
44
|
-
later_possibles = init_possibles + string.digits
|
45
|
-
for a in init_possibles:
|
46
|
-
if len(self.names) >= MAX_NAMES: break
|
47
|
-
self.names.append(a)
|
48
|
-
for a in init_possibles:
|
49
|
-
for b in later_possibles:
|
50
|
-
if len(self.names) >= MAX_NAMES: break
|
51
|
-
curr = a + b
|
52
|
-
if curr not in INVALID_2: self.names.append(curr)
|
53
|
-
for a in init_possibles:
|
54
|
-
for b in later_possibles:
|
55
|
-
for c in later_possibles:
|
56
|
-
if len(self.names) >= MAX_NAMES: break
|
57
|
-
curr = a + b + c
|
58
|
-
if curr not in INVALID_3: self.names.append(curr)
|
59
35
|
|
60
36
|
def minify_shell(self, shell, minify_whitespace, source_map=False):
|
61
|
-
#print >> sys.stderr, "MINIFY SHELL 1111111111", shell, "\n222222222222222"
|
62
37
|
# Run through js-optimizer.js to find and minify the global symbols
|
63
38
|
# We send it the globals, which it parses at the proper time. JS decides how
|
64
39
|
# to minify all global names, we receive a dictionary back, which is then
|
@@ -91,7 +66,6 @@ class Minifier:
|
|
91
66
|
|
92
67
|
def serialize(self):
|
93
68
|
return {
|
94
|
-
'names': self.names,
|
95
69
|
'globals': self.globs
|
96
70
|
}
|
97
71
|
|
@@ -187,7 +161,7 @@ EMSCRIPTEN_FUNCS();
|
|
187
161
|
js = js[start_funcs + len(start_funcs_marker):end_funcs]
|
188
162
|
|
189
163
|
# we assume there is a maximum of one new name per line
|
190
|
-
minifier = Minifier(js, js_engine
|
164
|
+
minifier = Minifier(js, js_engine)
|
191
165
|
asm_shell_pre, asm_shell_post = minifier.minify_shell(asm_shell, 'minifyWhitespace' in passes, source_map).split('EMSCRIPTEN_FUNCS();');
|
192
166
|
asm_shell_post = asm_shell_post.replace('});', '})');
|
193
167
|
pre += asm_shell_pre + '\n' + start_funcs_marker
|
@@ -272,9 +272,17 @@ if EM_POPEN_WORKAROUND and os.name == 'nt':
|
|
272
272
|
|
273
273
|
EXPECTED_LLVM_VERSION = (3,2)
|
274
274
|
|
275
|
+
actual_clang_version = None
|
276
|
+
|
277
|
+
def get_clang_version():
|
278
|
+
global actual_clang_version
|
279
|
+
if actual_clang_version is None:
|
280
|
+
actual_clang_version = Popen([CLANG, '-v'], stderr=PIPE).communicate()[1].split('\n')[0].split(' ')[2]
|
281
|
+
return actual_clang_version
|
282
|
+
|
275
283
|
def check_clang_version():
|
276
|
-
expected = '
|
277
|
-
actual =
|
284
|
+
expected = '.'.join(map(str, EXPECTED_LLVM_VERSION))
|
285
|
+
actual = get_clang_version()
|
278
286
|
if expected in actual:
|
279
287
|
return True
|
280
288
|
logging.warning('LLVM version appears incorrect (seeing "%s", expected "%s")' % (actual, expected))
|
@@ -286,6 +294,21 @@ def check_llvm_version():
|
|
286
294
|
except Exception, e:
|
287
295
|
logging.warning('Could not verify LLVM version: %s' % str(e))
|
288
296
|
|
297
|
+
def check_fastcomp():
|
298
|
+
try:
|
299
|
+
llc_version_info = Popen([LLVM_COMPILER, '--version'], stdout=PIPE).communicate()[0]
|
300
|
+
pre, targets = llc_version_info.split('Registered Targets:')
|
301
|
+
if 'js' not in targets or 'JavaScript (asm.js, emscripten) backend' not in targets:
|
302
|
+
logging.critical('fastcomp in use, but LLVM has not been built with the JavaScript backend as a target, llc reports:')
|
303
|
+
print >> sys.stderr, '==========================================================================='
|
304
|
+
print >> sys.stderr, llc_version_info,
|
305
|
+
print >> sys.stderr, '==========================================================================='
|
306
|
+
return False
|
307
|
+
return True
|
308
|
+
except Exception, e:
|
309
|
+
logging.warning('cound not check fastcomp: %s' % str(e))
|
310
|
+
return True
|
311
|
+
|
289
312
|
EXPECTED_NODE_VERSION = (0,8,0)
|
290
313
|
|
291
314
|
def check_node_version():
|
@@ -322,10 +345,10 @@ def find_temp_directory():
|
|
322
345
|
# we re-check sanity when the settings are changed)
|
323
346
|
# We also re-check sanity and clear the cache when the version changes
|
324
347
|
|
325
|
-
EMSCRIPTEN_VERSION = '1.8.
|
348
|
+
EMSCRIPTEN_VERSION = '1.8.6'
|
326
349
|
|
327
350
|
def generate_sanity():
|
328
|
-
return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT
|
351
|
+
return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT + '|' + get_clang_version()
|
329
352
|
|
330
353
|
def check_sanity(force=False):
|
331
354
|
try:
|
@@ -353,9 +376,11 @@ def check_sanity(force=False):
|
|
353
376
|
Cache.erase()
|
354
377
|
force = False # the check actually failed, so definitely write out the sanity file, to avoid others later seeing failures too
|
355
378
|
|
356
|
-
# some warning, not fatal checks - do them even if EM_IGNORE_SANITY is on
|
379
|
+
# some warning, mostly not fatal checks - do them even if EM_IGNORE_SANITY is on
|
357
380
|
check_llvm_version()
|
358
381
|
check_node_version()
|
382
|
+
if os.environ.get('EMCC_FAST_COMPILER') == '1':
|
383
|
+
fastcomp_ok = check_fastcomp()
|
359
384
|
|
360
385
|
if os.environ.get('EM_IGNORE_SANITY'):
|
361
386
|
logging.info('EM_IGNORE_SANITY set, ignoring sanity checks')
|
@@ -377,6 +402,11 @@ def check_sanity(force=False):
|
|
377
402
|
logging.critical('Cannot find %s, check the paths in %s' % (cmd, EM_CONFIG))
|
378
403
|
sys.exit(1)
|
379
404
|
|
405
|
+
if os.environ.get('EMCC_FAST_COMPILER') == '1':
|
406
|
+
if not fastcomp_ok:
|
407
|
+
logging.critical('failing sanity checks due to previous fastcomp failure')
|
408
|
+
sys.exit(1)
|
409
|
+
|
380
410
|
try:
|
381
411
|
subprocess.call([JAVA, '-version'], stdout=PIPE, stderr=PIPE)
|
382
412
|
except:
|
@@ -1141,6 +1171,8 @@ class Building:
|
|
1141
1171
|
if type(opts) is int:
|
1142
1172
|
opts = Building.pick_llvm_opts(opts)
|
1143
1173
|
#opts += ['-debug-pass=Arguments']
|
1174
|
+
if get_clang_version() == '3.4' and not Settings.SIMD:
|
1175
|
+
opts += ['-disable-loop-vectorization', '-disable-slp-vectorization'] # llvm 3.4 has these on by default
|
1144
1176
|
logging.debug('emcc: LLVM opts: ' + str(opts))
|
1145
1177
|
target = out or (filename + '.opt.bc')
|
1146
1178
|
output = Popen([LLVM_OPT, filename] + opts + ['-o', target], stdout=PIPE).communicate()[0]
|
@@ -1382,6 +1414,8 @@ class Building:
|
|
1382
1414
|
if not os.path.exists(CLOSURE_COMPILER):
|
1383
1415
|
raise Exception('Closure compiler appears to be missing, looked at: ' + str(CLOSURE_COMPILER))
|
1384
1416
|
|
1417
|
+
CLOSURE_EXTERNS = path_from_root('src', 'closure-externs.js')
|
1418
|
+
|
1385
1419
|
# Something like this (adjust memory as needed):
|
1386
1420
|
# java -Xmx1024m -jar CLOSURE_COMPILER --compilation_level ADVANCED_OPTIMIZATIONS --variable_map_output_file src.cpp.o.js.vars --js src.cpp.o.js --js_output_file src.cpp.o.cc.js
|
1387
1421
|
args = [JAVA,
|
@@ -1389,6 +1423,7 @@ class Building:
|
|
1389
1423
|
'-jar', CLOSURE_COMPILER,
|
1390
1424
|
'--compilation_level', 'ADVANCED_OPTIMIZATIONS',
|
1391
1425
|
'--language_in', 'ECMASCRIPT5',
|
1426
|
+
'--externs', CLOSURE_EXTERNS,
|
1392
1427
|
#'--variable_map_output_file', filename + '.vars',
|
1393
1428
|
'--js', filename, '--js_output_file', filename + '.cc.js']
|
1394
1429
|
if pretty: args += ['--formatting', 'PRETTY_PRINT']
|
@@ -1438,7 +1473,7 @@ class Building:
|
|
1438
1473
|
@staticmethod
|
1439
1474
|
def ensure_relooper(relooper):
|
1440
1475
|
if os.path.exists(relooper): return
|
1441
|
-
if os.environ.get('EMCC_FAST_COMPILER'):
|
1476
|
+
if os.environ.get('EMCC_FAST_COMPILER') == '1':
|
1442
1477
|
logging.debug('not building relooper to js, using it in c++ backend')
|
1443
1478
|
return
|
1444
1479
|
|
@@ -1513,6 +1548,8 @@ class Building:
|
|
1513
1548
|
text = m.groups(0)[0]
|
1514
1549
|
assert text.count('(') == 1 and text.count(')') == 1, 'must have simple expressions in emscripten_jcache_printf calls, no parens'
|
1515
1550
|
assert text.count('"') == 2, 'must have simple expressions in emscripten_jcache_printf calls, no strings as varargs parameters'
|
1551
|
+
if os.environ.get('EMCC_FAST_COMPILER') == '1': # fake it in fastcomp
|
1552
|
+
return text.replace('emscripten_jcache_printf', 'printf')
|
1516
1553
|
start = text.index('(')
|
1517
1554
|
end = text.rindex(')')
|
1518
1555
|
args = text[start+1:end].split(',')
|
@@ -155,7 +155,7 @@ typedef struct mrb_value {
|
|
155
155
|
#define mrb_tt(o) (((o).value.ttt & 0xfc000)>>14)
|
156
156
|
#define mrb_mktt(tt) (0xfff00000|((tt)<<14))
|
157
157
|
#define mrb_type(o) ((uint32_t)0xfff00000 < (o).value.ttt ? mrb_tt(o) : MRB_TT_FLOAT)
|
158
|
-
#define mrb_ptr(o) ((void*)((((
|
158
|
+
#define mrb_ptr(o) ((void*)((((uintptr_t)0x3fffffffffff)&((uintptr_t)((o).value.p)))<<2))
|
159
159
|
#define mrb_float(o) (o).f
|
160
160
|
|
161
161
|
#define MRB_SET_VALUE(o, tt, attr, v) do {\
|
@@ -166,7 +166,7 @@ typedef struct mrb_value {
|
|
166
166
|
case MRB_TT_UNDEF:\
|
167
167
|
case MRB_TT_FIXNUM:\
|
168
168
|
case MRB_TT_SYMBOL: (o).attr = (v); break;\
|
169
|
-
default: (o).value.i = 0; (o).value.p = (void*)((
|
169
|
+
default: (o).value.i = 0; (o).value.p = (void*)((uintptr_t)(o).value.p | (((uintptr_t)(v))>>2)); break;\
|
170
170
|
}\
|
171
171
|
} while (0)
|
172
172
|
|
@@ -315,6 +315,7 @@ mrb_float_value(struct mrb_state *mrb, mrb_float f)
|
|
315
315
|
#define mrb_bool(o) ((o).w != MRB_Qnil && (o).w != MRB_Qfalse)
|
316
316
|
|
317
317
|
#else
|
318
|
+
|
318
319
|
#define mrb_cptr(o) mrb_ptr(o)
|
319
320
|
#define mrb_fixnum_p(o) (mrb_type(o) == MRB_TT_FIXNUM)
|
320
321
|
#define mrb_undef_p(o) (mrb_type(o) == MRB_TT_UNDEF)
|
@@ -8,21 +8,17 @@
|
|
8
8
|
|
9
9
|
#include <stdlib.h>
|
10
10
|
#include <string.h>
|
11
|
-
|
12
|
-
#include <mruby.h>
|
11
|
+
#include "mruby.h"
|
13
12
|
#include "mruby/array.h"
|
14
|
-
#include
|
15
|
-
#include
|
16
|
-
#include
|
13
|
+
#include "mruby/proc.h"
|
14
|
+
#include "mruby/compile.h"
|
15
|
+
#include "mruby/string.h"
|
16
|
+
|
17
17
|
#ifdef ENABLE_READLINE
|
18
18
|
#include <limits.h>
|
19
19
|
#include <readline/readline.h>
|
20
20
|
#include <readline/history.h>
|
21
|
-
#endif
|
22
|
-
#include <mruby/string.h>
|
23
21
|
|
24
|
-
|
25
|
-
#ifdef ENABLE_READLINE
|
26
22
|
static const char *history_file_name = ".mirb_history";
|
27
23
|
char history_path[PATH_MAX];
|
28
24
|
#endif
|
@@ -1,13 +1,11 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <string.h>
|
1
4
|
#include "mruby.h"
|
2
|
-
#include "mruby/proc.h"
|
3
5
|
#include "mruby/array.h"
|
4
|
-
#include "mruby/string.h"
|
5
6
|
#include "mruby/compile.h"
|
6
7
|
#include "mruby/dump.h"
|
7
8
|
#include "mruby/variable.h"
|
8
|
-
#include <stdio.h>
|
9
|
-
#include <stdlib.h>
|
10
|
-
#include <string.h>
|
11
9
|
|
12
10
|
#ifndef ENABLE_STDIO
|
13
11
|
static void
|
@@ -7,7 +7,7 @@ r_le(mrb_state *mrb, mrb_value a, mrb_value b)
|
|
7
7
|
mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b); /* compare result */
|
8
8
|
/* output :a < b => -1, a = b => 0, a > b => +1 */
|
9
9
|
|
10
|
-
if (
|
10
|
+
if (mrb_fixnum_p(r)) {
|
11
11
|
mrb_int c = mrb_fixnum(r);
|
12
12
|
if (c == 0 || c == -1) return TRUE;
|
13
13
|
}
|
@@ -21,11 +21,7 @@ r_lt(mrb_state *mrb, mrb_value a, mrb_value b)
|
|
21
21
|
mrb_value r = mrb_funcall(mrb, a, "<=>", 1, b);
|
22
22
|
/* output :a < b => -1, a = b => 0, a > b => +1 */
|
23
23
|
|
24
|
-
|
25
|
-
if (mrb_fixnum(r) == -1) return TRUE;
|
26
|
-
}
|
27
|
-
|
28
|
-
return FALSE;
|
24
|
+
return mrb_fixnum_p(r) && mrb_fixnum(r) == -1;
|
29
25
|
}
|
30
26
|
|
31
27
|
/*
|
@@ -15,10 +15,6 @@
|
|
15
15
|
#include <math.h>
|
16
16
|
#include <ctype.h>
|
17
17
|
|
18
|
-
#ifdef HAVE_IEEEFP_H
|
19
|
-
#include <ieeefp.h>
|
20
|
-
#endif
|
21
|
-
|
22
18
|
#define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */
|
23
19
|
#define BITSPERDIG (sizeof(mrb_int)*CHAR_BIT)
|
24
20
|
#define EXTENDSIGN(n, l) (((~0 << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0 << (n)))
|
@@ -49,4 +49,26 @@ class String
|
|
49
49
|
def casecmp(str)
|
50
50
|
self.downcase <=> str.downcase
|
51
51
|
end
|
52
|
+
|
53
|
+
def partition(sep)
|
54
|
+
raise TypeError, "type mismatch: #{sep.class} given" unless sep.is_a? String
|
55
|
+
n = index(sep)
|
56
|
+
unless n.nil?
|
57
|
+
m = n + sep.size
|
58
|
+
[ slice(0, n), sep, slice(m, size - m) ]
|
59
|
+
else
|
60
|
+
[ self, "", "" ]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def rpartition(sep)
|
65
|
+
raise TypeError, "type mismatch: #{sep.class} given" unless sep.is_a? String
|
66
|
+
n = rindex(sep)
|
67
|
+
unless n.nil?
|
68
|
+
m = n + sep.size
|
69
|
+
[ slice(0, n), sep, slice(m, size - m) ]
|
70
|
+
else
|
71
|
+
[ "", "", self ]
|
72
|
+
end
|
73
|
+
end
|
52
74
|
end
|
@@ -20,8 +20,7 @@ assert('String#dump') do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
assert('String#strip') do
|
23
|
-
s = " abc "
|
24
|
-
s.strip
|
23
|
+
s = " abc "
|
25
24
|
"".strip == "" and " \t\r\n\f\v".strip == "" and
|
26
25
|
"\0a\0".strip == "\0a" and
|
27
26
|
"abc".strip == "abc" and
|
@@ -114,3 +113,23 @@ assert('String#end_with?') do
|
|
114
113
|
assert_true !"ng".end_with?("ing", "mng")
|
115
114
|
assert_raise TypeError do "hello".end_with?(true) end
|
116
115
|
end
|
116
|
+
|
117
|
+
assert('String#partition') do
|
118
|
+
assert_equal ["a", "x", "axa"], "axaxa".partition("x")
|
119
|
+
assert_equal ["aaaaa", "", ""], "aaaaa".partition("x")
|
120
|
+
assert_equal ["", "", "aaaaa"], "aaaaa".partition("")
|
121
|
+
assert_equal ["", "a", "aaaa"], "aaaaa".partition("a")
|
122
|
+
assert_equal ["aaaa", "b", ""], "aaaab".partition("b")
|
123
|
+
assert_equal ["", "b", "aaaa"], "baaaa".partition("b")
|
124
|
+
assert_equal ["", "", ""], "".partition("a")
|
125
|
+
end
|
126
|
+
|
127
|
+
assert('String#rpartition') do
|
128
|
+
assert_equal ["axa", "x", "a"], "axaxa".rpartition("x")
|
129
|
+
assert_equal ["", "", "aaaaa"], "aaaaa".rpartition("x")
|
130
|
+
assert_equal ["aaaaa", "", ""], "aaaaa".rpartition("")
|
131
|
+
assert_equal ["aaaa", "a", ""], "aaaaa".rpartition("a")
|
132
|
+
assert_equal ["aaaa", "b", ""], "aaaab".rpartition("b")
|
133
|
+
assert_equal ["", "b", "aaaa"], "baaaa".rpartition("b")
|
134
|
+
assert_equal ["", "", ""], "".rpartition("a")
|
135
|
+
end
|
@@ -0,0 +1,297 @@
|
|
1
|
+
#include "mruby.h"
|
2
|
+
#include "mruby/string.h"
|
3
|
+
#include "mruby/range.h"
|
4
|
+
#include <ctype.h>
|
5
|
+
#include <string.h>
|
6
|
+
|
7
|
+
/* TODO: duplicate definition in src/re.h */
|
8
|
+
#define REGEXP_CLASS "Regexp"
|
9
|
+
|
10
|
+
static size_t utf8len_tab[256] =
|
11
|
+
{
|
12
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
13
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
14
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
15
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
16
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
17
|
+
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
18
|
+
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
19
|
+
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
|
20
|
+
};
|
21
|
+
|
22
|
+
static size_t
|
23
|
+
utf8len(unsigned char* p)
|
24
|
+
{
|
25
|
+
size_t len;
|
26
|
+
int i;
|
27
|
+
|
28
|
+
if (*p == 0)
|
29
|
+
return 1;
|
30
|
+
len = utf8len_tab[*p];
|
31
|
+
for (i = 1; i < len; ++i)
|
32
|
+
if ((p[i] & 0xc0) != 0x80)
|
33
|
+
return 1;
|
34
|
+
return len;
|
35
|
+
}
|
36
|
+
|
37
|
+
static size_t
|
38
|
+
mrb_utf8_strlen(mrb_value str)
|
39
|
+
{
|
40
|
+
size_t total = 0;
|
41
|
+
unsigned char* p = (unsigned char*) RSTRING_PTR(str);
|
42
|
+
unsigned char* e = p + RSTRING_LEN(str);
|
43
|
+
while (p<e) {
|
44
|
+
p += utf8len(p);
|
45
|
+
total++;
|
46
|
+
}
|
47
|
+
return total;
|
48
|
+
}
|
49
|
+
|
50
|
+
static mrb_value
|
51
|
+
mrb_str_size(mrb_state *mrb, mrb_value str)
|
52
|
+
{
|
53
|
+
size_t size = mrb_utf8_strlen(str);
|
54
|
+
|
55
|
+
return mrb_fixnum_value(size);
|
56
|
+
}
|
57
|
+
|
58
|
+
#define RSTRING_LEN_UTF8(s) mrb_utf8_strlen(s)
|
59
|
+
|
60
|
+
static mrb_value
|
61
|
+
noregexp(mrb_state *mrb, mrb_value self)
|
62
|
+
{
|
63
|
+
mrb_raise(mrb, E_NOTIMP_ERROR, "Regexp class not implemented");
|
64
|
+
return mrb_nil_value();
|
65
|
+
}
|
66
|
+
|
67
|
+
static void
|
68
|
+
regexp_check(mrb_state *mrb, mrb_value obj)
|
69
|
+
{
|
70
|
+
if (!memcmp(mrb_obj_classname(mrb, obj), REGEXP_CLASS, sizeof(REGEXP_CLASS) - 1)) {
|
71
|
+
noregexp(mrb, obj);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
static inline mrb_int
|
76
|
+
mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mrb_int n)
|
77
|
+
{
|
78
|
+
const unsigned char *x = xs, *xe = xs + m;
|
79
|
+
const unsigned char *y = ys;
|
80
|
+
int i, qstable[256];
|
81
|
+
|
82
|
+
/* Preprocessing */
|
83
|
+
for (i = 0; i < 256; ++i)
|
84
|
+
qstable[i] = m + 1;
|
85
|
+
for (; x < xe; ++x)
|
86
|
+
qstable[*x] = xe - x;
|
87
|
+
/* Searching */
|
88
|
+
for (; y + m <= ys + n; y += *(qstable + y[m])) {
|
89
|
+
if (*xs == *y && memcmp(xs, y, m) == 0)
|
90
|
+
return y - ys;
|
91
|
+
}
|
92
|
+
return -1;
|
93
|
+
}
|
94
|
+
static mrb_int
|
95
|
+
mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
|
96
|
+
{
|
97
|
+
const unsigned char *x = (const unsigned char *)x0, *y = (const unsigned char *)y0;
|
98
|
+
|
99
|
+
if (m > n) return -1;
|
100
|
+
else if (m == n) {
|
101
|
+
return memcmp(x0, y0, m) == 0 ? 0 : -1;
|
102
|
+
}
|
103
|
+
else if (m < 1) {
|
104
|
+
return 0;
|
105
|
+
}
|
106
|
+
else if (m == 1) {
|
107
|
+
const unsigned char *ys = y, *ye = ys + n;
|
108
|
+
for (; y < ye; ++y) {
|
109
|
+
if (*x == *y)
|
110
|
+
return y - ys;
|
111
|
+
}
|
112
|
+
return -1;
|
113
|
+
}
|
114
|
+
return mrb_memsearch_qs((const unsigned char *)x0, m, (const unsigned char *)y0, n);
|
115
|
+
}
|
116
|
+
|
117
|
+
static mrb_value
|
118
|
+
str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
|
119
|
+
{
|
120
|
+
int i;
|
121
|
+
unsigned char *p = (unsigned char*) RSTRING_PTR(str), *t;
|
122
|
+
unsigned char *e = p + RSTRING_LEN(str);
|
123
|
+
|
124
|
+
|
125
|
+
for (i = 0; i < beg && p<e; i++) {
|
126
|
+
p += utf8len(p);
|
127
|
+
}
|
128
|
+
t = p;
|
129
|
+
for (i = 0; i < len && t<e; i++) {
|
130
|
+
t += utf8len(t);
|
131
|
+
}
|
132
|
+
return mrb_str_new(mrb, (const char*)p, (int)(t - p));
|
133
|
+
}
|
134
|
+
|
135
|
+
static mrb_value
|
136
|
+
str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
|
137
|
+
{
|
138
|
+
mrb_value str2;
|
139
|
+
int len8 = RSTRING_LEN_UTF8(str);
|
140
|
+
|
141
|
+
if (len < 0) return mrb_nil_value();
|
142
|
+
if (len8 == 0) {
|
143
|
+
len = 0;
|
144
|
+
}
|
145
|
+
else if (beg < 0) {
|
146
|
+
beg = len8 + beg;
|
147
|
+
}
|
148
|
+
if (beg > len8) return mrb_nil_value();
|
149
|
+
if (beg < 0) {
|
150
|
+
beg += len8;
|
151
|
+
if (beg < 0) return mrb_nil_value();
|
152
|
+
}
|
153
|
+
if (beg + len > len8)
|
154
|
+
len = len8 - beg;
|
155
|
+
if (len <= 0) {
|
156
|
+
len = 0;
|
157
|
+
}
|
158
|
+
str2 = str_subseq(mrb, str, beg, len);
|
159
|
+
|
160
|
+
return str2;
|
161
|
+
}
|
162
|
+
|
163
|
+
static mrb_int
|
164
|
+
str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset)
|
165
|
+
{
|
166
|
+
mrb_int pos;
|
167
|
+
char *s, *sptr;
|
168
|
+
mrb_int len, slen;
|
169
|
+
|
170
|
+
len = RSTRING_LEN(str);
|
171
|
+
slen = RSTRING_LEN(sub);
|
172
|
+
if (offset < 0) {
|
173
|
+
offset += len;
|
174
|
+
if (offset < 0) return -1;
|
175
|
+
}
|
176
|
+
if (len - offset < slen) return -1;
|
177
|
+
s = RSTRING_PTR(str);
|
178
|
+
if (offset) {
|
179
|
+
s += offset;
|
180
|
+
}
|
181
|
+
if (slen == 0) return offset;
|
182
|
+
/* need proceed one character at a time */
|
183
|
+
sptr = RSTRING_PTR(sub);
|
184
|
+
slen = RSTRING_LEN(sub);
|
185
|
+
len = RSTRING_LEN(str) - offset;
|
186
|
+
pos = mrb_memsearch(sptr, slen, s, len);
|
187
|
+
if (pos < 0) return pos;
|
188
|
+
return pos + offset;
|
189
|
+
}
|
190
|
+
|
191
|
+
static mrb_value
|
192
|
+
mrb_str_aref(mrb_state *mrb, mrb_value str, mrb_value indx)
|
193
|
+
{
|
194
|
+
mrb_int idx;
|
195
|
+
|
196
|
+
regexp_check(mrb, indx);
|
197
|
+
switch (mrb_type(indx)) {
|
198
|
+
case MRB_TT_FIXNUM:
|
199
|
+
idx = mrb_fixnum(indx);
|
200
|
+
|
201
|
+
num_index:
|
202
|
+
str = str_substr(mrb, str, idx, 1);
|
203
|
+
if (!mrb_nil_p(str) && RSTRING_LEN(str) == 0) return mrb_nil_value();
|
204
|
+
return str;
|
205
|
+
|
206
|
+
case MRB_TT_STRING:
|
207
|
+
if (str_index(mrb, str, indx, 0) != -1)
|
208
|
+
return mrb_str_dup(mrb, indx);
|
209
|
+
return mrb_nil_value();
|
210
|
+
|
211
|
+
case MRB_TT_RANGE:
|
212
|
+
/* check if indx is Range */
|
213
|
+
{
|
214
|
+
mrb_int beg, len;
|
215
|
+
mrb_value tmp;
|
216
|
+
|
217
|
+
len = RSTRING_LEN_UTF8(str);
|
218
|
+
if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) {
|
219
|
+
tmp = str_subseq(mrb, str, beg, len);
|
220
|
+
return tmp;
|
221
|
+
}
|
222
|
+
else {
|
223
|
+
return mrb_nil_value();
|
224
|
+
}
|
225
|
+
}
|
226
|
+
default:
|
227
|
+
idx = mrb_fixnum(indx);
|
228
|
+
goto num_index;
|
229
|
+
}
|
230
|
+
return mrb_nil_value(); /* not reached */
|
231
|
+
}
|
232
|
+
|
233
|
+
static mrb_value
|
234
|
+
mrb_str_aref_m(mrb_state *mrb, mrb_value str)
|
235
|
+
{
|
236
|
+
mrb_value a1, a2;
|
237
|
+
int argc;
|
238
|
+
|
239
|
+
argc = mrb_get_args(mrb, "o|o", &a1, &a2);
|
240
|
+
if (argc == 2) {
|
241
|
+
regexp_check(mrb, a1);
|
242
|
+
return str_substr(mrb, str, mrb_fixnum(a1), mrb_fixnum(a2));
|
243
|
+
}
|
244
|
+
if (argc != 1) {
|
245
|
+
mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1)", mrb_fixnum_value(argc));
|
246
|
+
}
|
247
|
+
return mrb_str_aref(mrb, str, a1);
|
248
|
+
}
|
249
|
+
|
250
|
+
static mrb_value
|
251
|
+
mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
|
252
|
+
{
|
253
|
+
int utf8_len = mrb_utf8_strlen(str);
|
254
|
+
if (utf8_len > 1) {
|
255
|
+
int len = RSTRING_LEN(str);
|
256
|
+
char *buf = (char *)mrb_malloc(mrb, len);
|
257
|
+
unsigned char* p = (unsigned char*)buf;
|
258
|
+
unsigned char* e = (unsigned char*)buf + len;
|
259
|
+
unsigned char* r = (unsigned char*)RSTRING_END(str);
|
260
|
+
|
261
|
+
memcpy(buf, RSTRING_PTR(str), len);
|
262
|
+
mrb_str_modify(mrb, mrb_str_ptr(str));
|
263
|
+
|
264
|
+
while (p<e) {
|
265
|
+
int clen = utf8len(p);
|
266
|
+
r -= clen;
|
267
|
+
memcpy(r, p, clen);
|
268
|
+
p += clen;
|
269
|
+
}
|
270
|
+
mrb_free(mrb, buf);
|
271
|
+
}
|
272
|
+
|
273
|
+
return str;
|
274
|
+
}
|
275
|
+
|
276
|
+
static mrb_value
|
277
|
+
mrb_str_reverse(mrb_state *mrb, mrb_value str)
|
278
|
+
{
|
279
|
+
return mrb_str_reverse_bang(mrb, mrb_str_dup(mrb, str));
|
280
|
+
}
|
281
|
+
|
282
|
+
void
|
283
|
+
mrb_mruby_string_utf8_gem_init(mrb_state* mrb)
|
284
|
+
{
|
285
|
+
struct RClass * s = mrb->string_class;
|
286
|
+
|
287
|
+
mrb_define_method(mrb, s, "size", mrb_str_size, MRB_ARGS_NONE());
|
288
|
+
mrb_define_method(mrb, s, "[]", mrb_str_aref_m, MRB_ARGS_ANY());
|
289
|
+
mrb_define_method(mrb, s, "slice", mrb_str_aref_m, MRB_ARGS_ANY());
|
290
|
+
mrb_define_method(mrb, s, "reverse", mrb_str_reverse, MRB_ARGS_NONE());
|
291
|
+
mrb_define_method(mrb, s, "reverse!", mrb_str_reverse_bang, MRB_ARGS_NONE());
|
292
|
+
}
|
293
|
+
|
294
|
+
void
|
295
|
+
mrb_mruby_string_utf8_gem_final(mrb_state* mrb)
|
296
|
+
{
|
297
|
+
}
|