Explorar el Código

Merge pull request #15 from mtardy/slice

Add slice '[n:m]' for strings and array-like maps
master
mtardy hace 4 años
cometido por GitHub
padre
commit
73dcfca222
No se encontró ninguna clave conocida en la base de datos para esta firma ID de clave GPG: 4AEE18F83AFDEB23
Se han modificado 5 ficheros con 135 adiciones y 31 borrados
  1. +49
    -10
      object.c
  2. +73
    -18
      parse.leg
  3. +1
    -2
      test-module.txt
  4. +2
    -1
      test-require.txt
  5. +10
    -0
      test-slice.txt

+ 49
- 10
object.c Ver fichero

@ -205,6 +205,7 @@ oop makeInteger(int value)
#endif
}
// value will be copied
oop makeString(char *value)
{
oop newString = memcheck(malloc(sizeof(union object)));
@ -214,11 +215,37 @@ oop makeString(char *value)
return newString;
}
// value will be used directly
oop makeStringFrom(char *value, size_t l)
{
oop newString = memcheck(malloc(sizeof(union object)));
newString->type = String;
newString->String.value = value;
newString->String.size = l;
return newString;
}
size_t string_size(oop s)
{
return get(s, String, size);
}
oop string_slice(oop str, ssize_t start, ssize_t stop) {
assert(is(String, str));
size_t len = string_size(str);
if (start < 0) start= start + len;
if (stop < 0) stop= stop + len;
if (start < 0 || start > len) return NULL;
if (stop < 0 || stop > len) return NULL;
if (start > stop) return NULL;
size_t cpylen = stop - start;
char *slice= memcheck(malloc(sizeof(char) * (cpylen + 1)));
memcpy(slice, get(str, String, value) + start, cpylen);
slice[cpylen]= '\0';
return makeStringFrom(slice, cpylen);
}
oop string_concat(oop str1, oop str2)
{
size_t len = string_size(str1) + string_size(str2);
@ -226,11 +253,7 @@ oop string_concat(oop str1, oop str2)
memcpy(concat, get(str1, String, value), string_size(str1));
memcpy(concat + string_size(str1), get(str2, String, value), string_size(str2));
concat[len]= '\0';
oop newString = memcheck(malloc(sizeof(union object)));
newString->type = String;
newString->String.value = concat;
newString->String.size = len;
return newString;
return makeStringFrom(concat, len);
}
oop string_mul(oop str, oop factor)
@ -242,11 +265,7 @@ oop string_mul(oop str, oop factor)
memcpy(concat + (i * string_size(str)), get(str, String, value), string_size(str));
}
concat[len]= '\0';
oop newString = memcheck(malloc(sizeof(union object)));
newString->type = String;
newString->String.value = concat;
newString->String.size = len;
return newString;
return makeStringFrom(concat, len);
}
oop makeSymbol(char *name)
@ -459,6 +478,26 @@ oop map_values(oop map)
return values;
}
oop map_slice(oop map, ssize_t start, ssize_t stop) {
assert(is(Map, map));
size_t len = map_size(map);
if (start < 0) start= start + len;
if (stop < 0) stop= stop + len;
if (start < 0 || start > len) return NULL;
if (stop < 0 || stop > len) return NULL;
if (start > stop) return NULL;
oop slice= makeMap();
if (start < stop) {
if (!map_hasIntegerKey(map, start )) return NULL;
if (!map_hasIntegerKey(map, stop - 1)) return NULL;
for (size_t i= start; i < stop; ++i) {
map_append(slice, get(map, Map, elements)[i].value);
}
}
return slice;
}
DECLARE_BUFFER(oop, OopStack);
OopStack printing = BUFFER_INITIALISER;

+ 73
- 18
parse.leg Ver fichero

@ -17,7 +17,7 @@
_DO(PostIncVariable) _DO(PostIncMember) _DO(PostIncIndex) \
_DO(PreDecVariable) _DO(PreDecMember) _DO(PreDecIndex) \
_DO(PostDecVariable) _DO(PostDecMember) _DO(PostDecIndex) \
_DO(GetVariable) _DO(GetMember) _DO(SetMember) _DO(GetIndex) _DO(SetIndex) \
_DO(GetVariable) _DO(GetMember) _DO(SetMember) _DO(GetIndex) _DO(SetIndex) _DO(Slice) \
_DO(Return) _DO(Break) _DO(Continue) _DO(Throw) _DO(Try) \
_DO(Quasiquote) _DO(Unquote)
@ -75,7 +75,8 @@ oop globals= 0;
_DO(lhs) _DO(rhs) _DO(scope) _DO(args) _DO(expression) _DO(labels) _DO(statements) _DO(initialise) \
_DO(update) _DO(this) _DO(fixed) _DO(operator) _DO(map) _DO(func) \
_DO(try) _DO(catch) _DO(finally) _DO(exception) \
_DO(__line__) _DO(__file__)
_DO(__line__) _DO(__file__) \
_DO(start) _DO(stop)
#define _DO(NAME) oop NAME##_symbol;
DO_SYMBOLS()
@ -547,6 +548,15 @@ oop newContinue(void)
return obj;
}
oop newSlice(oop value, oop start, oop stop)
{
oop obj= newObject(Slice_proto);
map_set(obj, value_symbol, value);
map_set(obj, start_symbol, start);
map_set(obj, stop_symbol, stop);
return obj;
}
oop newTry(oop try, oop exception, oop catch, oop finally)
{
oop obj = newObject(Try_proto);
@ -664,24 +674,24 @@ cond = c:logor QUERY t:exp COLON f:cond { $$ = newIf(c, t,
| logor
logor = l:logand
( LOGOR r:logand { l = newBinary(Logor_proto, l, r) }
)* { $$ = l }
( LOGOR r:logand { l = newBinary(Logor_proto, l, r) }
)* { $$ = l }
logand = l:bitor
( LOGAND r:bitor { l = newBinary(Logand_proto, l, r) }
)* { $$ = l }
( LOGAND r:bitor { l = newBinary(Logand_proto, l, r) }
)* { $$ = l }
bitor = l:bitxor
( BITOR r:bitxor { l = newBinary(Bitor_proto, l, r) }
)* { $$ = l }
( BITOR r:bitxor { l = newBinary(Bitor_proto, l, r) }
)* { $$ = l }
bitxor = l:bitand
( BITXOR r:bitand { l = newBinary(Bitxor_proto, l, r) }
)* { $$ = l }
( BITXOR r:bitand { l = newBinary(Bitxor_proto, l, r) }
)* { $$ = l }
bitand = l:eq
( BITAND r:eq { l = newBinary(Bitand_proto, l, r) }
)* { $$ = l }
( BITAND r:eq { l = newBinary(Bitand_proto, l, r) }
)* { $$ = l }
eq = l:ineq
( EQUAL r:ineq { l = newBinary(Equal_proto, l, r) }
@ -701,8 +711,8 @@ shift = l:sum
)* { $$ = l }
sum = l:prod
( PLUS r:prod { l = newBinary(Add_proto, l, r) }
| MINUS r:prod { l = newBinary(Sub_proto, l, r) }
( PLUS r:prod { l = newBinary(Add_proto, l, r) }
| MINUS r:prod { l = newBinary(Sub_proto, l, r) }
)* { $$ = l }
prod = l:prefix
@ -723,6 +733,10 @@ prefix = PLUS n:prefix { $$= n }
postfix = i:value ( DOT s:IDENT a:argumentList { i = newInvoke(i, s, a) }
| DOT s:IDENT !assignOp { i = newGetMap(GetMember_proto, i, s) }
| LBRAC e1:exp COLON e2:exp RBRAC !assignOp { i = newSlice(i, e1, e2) }
| LBRAC e1:exp COLON RBRAC !assignOp { i = newSlice(i, e1, null) }
| LBRAC COLON e2:exp RBRAC !assignOp { i = newSlice(i, null, e2) }
| LBRAC COLON RBRAC !assignOp { i = newSlice(i, null, null) }
| LBRAC p:exp RBRAC !assignOp { i = newGetMap(GetIndex_proto, i, p) }
| a:argumentList { i = (null != getSyntax(1, i)) ? apply(globals, getSyntax(1, i), a) : newCall(i, a) }
| PLUSPLUS { i = newPostIncrement(i) }
@ -1556,11 +1570,23 @@ oop eval(oop scope, oop ast)
oop key = eval(scope, map_get(ast, key_symbol));
switch (getType(map)) {
case String:
if (getInteger(key) >= get(map, String, size)) {
runtimeError("GetIndex out of range on String");
if (!isInteger(key)) {
runtimeError("non-integer index");
}
ssize_t i= getInteger(key);
size_t len= string_size(map);
if (i < 0) i+= len;
if (i < 0 || i >= len) {
runtimeError("GetIndex out of bounds on String");
}
return makeInteger(unescape(get(map, String, value))[getInteger(key)]);
return makeInteger(get(map, String, value)[i]);
case Map:
if (isInteger(key) && getInteger(key) < 0) {
size_t size= map_size(map);
if (size > 0 && map_hasIntegerKey(map, size - 1)) {
key= makeInteger(getInteger(key) + size);
}
}
return map_get(map, key);
default:
runtimeError("GetIndex on non Map or String");
@ -1574,7 +1600,7 @@ oop eval(oop scope, oop ast)
switch (getType(map)) {
case String:
if (getInteger(key) >= get(map, String, size)) {
runtimeError("SetIndex out of range on String");
runtimeError("SetIndex out of bounds on String");
}
get(map, String, value)[getInteger(key)] = getInteger(value);
return value;
@ -1586,6 +1612,35 @@ oop eval(oop scope, oop ast)
}
}
case t_Slice: {
oop pre= eval(scope, map_get(ast, value_symbol));
oop start= eval(scope, map_get(ast, start_symbol));
oop stop= eval(scope, map_get(ast, stop_symbol));
ssize_t first= start == null ? 0 : getInteger(start);
if (start == null) {
start= makeInteger(0);
}
switch (getType(pre)) {
case String: {
ssize_t last= stop == null ? string_size(pre) : getInteger(stop);
oop res= string_slice(pre, first, last);
if (NULL == res) {
runtimeError("index out of bounds");
}
return res;
}
case Map: {
ssize_t last= stop == null ? map_size(pre) : getInteger(stop);
oop res= map_slice(pre, first, last);
if (NULL == res) {
runtimeError("index out of bounds");
}
return res;
}
}
runtimeError("slicing a non-String or non-Map");
}
case t_Symbol:
case t_Integer:
case t_String: {

+ 1
- 2
test-module.txt Ver fichero

@ -2,5 +2,4 @@ var pi = 3
fun sum(a, b) {
return a+b;
}
println("Hello from test-module.txt");
}

+ 2
- 1
test-require.txt Ver fichero

@ -3,4 +3,5 @@ var mod = require("test-module.txt");
println(mod.sum(40, 2));
println(mod.pi);
var mod2 = require("test-module.txt");
println(mod2.pi);
println(mod2.pi);
println(invoke(mod2, mod2.pi, [2, 4]))

+ 10
- 0
test-slice.txt Ver fichero

@ -0,0 +1,10 @@
s = "hello"
b = [2, 4, 6]
b.pizza= "ok"
println(s[-4:-3])
println(s[:-3])
println(s[-4:])
println(s[:])
println(s[:])
m = { 3: "three", 1: "four", 2: "five" }
println({}[-0]);

Cargando…
Cancelar
Guardar