Skip to content

Commit

Permalink
First go at eval
Browse files Browse the repository at this point in the history
- Basic cases work.
- Not working in the REPL yet, that's up next.
- Adds a header file to the flex scanner gen. Removes the extra
  declarations in the parser spec.
  • Loading branch information
ndreynolds committed Apr 11, 2013
1 parent ab5382d commit 98d0228
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
bin/flat
y.*
lex.yy.c
lex.yy.?
*.out
tags
*.o
Expand Down
18 changes: 12 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@

CC = gcc
CFLAGS = -Wall -Wextra -Wno-unused-parameter -O3 -std=c99 -pedantic -D_XOPEN_SOURCE
YACC = bison -y -d -t -v

YACC = bison
YACC_FLAGS = -y -d -t -v

LEX = flex
LEX_FLAGS =

LIBS = -I/usr/local/include -I/usr/include -L/usr/local/lib -L/usr/lib -lm
OBJ_FILES = y.tab.o lex.yy.o src/eval.o src/str.o src/regexp.o src/cli.o \
Expand Down Expand Up @@ -77,13 +81,15 @@ malloc-debug: LIBS += -lefence
malloc-debug: debug


lex.yy.o: $(LEX_FILE)
$(LEX) $(LEX_FILE)
lex.yy.c:
$(LEX) --header-file=lex.yy.h $(LEX_FLAGS) $(LEX_FILE)

lex.yy.o: lex.yy.c $(LEX_FILE)
@echo "[CC -o] lex.yy.o"
@$(CC) -c $(CFLAGS) lex.yy.c -o lex.yy.o

y.tab.o: $(YACC_FILE)
$(YACC) $(YACC_FILE)
y.tab.o: lex.yy.c $(YACC_FILE)
$(YACC) $(YACC_FLAGS) $(YACC_FILE)
@echo "[CC -o] y.tab.o"
@$(CC) -c $(CFLAGS) y.tab.c -o y.tab.o

Expand All @@ -94,7 +100,7 @@ linker: $(OBJ_FILES)
@$(CC) -c $(CFLAGS) $< -o $@

clean:
rm -rf y.* lex.yy.c $(OUT_FILE) $(OBJ_FILES)
rm -rf y.* lex.yy.c y.tab.c y.tab.h $(OUT_FILE) $(OBJ_FILES)

install:
cp $(OUT_FILE) /usr/local/bin/
Expand Down
3 changes: 2 additions & 1 deletion src/flathead.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,8 @@ eval_state * fh_new_state(int, int);
js_val * fh_get_arg(js_args *, int);
unsigned int fh_arg_len(js_args*);

js_val * fh_eval_file(FILE *, js_val *, int);
js_val * fh_eval_file(FILE *, js_val *);
js_val * fh_eval_string(char *, js_val *);
js_val * fh_try_get_proto(char *);

bool fh_is_callable(js_val *);
Expand Down
28 changes: 21 additions & 7 deletions src/grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <readline/history.h>
#endif

#include "lex.yy.h"
#include "src/flathead.h"
#include "src/nodes.h"
#include "src/eval.h"
Expand Down Expand Up @@ -99,10 +100,7 @@
#define NEW_WITH(exp,stmt) NEW_NODE(NODE_WITH_STMT,exp,stmt,0,0,0)

void yyerror(const char *);
void yyrestart(FILE *);
int yylex(void);
int yydebug;
FILE *yyin;
int fh_get_input(char *, int);
ast_node *root;
eval_state *state;
Expand Down Expand Up @@ -1142,8 +1140,10 @@ fh_get_input(char *buf, int size)
return 0;
}
strcpy(buf, line);
// Ghetto ASI

// Poor man's ASI:
if (!strchr(buf, ';')) strcat(buf, ";");

strcat(buf, "\n");
free(line);
add_history(buf);
Expand All @@ -1162,7 +1162,7 @@ fh_get_input(char *buf, int size)
}

js_val *
fh_eval_file(FILE *file, js_val *ctx, int is_repl)
fh_eval_file(FILE *file, js_val *ctx)
{
yyrestart(file);
yyparse();
Expand All @@ -1174,6 +1174,20 @@ fh_eval_file(FILE *file, js_val *ctx, int is_repl)
return res;
}

js_val *
fh_eval_string(char *string, js_val *ctx)
{
void *buffer = yy_scan_string(string);
yyparse();

if (fh->opt_print_ast)
print_node(root, true, 0);

js_val *res = fh_eval(ctx, root);
yy_delete_buffer(buffer);
return res;
}

int
main(int argc, char **argv)
{
Expand Down Expand Up @@ -1227,10 +1241,10 @@ main(int argc, char **argv)
// continue. Use setjmp here and longjmp in `fh_error` to simulate
// exception handling.
if (!setjmp(fh->jmpbuf))
DEBUG(fh_eval_file(source, fh->global, true));
DEBUG(fh_eval_file(source, fh->global));
}
} else {
fh_eval_file(source, fh->global, false);
fh_eval_file(source, fh->global);
}

return 0;
Expand Down
2 changes: 2 additions & 0 deletions src/lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
int yycolumn = 1;
int prev_token = 0;
void yyuseraction(void);
YY_BUFFER_STATE yy_scan_string(const char *);
void yy_delete_buffer(YY_BUFFER_STATE);

char * fh_extract_string(char *);
void fh_parse_error(char *);
Expand Down
8 changes: 4 additions & 4 deletions src/runtime/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ global_parse_float(js_val *instance, js_args *args, eval_state *state)
js_val *
global_eval(js_val *instance, js_args *args, eval_state *state)
{
// TODO: implement
fh_error(state, E_ERROR, "eval is not yet implemented");
UNREACHABLE();
js_val *code = TO_STR(ARG(args, 0));
code->string.ptr[code->string.length] = '\0';
return fh_eval_string(code->string.ptr, state->ctx);
}

// gc()
Expand All @@ -108,7 +108,7 @@ global_load(js_val *instance, js_args *args, eval_state *state)
fh_error(state, E_ERROR, "File could not be read");

FILE *file = fopen(name->string.ptr, "r");
fh_eval_file(file, fh->global, false);
fh_eval_file(file, fh->global);
fclose(file);
}
return JSUNDEF();
Expand Down
20 changes: 20 additions & 0 deletions test/test_eval.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// test_eval.js
// ------------
// Note the unfortunate limitation that until ASI is added, statements within
// strings passed to eval need to be semicolon-terminated.

(this.load || require)((this.load ? 'test' : '.') + '/tools/assertions.js');


test('eval without references', function() {
assertEquals(1, eval('1;'));
assertEquals(4, eval('2 + 2;'));
assertEquals(42, eval('(function() { return 42; });')());
});

test('eval with references', function() {
var x = 42;
assertEquals(x, eval('x;'));
assertEquals(f, eval('f;'));
function f() { return 'The f function'; };
});
31 changes: 17 additions & 14 deletions test/test_globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,23 @@ test('global functions', function() {
assertIsFunction(parseInt, 2);

// without radix
assert(parseInt("42") === 42);
assert(parseInt("3.14") === 3);
assertEquals(42, parseInt("42"));
assertEquals(3, parseInt("3.14"));
assertNaN(parseInt("Not a number"));

// with radix
assert(parseInt(" 0xF", 16) === 15);
assert(parseInt(" F", 16) === 15);
assert(parseInt("17", 8) === 15);
// FIXME: assert(parseInt(021, 8) === 15);
assert(parseInt("015", 10) === 15);
assert(parseInt(15.99, 10) === 15);
// FIXME: assert(parseInt("FXX123", 16) === 15);
assert(parseInt("1111", 2) === 15);
// FIXME: assert(parseInt("15*3", 10) === 15);
// FIXME: assert(parseInt("15e2", 10) === 15);
// FIXME: assert(parseInt("15px", 10) === 15);
assert(parseInt("12", 13) === 15);
assertEquals(15, parseInt(" 0xF", 16));
assertEquals(15, parseInt(" F", 16));
assertEquals(15, parseInt("17", 8));
// FIXME: assertEquals(15, parseInt(021, 8));
assertEquals(15, parseInt("015", 10));
assertEquals(15, parseInt(15.99, 10));
// FIXME: assertEquals(15, parseInt("FXX123", 16));
assertEquals(15, parseInt("1111", 2));
// FIXME: assertEquals(15, parseInt("15*3", 10));
// FIXME: assertEquals(15, parseInt("15e2", 10));
// FIXME: assertEquals(15, parseInt("15px", 10));
assertEquals(15, parseInt("12", 13));
assertNaN(parseInt("Not a number", 10));
});

Expand All @@ -82,7 +82,10 @@ test('global functions', function() {
});

test('eval(x)', function() {
// See also: test_eval.js
assertIsFunction(eval, 1);
assertEquals(4, eval('2 + 2;'));
assertEquals(42, eval('21 * 2;'));
});

});
Expand Down

0 comments on commit 98d0228

Please sign in to comment.