Skip to content

Commit

Permalink
Adds assignment to var statement, isFinite, parseInt & parseFloat
Browse files Browse the repository at this point in the history
- Also cleans up casts, and adds handling for Object & Functions casting
  • Loading branch information
ndreynolds committed Aug 12, 2012
1 parent 2042c00 commit bd5dcba
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 61 deletions.
23 changes: 23 additions & 0 deletions ctest/test_casting.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ test_numbers_are_correctly_cast()
TEST(JLCAST(int_num, T_UNDEF)->type == T_UNDEF);
}

void
test_objects_are_correctly_cast()
{
JLVALUE *obj = JLOBJ();

TEST(JLCAST(obj, T_BOOLEAN)->boolean.val == 1);
TEST(JLCAST(obj, T_NUMBER)->number.is_nan);
TEST(STREQ(JLCAST(obj, T_STRING)->string.ptr, "[Object object]"));
}

void
test_functions_are_correctly_cast()
{
void *fake_node = malloc(sizeof(void *));
JLVALUE *func = JLFUNC(fake_node);

TEST(JLCAST(func, T_BOOLEAN)->boolean.val == 1);
TEST(JLCAST(func, T_NUMBER)->number.is_nan);
TEST(STREQ(JLCAST(func, T_STRING)->string.ptr, "[Function]"));
}

void
test_zero_is_false_others_true()
{
Expand Down Expand Up @@ -93,6 +114,8 @@ main()
test_numeric_strings_are_correctly_cast();
test_non_numeric_strings_are_NaN_when_cast_to_num();
test_numbers_are_correctly_cast();
test_objects_are_correctly_cast();
test_functions_are_correctly_cast();
test_zero_is_false_others_true();
test_keywords_and_specials_cast_to_strings();
test_null_and_undefined_correctly_cast_to_number();
Expand Down
8 changes: 5 additions & 3 deletions src/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,13 @@ jl_eval(JLVALUE *this, JLNode *node)
while(!node->visited) result = jl_eval(this, pop_node(node));
break;
case NODE_PROP:
jl_assign(this, node->e1->sval, jl_eval_exp(this, node->e2), "=");
jl_set(this, node->e1->sval, jl_eval_exp(this, node->e2));
break;
case NODE_VAR_STMT:
// For now we just initialize the property to null.
jl_assign(this, node->e1->sval, JLNULL(), "=");
if (node->e2 != 0)
jl_set(this, node->e1->sval, jl_eval_exp(this, node->e2));
else
jl_set(this, node->e1->sval, JLNULL());
break;
case NODE_WHILE:
jl_while(this, node->e1, node->e2);
Expand Down
3 changes: 2 additions & 1 deletion src/grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ StatementList:
;

VariableStatement:
VAR Identifier ';' { $$ = NEW_VARSTMT($2); }
VAR Identifier ';' { $$ = NEW_VARSTMT($2, NULL); }
| VAR Identifier '=' AssignmentExpression ';' { $$ = NEW_VARSTMT($2, $4); }
;

EmptyStatement:
Expand Down
102 changes: 67 additions & 35 deletions src/jslite.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,47 +227,79 @@ JLVALUE *
jl_cast(JLVALUE *val, JLTYPE type)
{
if (val->type == type) return val;
if (val->type == T_NUMBER && type == T_STRING) {
if (val->number.is_nan) return JLSTR("NaN");
if (val->number.is_inf) return JLSTR("Infinity");
char tmp[100];
sprintf(tmp, "%g", val->number.val);
return JLSTR(tmp);
if (type == T_NULL) return JLNULL();
if (type == T_UNDEF) return JLUNDEF();

// Number => x
if (val->type == T_NUMBER) {
if (type == T_STRING) {
if (val->number.is_nan) return JLSTR("NaN");
if (val->number.is_inf) return JLSTR("Infinity");
char tmp[100];
sprintf(tmp, "%g", val->number.val);
return JLSTR(tmp);
}
if (type == T_BOOLEAN) {
// O is false, x < 0 & x > 0 true
if (val->number.val == 0) return JLBOOL(0);
return JLBOOL(1);
}
}

// String => x
if (val->type == T_STRING) {
if (type == T_NUMBER) {
char *err;
double d = strtod(val->string.ptr, &err);
if (*err != 0) return JLNAN();
return JLNUM(d);
}
if (type == T_BOOLEAN) {
// "" is false, all others true
if (val->string.len == 0) return JLBOOL(0);
return JLBOOL(1);
}
}
if (val->type == T_STRING && type == T_NUMBER) {
char *err;
double d = strtod(val->string.ptr, &err);
if (*err != 0) return JLNAN();
return JLNUM(d);

// Boolean => x
if (val->type == T_BOOLEAN) {
if (type == T_STRING) {
if (val->boolean.val == 1) return JLSTR("true");
return JLSTR("false");
}
if (type == T_NUMBER) {
if (val->boolean.val == 1) return JLNUM(1);
return JLNUM(0);
}
}
if (val->type == T_NULL && type == T_STRING)
return JLSTR("null");
if (val->type == T_NULL && type == T_NUMBER)
return JLNUM(0);
if (val->type == T_UNDEF && type == T_STRING)
return JLSTR("undefined");
if (val->type == T_UNDEF && type == T_NUMBER)
return JLNAN();
if (val->type == T_BOOLEAN && type == T_STRING) {
if (val->boolean.val == 1) return JLSTR("true");
return JLSTR("false");

// Object => x
if (val->type == T_OBJECT) {
if (type == T_BOOLEAN) return JLBOOL(1);
if (type == T_NUMBER) return JLNAN();
// TODO: Call Object.toString()
if (type == T_STRING) return JLSTR("[Object object]");
}
if (val->type == T_BOOLEAN && type == T_NUMBER) {
if (val->boolean.val == 1) return JLNUM(1);
return JLNUM(0);

// Function => x
if (val->type == T_FUNCTION) {
if (type == T_BOOLEAN) return JLBOOL(1);
if (type == T_NUMBER) return JLNAN();
// TODO: Call Function.toString()
if (type == T_STRING) return JLSTR("[Function]");
}
if (val->type == T_NUMBER && type == T_BOOLEAN) {
// O is false, x < 0 & x > 0 true
if (val->number.val == 0) return JLBOOL(0);
return JLBOOL(1);

// null => x
if (val->type == T_NULL) {
if (type == T_STRING) return JLSTR("null");
if (type == T_NUMBER) return JLNUM(0);
}
if (val->type == T_STRING && type == T_BOOLEAN) {
// "" is false, all others true
if (val->string.len == 0) return JLBOOL(0);
return JLBOOL(1);

// undefined => x
if (val->type == T_UNDEF) {
if (type == T_STRING) return JLSTR("undefined");
if (type == T_NUMBER) return JLNAN();
}
if (type == T_NULL) return JLNULL();
if (type == T_UNDEF) return JLUNDEF();
}

void
Expand Down
2 changes: 1 addition & 1 deletion src/nodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void rewind_node(JLNode *);
bool empty_node(JLNode *);

#define NEW_IDENT(name) new_node(NODE_IDENT,0,0,0,0,name)
#define NEW_VARSTMT(ident) new_node(NODE_VAR_STMT,ident,0,0,0,0)
#define NEW_VARSTMT(ident,exp) new_node(NODE_VAR_STMT,ident,exp,0,0,0)
#define NEW_WHILE(cnd,blck) new_node(NODE_WHILE,cnd,blck,0,0,0)
#define NEW_DOWHILE(cnd,blck) new_node(NODE_DOWHILE,cnd,blck,0,0,0)
#define NEW_BLOCK(stmtlst) new_node(NODE_BLOCK,stmtlst,0,0,0,0)
Expand Down
27 changes: 27 additions & 0 deletions src/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <math.h>
#include "runtime.h"
#include "../lib/console.h"

Expand All @@ -31,6 +32,29 @@ jl_is_nan(JLARGS *args)
return JLBOOL(1);
}

JLVALUE *
jl_is_finite(JLARGS *args)
{
JLVALUE *num = JLCAST(args->arg == 0 ? JLUNDEF() : args->arg, T_NUMBER);
if (num->number.is_nan || num->number.is_inf) return JLBOOL(0);
return JLBOOL(1);
}

JLVALUE *
jl_parse_int(JLARGS *args)
{
// Ecma 15.1.2.2
// TODO: use radix argument, strip whitespace.
JLVALUE *num = JLCAST(args->arg == 0 ? JLUNDEF() : args->arg, T_NUMBER);
return JLNUM(floor(num->number.val));
}

JLVALUE *
jl_parse_float(JLARGS *args)
{
return JLCAST(args->arg == 0 ? JLUNDEF() : args->arg, T_NUMBER);
}

JLVALUE *
jl_bootstrap()
{
Expand All @@ -40,6 +64,9 @@ jl_bootstrap()
jl_set(global, "NaN", JLNAN());
jl_set(global, "Infinity", JLINF());
jl_set(global, "isNaN", JLNFUNC((JLNATVFUNC)&jl_is_nan));
jl_set(global, "isFinite", JLNFUNC((JLNATVFUNC)&jl_is_finite));
jl_set(global, "parseInt", JLNFUNC((JLNATVFUNC)&jl_parse_int));
jl_set(global, "parseFloat", JLNFUNC((JLNATVFUNC)&jl_parse_float));
jl_set(global, "undefined", JLUNDEF());
jl_set(global, "this", global);

Expand Down
2 changes: 2 additions & 0 deletions src/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@
#include "jslite.h"

JLVALUE * jl_bootstrap(void);
JLVALUE * jl_is_nan(JLARGS *);
JLVALUE * jl_is_finite(JLARGS *);
2 changes: 1 addition & 1 deletion test/test_assignment.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// test_assignment.js
// ------------------

x = 0;
var x = 0;

x += 4;
console.assert(x == 4);
Expand Down
1 change: 0 additions & 1 deletion test/test_boolean.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// test_boolean.js
// ---------------
// Tests adapted from v8's msjunit

console.assert(true == !false);
console.assert(false == !true);
Expand Down
2 changes: 1 addition & 1 deletion test/test_calls.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// test_calls.js
// -------------

myObject = {
var myObject = {
myMethod: function() {
return 42;
}
Expand Down
21 changes: 15 additions & 6 deletions test/test_functions.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,41 @@
// test_functions.js
// -----------------

assertEquals = function(a, b) {
var assertEquals = function(a, b) {
return console.assert(a == b);
};

add = function(a, b) {
var add = function(a, b) {
return a + b;
};

square = function(x) {
var square = function(x) {
return x * x;
};

incrementSquare = function(x) {
var incrementSquare = function(x) {
return add(square(x), 1);
};

recursive = function(x) {
var recursive1 = function(x) {
if (x < 10) {
x = x + 1;
return arguments.callee(x);
}
return x;
};

var recursive2 = function(x) {
if (x < 10) {
x = x + 1;
return recursive2(x);
}
return x;
};

assertEquals(square(3), 9);
assertEquals(add(2, 2), 4);
assertEquals(incrementSquare(9), 82);
assertEquals(incrementSquare(20), 401);
assertEquals(recursive(1), 10);
assertEquals(recursive1(1), 10);
assertEquals(recursive2(1), 10);
18 changes: 18 additions & 0 deletions test/test_globals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// test_globals.js
// ---------------
// Test methods and properties on the global object.

var assert = console.assert;

assert(isFinite(42));
assert(!isFinite(undefined));
assert(!isFinite(NaN));

assert(isNaN(NaN));
assert(isNaN(undefined));
assert(!isNaN(12));
assert(!isNaN(null));

assert(undefined === undefined);

assert(this);
Loading

0 comments on commit bd5dcba

Please sign in to comment.