1 /** 2 This module implements script functions that are stored in the global namespace. 3 See https://pillager86.github.io/dmildew/global.html for more information. 4 5 ──────────────────────────────────────────────────────────────────────────────── 6 7 Copyright (C) 2021 pillager86.rf.gd 8 9 This program is free software: you can redistribute it and/or modify it under 10 the terms of the GNU General Public License as published by the Free Software 11 Foundation, either version 3 of the License, or (at your option) any later 12 version. 13 14 This program is distributed in the hope that it will be useful, but WITHOUT ANY 15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 PARTICULAR PURPOSE. See the GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 module mildew.stdlib.global; 22 23 import mildew.environment; 24 import mildew.exceptions; 25 import mildew.interpreter; 26 import mildew.types; 27 28 /** 29 * This is called by the interpreter's initializeStdlib method to store functions in the global namespace. 30 * Documentation for these functions can be found at https://pillager86.github.io/dmildew/global.html 31 * Params: 32 * interpreter = The Interpreter instance to load the functions into. 33 */ 34 void initializeGlobalLibrary(Interpreter interpreter) 35 { 36 // experimental: runFile 37 interpreter.forceSetGlobal("runFile", new ScriptFunction("runFile", &native_runFile)); 38 interpreter.forceSetGlobal("clearImmediate", new ScriptFunction("clearImmediate", &native_clearImmediate)); 39 interpreter.forceSetGlobal("clearTimeout", new ScriptFunction("clearTimeout", &native_clearTimeout)); 40 interpreter.forceSetGlobal("decodeURI", new ScriptFunction("decodeURI", &native_decodeURI)); 41 interpreter.forceSetGlobal("decodeURIComponent", new ScriptFunction("decodeURIComponent", 42 &native_decodeURIComponent)); 43 interpreter.forceSetGlobal("encodeURI", new ScriptFunction("encodeURI", &native_encodeURI)); 44 interpreter.forceSetGlobal("encodeURIComponent", new ScriptFunction("encodeURIComponent", 45 &native_encodeURIComponent)); 46 interpreter.forceSetGlobal("isdefined", new ScriptFunction("isdefined", &native_isdefined)); 47 interpreter.forceSetGlobal("isFinite", new ScriptFunction("isFinite", &native_isFinite)); 48 interpreter.forceSetGlobal("isNaN", new ScriptFunction("isNaN", &native_isNaN)); 49 interpreter.forceSetGlobal("parseFloat", new ScriptFunction("parseFloat", &native_parseFloat)); 50 interpreter.forceSetGlobal("parseInt", new ScriptFunction("parseInt", &native_parseInt)); 51 interpreter.forceSetGlobal("setImmediate", new ScriptFunction("setImmediate", &native_setImmediate)); 52 interpreter.forceSetGlobal("setTimeout", new ScriptFunction("setTimeout", &native_setTimeout)); 53 } 54 55 // 56 // Global method implementations 57 // 58 59 // experimental DO NOT USE 60 private ScriptAny native_runFile(Environment env, ScriptAny* thisObj, 61 ScriptAny[] args, ref NativeFunctionError nfe) 62 { 63 if(args.length < 1) 64 { 65 nfe = NativeFunctionError.WRONG_NUMBER_OF_ARGS; 66 return ScriptAny.UNDEFINED; 67 } 68 auto fileName = args[0].toString(); 69 try 70 { 71 return env.g.interpreter.evaluateFile(fileName); 72 73 } 74 catch(Exception ex) 75 { 76 nfe = NativeFunctionError.RETURN_VALUE_IS_EXCEPTION; 77 return ScriptAny(ex.msg); 78 } 79 } 80 81 private ScriptAny native_clearImmediate(Environment env, ScriptAny* thisObj, 82 ScriptAny[] args, ref NativeFunctionError nfe) 83 { 84 import mildew.vm.virtualmachine: VirtualMachine; 85 import mildew.vm.fiber: ScriptFiber; 86 87 if(args.length < 1) 88 { 89 nfe = NativeFunctionError.WRONG_NUMBER_OF_ARGS; 90 return ScriptAny.UNDEFINED; 91 } 92 auto sfib = args[0].toNativeObject!ScriptFiber; 93 if(sfib is null) 94 { 95 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 96 return ScriptAny.UNDEFINED; 97 } 98 if(sfib.toString() != "Immediate") 99 return ScriptAny(false); 100 return ScriptAny(env.g.interpreter.vm.removeFiber(sfib)); 101 } 102 103 private ScriptAny native_clearTimeout(Environment env, ScriptAny* thisObj, 104 ScriptAny[] args, ref NativeFunctionError nfe) 105 { 106 import mildew.vm.virtualmachine: VirtualMachine; 107 import mildew.vm.fiber: ScriptFiber; 108 109 if(args.length < 1) 110 { 111 nfe = NativeFunctionError.WRONG_NUMBER_OF_ARGS; 112 return ScriptAny.UNDEFINED; 113 } 114 auto sfib = args[0].toNativeObject!ScriptFiber; 115 if(sfib is null) 116 { 117 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 118 return ScriptAny.UNDEFINED; 119 } 120 if(sfib.toString() != "Timeout") 121 return ScriptAny(false); 122 return ScriptAny(env.g.interpreter.vm.removeFiber(sfib)); 123 } 124 125 private ScriptAny native_decodeURI(Environment env, ScriptAny* thisObj, 126 ScriptAny[] args, ref NativeFunctionError nfe) 127 { 128 import std.uri: decode, URIException; 129 if(args.length < 1) 130 return ScriptAny.UNDEFINED; 131 try 132 { 133 return ScriptAny(decode(args[0].toString())); 134 } 135 catch(URIException ex) 136 { 137 throw new ScriptRuntimeException(ex.msg); 138 } 139 } 140 141 private ScriptAny native_decodeURIComponent(Environment env, ScriptAny* thisObj, 142 ScriptAny[] args, ref NativeFunctionError nfe) 143 { 144 import std.uri: decodeComponent, URIException; 145 if(args.length < 1) 146 return ScriptAny.UNDEFINED; 147 try 148 { 149 return ScriptAny(decodeComponent(args[0].toString())); 150 } 151 catch(URIException ex) 152 { 153 throw new ScriptRuntimeException(ex.msg); 154 } 155 } 156 157 private ScriptAny native_encodeURI(Environment env, ScriptAny* thisObj, 158 ScriptAny[] args, ref NativeFunctionError nfe) 159 { 160 import std.uri: encode, URIException; 161 if(args.length < 1) 162 return ScriptAny.UNDEFINED; 163 try 164 { 165 return ScriptAny(encode(args[0].toString())); 166 } 167 catch(URIException ex) 168 { 169 throw new ScriptRuntimeException(ex.msg); 170 } 171 } 172 173 private ScriptAny native_encodeURIComponent(Environment env, ScriptAny* thisObj, 174 ScriptAny[] args, ref NativeFunctionError nfe) 175 { 176 import std.uri: encodeComponent, URIException; 177 if(args.length < 1) 178 return ScriptAny.UNDEFINED; 179 try 180 { 181 return ScriptAny(encodeComponent(args[0].toString())); 182 } 183 catch(URIException ex) 184 { 185 throw new ScriptRuntimeException(ex.msg); 186 } 187 } 188 189 private ScriptAny native_isdefined(Environment env, 190 ScriptAny* thisObj, 191 ScriptAny[] args, 192 ref NativeFunctionError nfe) 193 { 194 if(args.length < 1) 195 return ScriptAny(false); 196 auto varToLookup = args[0].toString(); 197 return ScriptAny(env.variableOrConstExists(varToLookup)); 198 } 199 200 private ScriptAny native_isFinite(Environment env, ScriptAny* thisObj, 201 ScriptAny[] args, ref NativeFunctionError nfe) 202 { 203 import std.math: isFinite; 204 if(args.length < 1) 205 return ScriptAny.UNDEFINED; 206 if(!args[0].isNumber) 207 return ScriptAny.UNDEFINED; 208 immutable value = args[0].toValue!double; 209 return ScriptAny(isFinite(value)); 210 } 211 212 private ScriptAny native_isNaN(Environment env, ScriptAny* thisObj, 213 ScriptAny[] args, ref NativeFunctionError nfe) 214 { 215 import std.math: isNaN; 216 if(args.length < 1) 217 return ScriptAny.UNDEFINED; 218 if(!args[0].isNumber) 219 return ScriptAny(true); 220 immutable value = args[0].toValue!double; 221 return ScriptAny(isNaN(value)); 222 } 223 224 private ScriptAny native_parseFloat(Environment env, ScriptAny* thisObj, 225 ScriptAny[] args, ref NativeFunctionError nfe) 226 { 227 import std.conv: to, ConvException; 228 if(args.length < 1) 229 return ScriptAny(double.nan); 230 auto str = args[0].toString(); 231 try 232 { 233 immutable value = to!double(str); 234 return ScriptAny(value); 235 } 236 catch(ConvException) 237 { 238 return ScriptAny(double.nan); 239 } 240 } 241 242 private ScriptAny native_parseInt(Environment env, ScriptAny* thisObj, 243 ScriptAny[] args, ref NativeFunctionError nfe) 244 { 245 import std.conv: to, ConvException; 246 if(args.length < 1) 247 return ScriptAny.UNDEFINED; 248 auto str = args[0].toString(); 249 immutable radix = args.length > 1 ? args[1].toValue!int : 10; 250 try 251 { 252 immutable value = to!long(str, radix); 253 return ScriptAny(value); 254 } 255 catch(ConvException) 256 { 257 return ScriptAny.UNDEFINED; 258 } 259 } 260 261 private ScriptAny native_setImmediate(Environment env, ScriptAny* thisObj, 262 ScriptAny[] args, ref NativeFunctionError nfe) 263 { 264 import mildew.types.bindings: getLocalThis; 265 // all environments are supposed to be linked to the global one. if not, there is a bug 266 auto vm = env.g.interpreter.vm; 267 if(args.length < 1) 268 { 269 nfe = NativeFunctionError.WRONG_NUMBER_OF_ARGS; 270 return ScriptAny.UNDEFINED; 271 } 272 auto func = args[0].toValue!ScriptFunction; 273 if(func is null) 274 { 275 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 276 return ScriptAny.UNDEFINED; 277 } 278 args = args[1..$]; 279 auto thisToUse = args.length > 0 ? getLocalThis(env, args[0]) : ScriptAny.UNDEFINED; 280 ScriptFunction funcToAsync = new ScriptFunction(func.functionName, 281 delegate ScriptAny(Environment env, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError) { 282 return vm.runFunction(func, thisToUse, args); 283 }); 284 auto retVal = vm.addFiberFirst("Immediate", funcToAsync, thisToUse, args); 285 return ScriptAny(retVal); 286 } 287 288 private ScriptAny native_setTimeout(Environment env, ScriptAny* thisObj, 289 ScriptAny[] args, ref NativeFunctionError nfe) 290 { 291 import std.datetime: dur, Clock; 292 import std.concurrency: yield; 293 import mildew.types.bindings: getLocalThis; 294 295 // all environments are supposed to be linked to the global one. if not, there is a bug 296 auto vm = env.g.interpreter.vm; 297 if(args.length < 2) 298 { 299 nfe = NativeFunctionError.WRONG_NUMBER_OF_ARGS; 300 return ScriptAny.UNDEFINED; 301 } 302 auto func = args[0].toValue!ScriptFunction; 303 if(func is null) 304 { 305 nfe = NativeFunctionError.WRONG_TYPE_OF_ARG; 306 return ScriptAny.UNDEFINED; 307 } 308 auto timeout = args[1].toValue!size_t; 309 args = args[2..$]; 310 auto thisToUse = args.length > 0 ? getLocalThis(env, args[0]) : ScriptAny.UNDEFINED; 311 ScriptFunction funcToAsync = new ScriptFunction(func.functionName, 312 delegate ScriptAny(Environment env, ScriptAny* thisObj, ScriptAny[] args, ref NativeFunctionError) { 313 immutable start = Clock.currStdTime() / 10_000; 314 long current = start; 315 while(current - start <= timeout) 316 { 317 yield(); 318 current = Clock.currStdTime() / 10_000; 319 } 320 return vm.runFunction(func, thisToUse, args); 321 }); 322 323 auto retVal = vm.addFiber("Timeout", funcToAsync, thisToUse, args); 324 return ScriptAny(retVal); 325 }