refactor: clean and plugin tests (#26)
* refactor: remove gi_c * refactor: new intergation example. * chore: adds new targets. * doc: adds issue template.
This commit is contained in:
committed by
Marc Vertes
parent
3c674c2cc4
commit
3f000e5fac
27
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
Normal file
27
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
The following program `sample.go` triggers a panic:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
func main() {
|
||||
// add a sample
|
||||
}
|
||||
```
|
||||
|
||||
Expected result:
|
||||
```console
|
||||
$ go run ./sample.go
|
||||
// ouput
|
||||
```
|
||||
|
||||
Got:
|
||||
```console
|
||||
$ dyngo ./sample.go
|
||||
// ouput
|
||||
```
|
||||
7
Makefile
7
Makefile
@@ -13,4 +13,9 @@ gen_all_syscall: cmd/goexports/goexports
|
||||
cmd/goexports/goexports: cmd/goexports/goexports.go
|
||||
go generate cmd/goexports/goexports.go
|
||||
|
||||
.PHONY: check gen_all_syscall
|
||||
gen_tests:
|
||||
make -C _test
|
||||
|
||||
generate: gen_all_syscall cmd/goexports/goexports gen_tests
|
||||
|
||||
.PHONY: check gen_all_syscall gen_tests
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
sys = $(shell uname -s)
|
||||
|
||||
CPPFLAGS ?= -Wall -Ideps/include
|
||||
CFLAGS ?= -g
|
||||
|
||||
# Linux linker requires rpath set if lib is not in default path
|
||||
Linux_LDFLAGS = -Wl,-rpath=$(CURDIR)/deps/lib
|
||||
|
||||
LDFLAGS ?= $($(sys)_LDFLAGS) -Ldeps/lib -llightning
|
||||
|
||||
all: deps gi l2 loop2
|
||||
|
||||
gi: gi.o graph.o hash.o init_go.o node.o parse_go.o run_cfg.o run_jit.o scan.o
|
||||
|
||||
l2: l2.go
|
||||
go build -o l2 l2.go
|
||||
|
||||
loop2: loop2.go
|
||||
go build -o loop2 loop2.go
|
||||
|
||||
test: gi
|
||||
./gi -acx loop2.go
|
||||
|
||||
deps:
|
||||
$(MAKE) -C deps
|
||||
|
||||
clean:
|
||||
rm -f *.o gi loop2 l2
|
||||
|
||||
.PHONY: deps clean
|
||||
@@ -1,23 +0,0 @@
|
||||
# gi_c
|
||||
|
||||
Proof of concept for a go interpreter, using previous private works
|
||||
|
||||
# Install
|
||||
|
||||
dependencies: graphviz for AST / CFG visualization
|
||||
|
||||
```
|
||||
make
|
||||
make test
|
||||
```
|
||||
|
||||
# Notes
|
||||
|
||||
Language scope is very limited, just enough to run the demo script `loop2.go`. Interesting enough to get an idea of performances compared with binaries, with or without JIT compilation.
|
||||
|
||||
the machine code generator is using GNU-lightning (installed with `make deps`).
|
||||
|
||||
Do not expect many improvements here, the real work will take place in Go, and will try to reuse as much as possible existing Go assets.
|
||||
|
||||
--
|
||||
Marc
|
||||
@@ -1,7 +0,0 @@
|
||||
# Build and install dependencies
|
||||
|
||||
build:
|
||||
for dep in *.makefile; do make -f $$dep build; done
|
||||
|
||||
clean:
|
||||
for dep in *.makefile; do make -f $$dep clean; done
|
||||
@@ -1,24 +0,0 @@
|
||||
# fetch, build and install a dependency
|
||||
# Just include this file and provide URL variable with the source location
|
||||
|
||||
TGZ ?= $(notdir $(URL))
|
||||
DIR ?= $(shell a=$(TGZ); echo $${a%.t*z})
|
||||
DEST = $(CURDIR)
|
||||
|
||||
all: build
|
||||
|
||||
build: $(DIR)/.build_ok
|
||||
|
||||
clean:
|
||||
rm -rf $(DIR)
|
||||
|
||||
$(DIR)/.build_ok: $(DIR)
|
||||
cd $(DIR) && ./configure --prefix=$(DEST) && make && make install
|
||||
touch $(DIR)/.build_ok
|
||||
|
||||
$(DIR): $(TGZ)
|
||||
tar xvfz $(TGZ) || { rm -rf $(DIR); false; }
|
||||
|
||||
$(TGZ):
|
||||
curl -L -o $@.tmp $(URL)
|
||||
mv $@.tmp $@
|
||||
@@ -1,3 +0,0 @@
|
||||
URL = http://ftp.gnu.org/gnu/lightning/lightning-2.1.2.tar.gz
|
||||
|
||||
include deps.mk
|
||||
135
_gi_c/gi.c
135
_gi_c/gi.c
@@ -1,135 +0,0 @@
|
||||
/* a go interpreter */
|
||||
|
||||
#define VERSION "gi-c-0.1"
|
||||
|
||||
static const char man_txt[] =
|
||||
"NAME\n"
|
||||
" gi - go interpreter\n"
|
||||
"SYNOPSIS\n"
|
||||
" gi [-acnsVx] [-A ast_file] [-C cfg_file] [--] [script_file [args ...]]\n"
|
||||
"DESCRIPTION\n"
|
||||
" gi is an interpreter that executes commands read from a file or the\n"
|
||||
" standard input.\n"
|
||||
"OPTIONS\n"
|
||||
" -A ast_file \n"
|
||||
" Write the abstract syntax tree in dot(1) format to ast_file or\n"
|
||||
" standard output if ast_file is -\n"
|
||||
" -a Display AST graph using dotty(1)\n"
|
||||
" -C cfg_file \n"
|
||||
" Write the control flow graph in dot(1) format to cfg_file or\n"
|
||||
" standard output if cfg_file is -\n"
|
||||
" -c Display CFG graph using dotty(1)\n"
|
||||
" -n Compile only, do not run\n"
|
||||
" -x Generate and execute machine code using a JIT compiler\n"
|
||||
" -v Trace each instruction during execution\n"
|
||||
" -V Print interpreter version and exit\n"
|
||||
"BIP LANGUAGE\n"
|
||||
" Commands are read in terms of lines of words separated by whitespaces\n"
|
||||
" (blanks or tabs) and certain sequences of characters called ``operators''.\n"
|
||||
" commands may also be separated by ';' or grouped between braces into a\n"
|
||||
" list\n"
|
||||
" OPERATORS\n"
|
||||
" Bip uses the usual infix notation for operators (example: c = a + b).\n"
|
||||
" Precedence rules identical to C are applied. Parenthesis are used to\n"
|
||||
" group expression and make precedence explicit.\n"
|
||||
" + - * / % \n"
|
||||
" Arithmetic: addition, substraction, multiplication, division\n"
|
||||
" and modulo.\n"
|
||||
" < <= > >= == != \n"
|
||||
" Comparison: lower, lower or equal, greater, greater or equal,\n"
|
||||
" equal, not equal.\n"
|
||||
" ! && || \n"
|
||||
" Logical: not, and, or.\n"
|
||||
" = Assignement.\n"
|
||||
" << >> & | \n"
|
||||
" Binary: left shift, right shift, boolean and, boolean or.\n"
|
||||
" FLOW CONTROL\n"
|
||||
" if cond list1 [else list0] \n"
|
||||
" the cond is executed and if it returns a non zero value, list1\n"
|
||||
" is executed. Otherwise, if defined, list0 is executed.\n"
|
||||
" while cond list \n"
|
||||
" cond and list are repeatedly executed while cond returns non zero.\n"
|
||||
"AUTHORS\n"
|
||||
" MV\n"
|
||||
;
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "init_go.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define MSIZE 4096
|
||||
|
||||
int source_stream(bip_t *ip, FILE *fd)
|
||||
{
|
||||
int len = 0, max = 0;
|
||||
char *src = NULL;
|
||||
|
||||
while (len == max) { /* Grow src buffer until everything is read */
|
||||
max += MSIZE;
|
||||
src = (char *)realloc(src, max);
|
||||
len += fread(src + len, 1, MSIZE, fd);
|
||||
}
|
||||
src[len] = 0;
|
||||
eval_str(ip, NULL, src, len);
|
||||
printf("%s", ip->out);
|
||||
ip->out[0] = 0;
|
||||
free(src);
|
||||
return len;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char *env[])
|
||||
{
|
||||
int opt;
|
||||
bip_t *ip = bip_init(0);
|
||||
FILE *fd;
|
||||
|
||||
while ((opt = getopt(argc, argv, "A:aC:chnpVvx")) != -1) {
|
||||
switch (opt) {
|
||||
case 'A':
|
||||
ip->fd_ast = strcmp(optarg, "-") ?
|
||||
fopen(optarg, "w") : stdout;
|
||||
break;
|
||||
case 'a':
|
||||
ip->opt.a = 1;
|
||||
break;
|
||||
case 'C':
|
||||
ip->fd_cfg = strcmp(optarg, "-") ?
|
||||
fopen(optarg, "w") : stdout;
|
||||
break;
|
||||
case 'c':
|
||||
ip->opt.c = 1;
|
||||
break;
|
||||
case 'h':
|
||||
printf("%s", man_txt);
|
||||
exit(0);
|
||||
case 'n':
|
||||
ip->opt.n = 1;
|
||||
break;
|
||||
case 'p':
|
||||
ip->opt.p = 1;
|
||||
break;
|
||||
case 'v':
|
||||
ip->opt.v = 1;
|
||||
break;
|
||||
case 'V':
|
||||
printf("%s\n", VERSION);
|
||||
exit(0);
|
||||
case 'x':
|
||||
ip->opt.x = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Usage: b1 [-acnVvx] [-A astname] "
|
||||
"[-C fgname] [file]\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
fd = ((argc - optind) > 0) ? fopen(argv[optind], "r") : stdin;
|
||||
if (fd == NULL)
|
||||
return 1;
|
||||
while (source_stream(ip, fd));
|
||||
return 0;
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Generate a serial control flow graph from an abstract syntax tree
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "node.h"
|
||||
#include "trace.h"
|
||||
|
||||
static node_t *add_cond_branch(bip_t *ip, node_t *n)
|
||||
{
|
||||
node_t *node = (node_t *)calloc(1, sizeof(node_t));
|
||||
node->type = COND_BRANCH;
|
||||
node->num = ++ip->nc;
|
||||
node->pv = n->pv;
|
||||
node->sym = getsym(ip, "CB", 2);
|
||||
node->f = node->sym->f;
|
||||
return node;
|
||||
}
|
||||
|
||||
static void cfg_out(bip_t *ip, node_t *node, void *data)
|
||||
{
|
||||
int i;
|
||||
node_t *n;
|
||||
|
||||
switch ((int)node->type) {
|
||||
case FUN: case OP: case OPS: case SL:
|
||||
for (i = 0; i < node->nchild; i++) {
|
||||
if (!is_leaf(node->child[i])) {
|
||||
node->start = node->child[i]->start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!node->start)
|
||||
node->start = node;
|
||||
for (i = 1; i < node->nchild; i++) {
|
||||
node->child[i-1]->snext = node->child[i]->start;
|
||||
}
|
||||
for (i = node->nchild - 1; i >= 0; i--) {
|
||||
if (!is_leaf(node->child[i])) {
|
||||
node->child[i]->snext = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IF:
|
||||
node->start = node->child[0]->start;
|
||||
node->child[1]->snext = node;
|
||||
if (node->nchild == 3) {
|
||||
node->child[2]->snext = node;
|
||||
}
|
||||
n = add_cond_branch(ip, node->child[0]);
|
||||
node->child[0]->snext = n;
|
||||
n->next[TRUE] = node->child[1]->start;
|
||||
if (node->nchild == 3) {
|
||||
n->next[FALSE] = node->child[2]->start;
|
||||
} else {
|
||||
n->next[FALSE] = node;
|
||||
}
|
||||
break;
|
||||
case WHILE:
|
||||
node->start = node->child[0]->start;
|
||||
node->child[1]->snext = node->start;
|
||||
n = add_cond_branch(ip, node->child[0]);
|
||||
node->child[0]->snext = n;
|
||||
n->next[TRUE] = node->child[1]->start;
|
||||
n->next[FALSE] = node;
|
||||
break;
|
||||
case FOR:
|
||||
node->start = node->child[0]->start;
|
||||
node->child[0]->snext = node->child[1]->start;
|
||||
n = add_cond_branch(ip, node->child[1]);
|
||||
node->child[1]->snext = n;
|
||||
n->next[TRUE] = node->child[3]->start;
|
||||
n->next[FALSE] = node;
|
||||
node->child[3]->snext = node->child[2]->start;
|
||||
node->child[2]->snext = node->child[1]->start;
|
||||
break;
|
||||
default:
|
||||
; //t_s(nodetype[node->type]);
|
||||
}
|
||||
}
|
||||
|
||||
void ast2cfg(bip_t *ip, node_t *node)
|
||||
{
|
||||
tree_walk(ip, node, NULL, cfg_out, NULL);
|
||||
addentry(ip, node->start);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef GRAPH_H
|
||||
#define GRAPH_H
|
||||
|
||||
#include "node.h"
|
||||
|
||||
void ast2cfg(bip_t *ip, node_t *node);
|
||||
|
||||
#endif /* GRAPH_H */
|
||||
102
_gi_c/hash.c
102
_gi_c/hash.c
@@ -1,102 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
hash_t *hinit(unsigned int n, cmpfun_t cmpf)
|
||||
{
|
||||
hash_t *h = (hash_t *)malloc(sizeof(hash_t));
|
||||
h->htab = (hitem_t **)calloc(n, sizeof(hitem_t *));
|
||||
h->cmpf = cmpf;
|
||||
h->len = n;
|
||||
h->nhash = 0;
|
||||
return h;
|
||||
}
|
||||
|
||||
static void hresize(hash_t *h, unsigned int n)
|
||||
{
|
||||
unsigned int i, j;
|
||||
hitem_t *p, *pp, **tab = (hitem_t **)calloc(n, sizeof(hitem_t *));
|
||||
|
||||
for (i = 0; i < h->len; i++) {
|
||||
p = h->htab[i];
|
||||
while (p) {
|
||||
pp = p->next;
|
||||
j = p->key % n;
|
||||
p->next = tab[j];
|
||||
tab[j] = p;
|
||||
p = pp;
|
||||
}
|
||||
}
|
||||
free(h->htab);
|
||||
h->htab = tab;
|
||||
h->len = n;
|
||||
}
|
||||
|
||||
unsigned int hkey(char *s)
|
||||
{
|
||||
unsigned int h = 0;
|
||||
while (*s)
|
||||
h = h * 31 + *s++;
|
||||
return h;
|
||||
}
|
||||
|
||||
unsigned int hnkey(const char *s, int n, unsigned int h)
|
||||
{
|
||||
while (n--)
|
||||
h = h * 31 + *s++;
|
||||
return h;
|
||||
}
|
||||
|
||||
void *hadd(hash_t *h, unsigned int key, void *index, void *data)
|
||||
{
|
||||
hitem_t *p;
|
||||
unsigned int i;
|
||||
|
||||
if (h->nhash >= h->len && h->len < HNITEM_MAX)
|
||||
hresize(h, h->len * 2);
|
||||
p = (hitem_t *)malloc(sizeof(hitem_t));
|
||||
i = key < h->len ? key : key % h->len;
|
||||
p->key = key;
|
||||
p->data = data;
|
||||
p->index = index;
|
||||
p->next = h->htab[i];
|
||||
h->htab[i] = p;
|
||||
h->nhash++;
|
||||
return data;
|
||||
}
|
||||
|
||||
void *hdel(hash_t *h, hitem_t *item)
|
||||
{
|
||||
unsigned int i = item->key % h->len;
|
||||
hitem_t *p = h->htab[i];
|
||||
void *data = item->data;
|
||||
|
||||
if (p == item) {
|
||||
h->htab[i] = p->next;
|
||||
goto del;
|
||||
}
|
||||
for (; p; p = p->next)
|
||||
if (p->next == item) {
|
||||
p->next = p->next->next;
|
||||
goto del;
|
||||
}
|
||||
return (void *)-1;
|
||||
del: h->nhash--;
|
||||
free(item);
|
||||
return data;
|
||||
}
|
||||
|
||||
void *hlookup(hash_t *h, unsigned int key, void *data, int len)
|
||||
{
|
||||
hitem_t *p;
|
||||
unsigned int i = key < h->len ? key : key % h->len;
|
||||
for (p = h->htab[i]; p; p = p->next) {
|
||||
if (p->key == key) {
|
||||
if (data && h->cmpf && (*h->cmpf)(data, p->data, len))
|
||||
continue; /* key collision */
|
||||
else
|
||||
return p->data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
37
_gi_c/hash.h
37
_gi_c/hash.h
@@ -1,37 +0,0 @@
|
||||
#ifndef HASH_H
|
||||
#define HASH_H
|
||||
|
||||
/* hash item */
|
||||
typedef struct hitem_t {
|
||||
struct hitem_t *next; /* next item in same slot */
|
||||
void *index; /* pointer to index data */
|
||||
void *data; /* pointer to value data */
|
||||
unsigned int key; /* hash key, obtained from index */
|
||||
} hitem_t;
|
||||
|
||||
/* key hash comparison function type */
|
||||
typedef int (*cmpfun_t)(void *, void *, int);
|
||||
|
||||
/* dynamically resizable array / hash table */
|
||||
typedef struct hash_t {
|
||||
hitem_t **htab; /* hash slots */
|
||||
cmpfun_t cmpf; /* user provided key comparison function */
|
||||
unsigned int len; /* tab size */
|
||||
unsigned int nhash; /* number of hashed items */
|
||||
} hash_t;
|
||||
|
||||
/* hash table iterator */
|
||||
#define hforeach(h, i, c) \
|
||||
for (c = 0; (unsigned int)c < (h)->len; c++) \
|
||||
for (i = (h)->htab[c]; i; i = i->next)
|
||||
|
||||
#define HNITEM_MAX ((unsigned)(1 << (8 * sizeof(int) -1))) /* 2^31 on 32 bit */
|
||||
|
||||
hash_t *hinit(unsigned int n, cmpfun_t cmpf);
|
||||
unsigned int hkey(char *s);
|
||||
unsigned int hnkey(const char *s, int n, unsigned int h);
|
||||
void *hadd(hash_t *h, unsigned int key, void *index, void *data);
|
||||
void *hdel(hash_t *h, hitem_t *item);
|
||||
void *hlookup(hash_t *h, unsigned int key, void *data, int len);
|
||||
|
||||
#endif /* HASH_H */
|
||||
133
_gi_c/init_go.c
133
_gi_c/init_go.c
@@ -1,133 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "graph.h"
|
||||
#include "node.h"
|
||||
#include "parse_go.h"
|
||||
#include "run_cfg.h"
|
||||
#include "run_jit.h"
|
||||
#include "scan.h"
|
||||
|
||||
#define X4_scan_bad scan_bad, scan_bad, scan_bad, scan_bad
|
||||
#define X16_scan_bad X4_scan_bad, X4_scan_bad, X4_scan_bad, X4_scan_bad
|
||||
#define X64_scan_bad X16_scan_bad, X16_scan_bad, X16_scan_bad, X16_scan_bad
|
||||
|
||||
/* BIP language lexical table */
|
||||
|
||||
static const scan_fun_t scanfun[256] = {
|
||||
scan_bad, scan_bad, scan_bad, scan_bad, scan_bad, // NUL SOH STX ETX EOT
|
||||
scan_bad, scan_bad, scan_bad, scan_bad, scan_wsep, // ENQ ACQ BELL BS HT
|
||||
scan_csep, scan_bad, scan_bad, scan_csep, scan_bad, // LF VT FF CR SO
|
||||
scan_bad, scan_bad, scan_bad, scan_bad, scan_bad, // SI DLE DC1 DC2 DC3
|
||||
scan_bad, scan_bad, scan_bad, scan_bad, scan_bad, // DC4 NAK SYN ETB CAN
|
||||
scan_bad, scan_bad, scan_bad, scan_bad, scan_bad, // EM SUB ESC FS GS
|
||||
scan_bad, scan_bad, scan_wsep, scan_go_op, scan_str, // RS US ' ' ! "
|
||||
scan_cmt, scan_go_op, scan_go_op, scan_go_op, scan_go_op, // # $ % & '
|
||||
scan_paren, scan_bad, scan_go_op, scan_go_op, scan_lsep, // ( ) * + ,
|
||||
scan_go_op, scan_go_op, scan_go_op, scan_num, scan_num, // - . / 0 1
|
||||
scan_num, scan_num, scan_num, scan_num, scan_num, // 2 3 4 5 6
|
||||
scan_num, scan_num, scan_num, scan_go_op, scan_csep, // 7 8 9 : ;
|
||||
scan_go_op, scan_go_op, scan_go_op, scan_go_op, scan_go_op, // < = > ? @
|
||||
scan_id, scan_id, scan_id, scan_id, scan_id, // A B C D E
|
||||
scan_id, scan_id, scan_id, scan_id, scan_id, // F G H I J
|
||||
scan_id, scan_id, scan_id, scan_id, scan_id, // K L M N O
|
||||
scan_id, scan_id, scan_id, scan_id, scan_id, // P Q R S T
|
||||
scan_id, scan_id, scan_id, scan_id, scan_id, // U V W X Y
|
||||
scan_id, scan_bracket, scan_bad, scan_bad, scan_go_op, // Z [ \ ] ^
|
||||
scan_id, scan_go_op, scan_id, scan_id, scan_id, // _ ` a b c
|
||||
scan_id, scan_id, scan_id, scan_id, scan_id, // d e f g h
|
||||
scan_id, scan_id, scan_id, scan_id, scan_id, // i j k l m
|
||||
scan_id, scan_id, scan_id, scan_id, scan_id, // n o p q r
|
||||
scan_id, scan_id, scan_id, scan_id, scan_id, // s t u v w
|
||||
scan_id, scan_id, scan_id, scan_brace, scan_go_op, // x y z { |
|
||||
scan_bad, scan_go_op, scan_bad, // } ~ DEL
|
||||
X64_scan_bad, X64_scan_bad // Non ASCII
|
||||
};
|
||||
|
||||
static int cmpsym(void *data, void *sym, int n)
|
||||
{
|
||||
return strncmp((char *)data, ((sym_t *)sym)->name, n);
|
||||
}
|
||||
|
||||
bip_t *bip_init(int trace_opt)
|
||||
{
|
||||
bip_t *ip = (bip_t *)calloc(1, sizeof(*ip));
|
||||
|
||||
ip->scanfun = (scan_fun_t *)scanfun;
|
||||
ip->gsym = hinit(64, cmpsym);
|
||||
ip->lsym = hinit(16, cmpsym);
|
||||
newsym(ip->gsym, "if", IF, 0, nop, j_nop);
|
||||
newsym(ip->gsym, "break", BREAK, 0, NULL, j_nop);
|
||||
newsym(ip->gsym, "continue", CONTINUE, 0, NULL, j_nop);
|
||||
newsym(ip->gsym, "for", FOR, 0, nop, j_nop);
|
||||
newsym(ip->gsym, "func", DEF, 0, NULL, j_nop);
|
||||
newsym(ip->gsym, "return", RETURN, 0, NULL, j_nop);
|
||||
newsym(ip->gsym, "local", LOCAL, 0, NULL, j_nop);
|
||||
newsym(ip->gsym, "eval", FUN, 0, NULL, j_nop);
|
||||
newsym(ip->gsym, "print", FUN, 0, NULL, j_nop);
|
||||
newsym(ip->gsym, "println", FUN, 0, echo, j_echo);
|
||||
newsym(ip->gsym, "source", FUN, 0, NULL, j_nop);
|
||||
newsym(ip->gsym, "dsym", FUN, 0, NULL, j_nop);
|
||||
newsym(ip->gsym, "map", FUN, 0, NULL, j_nop);
|
||||
newsym(ip->gsym, "nop", OP, 0, nop, j_nop);
|
||||
newsym(ip->gsym, "SL", SL, 0, nop, j_nop);
|
||||
newsym(ip->gsym, "CB", COND_BRANCH, 0, cond_branch, j_nop);
|
||||
newsym(ip->gsym, "package", NAMESPACE, 0, nop, j_nop);
|
||||
newsym(ip->gsym, "++", OPS, 0, inc, j_inc);
|
||||
newsym(ip->gsym, "--", OPS, 0, NULL, j_nop);
|
||||
newsym(ip->gsym, "!", OP, 10, NULL, j_not);
|
||||
newsym(ip->gsym, "+", OP, 8, add, j_add);
|
||||
newsym(ip->gsym, "-", OP, 8, sub, j_sub);
|
||||
newsym(ip->gsym, "~", OP, 10, NULL, j_nop);
|
||||
newsym(ip->gsym, "^", OP, 10, NULL, j_xor);
|
||||
newsym(ip->gsym, "*", OP, 9, mul, j_mul);
|
||||
newsym(ip->gsym, "/", OP, 9, fdiv, j_div);
|
||||
newsym(ip->gsym, "%", OP, 9, mod, j_rem);
|
||||
newsym(ip->gsym, "<", OP, 6, lt, j_lt);
|
||||
newsym(ip->gsym, "<=", OP, 6, le, j_le);
|
||||
newsym(ip->gsym, ">=", OP, 6, ge, j_ge);
|
||||
newsym(ip->gsym, ">", OP, 6, gt, j_gt);
|
||||
newsym(ip->gsym, "==", OP, 5, eq, j_eq);
|
||||
newsym(ip->gsym, "!=", OP, 5, neq, j_ne);
|
||||
newsym(ip->gsym, ":=", OP, 0, assign, j_assign);
|
||||
newsym(ip->gsym, "=", OP, 0, assign, j_assign);
|
||||
newsym(ip->gsym, "&&", OP, 2, NULL, j_land);
|
||||
newsym(ip->gsym, "||", OP, 1, NULL, j_lor);
|
||||
newsym(ip->gsym, "&", OP, 4, band, j_and);
|
||||
newsym(ip->gsym, "|", OP, 3, bor, j_or);
|
||||
newsym(ip->gsym, "<<", OP, 7, lshift, j_lsh);
|
||||
newsym(ip->gsym, ">>", OP, 7, rshift, j_rsh);
|
||||
ip->out = (char *)calloc(1, 1024);
|
||||
ip->opt.x = trace_opt;
|
||||
return ip;
|
||||
}
|
||||
|
||||
node_t *eval_str(bip_t *ip, node_t *node, char *s, int len)
|
||||
{
|
||||
node_t *n = parse_sl(ip, &s, &len);
|
||||
|
||||
if (n->nchild == 0)
|
||||
return node;
|
||||
if (ip->fd_ast)
|
||||
print_tree(ip, ip->fd_ast, n);
|
||||
if (ip->opt.a)
|
||||
dotty(ip, n, print_tree);
|
||||
n = n->child[1]->child[2];
|
||||
ast2cfg(ip, n);
|
||||
if (ip->fd_cfg)
|
||||
print_flow(ip, ip->fd_cfg, n);
|
||||
if (ip->opt.c)
|
||||
dotty(ip, n, print_flow);
|
||||
if (ip->opt.x)
|
||||
run_jit(ip, n);
|
||||
else if (!ip->opt.n) {
|
||||
run_cfg(ip);
|
||||
}
|
||||
return node ? node : n;
|
||||
}
|
||||
|
||||
void bip_eval(bip_t *ip, char *s, char **res)
|
||||
{
|
||||
eval_str(ip, NULL, s, strlen(s));
|
||||
*res = ip->out;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#ifndef INIT_H
|
||||
#define INIT_H
|
||||
|
||||
#include "node.h"
|
||||
|
||||
bip_t *bip_init(int trace_opt);
|
||||
node_t *eval_str(bip_t *ip, node_t *node, char *s, int len);
|
||||
|
||||
#endif /* INIT_H */
|
||||
@@ -1,9 +0,0 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
for a := 0; a < 20000; a++ {
|
||||
if (a & 0x8ff) == 0x800 {
|
||||
println(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
for a := 0; a < 20000000; a++ {
|
||||
if (a & 0x8ffff) == 0x80000 {
|
||||
println(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
for a := 0; a < 2000000000; a++ {
|
||||
if (a & 0x8ffff) == 0x80000 {
|
||||
println(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
247
_gi_c/node.c
247
_gi_c/node.c
@@ -1,247 +0,0 @@
|
||||
/* generic node utility functions */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "node.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* Maintain the following in consistency with enum nodetype_t */
|
||||
const char *nodetype[NODETYPE_LEN] = {
|
||||
"UNDEF", "SL", "IF", "WHILE", "BREAK", "CONTINUE", "DEF", "FOR",
|
||||
"RETURN", "LOCAL", "MAP", "OPS", "OP", "TERM", "VAR", "FUN",
|
||||
"LVAR", "ARRAY", "COND_BRANCH", "NAMESPACE"
|
||||
};
|
||||
|
||||
/* Recursive implementation of tree walk, depth first */
|
||||
void tree_walk(bip_t *ip, node_t *node, tw_fun_t in, tw_fun_t out, void *data)
|
||||
{
|
||||
int i;
|
||||
if (in)
|
||||
in(ip, node, data);
|
||||
for (i = 0; node && i < node->nchild; i++)
|
||||
tree_walk(ip, node->child[i], in, out, data);
|
||||
if (out)
|
||||
out(ip, node, data);
|
||||
}
|
||||
|
||||
/* Non recursive tree walk */
|
||||
void new_tree_walk(bip_t *ip, node_t *node, tw_fun_t in, tw_fun_t out, void *data)
|
||||
{
|
||||
ip->cur = node;
|
||||
if (in)
|
||||
in(ip, ip->cur, NULL);
|
||||
while (1) {
|
||||
++ip->cur->visits;
|
||||
if (ip->cur->nchild > 0 && ip->cur->visits <= ip->cur->nchild) {
|
||||
ip->cur = ip->cur->child[ip->cur->visits - 1];
|
||||
if (in)
|
||||
in(ip, ip->cur, NULL);
|
||||
} else {
|
||||
ip->cur->visits = 0;
|
||||
if (out)
|
||||
out(ip, ip->cur, NULL);
|
||||
if (ip->cur == node)
|
||||
break;
|
||||
else
|
||||
ip->cur = ip->cur->anc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* append child node to the list of anc children node */
|
||||
void appchild(node_t *anc, node_t *child)
|
||||
{
|
||||
if (child == NULL) {
|
||||
//t_s("nil child");
|
||||
return;
|
||||
}
|
||||
anc->child = (node_t **)realloc(anc->child,
|
||||
++anc->nchild * sizeof(node_t *));
|
||||
anc->child[anc->nchild - 1] = child;
|
||||
child->anc = anc;
|
||||
}
|
||||
|
||||
/* insert child node at first position in anc children list */
|
||||
void inschild(node_t *anc, node_t *child)
|
||||
{
|
||||
node_t **ochild = anc->child;
|
||||
int onchild = anc->nchild, i;
|
||||
|
||||
anc->nchild = 0;
|
||||
anc->child = NULL;
|
||||
appchild(anc, child);
|
||||
for (i = 0; i < onchild; i++)
|
||||
appchild(anc, ochild[i]);
|
||||
free(ochild);
|
||||
}
|
||||
|
||||
void delchild(node_t *anc, node_t *child)
|
||||
{
|
||||
node_t **ochild = anc->child;
|
||||
int onchild = anc->nchild, i;
|
||||
|
||||
anc->nchild = 0;
|
||||
anc->child = NULL;
|
||||
for (i = 0; i < onchild; i++)
|
||||
if (ochild[i] != child)
|
||||
appchild(anc, ochild[i]);
|
||||
free(ochild);
|
||||
}
|
||||
|
||||
void print_val(FILE *fd, val_t *pv, int quote)
|
||||
{
|
||||
switch ((int)pv->type) {
|
||||
case VINT:
|
||||
fprintf(fd, "%ld", pv->u.num);
|
||||
break;
|
||||
case VFLOAT:
|
||||
fprintf(fd, "%g", pv->u.fnum);
|
||||
break;
|
||||
case VSTR:
|
||||
if (quote == 0)
|
||||
fprintf(fd, "\\\"%s\\\"", pv->u.str);
|
||||
else if (quote == 2)
|
||||
fprintf(fd, "\"%s\"", pv->u.str);
|
||||
else
|
||||
fprintf(fd, "%s", pv->u.str);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void print_node_label(FILE *fd, node_t *node, int flow)
|
||||
{
|
||||
switch ((int)node->type) {
|
||||
case TERM:
|
||||
fprintf(fd, " %d: ", node->num);
|
||||
//fprintf(fd, " ");
|
||||
print_val(fd, node->pv, flow);
|
||||
break;
|
||||
case SL:
|
||||
fprintf(fd, " %d: %s", node->num, nodetype[node->type]);
|
||||
//fprintf(fd, " %s", nodetype[node->type]);
|
||||
break;
|
||||
case VAR:
|
||||
fprintf(fd, " %d: %s", node->num, node->sym->name);
|
||||
//fprintf(fd, " %s", node->sym->name);
|
||||
break;
|
||||
default:
|
||||
if (flow)
|
||||
fprintf(fd, " $%d:", node->num);
|
||||
//fprintf(fd, " ");
|
||||
else
|
||||
if (node->sym)
|
||||
fprintf(fd, " %d: %s", node->num, node->sym->name);
|
||||
//fprintf(fd, " %s", node->sym->name);
|
||||
else
|
||||
fprintf(fd, " %d: undefined", node->num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void pnode(bip_t *ip, node_t *node, void *data)
|
||||
{
|
||||
FILE *fd = (FILE *)data;
|
||||
fprintf(fd, "%d [type=\"%s\", label=\"", node->num,
|
||||
nodetype[node->type]);
|
||||
print_node_label(fd, node, 0);
|
||||
fprintf(fd, "\"]\n");
|
||||
if (node->anc)
|
||||
fprintf(fd, "%d -> %d\n", node->anc->num, node->num);
|
||||
}
|
||||
|
||||
void print_tree(bip_t *ip, FILE *fd, node_t *node)
|
||||
{
|
||||
fprintf(fd, "digraph ast {\n");
|
||||
tree_walk(ip, node, pnode, NULL, fd);
|
||||
fprintf(fd, "}\n");
|
||||
}
|
||||
|
||||
static void pflow(bip_t *ip, node_t *node, void *data)
|
||||
{
|
||||
int i, start = 0;
|
||||
FILE *fd = (FILE *)data;
|
||||
|
||||
if (node == NULL || node->type == TERM || node->type == VAR ||
|
||||
node->type == BREAK || node->type == CONTINUE)
|
||||
return;
|
||||
fprintf(fd, "%d [label=\"%d:", node->num, node->num);
|
||||
if (node->type == OP) {
|
||||
print_node_label(fd, node->child[0], 1);
|
||||
start = 1;
|
||||
}
|
||||
print_node_label(fd, node, 0);
|
||||
for (i = start; i < node->nchild; i++)
|
||||
print_node_label(fd, node->child[i], 1);
|
||||
fprintf(fd, "\"]\n");
|
||||
if (!node->snext)
|
||||
return;
|
||||
|
||||
if (node->snext->next[TRUE]) {
|
||||
fprintf(fd, "%d -> %d [color=green]\n", node->num,
|
||||
node->snext->next[TRUE]->num);
|
||||
}
|
||||
if (node->snext->next[FALSE]) {
|
||||
fprintf(fd, "%d -> %d [color=red]\n", node->num,
|
||||
node->snext->next[FALSE]->num);
|
||||
}
|
||||
if (!node->snext->next[TRUE] && !node->snext->next[FALSE]) {
|
||||
fprintf(fd, "%d -> %d\n", node->num, node->snext->num);
|
||||
}
|
||||
}
|
||||
|
||||
void print_flow(bip_t *ip, FILE *fd, node_t *node)
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf(fd, "digraph cfg {\n");
|
||||
tree_walk(ip, node, NULL, pflow, fd);
|
||||
for (i = 0; i < ip->nentry_points; i++)
|
||||
fprintf(fd, "%d [color=red]", ip->entry_points[i]->num);
|
||||
fprintf(fd, "}\n");
|
||||
}
|
||||
|
||||
void dotty(bip_t *ip, node_t *node, dotty_fun_t dotty_fun)
|
||||
{
|
||||
FILE *fd = popen("dotty -", "w");
|
||||
if (fd == NULL) {
|
||||
perror("dotty");
|
||||
return;
|
||||
}
|
||||
dotty_fun(ip, fd, node);
|
||||
fflush(fd);
|
||||
//getchar();
|
||||
}
|
||||
|
||||
/* Add a new entry (start of thread) for parallel execution */
|
||||
void addentry(bip_t *ip, node_t *node)
|
||||
{
|
||||
ip->entry = (node_t **)realloc(ip->entry, ++ip->nentry * sizeof(node));
|
||||
ip->entry[ip->nentry - 1] = node;
|
||||
}
|
||||
|
||||
/* Add node at end of list, increase list_len */
|
||||
void appnode(node_t ***list, node_t *node, int *list_len)
|
||||
{
|
||||
*list = (node_t **)realloc(*list, ++(*list_len) * sizeof(node));
|
||||
(*list)[*list_len - 1] = node;
|
||||
}
|
||||
|
||||
sym_t *newsym(hash_t *h, const char *s, nodetype_t type, int prio, fun_t ifun,
|
||||
fun_t cfun)
|
||||
{
|
||||
sym_t *sym = (sym_t *)calloc(1, sizeof(*sym));
|
||||
sym->name = (char *)s;
|
||||
sym->type = type;
|
||||
sym->prio = prio;
|
||||
sym->f = ifun;
|
||||
sym->jf = cfun;
|
||||
return (sym_t *)hadd(h, hkey(sym->name), sym->name, sym);
|
||||
}
|
||||
|
||||
sym_t *getsym(bip_t *ip, const char *s, int len)
|
||||
{
|
||||
unsigned int key = hnkey(s, len, 0);
|
||||
return (sym_t *)hlookup(ip->gsym, key, (void *)s, len);
|
||||
}
|
||||
140
_gi_c/node.h
140
_gi_c/node.h
@@ -1,140 +0,0 @@
|
||||
#ifndef NODE_H
|
||||
#define NODE_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "hash.h"
|
||||
#include "scan.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define UP 0
|
||||
#define DOWN 1
|
||||
#define RD 0
|
||||
#define WR 1
|
||||
|
||||
// types which could be part of expressions must be defined after OP
|
||||
typedef enum nodetype_t {
|
||||
UNDEF, SL, IF, WHILE, BREAK, CONTINUE, DEF, FOR, RETURN, LOCAL, MAP, OPS,
|
||||
OP, TERM, VAR, FUN, LVAR, ARRAY, COND_BRANCH, NAMESPACE,
|
||||
NODETYPE_LEN
|
||||
} nodetype_t;
|
||||
|
||||
// String version of above, for debug
|
||||
extern const char *nodetype[NODETYPE_LEN];
|
||||
|
||||
typedef enum valtype_t {
|
||||
VINT, VSTR, VFUN, VTAB, VPTR, VFLOAT, VSYM, VVAR, VPINT, VPFLOAT,
|
||||
VVOID, VSHORT, VQUAD, VBIN
|
||||
} valtype_t;
|
||||
|
||||
typedef struct bip_t bip_t;
|
||||
typedef struct node_t node_t;
|
||||
typedef void (*fun_t)(node_t *n);
|
||||
typedef struct jit_node jit_node_t; /* from lightning.h */
|
||||
|
||||
typedef struct val_t {
|
||||
int len;
|
||||
valtype_t type; /* type of following field */
|
||||
union {
|
||||
long num; /* integer value */
|
||||
double fnum; /* floating point value */
|
||||
char *str; /* string value */
|
||||
void *data; /* user data value */
|
||||
// unsigned char *bin; /* binary data */
|
||||
// struct sym_t *sym; /* symbol value */
|
||||
// fun_t fun; /* function value */
|
||||
} u;
|
||||
} val_t;
|
||||
|
||||
typedef struct sym_t {
|
||||
char *name; /* symbol unique name */
|
||||
nodetype_t type; /* symbol type */
|
||||
int prio; /* operator priority */
|
||||
node_t *assign; /* node which sets this symbol */
|
||||
val_t v; /* data value */
|
||||
fun_t f; /* function to run during execution */
|
||||
fun_t jf; /* jit compiler callback */
|
||||
node_t **access[2];
|
||||
int naccess[2];
|
||||
int reg; /* jit register number */
|
||||
} sym_t;
|
||||
|
||||
struct node_t {
|
||||
node_t *anc; /* unique ancestor */
|
||||
node_t **child; /* array of children */
|
||||
sym_t *sym; /* symbol (variable, function, op) */
|
||||
nodetype_t type;
|
||||
int num; /* unique serial number */
|
||||
int nchild; /* number of children */
|
||||
int prio; /* operator precedence (from sym) */
|
||||
val_t v; /* value during execution */
|
||||
val_t *pv; /* pointer on above or sym value */
|
||||
fun_t f; /* function to run during execution */
|
||||
int visits; /* Number of node visits for non rec tree_walk */
|
||||
|
||||
node_t *start; /* entry point in subtree (CFG) */
|
||||
node_t *snext; /* next node to eval (CFG) */
|
||||
node_t *next[2]; /* false and true branches in CFG */
|
||||
|
||||
jit_node_t *label; /* label to jump to (JIT) */
|
||||
int reg; /* register number (JIT) */
|
||||
};
|
||||
|
||||
/* Interpreter state, used during compilation and execution */
|
||||
struct bip_t {
|
||||
scan_fun_t *scanfun; /* lexical scanner table of functions */
|
||||
hash_t *gsym; /* parse: global hashed symbol table */
|
||||
hash_t *lsym; /* parse: local hashed symbol table */
|
||||
node_t *root;
|
||||
node_t *cur;
|
||||
node_t *prev;
|
||||
node_t **entry; /* run: array of entry points */
|
||||
int nentry; /* number of entry points (threads) */
|
||||
int nc; /* node counter */
|
||||
int last_direction;
|
||||
node_t *fork_node; /* To replace jump stack */
|
||||
node_t *ctx_node; /* context ID */
|
||||
node_t **entry_points;
|
||||
int nentry_points;
|
||||
node_t *global_fork_node;
|
||||
struct {
|
||||
unsigned int a : 1; /* AST option */
|
||||
unsigned int c : 1; /* CFG option */
|
||||
unsigned int n : 1; /* no-run option */
|
||||
unsigned int p : 1; /* parallel option */
|
||||
unsigned int v : 1; /* trace option */
|
||||
unsigned int x : 1; /* native exec option */
|
||||
} opt;
|
||||
FILE *fd_ast; /* file to write AST */
|
||||
FILE *fd_cfg; /* file to write CFG */
|
||||
char *out;
|
||||
int outlen;
|
||||
pthread_mutex_t outm;
|
||||
};
|
||||
|
||||
#define is_leaf(node) ((node)->type == TERM || (node)->type == VAR)
|
||||
|
||||
typedef void (*tw_fun_t)(bip_t *, node_t *, void *data);
|
||||
typedef void (*dotty_fun_t)(bip_t *ip, FILE *fd, node_t *node);
|
||||
|
||||
void tree_walk(bip_t *ip, node_t *node, tw_fun_t in, tw_fun_t out, void *data);
|
||||
void new_tree_walk(bip_t *ip, node_t *node, tw_fun_t in, tw_fun_t out, void *data);
|
||||
void appchild(node_t *anc, node_t *child);
|
||||
void inschild(node_t *anc, node_t *child);
|
||||
void delchild(node_t *anc, node_t *child);
|
||||
void print_val(FILE *fd, val_t *pv, int quote);
|
||||
void print_node_label(FILE *fd, node_t *node, int flow);
|
||||
void print_tree(bip_t *ip, FILE *fd, node_t *node);
|
||||
void print_flow(bip_t *ip, FILE *fd, node_t *node);
|
||||
void dotty(bip_t *ip, node_t *node, dotty_fun_t dotty_fun);
|
||||
void addentry(bip_t *ip, node_t *node);
|
||||
void appnode(node_t ***list, node_t *node, int *list_len);
|
||||
sym_t *newsym(hash_t *h, const char *s, nodetype_t type, int prio, fun_t ifun, fun_t cfun);
|
||||
sym_t *getsym(bip_t *ip, const char *s, int len);
|
||||
|
||||
#endif /* NODE_H */
|
||||
278
_gi_c/parse_go.c
278
_gi_c/parse_go.c
@@ -1,278 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "node.h"
|
||||
#include "scan.h"
|
||||
#include "run_cfg.h"
|
||||
#include "trace.h"
|
||||
|
||||
static node_t *parse_1(bip_t *ip, char **pstr, int *plen);
|
||||
static node_t *parse_statement(bip_t *ip, char **pstr, int *plen);
|
||||
node_t *parse_sl(bip_t *ip, char **pstr, int *plen);
|
||||
|
||||
static char *strdupn(char *str, int len)
|
||||
{
|
||||
char *s = (char *)malloc(len + 1);
|
||||
strncpy(s, str, len);
|
||||
s[len] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
static node_t *parse_int(bip_t *ip, scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
node_t *node = (node_t *)calloc(1, sizeof(node_t));
|
||||
node->type = TERM;
|
||||
node->num = ++ip->nc;
|
||||
node->pv = &node->v;
|
||||
node->pv->type = VINT;
|
||||
node->pv->u.num = ps->num;
|
||||
return node;
|
||||
}
|
||||
|
||||
static node_t *parse_float(bip_t *ip, scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
node_t *node = (node_t *)calloc(1, sizeof(node_t));
|
||||
node->type = TERM;
|
||||
node->num = ++ip->nc;
|
||||
node->pv = &node->v;
|
||||
node->pv->type = VFLOAT;
|
||||
node->pv->u.fnum = ps->fnum;
|
||||
return node;
|
||||
}
|
||||
|
||||
static node_t *parse_str(bip_t *ip, scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
node_t *node = (node_t *)calloc(1, sizeof(node_t));
|
||||
node->type = TERM;
|
||||
node->num = ++ip->nc;
|
||||
node->pv = &node->v;
|
||||
node->pv->type = VSTR;
|
||||
node->pv->len = ps->len;
|
||||
node->pv->u.str = strdupn(ps->tok, ps->len);
|
||||
return node;
|
||||
}
|
||||
|
||||
static node_t *parse_parenthesis(bip_t *ip, scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
node_t *node = (node_t *)calloc(1, sizeof(node_t));
|
||||
node->num = ++ip->nc;
|
||||
node->type = SL;
|
||||
node->pv = &node->v;
|
||||
appchild(node, parse_statement(ip, &ps->tok, &ps->len));
|
||||
return node;
|
||||
}
|
||||
|
||||
static node_t *parse_paren(bip_t *ip, scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
node_t *node = parse_statement(ip, &ps->tok, &ps->len);
|
||||
node->prio = 20; // override precedence
|
||||
return node;
|
||||
}
|
||||
|
||||
static node_t *parse_bracket(bip_t *ip, scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
node_t *node = (node_t *)calloc(1, sizeof(node_t));
|
||||
node->num = ++ip->nc;
|
||||
node->type = ARRAY;
|
||||
appchild(node, parse_statement(ip, &ps->tok, &ps->len));
|
||||
return node;
|
||||
}
|
||||
|
||||
static node_t *parse_oper(bip_t *ip, scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
node_t *node = (node_t *)calloc(1, sizeof(node_t));
|
||||
node->num = ++ip->nc;
|
||||
node->pv = &node->v;
|
||||
if ((node->sym = getsym(ip, ps->tok, ps->len))) {
|
||||
node->type = node->sym->type;
|
||||
node->f = node->sym->f;
|
||||
}
|
||||
if (node->type != OPS)
|
||||
appchild(node, parse_1(ip, pstr, plen));
|
||||
return node;
|
||||
}
|
||||
|
||||
static node_t *parse_id(bip_t *ip, scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
node_t *node = (node_t *)calloc(1, sizeof(node_t)), *n;
|
||||
scan_t sc;
|
||||
char *s;
|
||||
int l;
|
||||
|
||||
node->num = ++ip->nc;
|
||||
if ((node->sym = getsym(ip, ps->tok, ps->len))) {
|
||||
node->type = node->sym->type;
|
||||
} else {
|
||||
node->type = VAR;
|
||||
node->sym = newsym(ip->gsym, strdupn(ps->tok, ps->len),
|
||||
VAR, 0, nop, NULL);
|
||||
}
|
||||
node->f = node->sym->f;
|
||||
switch ((int)node->sym->type) {
|
||||
case NAMESPACE:
|
||||
appchild(node, parse_1(ip, pstr, plen));
|
||||
break;
|
||||
case DEF:
|
||||
// FIXME: handle all variants of DEF
|
||||
// function name
|
||||
appchild(node, parse_1(ip, pstr, plen));
|
||||
|
||||
|
||||
// function args
|
||||
l = *plen;
|
||||
s = *pstr;
|
||||
scan(ip->scanfun, &sc, &s, &l);
|
||||
appchild(node, parse_parenthesis(ip, &sc, pstr, plen));
|
||||
*pstr = s;
|
||||
*plen = l;
|
||||
|
||||
// function body
|
||||
appchild(node, parse_1(ip, pstr, plen));
|
||||
break;
|
||||
case FOR:
|
||||
// FIXME: handle all variants of FOR
|
||||
appchild(node, parse_statement(ip, pstr, plen));
|
||||
appchild(node, parse_statement(ip, pstr, plen));
|
||||
appchild(node, parse_statement(ip, pstr, plen));
|
||||
appchild(node, parse_statement(ip, pstr, plen));
|
||||
break;
|
||||
case IF:
|
||||
appchild(node, parse_statement(ip, pstr, plen));
|
||||
appchild(node, parse_statement(ip, pstr, plen));
|
||||
s = *pstr;
|
||||
l = *plen;
|
||||
scan(ip->scanfun, &sc, &s, &l);
|
||||
if (sc.type == ID && sc.len == 4 &&
|
||||
strncmp(sc.tok, "else", 4) == 0) {
|
||||
*pstr = s;
|
||||
*plen = l;
|
||||
appchild(node, parse_statement(ip, pstr, plen));
|
||||
}
|
||||
break;
|
||||
case OP:
|
||||
appchild(node, parse_1(ip, pstr, plen));
|
||||
break;
|
||||
case RETURN:
|
||||
appchild(node, parse_statement(ip, pstr, plen));
|
||||
break;
|
||||
case FUN:
|
||||
node->pv = &node->v;
|
||||
while ((n = parse_1(ip, pstr, plen)))
|
||||
appchild(node, n);
|
||||
break;
|
||||
case VAR:
|
||||
node->pv = &node->sym->v;
|
||||
s = *pstr;
|
||||
l = *plen;
|
||||
scan(ip->scanfun, &sc, &s, &l);
|
||||
if (sc.type == OPER) {
|
||||
sym_t *sym = getsym(ip, sc.tok, sc.len);
|
||||
if (sym && sym->type == OPS) {
|
||||
n = parse_1(ip, pstr, plen);
|
||||
appchild(n, node);
|
||||
node = n;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
t_s(nodetype[node->sym->type]);
|
||||
break;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static node_t *parse_brace(bip_t *ip, scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
return parse_sl(ip, &ps->tok, &ps->len);
|
||||
}
|
||||
|
||||
static node_t *parse_bad(bip_t *ip, scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef node_t *(*parse_fun_t) (bip_t *, scan_t *, char **, int *);
|
||||
|
||||
// Table indiced by scan_token_t
|
||||
static const parse_fun_t parse_fun[] = {
|
||||
parse_bad, parse_brace, parse_bracket, parse_bad, parse_bad,
|
||||
parse_float, parse_id, parse_int, parse_bad, parse_oper,
|
||||
parse_paren, parse_str,
|
||||
};
|
||||
|
||||
/* Return a single node, possibly a complex subtree. */
|
||||
static node_t *parse_1(bip_t *ip, char **pstr, int *plen)
|
||||
{
|
||||
scan_t sc;
|
||||
scan(ip->scanfun, &sc, pstr, plen);
|
||||
return parse_fun[sc.type](ip, &sc, pstr, plen);
|
||||
}
|
||||
|
||||
/* Return a statement node. Apply operator precedence rules (reordering nodes). */
|
||||
static node_t *parse_statement(bip_t *ip, char **pstr, int *plen)
|
||||
{
|
||||
scan_t sc = {};
|
||||
char *s = *pstr;
|
||||
int len = *plen;
|
||||
node_t *first = NULL, *node = NULL, *n, *n1;
|
||||
|
||||
start:
|
||||
while (len > 0 && scan(ip->scanfun, &sc, &s, &len) != CSEP) {
|
||||
if (first && sc.type == BRACE) {
|
||||
unscan(&sc, &s, &len);
|
||||
break;
|
||||
}
|
||||
node = parse_fun[sc.type](ip, &sc, &s, &len);
|
||||
if (!first) {
|
||||
first = node;
|
||||
} else if (node->type == OP) {
|
||||
node->prio = node->sym->prio;
|
||||
for (n = first; n; n = n->nchild > 1 ? n->child[1] : NULL) {
|
||||
if (n->type != OP || node->prio <= n->prio
|
||||
|| (n->type == OP && n->nchild == 1)) {
|
||||
if (n == first) {
|
||||
first = node;
|
||||
} else {
|
||||
n1 = n->anc;
|
||||
delchild(n1, n);
|
||||
appchild(n1, node);
|
||||
}
|
||||
inschild(node, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unscan(&sc, &s, &len);
|
||||
break;
|
||||
}
|
||||
// If node is a kind of statement not part of an expression, stop here
|
||||
if (node->type < OP)
|
||||
break;
|
||||
}
|
||||
if (!first) {
|
||||
// FIXME: handle parse error
|
||||
if (len > 0 && sc.type == CSEP) {
|
||||
(*pstr)++;
|
||||
(*plen)--;
|
||||
goto start;
|
||||
}
|
||||
//t_s(scan_token[sc.type]);
|
||||
}
|
||||
*pstr = s;
|
||||
*plen = len;
|
||||
return first;
|
||||
}
|
||||
|
||||
/* Return a statement list node */
|
||||
node_t *parse_sl(bip_t *ip, char **pstr, int *plen)
|
||||
{
|
||||
node_t *node = (node_t *)calloc(1, sizeof(node_t));
|
||||
node->type = SL;
|
||||
node->num = ++ip->nc;
|
||||
node->sym = getsym(ip, "SL", 2);
|
||||
node->f = node->sym->f;
|
||||
while (*plen > 0)
|
||||
appchild(node, parse_statement(ip, pstr, plen));
|
||||
return node;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef PARSE_GO_HH
|
||||
#define PARSE_GO_HH
|
||||
|
||||
#include "node.h"
|
||||
|
||||
node_t *parse_sl(bip_t *ip, char **pstr, int *plen);
|
||||
|
||||
#endif /* PARSE_GO_H */
|
||||
186
_gi_c/run_cfg.c
186
_gi_c/run_cfg.c
@@ -1,186 +0,0 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "node.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
void nop(node_t *n)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void assign(node_t *n)
|
||||
{
|
||||
*n->pv = *n->child[0]->pv = *n->child[1]->pv;
|
||||
}
|
||||
|
||||
void cond_branch(node_t *n)
|
||||
{
|
||||
n->snext = n->pv->u.num ? n->next[TRUE] : n->next[FALSE];
|
||||
}
|
||||
|
||||
void inc(node_t *n)
|
||||
{
|
||||
n->child[0]->pv->u.num++;
|
||||
}
|
||||
|
||||
void bprintf_val(val_t *pv)
|
||||
{
|
||||
switch((int)pv->type) {
|
||||
case VINT:
|
||||
printf("%ld", pv->u.num);
|
||||
break;
|
||||
case VFLOAT:
|
||||
printf("%g", pv->u.fnum);
|
||||
case VSTR:
|
||||
printf("%s", pv->u.str);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void bprint_val(bip_t *ip, val_t *pv, int quote)
|
||||
{
|
||||
char s[100];
|
||||
|
||||
switch ((int)pv->type) {
|
||||
case VINT:
|
||||
snprintf(s, sizeof(s), "%ld", pv->u.num);
|
||||
break;
|
||||
case VFLOAT:
|
||||
snprintf(s, sizeof(s), "%g", pv->u.fnum);
|
||||
break;
|
||||
case VSTR:
|
||||
snprintf(s, sizeof(s), "%s", pv->u.str);
|
||||
break;
|
||||
if (quote == 0)
|
||||
snprintf(s, sizeof(s), "\\\"%s\\\"", pv->u.str);
|
||||
else if (quote == 2)
|
||||
snprintf(s, sizeof(s), "\"%s\"", pv->u.str);
|
||||
else
|
||||
snprintf(s, sizeof(s), "%s", pv->u.str);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
strcat(ip->out, s);
|
||||
}
|
||||
|
||||
void bprint_node_label(bip_t *ip, node_t *node, int flow)
|
||||
{
|
||||
char s[100];
|
||||
|
||||
switch ((int)node->type) {
|
||||
case TERM:
|
||||
strcat(ip->out, " ");
|
||||
bprint_val(ip, node->pv, flow);
|
||||
break;
|
||||
case SL:
|
||||
snprintf(s, sizeof(s), " %s", nodetype[node->type]);
|
||||
strcat(ip->out, s);
|
||||
break;
|
||||
case VAR:
|
||||
snprintf(s, sizeof(s), " %s", node->sym->name);
|
||||
strcat(ip->out, s);
|
||||
break;
|
||||
default:
|
||||
if (flow)
|
||||
snprintf(s, sizeof(s), " $%d", node->num);
|
||||
else
|
||||
snprintf(s, sizeof(s), " %s", node->sym->name);
|
||||
strcat(ip->out, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void echo(node_t *n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n->nchild; i++)
|
||||
bprintf_val(n->child[i]->pv);
|
||||
printf("\n");
|
||||
//bprint_val(ip, n->child[i]->pv, 1);
|
||||
//strcat(ip->out, "\n");
|
||||
}
|
||||
|
||||
void trace(FILE *fd, bip_t *ip, node_t *node, int tid)
|
||||
{
|
||||
int i, start = 0;
|
||||
char s[100];
|
||||
|
||||
if (node->sym->f == nop || node->type == SL)
|
||||
return;
|
||||
snprintf(s, sizeof(s), "[%d] $%d:", tid, node->num);
|
||||
strcat(ip->out, s);
|
||||
if (node->type == OP) {
|
||||
bprint_node_label(ip, node->child[0], 2);
|
||||
start = 1;
|
||||
}
|
||||
bprint_node_label(ip, node, 0);
|
||||
for (i = start; i < node->nchild; i++)
|
||||
bprint_node_label(ip, node->child[i], 2);
|
||||
strcat(ip->out, ": ");
|
||||
bprint_val(ip, node->pv, 2);
|
||||
strcat(ip->out, "\n");
|
||||
}
|
||||
|
||||
void run_cfg(bip_t *ip)
|
||||
{
|
||||
node_t *n = ip->entry[0];
|
||||
while (n) {
|
||||
n->f(n);
|
||||
n = n->snext;
|
||||
}
|
||||
}
|
||||
|
||||
#define define_arithmetic_opfun(name, op) \
|
||||
void name(node_t *n) \
|
||||
{ \
|
||||
val_t *v0, *v1; \
|
||||
const static val_t v = {0}; \
|
||||
if (n->nchild == 1) { \
|
||||
v0 = (val_t *)&v; \
|
||||
v1 = n->child[0]->pv; \
|
||||
} else { \
|
||||
v0 = n->child[0]->pv; \
|
||||
v1 = n->child[1]->pv; \
|
||||
} \
|
||||
n->pv->u.num = v0->u.num op v1->u.num; \
|
||||
}
|
||||
|
||||
#define define_comparison_opfun(name, op) \
|
||||
void name(node_t *n) \
|
||||
{ \
|
||||
n->pv->u.num = n->child[0]->pv->u.num op n->child[1]->pv->u.num;\
|
||||
}
|
||||
|
||||
#define define_bitwise_opfun(name, op) \
|
||||
void name(node_t *n) \
|
||||
{ \
|
||||
n->pv->u.num = n->child[0]->pv->u.num op n->child[1]->pv->u.num;\
|
||||
}
|
||||
|
||||
/* Generate code for common operators */
|
||||
#define check_zero_div(v) \
|
||||
{if (v == 0) fprintf(stderr, "run error: divide by zero\n"); return;}
|
||||
define_arithmetic_opfun(fdiv, /)
|
||||
#undef check_zero_div
|
||||
#define check_zero_div(v)
|
||||
define_arithmetic_opfun(add, +)
|
||||
define_arithmetic_opfun(sub, -)
|
||||
define_arithmetic_opfun(mul, *)
|
||||
define_bitwise_opfun(band, &)
|
||||
define_bitwise_opfun(bor, |)
|
||||
define_bitwise_opfun(lshift, <<)
|
||||
define_bitwise_opfun(rshift, >>)
|
||||
define_bitwise_opfun(mod, %)
|
||||
define_comparison_opfun(eq, ==)
|
||||
define_comparison_opfun(neq, !=)
|
||||
define_comparison_opfun(ge, >=)
|
||||
define_comparison_opfun(gt, >)
|
||||
define_comparison_opfun(le, <=)
|
||||
define_comparison_opfun(lt, <)
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef RUN_CFG_H
|
||||
#define RUN_CFG_H
|
||||
|
||||
#include "node.h"
|
||||
|
||||
void nop(node_t *n);
|
||||
void assign(node_t *n);
|
||||
void echo(node_t *n);
|
||||
void cond_branch(node_t *n);
|
||||
|
||||
void inc(node_t *n);
|
||||
void add(node_t *n);
|
||||
void sub(node_t *n);
|
||||
void mul(node_t *n);
|
||||
void fdiv(node_t *n);
|
||||
void band(node_t *n);
|
||||
void bor(node_t *n);
|
||||
void lshift(node_t *n);
|
||||
void rshift(node_t *n);
|
||||
void mod(node_t *n);
|
||||
void eq(node_t *n);
|
||||
void neq(node_t *n);
|
||||
void ge(node_t *n);
|
||||
void gt(node_t *n);
|
||||
void le(node_t *n);
|
||||
void lt(node_t *n);
|
||||
|
||||
void run_cfg(bip_t *ip);
|
||||
|
||||
#endif /* RUN_CFG_H */
|
||||
313
_gi_c/run_jit.c
313
_gi_c/run_jit.c
@@ -1,313 +0,0 @@
|
||||
/* jit runtime for bip */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <lightning.h>
|
||||
|
||||
#include "node.h"
|
||||
#include "run_jit.h"
|
||||
#include "trace.h"
|
||||
|
||||
typedef struct reg_t {
|
||||
sym_t *sym; /* symbol associated to register */
|
||||
} reg_t;
|
||||
|
||||
static reg_t regs[JIT_V_NUM];
|
||||
|
||||
static jit_state_t *_jit; /* XXX: should be in bip_t */
|
||||
|
||||
static inline void load(int reg, node_t *n)
|
||||
{
|
||||
if (n->type == VAR)
|
||||
n->reg = n->sym->reg;
|
||||
if (n->reg) {
|
||||
if (reg != n->reg)
|
||||
jit_movr(reg, n->reg);
|
||||
} else if (n->type == TERM)
|
||||
jit_movi(reg, n->pv->u.num);
|
||||
else if (reg != JIT_R0)
|
||||
jit_movr(reg, JIT_R0);
|
||||
//else if (0)
|
||||
// jit_ldi(reg, &n->pv->u.num);
|
||||
}
|
||||
|
||||
static inline int is_if_cond(node_t *n)
|
||||
{
|
||||
return (n->anc && n->anc->type == IF && n->anc->child[0] == n);
|
||||
}
|
||||
|
||||
static inline int is_for_cond(node_t *n)
|
||||
{
|
||||
return (n->anc && n->anc->type == FOR && n->anc->child[1] == n);
|
||||
}
|
||||
|
||||
static inline int is_while_cond(node_t *n)
|
||||
{
|
||||
return (n->anc && n->anc->type == WHILE && n->anc->child[0] == n);
|
||||
}
|
||||
|
||||
static inline int is_cond(node_t *n)
|
||||
{
|
||||
return is_if_cond(n) || is_for_cond(n) || is_while_cond(n);
|
||||
}
|
||||
|
||||
static int regalloc(sym_t *sym)
|
||||
{
|
||||
int i;
|
||||
if (sym->reg)
|
||||
return sym->reg; /* already allocated */
|
||||
for (i = 0; i < JIT_V_NUM; i++) {
|
||||
if (regs[i].sym == NULL) {
|
||||
regs[i].sym = sym;
|
||||
sym->reg = JIT_V(i);
|
||||
jit_ldi(sym->reg, &sym->v.u.num);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void j_assign(node_t *n)
|
||||
{
|
||||
sym_t *var = n->child[0]->sym;
|
||||
|
||||
if (regalloc(var)) {
|
||||
n->reg = n->child[0]->reg = var->reg;
|
||||
load(n->reg, n->child[1]);
|
||||
} else {
|
||||
load(JIT_R0, n->child[1]);
|
||||
jit_sti(&n->child[0]->pv->u.num, JIT_R0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int gen_branch(node_t *n, int r1)
|
||||
{
|
||||
jit_node_t **plabel;
|
||||
node_t *c1;
|
||||
|
||||
if (!is_cond(n))
|
||||
return 0;
|
||||
plabel = (n->anc->nchild == 3) ?
|
||||
&n->anc->child[2]->label :
|
||||
&n->anc->label;
|
||||
c1 = n->child[1];
|
||||
if (n->sym->jf == j_eq) {
|
||||
*plabel = (c1->type == TERM) ?
|
||||
jit_bnei(r1, c1->pv->u.num) :
|
||||
jit_bner(r1, c1->reg);
|
||||
} else if (n->sym->jf == j_ne) {
|
||||
*plabel = (c1->type == TERM) ?
|
||||
jit_beqi(r1, c1->pv->u.num) :
|
||||
jit_beqr(r1, c1->reg);
|
||||
} else if (n->sym->jf == j_le) {
|
||||
*plabel = (c1->type == TERM) ?
|
||||
jit_bgti(r1, c1->pv->u.num) :
|
||||
jit_bgtr(r1, c1->reg);
|
||||
} else if (n->sym->jf == j_gt) {
|
||||
*plabel = (c1->type == TERM) ?
|
||||
jit_blei(r1, c1->pv->u.num) :
|
||||
jit_bler(r1, c1->reg);
|
||||
} else if (n->sym->jf == j_lt) {
|
||||
*plabel = (c1->type == TERM) ?
|
||||
jit_bgei(r1, c1->pv->u.num) :
|
||||
jit_bger(r1, c1->reg);
|
||||
} else if (n->sym->jf == j_ge) {
|
||||
*plabel = (c1->type == TERM) ?
|
||||
jit_blti(r1, c1->pv->u.num) :
|
||||
jit_bltr(r1, c1->reg);
|
||||
} else {
|
||||
t_s(n->sym->name);
|
||||
*plabel = jit_beqi(r1, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define define_binary_operator(name) \
|
||||
void j_##name(node_t *n) \
|
||||
{ \
|
||||
int r0, r1; \
|
||||
if (n->anc->type == VAR) \
|
||||
n->reg = n->anc->reg = n->anc->sym->reg; \
|
||||
else if (n->anc->type == OP && n->anc->sym->jf == j_assign) \
|
||||
n->reg = n->anc->reg = n->anc->child[0]->sym->reg; \
|
||||
if (n->child[0]->type == VAR) \
|
||||
n->child[0]->reg = n->child[0]->sym->reg; \
|
||||
if (n->child[1]->type == VAR) \
|
||||
n->child[1]->reg = n->child[1]->sym->reg; \
|
||||
r0 = n->anc->reg; \
|
||||
r1 = n->child[0]->reg; \
|
||||
load(r1, n->child[0]); \
|
||||
if (gen_branch(n, r1)) \
|
||||
return; \
|
||||
if (n->child[1]->reg) { \
|
||||
jit_##name##r(r0, r1, JIT_V(n->child[1]->reg)); \
|
||||
} else if (n->child[1]->type == TERM) { \
|
||||
jit_##name##i(r0, r1, n->child[1]->pv->u.num); \
|
||||
} else { \
|
||||
jit_##name##r(r0, r1, JIT_R0); \
|
||||
} \
|
||||
if (0) jit_sti(&n->pv->u.num, JIT_V(n->anc->reg)); \
|
||||
}
|
||||
|
||||
define_binary_operator(add) /* c0 + c1 */
|
||||
define_binary_operator(sub) /* c0 - c1 */
|
||||
define_binary_operator(mul) /* c0 * c1 */
|
||||
define_binary_operator(div) /* c0 / c1 */
|
||||
define_binary_operator(rem) /* c0 % c1 */
|
||||
define_binary_operator(lt) /* c0 < c1 */
|
||||
define_binary_operator(le) /* c0 <= c1 */
|
||||
define_binary_operator(eq) /* c0 == c1 */
|
||||
define_binary_operator(ne) /* c0 != c1 */
|
||||
define_binary_operator(gt) /* c0 > c1 */
|
||||
define_binary_operator(ge) /* c0 >= c1 */
|
||||
define_binary_operator(and) /* c0 & c1 */
|
||||
define_binary_operator(or) /* c0 | c1 */
|
||||
define_binary_operator(xor) /* c0 ^ c1 */
|
||||
define_binary_operator(lsh) /* c0 << c1 */
|
||||
define_binary_operator(rsh) /* c0 >> c1 */
|
||||
|
||||
#define define_unary_operator(name) \
|
||||
void j_##name(node_t *n) \
|
||||
{ \
|
||||
jit_ldi(JIT_V0, &n->child[0]->pv->u.num); \
|
||||
jit_##name##r(JIT_V0, JIT_V0); \
|
||||
jit_sti(&n->pv->u.num, JIT_V0); \
|
||||
}
|
||||
|
||||
define_unary_operator(neg)
|
||||
define_unary_operator(com)
|
||||
|
||||
static void do_echo_i(int i)
|
||||
{
|
||||
printf("%d\n", i);
|
||||
}
|
||||
|
||||
void j_echo(node_t *n)
|
||||
{
|
||||
jit_prepare();
|
||||
load(JIT_R0, n->child[0]);
|
||||
jit_pushargr(JIT_R0);
|
||||
jit_finishi((jit_pointer_t)do_echo_i);
|
||||
}
|
||||
|
||||
void j_land(node_t *n)
|
||||
{
|
||||
load(JIT_R0, n->child[0]);
|
||||
n->label = jit_beqi(JIT_R0, 0);
|
||||
load(JIT_R0, n->child[1]);
|
||||
jit_patch(n->label);
|
||||
}
|
||||
|
||||
void j_lor(node_t *n)
|
||||
{
|
||||
load(JIT_R0, n->child[0]);
|
||||
n->label = jit_bnei(JIT_R0, 0);
|
||||
load(JIT_R0, n->child[1]);
|
||||
jit_patch(n->label);
|
||||
}
|
||||
|
||||
void j_nop(node_t *n)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void j_inc(node_t *n)
|
||||
{
|
||||
// Avoid costly (and useless in loops) load/store between memory and register
|
||||
//jit_ldi(JIT_V0, &n->child[0]->pv->u.num);
|
||||
//jit_addi(JIT_V0, JIT_V0, 1);
|
||||
//jit_sti(&n->child[0]->pv->u.num, JIT_V0);
|
||||
int reg = n->child[0]->sym->reg;
|
||||
jit_addi(reg, reg, 1);
|
||||
}
|
||||
|
||||
void j_not(node_t *n)
|
||||
{
|
||||
load(JIT_R0, n->child[0]);
|
||||
jit_eqi(JIT_R0, JIT_R0, 0);
|
||||
jit_sti(&n->pv->u.num, JIT_R0);
|
||||
}
|
||||
|
||||
/* code generated by postorder traveral of the abstract syntax tree */
|
||||
static void code_generation(bip_t *ip, node_t *n, void *data)
|
||||
{
|
||||
node_t *anc = n->anc;
|
||||
|
||||
if (is_leaf(n)) {
|
||||
if (is_cond(n)) {
|
||||
load(JIT_R0, n);
|
||||
if (anc->nchild == 3)
|
||||
anc->child[2]->label = jit_beqi(JIT_R0, 0);
|
||||
else
|
||||
anc->label = jit_beqi(JIT_R0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (n->label)
|
||||
jit_patch(n->label);
|
||||
if (is_for_cond(n))
|
||||
n->label = jit_label();
|
||||
if (is_while_cond(n))
|
||||
n->label = jit_label();
|
||||
n->sym->jf(n);
|
||||
|
||||
if (anc == NULL)
|
||||
return;
|
||||
if (anc->type == IF) {
|
||||
if (anc->child[1] == n) { /* in true block */
|
||||
if (anc->nchild == 3)
|
||||
anc->child[1]->label = jit_jmpi();
|
||||
} else if (anc->nchild == 3 && anc->child[2] == n) { /* in false block */
|
||||
jit_patch_at(n->anc->child[1]->label, jit_label());
|
||||
}
|
||||
} else if (anc->type == FOR) {
|
||||
if (anc->child[3] == n) /* in true block */
|
||||
jit_patch_at(jit_jmpi(), anc->child[1]->label);
|
||||
} else if (anc->type == WHILE) {
|
||||
if (anc->child[1] == n) /* in true block */
|
||||
jit_patch_at(jit_jmpi(), anc->child[0]->label);
|
||||
}
|
||||
}
|
||||
|
||||
/* compute necessary space for stack allocation, tag nodes using stack */
|
||||
static void stack_analysis(bip_t *ip, node_t *n, void *data)
|
||||
{
|
||||
if (n->type == OP) {
|
||||
t_s(n->sym->name);
|
||||
if (!is_leaf(n->child[0])) {
|
||||
t_d(n->num);
|
||||
t_d(ip->prev->num);
|
||||
t_d(n->child[0]->num);
|
||||
t_s(n->child[0]->sym->name);
|
||||
}
|
||||
if (!is_leaf(n->child[1])) {
|
||||
t_d(n->num);
|
||||
t_d(ip->prev->num);
|
||||
t_d(n->child[1]->num);
|
||||
t_s(n->child[1]->sym->name);
|
||||
}
|
||||
}
|
||||
ip->prev = n;
|
||||
}
|
||||
|
||||
void run_jit(bip_t *ip, node_t *node)
|
||||
{
|
||||
void (*func)(void);
|
||||
|
||||
init_jit("b1");
|
||||
_jit = jit_new_state();
|
||||
|
||||
jit_prolog();
|
||||
tree_walk(ip, node, NULL, stack_analysis, NULL);
|
||||
tree_walk(ip, node, NULL, code_generation, NULL);
|
||||
jit_epilog();
|
||||
|
||||
func = (void (*)(void))jit_emit();
|
||||
if (ip->opt.v) {
|
||||
jit_print();
|
||||
jit_disassemble();
|
||||
}
|
||||
if (!ip->opt.n)
|
||||
func();
|
||||
finish_jit();
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef RUN_JIT_H
|
||||
#define RUN_JIT_H
|
||||
|
||||
#include "node.h"
|
||||
|
||||
void j_assign(node_t *n);
|
||||
void j_echo(node_t *n);
|
||||
void j_nop(node_t *n);
|
||||
|
||||
void j_inc(node_t *n);
|
||||
|
||||
void j_add(node_t *n); /* c0 + c1 */
|
||||
void j_sub(node_t *n); /* c0 - c1 */
|
||||
void j_mul(node_t *n); /* c0 * c1 */
|
||||
void j_div(node_t *n); /* c0 / c1 */
|
||||
void j_rem(node_t *n); /* c0 % c1 */
|
||||
void j_lt(node_t *n); /* c0 < c1 */
|
||||
void j_le(node_t *n); /* c0 <= c1 */
|
||||
void j_eq(node_t *n); /* c0 == c1 */
|
||||
void j_ne(node_t *n); /* c0 != c1 */
|
||||
void j_gt(node_t *n); /* c0 > c1 */
|
||||
void j_ge(node_t *n); /* c0 >= c1 */
|
||||
void j_and(node_t *n); /* c0 & c1 */
|
||||
void j_or(node_t *n); /* c0 | c1 */
|
||||
void j_xor(node_t *n); /* c0 ^ c1 */
|
||||
void j_lsh(node_t *n); /* c0 << c1 */
|
||||
void j_rsh(node_t *n); /* c0 >> c1 */
|
||||
void j_land(node_t *n); /* c0 && c1 */
|
||||
void j_lor(node_t *n); /* c0 || c1 */
|
||||
void j_neg(node_t *n);
|
||||
void j_com(node_t *n);
|
||||
void j_not(node_t *n); /* ! c0 */
|
||||
|
||||
void run_jit(bip_t *ip, node_t *node);
|
||||
|
||||
#endif /* RUN_JIT_H */
|
||||
232
_gi_c/scan.c
232
_gi_c/scan.c
@@ -1,232 +0,0 @@
|
||||
/* scanner: lexical analysis functions */
|
||||
|
||||
/*
|
||||
* Todo:
|
||||
* - line counting
|
||||
* - better error reporting
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "scan.h"
|
||||
#include "trace.h"
|
||||
|
||||
/* scan_token strings for debug. Keep in sync with scan_token_t in scan.h */
|
||||
const char *scan_token[SCAN_TOKEN_LEN] = {
|
||||
"BAD", "BRACE", "BRACKET", "BSTR", "CSEP", "FLOAT", "ID", "INT", "LSEP",
|
||||
"OPER", "PAREN", "STR"
|
||||
};
|
||||
|
||||
#define isdigit(c) ('0' <= (c) && (c) <= '9')
|
||||
#define isalpha(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z'))
|
||||
#define isalnum(c) (isdigit((c)) || isalpha((c)))
|
||||
|
||||
/* Return a pointer on the first occurence of char c in string s of length len */
|
||||
static char *strnchr(char *s, int len, char c)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++)
|
||||
if (s[i] == c)
|
||||
return &s[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Flat scan of block delimited by i.e (), [], or {} */
|
||||
int scan_block(scan_t *ps, char *s, scan_token_t type, int len, char bstart, char bend, char sdelim)
|
||||
{
|
||||
char c;
|
||||
int complete = 0, inquote = 0, level = 0;
|
||||
|
||||
ps->tok = ++s;
|
||||
c = *s;
|
||||
while (len--) {
|
||||
if (c == sdelim)
|
||||
inquote = 1 - inquote;
|
||||
else if (inquote && c == '\\')
|
||||
s++;
|
||||
else if (!inquote && c == bstart)
|
||||
level++;
|
||||
else if (!inquote && c == bend) {
|
||||
if (--level < 0) {
|
||||
complete = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
c = *++s;
|
||||
}
|
||||
ps->type = complete ? type : BAD;
|
||||
ps->end = s + 1;
|
||||
ps->len = ps->end - ps->tok -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scan_paren(scan_t *ps, char *s, int len)
|
||||
{
|
||||
return scan_block(ps, s, PAREN, len, '(', ')', '"');
|
||||
}
|
||||
|
||||
int scan_brace(scan_t *ps, char *s, int len)
|
||||
{
|
||||
return scan_block(ps, s, BRACE, len, '{', '}', '"');
|
||||
}
|
||||
|
||||
int scan_bracket(scan_t *ps, char *s, int len)
|
||||
{
|
||||
return scan_block(ps, s, BRACKET, len, '[', ']', '"');
|
||||
}
|
||||
|
||||
int scan_cmt(scan_t *ps, char *s, int len)
|
||||
{
|
||||
char c, *smax = s + len;
|
||||
for (c = *++s; s < smax && c != '\n'; c = *++s);
|
||||
ps->end = s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int scan_num(scan_t *ps, char *s, int len)
|
||||
{
|
||||
ps->fnum = strtod(s, &ps->end);
|
||||
ps->tok = s;
|
||||
ps->len = ps->end - ps->tok;
|
||||
if (strnchr(ps->tok, ps->len, '.'))
|
||||
ps->type = FLOAT;
|
||||
else {
|
||||
if (ps->tok[0] == '0' && ps->tok[1] != 'x')
|
||||
ps->num = strtol(ps->tok, &ps->end, 8);
|
||||
else
|
||||
ps->num = (long)ps->fnum;
|
||||
ps->type = INT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scan_id(scan_t *ps, char *s, int len)
|
||||
{
|
||||
char c, *smax = s + len;
|
||||
ps->tok = s;
|
||||
ps->type = ID;
|
||||
for (c = *++s; s < smax; c = *++s)
|
||||
if (!(isalnum(c) || c == '_')) /* XXX could be accelerated */
|
||||
break;
|
||||
ps->end = s;
|
||||
ps->len = s - ps->tok;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scan_wsep(scan_t *ps, char *s, int len)
|
||||
{
|
||||
char c, *smax = s + len;
|
||||
for (c = *++s; s < smax; c = *++s) {
|
||||
if (c != ' ' && c != '\t')
|
||||
break;
|
||||
}
|
||||
ps->end = s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int scan_lsep(scan_t *ps, char *s, int len)
|
||||
{
|
||||
ps->type = LSEP;
|
||||
ps->end = s + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scan_csep(scan_t *ps, char *s, int len)
|
||||
{
|
||||
char c = *s, *smax = s + len;
|
||||
|
||||
for (c = *++s; s < smax; c = *++s)
|
||||
if (c != '\n' && c != ';' && c != ' ' && c != '\t')
|
||||
break;
|
||||
ps->type = CSEP;
|
||||
ps->end = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scan_str(scan_t *ps, char *s, int len)
|
||||
{
|
||||
char *smax = s + len, c, delim = *s;
|
||||
|
||||
ps->type = STR;
|
||||
ps->tok = ++s;
|
||||
for (c = *ps->tok; s < smax; c = *++s)
|
||||
if (c == '\\')
|
||||
s++, ps->type = BSTR;
|
||||
else if (c == delim)
|
||||
break;
|
||||
if (s == smax && c != delim)
|
||||
ps->type = BAD;
|
||||
ps->len = s - ps->tok;
|
||||
ps->end = s + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scan_c_op(scan_t *ps, char *s, int len)
|
||||
{
|
||||
ps->tok = s;
|
||||
ps->type = OPER;
|
||||
switch (*s) {
|
||||
case '!': if (s[1] == '=') s++; break;
|
||||
case '=': if (s[1] == '=') s++; break;
|
||||
case '<': if (s[1] == '=' || s[1] == '<') s++; break;
|
||||
case '>': if (s[1] == '=' || s[1] == '>') s++; break;
|
||||
case '&': if (s[1] == '&') s++; break;
|
||||
case '|': if (s[1] == '|') s++; break;
|
||||
case '+': if (s[1] == '+') s++; break;
|
||||
case '-': if (s[1] == '-') s++; break;
|
||||
}
|
||||
ps->end = s + 1;
|
||||
ps->len = ps->end - ps->tok;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scan_go_op(scan_t *ps, char *s, int len)
|
||||
{
|
||||
ps->tok = s;
|
||||
ps->type = OPER;
|
||||
switch (*s) {
|
||||
case ':': if (s[1] == '=') s++; break;
|
||||
case '!': if (s[1] == '=') s++; break;
|
||||
case '=': if (s[1] == '=') s++; break;
|
||||
case '<': if (s[1] == '=' || s[1] == '<') s++; break;
|
||||
case '>': if (s[1] == '=' || s[1] == '>') s++; break;
|
||||
case '&': if (s[1] == '&') s++; break;
|
||||
case '|': if (s[1] == '|') s++; break;
|
||||
case '+': if (s[1] == '+') s++; break;
|
||||
case '-': if (s[1] == '-') s++; break;
|
||||
}
|
||||
ps->end = s + 1;
|
||||
ps->len = ps->end - ps->tok;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return a bad token */
|
||||
int scan_bad(scan_t *ps, char *s, int len)
|
||||
{
|
||||
t_c(*s);
|
||||
ps->tok = s;
|
||||
ps->end = s + 1;
|
||||
ps->type = BAD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* scanner entry point */
|
||||
int scan(scan_fun_t *scanfun, scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
char *s = *pstr, *smax = s + *plen;
|
||||
|
||||
ps->orig = s;
|
||||
ps->len = 0;
|
||||
ps->type = BAD;
|
||||
while (s < smax && (*scanfun[(int)*s])(ps, s, *plen))
|
||||
s = ps->end;
|
||||
*plen += *pstr - ps->end;
|
||||
*pstr = ps->end;
|
||||
return ps->type;
|
||||
}
|
||||
|
||||
/* undo scan operation, revert to previous state */
|
||||
void unscan(scan_t *ps, char **pstr, int *plen)
|
||||
{
|
||||
*pstr = ps->orig;
|
||||
*plen += ps->end - ps->orig;
|
||||
}
|
||||
47
_gi_c/scan.h
47
_gi_c/scan.h
@@ -1,47 +0,0 @@
|
||||
#ifndef SCAN_H
|
||||
#define SCAN_H
|
||||
|
||||
/* token types recognized by the scanner. For block operators, the
|
||||
* opening char is used.
|
||||
*/
|
||||
typedef enum scan_token_t {
|
||||
BAD, BRACE, BRACKET, BSTR, CSEP, FLOAT, ID, INT, LSEP, OPER, PAREN, STR,
|
||||
SCAN_TOKEN_LEN
|
||||
} scan_token_t;
|
||||
|
||||
/* strings of above for debug */
|
||||
extern const char *scan_token[SCAN_TOKEN_LEN];
|
||||
|
||||
/* scanner state */
|
||||
typedef struct scan_t {
|
||||
char *tok; /* token start position in input */
|
||||
char *end; /* next position in input */
|
||||
char *orig; /* previous position */
|
||||
scan_token_t type; /* token type */
|
||||
int len; /* token len */
|
||||
long num; /* scanner returned value if type is INT */
|
||||
double fnum; /* scanner returned value if type is FLOAT */
|
||||
} scan_t;
|
||||
|
||||
typedef int (*scan_fun_t)(scan_t *ps, char *s, int len);
|
||||
|
||||
int scan_block(scan_t *ps, char *s, scan_token_t type, int len, char bstart, char bend, char sdelim);
|
||||
|
||||
int scan_paren(scan_t *ps, char *s, int len);
|
||||
int scan_brace(scan_t *ps, char *s, int len);
|
||||
int scan_bracket(scan_t *ps, char *s, int len);
|
||||
int scan_cmt(scan_t *ps, char *s, int len);
|
||||
int scan_num(scan_t *ps, char *s, int len);
|
||||
int scan_id(scan_t *ps, char *s, int len);
|
||||
int scan_wsep(scan_t *ps, char *s, int len);
|
||||
int scan_lsep(scan_t *ps, char *s, int len);
|
||||
int scan_csep(scan_t *ps, char *s, int len);
|
||||
int scan_str(scan_t *ps, char *s, int len);
|
||||
int scan_c_op(scan_t *ps, char *s, int len);
|
||||
int scan_go_op(scan_t *ps, char *s, int len);
|
||||
int scan_bad(scan_t *ps, char *s, int len);
|
||||
|
||||
int scan(scan_fun_t *scanfun, scan_t *ps, char **pstr, int *plen);
|
||||
void unscan(scan_t *ps, char **pstr, int *plen);
|
||||
|
||||
#endif /* SCAN_H */
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef TRACE_H
|
||||
#define TRACE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Macros for temporary internal debug traces */
|
||||
#define _tr(fmt, type, exp) fprintf(stderr, "[%s:%d %s] %s: " fmt, __FILE__,\
|
||||
__LINE__, __func__, #exp, (type)(exp))
|
||||
#define t_c(s) _tr("'%c'\n", char, s)
|
||||
#define t_d(s) _tr("%ld\n", long int, s)
|
||||
#define t_g(s) _tr("%g\n", double, s)
|
||||
#define t_i(s) _tr("%d\n", int, s)
|
||||
#define t_p(s) _tr("%p\n", void *, s)
|
||||
#define t_s(s) _tr("'%s'\n", char *, s)
|
||||
#define t_u(s) _tr("%lu\n", unsigned long int, s)
|
||||
#define t_x(s) _tr("0x%lx\n", unsigned long int, s)
|
||||
#define t_v(exp) {fprintf(stderr, "[%s:%d %s] %s\n", __FILE__, __LINE__, __func__, #exp); (void)(exp);}
|
||||
|
||||
#define t_sn(s, n) do { \
|
||||
fprintf(stderr, "[%s:%d %s] %s: '", __FILE__, __LINE__, __func__, #s); \
|
||||
fwrite((s), (n), 1, stderr); fputs("'\n", stderr); } while (0)
|
||||
|
||||
#endif /* TRACE_H */
|
||||
@@ -11,7 +11,7 @@ var version = "v1"
|
||||
type Sample struct{ Name string }
|
||||
|
||||
// Handler is a Sample method to processes HTTP requests
|
||||
func (s *Sample) Handler(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Sample) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "Welcome to my website", s.Name, version)
|
||||
}
|
||||
|
||||
@@ -19,11 +19,12 @@ func (s *Sample) Handler(w http.ResponseWriter, r *http.Request) {
|
||||
func NewSample(name string) func(http.ResponseWriter, *http.Request) {
|
||||
s := &Sample{"test"}
|
||||
fmt.Println("in NewSample", name, version, s)
|
||||
return s.Handler
|
||||
return s.ServeHTTP
|
||||
}
|
||||
|
||||
//func main() {
|
||||
// s := &Sample{"Test"}
|
||||
// http.HandleFunc("/", s.Handler)
|
||||
// http.ListenAndServe(":8080", nil)
|
||||
//}
|
||||
// NewSampleHandler returns a new sample handler function
|
||||
func NewSampleHandler(name string) http.Handler {
|
||||
s := &Sample{"test"}
|
||||
fmt.Println("in NewSample", name, version, s)
|
||||
return s
|
||||
}
|
||||
|
||||
77
example/test_plugin/plugin_test.go
Normal file
77
example/test_plugin/plugin_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/containous/dyngo/interp"
|
||||
"github.com/containous/dyngo/stdlib"
|
||||
)
|
||||
|
||||
func TestPlugin(t *testing.T) {
|
||||
log.SetFlags(log.Lshortfile) // Debug: print source file locations in log output
|
||||
|
||||
// Init go interpreter
|
||||
i := interp.New(interp.Opt{})
|
||||
i.Use(stdlib.Value, stdlib.Type) // Use binary standard library
|
||||
|
||||
// Load plugin from sources
|
||||
if _, err := i.Eval(`import "github.com/containous/dyngo/example/test_plugin/plugin"`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Obtain a HTTP handler from the plugin
|
||||
value, err := i.Eval(`plugin.NewSample("test")`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
handler := value.Interface().(func(http.ResponseWriter, *http.Request))
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", handler)
|
||||
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
|
||||
resp, err := http.DefaultClient.Get(server.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bytes, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := "Welcome to my website test v1\n"
|
||||
if string(bytes) != expected {
|
||||
t.Errorf("Got %s, want %s", string(bytes), expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginMethod(t *testing.T) {
|
||||
log.SetFlags(log.Lshortfile) // Debug: print source file locations in log output
|
||||
|
||||
// Init go interpreter
|
||||
i := interp.New(interp.Opt{})
|
||||
i.Use(stdlib.Value, stdlib.Type) // Use binary standard library
|
||||
|
||||
// Load plugin from sources
|
||||
if _, err := i.Eval(`import "github.com/containous/dyngo/example/test_plugin/plugin"`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Obtain a HTTP handler from the plugin
|
||||
value, err := i.Eval(`plugin.NewSampleHandler("test")`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, ok := value.Interface().(http.Handler); ok {
|
||||
t.Fatal("methods can be used, it's not possible")
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/containous/dyngo/interp"
|
||||
"github.com/containous/dyngo/stdlib"
|
||||
)
|
||||
|
||||
// This program starts an interpreter which loads a plugin to handle HTTP requests
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.Lshortfile) // Debug: print source file locations in log output
|
||||
|
||||
// Init go interpreter
|
||||
i := interp.New(interp.Opt{})
|
||||
i.Use(stdlib.Value, stdlib.Type) // Use binary standard library
|
||||
|
||||
// Load plugin from sources
|
||||
if _, err := i.Eval(`import "github.com/containous/dyngo/example/test_plugin/plugin"`); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Obtain a HTTP handler from the plugin
|
||||
value, err := i.Eval(`plugin.NewSample("test")`)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
handler := value.Interface().(func(http.ResponseWriter, *http.Request))
|
||||
|
||||
http.HandleFunc("/", handler)
|
||||
if err = http.ListenAndServe(":8080", nil); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user