You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
8.5 KiB

/*
* TinyJS
*
* A single-file Javascript-alike engine
*
* - Useful language functions
*
* Authored By Gordon Williams <gw@pur3.co.uk>
*
* Copyright (C) 2009 Pur3 Ltd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "TinyJS_Functions.h"
#include <math.h>
#include <cstdlib>
#include <sstream>
using namespace std;
// ----------------------------------------------- Actual Functions
void scTrace(CScriptVar *c, void *userdata) {
CTinyJS *js = (CTinyJS*)userdata;
js->root->trace();
}
void scObjectDump(CScriptVar *c, void *) {
c->getParameter("this")->trace("> ");
}
void scObjectClone(CScriptVar *c, void *) {
CScriptVar *obj = c->getParameter("this");
c->getReturnVar()->copyValue(obj);
}
void scMathRand(CScriptVar *c, void *) {
c->getReturnVar()->setDouble((double)rand()/RAND_MAX);
}
void scMathRandInt(CScriptVar *c, void *) {
int min = c->getParameter("min")->getInt();
int max = c->getParameter("max")->getInt();
int val = min + (int)(rand()%(1+max-min));
c->getReturnVar()->setInt(val);
}
void scCharToInt(CScriptVar *c, void *) {
string str = c->getParameter("ch")->getString();;
int val = 0;
if (str.length()>0)
val = (int)str.c_str()[0];
c->getReturnVar()->setInt(val);
}
void scStringIndexOf(CScriptVar *c, void *) {
string str = c->getParameter("this")->getString();
string search = c->getParameter("search")->getString();
size_t p = str.find(search);
int val = (p==string::npos) ? -1 : p;
c->getReturnVar()->setInt(val);
}
void scStringSubstring(CScriptVar *c, void *) {
string str = c->getParameter("this")->getString();
int lo = c->getParameter("lo")->getInt();
int hi = c->getParameter("hi")->getInt();
int l = hi-lo;
if (l>0 && lo>=0 && lo+l<=(int)str.length())
c->getReturnVar()->setString(str.substr(lo, l));
else
c->getReturnVar()->setString("");
}
void scStringCharAt(CScriptVar *c, void *) {
string str = c->getParameter("this")->getString();
int p = c->getParameter("pos")->getInt();
if (p>=0 && p<(int)str.length())
c->getReturnVar()->setString(str.substr(p, 1));
else
c->getReturnVar()->setString("");
}
void scStringCharCodeAt(CScriptVar *c, void *) {
string str = c->getParameter("this")->getString();
int p = c->getParameter("pos")->getInt();
if (p>=0 && p<(int)str.length())
c->getReturnVar()->setInt(str.at(p));
else
c->getReturnVar()->setInt(0);
}
void scStringSplit(CScriptVar *c, void *) {
string str = c->getParameter("this")->getString();
string sep = c->getParameter("separator")->getString();
CScriptVar *result = c->getReturnVar();
result->setArray();
int length = 0;
size_t pos = str.find(sep);
while (pos != string::npos) {
result->setArrayIndex(length++, new CScriptVar(str.substr(0,pos)));
str = str.substr(pos+1);
pos = str.find(sep);
}
if (str.size()>0)
result->setArrayIndex(length++, new CScriptVar(str));
}
void scStringFromCharCode(CScriptVar *c, void *) {
char str[2];
str[0] = c->getParameter("char")->getInt();
str[1] = 0;
c->getReturnVar()->setString(str);
}
void scIntegerParseInt(CScriptVar *c, void *) {
string str = c->getParameter("str")->getString();
int val = strtol(str.c_str(),0,0);
c->getReturnVar()->setInt(val);
}
void scIntegerValueOf(CScriptVar *c, void *) {
string str = c->getParameter("str")->getString();
int val = 0;
if (str.length()==1)
val = str[0];
c->getReturnVar()->setInt(val);
}
void scJSONStringify(CScriptVar *c, void *) {
std::ostringstream result;
c->getParameter("obj")->getJSON(result);
c->getReturnVar()->setString(result.str());
}
void scExec(CScriptVar *c, void *data) {
CTinyJS *tinyJS = (CTinyJS *)data;
std::string str = c->getParameter("jsCode")->getString();
tinyJS->execute(str);
}
void scEval(CScriptVar *c, void *data) {
CTinyJS *tinyJS = (CTinyJS *)data;
std::string str = c->getParameter("jsCode")->getString();
c->setReturnVar(tinyJS->evaluateComplex(str).var);
}
void scArrayContains(CScriptVar *c, void *data) {
CScriptVar *obj = c->getParameter("obj");
CScriptVarLink *v = c->getParameter("this")->firstChild;
bool contains = false;
while (v) {
if (v->var->equals(obj)) {
contains = true;
break;
}
v = v->nextSibling;
}
c->getReturnVar()->setInt(contains);
}
void scArrayRemove(CScriptVar *c, void *data) {
CScriptVar *obj = c->getParameter("obj");
vector<int> removedIndices;
CScriptVarLink *v;
// remove
v = c->getParameter("this")->firstChild;
while (v) {
if (v->var->equals(obj)) {
removedIndices.push_back(v->getIntName());
}
v = v->nextSibling;
}
// renumber
v = c->getParameter("this")->firstChild;
while (v) {
int n = v->getIntName();
int newn = n;
for (size_t i=0;i<removedIndices.size();i++)
if (n>=removedIndices[i])
newn--;
if (newn!=n)
v->setIntName(newn);
v = v->nextSibling;
}
}
void scArrayJoin(CScriptVar *c, void *data) {
string sep = c->getParameter("separator")->getString();
CScriptVar *arr = c->getParameter("this");
ostringstream sstr;
int l = arr->getArrayLength();
for (int i=0;i<l;i++) {
if (i>0) sstr << sep;
sstr << arr->getArrayIndex(i)->getString();
}
c->getReturnVar()->setString(sstr.str());
}
// ----------------------------------------------- Register Functions
void registerFunctions(CTinyJS *tinyJS) {
tinyJS->addNative("function exec(jsCode)", scExec, tinyJS); // execute the given code
tinyJS->addNative("function eval(jsCode)", scEval, tinyJS); // execute the given string (an expression) and return the result
tinyJS->addNative("function trace()", scTrace, tinyJS);
tinyJS->addNative("function Object.dump()", scObjectDump, 0);
tinyJS->addNative("function Object.clone()", scObjectClone, 0);
tinyJS->addNative("function Math.rand()", scMathRand, 0);
tinyJS->addNative("function Math.randInt(min, max)", scMathRandInt, 0);
tinyJS->addNative("function charToInt(ch)", scCharToInt, 0); // convert a character to an int - get its value
tinyJS->addNative("function String.indexOf(search)", scStringIndexOf, 0); // find the position of a string in a string, -1 if not
tinyJS->addNative("function String.substring(lo,hi)", scStringSubstring, 0);
tinyJS->addNative("function String.charAt(pos)", scStringCharAt, 0);
tinyJS->addNative("function String.charCodeAt(pos)", scStringCharCodeAt, 0);
tinyJS->addNative("function String.fromCharCode(char)", scStringFromCharCode, 0);
tinyJS->addNative("function String.split(separator)", scStringSplit, 0);
tinyJS->addNative("function Integer.parseInt(str)", scIntegerParseInt, 0); // string to int
tinyJS->addNative("function Integer.valueOf(str)", scIntegerValueOf, 0); // value of a single character
tinyJS->addNative("function JSON.stringify(obj, replacer)", scJSONStringify, 0); // convert to JSON. replacer is ignored at the moment
// JSON.parse is left out as you can (unsafely!) use eval instead
tinyJS->addNative("function Array.contains(obj)", scArrayContains, 0);
tinyJS->addNative("function Array.remove(obj)", scArrayRemove, 0);
tinyJS->addNative("function Array.join(separator)", scArrayJoin, 0);
}