1 module orelang.operator.StringOperators; 2 import orelang.expression.ImmediateValue, 3 orelang.operator.IOperator, 4 orelang.Engine, 5 orelang.Value; 6 import std.algorithm, 7 std..string, 8 std.array; 9 10 /** 11 * This module provides operators with string. 12 * Current provided operators: 13 * - string-concat 14 * - string-join 15 * - string-split 16 * - string-length 17 * - string-slice 18 * - as-string 19 * - string-repeat 20 */ 21 22 /** 23 * concat strings into a string 24 */ 25 class StringConcatOperator : IOperator { 26 /** 27 * call 28 */ 29 public Value call(Engine engine, Value[] args) { 30 if (args[0].type == ValueType.Array && args.length == 1) { 31 return new Value( 32 engine.eval(args[0]).getArray 33 .map!(arg => (arg.type == ValueType.SymbolValue ? engine.eval(arg) : arg).getString) 34 .join 35 ); 36 } else if (args[0].type == ValueType.ImmediateValue && args[0].getImmediateValue.value.type == ValueType.Array && args.length == 1) { 37 return new Value( 38 args[0].getImmediateValue.value.getArray 39 .map!(arg => (arg.type == ValueType.SymbolValue ? engine.eval(arg) : arg).getString) 40 .join 41 ); 42 } else { 43 return new Value( 44 args 45 .map!(arg => engine.eval(arg).getString) 46 .join 47 ); 48 } 49 } 50 } 51 52 /** 53 * join strings into a string with a separator 54 */ 55 class StringJoinOperator : IOperator { 56 /** 57 * call 58 */ 59 public Value call(Engine engine, Value[] args) { 60 if (args[0].type == ValueType.Array && args.length >= 1) { 61 return new Value( 62 engine.eval(args[0]).getArray 63 .map!(arg => engine.eval(arg).getString) 64 .join(args.length == 1 ? "" : engine.eval(args[1]).getString) 65 ); 66 } else if (args[0].type == ValueType.ImmediateValue && args[0].getImmediateValue.value.type == ValueType.Array && args.length >= 1) { 67 return new Value( 68 args[0].getImmediateValue.value.getArray 69 .map!(arg => (arg.type == ValueType.SymbolValue ? engine.eval(arg) : arg).getString) 70 .join(args.length == 1 ? "" : engine.eval(args[1]).getString) 71 ); 72 } else { 73 return new Value( 74 args[0..$-1] 75 .map!(arg => engine.eval(arg).getString) 76 .join(engine.eval(args[$-1]).getString) 77 ); 78 } 79 } 80 } 81 82 /** 83 * split a string into strings with a separator 84 */ 85 class StringSplitOperator : IOperator { 86 /** 87 * call 88 */ 89 public Value call(Engine engine, Value[] args) { 90 Value[] rets; 91 92 foreach (value; engine.eval(args[0]).getString.split(args.length == 1 ? "" : engine.eval(args[1]).getString)) { 93 rets ~= new Value(value); 94 } 95 96 return new Value(rets); 97 } 98 } 99 100 /** 101 * return a length of the string 102 */ 103 class StringLengthOperator : IOperator { 104 /** 105 * call 106 */ 107 public Value call(Engine engine, Value[] args) { 108 import std.conv; 109 110 if (args[0].type == ValueType.String) { 111 return new Value(args[0].getString.length.to!double); 112 } else { 113 Value eargs0 = engine.eval(args[0]); 114 115 if (eargs0.type == ValueType.String) { 116 return new Value(eargs0.getString.length.to!double); 117 } else { 118 throw new Exception("[string-length] Invalid argument was given"); 119 } 120 } 121 } 122 } 123 124 /** 125 * Tak a slice from the range of the string 126 */ 127 class StringSliceOperator : IOperator { 128 /** 129 * call 130 */ 131 import std.conv; 132 public Value call(Engine engine, Value[] args) { 133 string str; 134 Value eargs0 = engine.eval(args[0]); 135 str = eargs0.getString; 136 137 long slice1 = engine.eval(args[1]).getNumeric.to!long, 138 slice2 = engine.eval(args[2]).getNumeric.to!long; 139 140 if ((0 <= slice1 && 0 <= slice2) && (slice1 <= str.length && slice2 <= str.length)) { 141 return new Value(str[slice1..slice2]); 142 } else { 143 throw new Exception("[string-slice] Invalid"); 144 } 145 } 146 } 147 148 class AsStringOperator : IOperator { 149 /** 150 * call 151 */ 152 import std.conv; 153 public Value call(Engine engine, Value[] args) { 154 return new Value(new ImmediateValue(new Value((args[0].type == ValueType.SymbolValue ? engine.eval(args[0]) : args[0]).toString))); 155 } 156 } 157 158 class StringRepeatOperator : IOperator { 159 /** 160 * call 161 */ 162 import std.algorithm, 163 std..string, 164 std.array, 165 std.range, 166 std.conv; 167 public Value call(Engine engine, Value[] args) { 168 string pattern; 169 long n; 170 171 if (args[0].type == ValueType.SymbolValue) { 172 pattern = engine.eval(args[0]).getString; 173 } else if (args[0].type == ValueType.String) { 174 pattern = args[0].getString; 175 } 176 177 if (args[1].type == ValueType.Numeric) { 178 n = args[1].getNumeric.to!long; 179 } else { 180 n = engine.eval(args[1]).getNumeric.to!long; 181 } 182 183 return new Value(n.iota.map!(i => pattern).array.join); 184 } 185 } 186 187 class StringChompOperator : IOperator { 188 /** 189 * call 190 */ 191 import std..string; 192 193 public Value call(Engine engine, Value[] args) { 194 return new Value(engine.eval(args[0]).getString.chomp); 195 } 196 }