├── .gitignore ├── plugin ├── org │ └── dejavu │ │ ├── icons.properties │ │ ├── icons │ │ ├── run.png │ │ ├── debug.png │ │ └── compile.png │ │ ├── ProgressPane.java │ │ ├── Writer.java │ │ └── Runner.java ├── driver.h ├── build.xml ├── dejavu.i ├── driver.cc ├── dejavu.svg └── dejavu-text.svg ├── include └── dejavu │ ├── runtime │ ├── scope.h │ ├── string.h │ ├── error.h │ └── variant.h │ ├── system │ ├── file.h │ ├── buffer.h │ ├── arena.h │ ├── string.h │ └── table.h │ ├── compiler │ ├── node_visitor.h │ ├── nodes.tbl │ ├── lexer.h │ ├── error_stream.h │ ├── printer.h │ ├── tokens.tbl │ ├── parser.h │ ├── codegen.h │ └── node.h │ └── linker │ ├── linker.h │ └── game.h ├── runtime ├── error.cc ├── game.cc ├── string.cc ├── LICENSE ├── scope.cc └── variant.cc ├── system ├── string.cc ├── file.cc └── arena.cc ├── test └── system │ ├── string.cc │ └── table.cc ├── LICENSE ├── README.md ├── Makefile ├── compiler ├── printer.cc ├── lexer.cc ├── parser.cc └── codegen.cc └── linker └── linker.cc /.gitignore: -------------------------------------------------------------------------------- 1 | *.[od] 2 | *.class 3 | *_wrap.* 4 | plugin/org/dejavu/backend 5 | *.bc 6 | *.so 7 | *.jar 8 | *.png 9 | -------------------------------------------------------------------------------- /plugin/org/dejavu/icons.properties: -------------------------------------------------------------------------------- 1 | Toolbar.COMPILE=compile.png 2 | Toolbar.RUN=run.png 3 | Toolbar.DEBUG=debug.png 4 | -------------------------------------------------------------------------------- /plugin/org/dejavu/icons/run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rpjohnst/dejavu-llvm/HEAD/plugin/org/dejavu/icons/run.png -------------------------------------------------------------------------------- /plugin/org/dejavu/icons/debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rpjohnst/dejavu-llvm/HEAD/plugin/org/dejavu/icons/debug.png -------------------------------------------------------------------------------- /plugin/org/dejavu/icons/compile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rpjohnst/dejavu-llvm/HEAD/plugin/org/dejavu/icons/compile.png -------------------------------------------------------------------------------- /include/dejavu/runtime/scope.h: -------------------------------------------------------------------------------- 1 | #ifndef SCOPE_H 2 | #define SCOPE_H 3 | 4 | #include 5 | #include 6 | 7 | struct scope : public table {}; 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/dejavu/runtime/string.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNTIME_STRING_H 2 | #define RUNTIME_STRING_H 3 | 4 | #include 5 | 6 | struct scope; 7 | 8 | extern "C" variant string( 9 | scope *self, scope *other, const variant &val 10 | ); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /include/dejavu/runtime/error.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNTIME_ERROR_H 2 | #define RUNTIME_ERROR_H 3 | 4 | #include 5 | 6 | struct scope; 7 | 8 | extern "C" variant show_error( 9 | scope *self, scope *other, const variant &msg, const variant &abort 10 | ); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /include/dejavu/system/file.h: -------------------------------------------------------------------------------- 1 | #ifndef FILE_H 2 | #define FILE_H 3 | 4 | #include 5 | 6 | class file_buffer : public buffer { 7 | public: 8 | file_buffer() : buffer(0, 0) {} 9 | ~file_buffer(); 10 | 11 | int open_file(const char *path); 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /runtime/error.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct scope; 6 | 7 | extern "C" variant show_error( 8 | scope *, scope *, const variant &msg, const variant &abort 9 | ) { 10 | string *error = to_string(msg); 11 | fputs("error: ", stderr); 12 | fwrite(error->data, 1, error->length, stderr); 13 | fputs("\n", stderr); 14 | 15 | if (to_real(abort)) exit(1); 16 | return 0.0; 17 | } 18 | -------------------------------------------------------------------------------- /plugin/driver.h: -------------------------------------------------------------------------------- 1 | #ifndef DRIVER_H 2 | #define DRIVER_H 3 | 4 | struct game; 5 | 6 | // impure-virtual to appease Java 7 | struct build_log { 8 | virtual ~build_log() {} 9 | virtual void append(const char*) {} 10 | virtual void message(const char*) {} 11 | virtual void percent(int) {} 12 | 13 | protected: 14 | build_log() {} 15 | }; 16 | 17 | bool compile( 18 | const char *output, const char *target, 19 | game &source, build_log &log, bool debug 20 | ); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/dejavu/system/buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef BUFFER_H 2 | #define BUFFER_H 3 | 4 | #include 5 | #include 6 | 7 | class buffer { 8 | public: 9 | buffer(size_t len, const char *data) : length(len), data(data) {} 10 | 11 | const char &operator[](size_t i) const { 12 | assert(i < length && "index out of range"); 13 | return data[i]; 14 | } 15 | 16 | const char *begin() const { return &data[0]; } 17 | const char *end() const { return &data[length]; } 18 | 19 | protected: 20 | size_t length; 21 | const char *data; 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/dejavu/compiler/node_visitor.h: -------------------------------------------------------------------------------- 1 | #ifndef NODE_VISITOR_H 2 | #define NODE_VISITOR_H 3 | 4 | #include "node.h" 5 | 6 | template 7 | struct node_visitor { 8 | ret visit(node *n) { 9 | switch (n->type) { 10 | default: return ret(); 11 | # define NODE(X) case X ## _node: \ 12 | return static_cast(this)->visit_ ## X( \ 13 | static_cast(n) \ 14 | ); 15 | # include "nodes.tbl" 16 | } 17 | } 18 | 19 | # define NODE(X) ret visit_ ## X(X*) { return ret(); } 20 | # include "nodes.tbl" 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /include/dejavu/compiler/nodes.tbl: -------------------------------------------------------------------------------- 1 | #ifndef NODE 2 | #define NODE(X) 3 | #endif 4 | 5 | NODE(expression_error) 6 | 7 | NODE(value) 8 | NODE(unary) 9 | NODE(binary) 10 | NODE(subscript) 11 | NODE(call) 12 | 13 | NODE(statement_error) 14 | 15 | NODE(assignment) 16 | NODE(invocation) 17 | NODE(declaration) 18 | NODE(block) 19 | 20 | NODE(ifstatement) 21 | NODE(whilestatement) 22 | NODE(dostatement) 23 | NODE(repeatstatement) 24 | NODE(forstatement) 25 | NODE(switchstatement) 26 | NODE(withstatement) 27 | 28 | NODE(jump) 29 | NODE(returnstatement) 30 | NODE(casestatement) 31 | 32 | #undef NODE 33 | -------------------------------------------------------------------------------- /include/dejavu/system/arena.h: -------------------------------------------------------------------------------- 1 | #ifndef ARENA_H 2 | #define ARENA_H 3 | 4 | #include 5 | 6 | class arena { 7 | public: 8 | arena(size_t slab_size = 4096); 9 | ~arena(); 10 | 11 | void *allocate(size_t s); 12 | void reset(); 13 | 14 | private: 15 | struct slab { 16 | size_t size; 17 | slab *next; 18 | }; 19 | 20 | void new_slab(); 21 | 22 | size_t slab_size; 23 | slab *current_slab; 24 | char *current; 25 | char *end; 26 | size_t bytes_allocated; 27 | 28 | size_t offset = 0; 29 | }; 30 | 31 | inline void *operator new (size_t size, arena &a) { 32 | return a.allocate(size); 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /system/string.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | size_t string::compute_hash(size_t l, const char *d) { 5 | size_t hash = l; 6 | size_t step = (l >> 5) + 1; // don't hash all chars of a long string 7 | for (; l >= step; l -= step) 8 | hash ^= (hash << 5) + (hash >> 2) + (unsigned char)d[l - 1]; 9 | 10 | return hash; 11 | } 12 | 13 | string::string(size_t l, const char *d) 14 | : hash(compute_hash(l, d)), length(l) { 15 | memcpy(data, d, length); 16 | } 17 | 18 | string *string_pool::intern(string *str) { 19 | string_table::node *n = pool.find(str); 20 | if (n != pool.end()) { 21 | return n->k; 22 | } 23 | 24 | pool.insert(str); 25 | str->pool = this; 26 | return str; 27 | } 28 | -------------------------------------------------------------------------------- /system/file.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int file_buffer::open_file(const char *path) { 9 | int fd = open(path, O_RDONLY); 10 | if (fd == -1) 11 | return errno; 12 | 13 | struct stat s; 14 | if (fstat(fd, &s) == -1) { 15 | close(fd); 16 | return errno; 17 | } 18 | length = s.st_size; 19 | 20 | data = static_cast(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0)); 21 | if (data == MAP_FAILED) { 22 | close(fd); 23 | return errno; 24 | } 25 | 26 | close(fd); 27 | return 0; 28 | } 29 | 30 | file_buffer::~file_buffer() { 31 | munmap(const_cast(data), length); 32 | } 33 | -------------------------------------------------------------------------------- /runtime/game.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" variant scr_0(scope *self, scope *other, short, variant args[]); 5 | 6 | string_pool strings; 7 | 8 | int main(int argc, char *argv[]) { 9 | variant *args = new variant[argc]; 10 | for (int i = 0; i < argc; i++) { 11 | args[i].type = 1; 12 | 13 | string *ptr = strings.intern(argv[i]); 14 | ptr->retain(); 15 | 16 | args[i].string = ptr; 17 | } 18 | 19 | scope self, other; 20 | variant *foo = new variant[1]; 21 | foo[0] = strings.intern("foo"); 22 | self[foo->string] = var{1, 1, foo}; 23 | 24 | scr_0(&self, &other, argc, args); 25 | 26 | for (int i = 0; i < argc; i++) { 27 | args[i].string->release(); 28 | } 29 | delete[] args; 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /runtime/string.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct scope; 7 | 8 | extern "C" variant string( 9 | scope *, scope *, const variant &val 10 | ) { 11 | switch (val.type) { 12 | case 0: { 13 | // TODO: replace snprintf so we don't have to allocate one extra byte? 14 | int length = snprintf(nullptr, 0, "%g", val.real); 15 | struct string *str = new (length + 1) struct string(length); 16 | 17 | snprintf(str->data, length + 1, "%g", val.real); 18 | str->hash = string::compute_hash(str->length, str->data); 19 | 20 | struct string *ret = strings.intern(str); 21 | ret->retain(); 22 | return ret; 23 | } 24 | 25 | case 1: return val; 26 | 27 | default: return show_error(0, 0, "bad value", true); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /include/dejavu/linker/linker.h: -------------------------------------------------------------------------------- 1 | #ifndef LINKER_H 2 | #define LINKER_H 3 | 4 | #include 5 | 6 | struct game; 7 | struct error_stream; 8 | 9 | namespace llvm { 10 | class DataLayout; 11 | } 12 | 13 | class linker { 14 | public: 15 | linker( 16 | const char *output, game&, error_stream&, 17 | const std::string &triple, llvm::LLVMContext &context 18 | ); 19 | bool build(const char *target, bool debug); 20 | 21 | private: 22 | bool link(const char *target, bool debug); 23 | 24 | void build_libraries(); 25 | void build_scripts(); 26 | void build_objects(); 27 | 28 | void add_function( 29 | size_t length, const char *code, 30 | const std::string &name, int args, bool var 31 | ); 32 | 33 | llvm::LLVMContext &context; 34 | std::unique_ptr runtime; 35 | const char *output; 36 | 37 | game &source; 38 | error_stream &errors; 39 | node_codegen compiler; 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /test/system/string.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static const char t[] = "abcde"; 6 | static const size_t l = sizeof(t) - 1; 7 | 8 | TEST(string, allocate) { 9 | string *s = new (l) string(l, t); 10 | s->retain(); 11 | 12 | EXPECT_EQ(0, memcmp(s->data, t, l)); 13 | } 14 | 15 | TEST(string, intern) { 16 | string_pool pool; 17 | 18 | string *p1 = pool.intern("hello"); 19 | p1->retain(); 20 | string *p2 = pool.intern("hello"); 21 | p2->retain(); 22 | string *p3 = pool.intern("world"); 23 | p3->retain(); 24 | 25 | EXPECT_EQ(2, pool.size()); 26 | EXPECT_EQ(p1, p2); 27 | EXPECT_NE(p1, p3); 28 | 29 | p1->release(); 30 | p2->release(); 31 | p3->release(); 32 | 33 | EXPECT_TRUE(pool.empty()); 34 | } 35 | 36 | TEST(string, use) { 37 | string_pool pool; 38 | 39 | string *str = new (l) string(l, t); 40 | str->retain(); 41 | 42 | EXPECT_EQ(str, pool.intern(str)); 43 | 44 | str->release(); 45 | } 46 | -------------------------------------------------------------------------------- /include/dejavu/runtime/variant.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNTIME_VARIANT_H 2 | #define RUNTIME_VARIANT_H 3 | 4 | #include 5 | 6 | extern string_pool strings; 7 | 8 | struct variant { 9 | variant() = default; 10 | 11 | variant(double r) : type(0), real(r) {} 12 | variant(string *s) : type(1), string(s) {} 13 | 14 | variant(const char *s) : variant(strings.intern(s)) {} 15 | 16 | // todo: remove magic numbers 17 | unsigned char type; 18 | union { 19 | double real; 20 | string *string; 21 | }; 22 | }; 23 | 24 | struct var { 25 | unsigned short x, y; 26 | variant *contents; 27 | }; 28 | 29 | extern "C" { 30 | double to_real(const variant &a); 31 | string *to_string(const variant &a); 32 | 33 | string *intern(string *s) __attribute__((pure)); 34 | 35 | variant *access( 36 | var *a, unsigned short x, unsigned short y, bool lvalue = false 37 | ); 38 | 39 | void retain(variant *a); 40 | void release(variant *a); 41 | 42 | void retain_var(var *a); 43 | void release_var(var *a); 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /system/arena.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | arena::arena(size_t slab_size) : 5 | slab_size(slab_size), current_slab(NULL), bytes_allocated(0) {} 6 | 7 | arena::~arena() { 8 | while (current_slab) { 9 | slab *next = current_slab->next; 10 | ::operator delete(current_slab); 11 | current_slab = next; 12 | } 13 | } 14 | 15 | void *arena::allocate(size_t size) { 16 | if (!current_slab) new_slab(); 17 | bytes_allocated += size; 18 | 19 | char *p = current; // TODO: align 20 | if (p + size <= end) { 21 | current = p + size; 22 | return p; 23 | } 24 | 25 | new_slab(); 26 | p = current; // TODO: align 27 | current = p + size; 28 | assert(current <= end && "Unable to allocate memory"); 29 | return p; 30 | } 31 | 32 | void arena::new_slab() { 33 | slab *s = static_cast(::operator new(slab_size)); 34 | s->size = slab_size; 35 | s->next = current_slab; 36 | 37 | current_slab = s; 38 | current = reinterpret_cast(current_slab + 1); 39 | end = reinterpret_cast(current_slab) + current_slab->size; 40 | } 41 | -------------------------------------------------------------------------------- /include/dejavu/compiler/lexer.h: -------------------------------------------------------------------------------- 1 | #ifndef TOKEN_H 2 | #define TOKEN_H 3 | 4 | #include 5 | #include 6 | 7 | class buffer; 8 | 9 | enum token_type { 10 | #define TOK(X) X, 11 | #include 12 | }; 13 | 14 | std::ostream &operator <<(std::ostream &o, token_type t); 15 | 16 | struct token { 17 | token() {} 18 | token(token_type t, size_t r, size_t c) : type(t), row(r), col(c) {} 19 | 20 | token_type type; 21 | size_t row, col; 22 | 23 | union { 24 | double real; 25 | struct { 26 | size_t length; 27 | const char *data; 28 | } string; 29 | }; 30 | }; 31 | 32 | std::ostream &operator <<(std::ostream &o, const token &t); 33 | 34 | class token_stream { 35 | public: 36 | token_stream(buffer &b); 37 | token gettoken(); 38 | 39 | private: 40 | // helper functions 41 | void skipwhitespace(); 42 | bool skipcomment(); 43 | void skipnewline(); 44 | token getname(); 45 | token getoperator(); 46 | token getnumber(); 47 | token getstring(); 48 | 49 | size_t row, col; 50 | const char *current, *buffer_end; 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /runtime/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Russell Johnston 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /plugin/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /plugin/dejavu.i: -------------------------------------------------------------------------------- 1 | %module(directors="1") dejavu 2 | 3 | %{ 4 | #include "dejavu/linker/game.h" 5 | #include "driver.h" 6 | %} 7 | 8 | %feature("director") build_log; 9 | 10 | %include "carrays.i" 11 | 12 | %define %array_move(type, array) 13 | %typemap(javacode) array %{ 14 | public type move() { 15 | swigCMemOwn = false; 16 | return cast(); 17 | } 18 | %} 19 | 20 | %array_class(type, array); 21 | %enddef 22 | 23 | %array_move(script, scriptArray); 24 | %array_move(object, objectArray); 25 | %array_move(event, eventArray); 26 | %array_move(action_type, actionTypeArray); 27 | %array_move(action, actionArray); 28 | %array_class(int, argumentTypeArray); 29 | %array_move(argument, argArray); 30 | 31 | %include "dejavu/linker/game.h" 32 | %include "driver.h" 33 | 34 | %pragma(java) jniclassimports="import java.io.File;" 35 | 36 | %pragma(java) jniclasscode=%{ 37 | static { 38 | try { 39 | File plugin = new File( 40 | $imclassname.class.getProtectionDomain().getCodeSource().getLocation().toURI() 41 | ); 42 | System.load(new File(plugin.getParent(), "dejavu.so").getPath()); 43 | } 44 | catch (Exception e) { 45 | System.err.println("Failed to load dejavu.so\n" + e); 46 | System.exit(1); 47 | } 48 | } 49 | %} 50 | -------------------------------------------------------------------------------- /include/dejavu/compiler/error_stream.h: -------------------------------------------------------------------------------- 1 | #ifndef ERROR_STREAM_H 2 | #define ERROR_STREAM_H 3 | 4 | #include 5 | 6 | struct unexpected_token_error { 7 | unexpected_token_error(token unexpected, const char *expected) : 8 | unexpected(unexpected), expected(expected) {} 9 | 10 | unexpected_token_error(token unexpected, token_type exp) : 11 | unexpected(unexpected), expected_token(exp) {} 12 | 13 | token unexpected; 14 | const char *expected = 0; 15 | token_type expected_token = ::unexpected; 16 | }; 17 | 18 | struct redefinition_error { 19 | redefinition_error(std::string name) : name(name) {} 20 | std::string name; 21 | }; 22 | 23 | struct unsupported_error { 24 | unsupported_error(std::string name, token position) : 25 | name(name), position(position) {} 26 | 27 | std::string name; 28 | token position; 29 | }; 30 | 31 | struct error_stream { 32 | virtual void set_context(const std::string &) = 0; 33 | virtual int count() = 0; 34 | 35 | virtual void error(const unexpected_token_error&) = 0; 36 | virtual void error(const redefinition_error&) = 0; 37 | virtual void error(const unsupported_error&) = 0; 38 | virtual void error(const std::string &) = 0; 39 | 40 | virtual void progress(int i, const std::string &) = 0; 41 | }; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /runtime/scope.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static scope global; 5 | 6 | static table globalvar; 7 | extern "C" void insert_globalvar(string *name) { 8 | globalvar[name] = &global[name]; 9 | } 10 | 11 | extern "C" var *lookup( 12 | scope *self, scope *other, double id, string *name, bool lvalue 13 | ) { 14 | scope *s = 0; 15 | switch ((int)id) { 16 | case -1: s = self; break; 17 | case -2: s = other; break; 18 | case -5: s = &global; break; 19 | 20 | // todo: check on all.foo 21 | case -3: case -4: 22 | show_error(self, other, "variable does not exist", true); 23 | return 0; 24 | case -6: 25 | show_error(self, other, "local is not supported", true); 26 | return 0; 27 | 28 | // todo: other instance access 29 | default: return 0; 30 | } 31 | 32 | if (s->find(name) == s->end()) { 33 | if (!lvalue) { 34 | show_error(self, other, "variable does not exist", true); 35 | return 0; 36 | } 37 | 38 | s->insert(name); 39 | } 40 | return &(*s)[name]; 41 | } 42 | 43 | extern "C" var *lookup_default( 44 | scope *self, scope *other, string *name, bool lvalue 45 | ) { 46 | table::node *n = globalvar.find(name); 47 | if (n != globalvar.end()) { 48 | return n->v; 49 | } 50 | 51 | return lookup(self, other, -1, name, lvalue); 52 | } 53 | -------------------------------------------------------------------------------- /include/dejavu/compiler/printer.h: -------------------------------------------------------------------------------- 1 | #ifndef PRINTER_H 2 | #define PRINTER_H 3 | 4 | #include 5 | #include 6 | 7 | void print_token(const token& t); 8 | 9 | class node_printer : public node_visitor { 10 | public: 11 | node_printer() : scope(0), precedence(0) {} 12 | 13 | void visit_expression_error(expression_error *e); 14 | 15 | void visit_value(value *v); 16 | void visit_unary(unary *u); 17 | void visit_binary(binary *b); 18 | void visit_subscript(subscript *s); 19 | void visit_call(call *c); 20 | 21 | void visit_assignment(assignment *a); 22 | void visit_invocation(invocation* i); 23 | void visit_declaration(declaration *d); 24 | void visit_block(block *b); 25 | 26 | void visit_ifstatement(ifstatement *i); 27 | void visit_whilestatement(whilestatement *w); 28 | void visit_dostatement(dostatement *d); 29 | void visit_repeatstatement(repeatstatement *r); 30 | void visit_forstatement(forstatement *f); 31 | void visit_switchstatement(switchstatement *s); 32 | void visit_withstatement(withstatement *w); 33 | 34 | void visit_jump(jump *j); 35 | void visit_returnstatement(returnstatement *r); 36 | void visit_casestatement(casestatement *c); 37 | 38 | void visit_statement_error(statement_error *e); 39 | 40 | private: 41 | void indent(); 42 | void print_branch(statement *s); 43 | 44 | template 45 | void print_list(I begin, I end); 46 | 47 | size_t scope; 48 | int precedence; 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Russell Johnston 2 | All rights reserved. 3 | 4 | Developed by: Russell Johnston 5 | http://www.abubalay.com 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the 9 | "Software"), to deal with the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | * Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimers. 17 | 18 | * Redistributions in binary form must reproduce the above 19 | copyright notice, this list of conditions and the following disclaimers 20 | in the documentation and/or other materials provided with the 21 | distribution. 22 | 23 | * Neither the names of DejaVu, nor the names of its contributors may be used 24 | to endorse or promote products derived from this Software without specific 25 | prior written permission. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 28 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 29 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 30 | IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR 31 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 32 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 33 | SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. 34 | -------------------------------------------------------------------------------- /test/system/table.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template<> 5 | struct hash { 6 | size_t operator()(int x) { return x; } 7 | }; 8 | 9 | template<> 10 | struct equal { 11 | bool operator()(int x, int y) { return x == y; } 12 | }; 13 | 14 | TEST(table, empty) { 15 | table t; 16 | EXPECT_EQ(t.end(), t.find(0)); 17 | } 18 | 19 | TEST(table, insert) { 20 | table t(3); 21 | 22 | t.insert(3) = 1; 23 | t.insert(5) = 2; 24 | t.insert(7) = 3; 25 | 26 | EXPECT_EQ(1, t.find(3)->v); 27 | EXPECT_EQ(2, t.find(5)->v); 28 | EXPECT_EQ(3, t.find(7)->v); 29 | } 30 | 31 | TEST(table, duplicate) { 32 | table t; 33 | 34 | t[0] = 1; 35 | t[1] = 1; 36 | t[0] = 2; 37 | 38 | EXPECT_EQ(2, t.size()); 39 | } 40 | 41 | TEST(table, remove) { 42 | table t(3); 43 | 44 | t.insert(0) = 1; 45 | t.insert(3) = 2; 46 | t.insert(2) = 3; 47 | 48 | t.remove(2); 49 | EXPECT_EQ(t.end(), t.find(2)); 50 | EXPECT_EQ(1, t.find(0)->v); 51 | EXPECT_EQ(2, t.find(3)->v); 52 | 53 | t.remove(0); 54 | EXPECT_EQ(t.end(), t.find(0)); 55 | EXPECT_EQ(2, t.find(3)->v); 56 | 57 | t.remove(3); 58 | EXPECT_EQ(t.end(), t.find(3)); 59 | } 60 | 61 | TEST(table, resize) { 62 | table t(1); 63 | 64 | t.insert(3) = 1; 65 | t.insert(5) = 2; 66 | 67 | EXPECT_EQ(1, t.find(3)->v); 68 | EXPECT_EQ(2, t.find(5)->v); 69 | } 70 | 71 | TEST(table, chain) { 72 | table t(2); 73 | 74 | t.insert(2) = 1; 75 | t.insert(4) = 2; 76 | 77 | EXPECT_EQ(1, t.find(2)->v); 78 | EXPECT_EQ(2, t.find(4)->v); 79 | } 80 | 81 | TEST(table, subscript) { 82 | table t; 83 | 84 | t[3] = 1; 85 | t[5] = 2; 86 | t[7] = 3; 87 | 88 | EXPECT_EQ(1, t[3]); 89 | EXPECT_EQ(2, t[5]); 90 | EXPECT_EQ(3, t[7]); 91 | } 92 | -------------------------------------------------------------------------------- /include/dejavu/linker/game.h: -------------------------------------------------------------------------------- 1 | #ifndef GAME_H 2 | #define GAME_H 3 | 4 | // todo: replace char* with std::string to reduce strlen() (and copying?) 5 | 6 | struct script { 7 | unsigned int id; 8 | char *name; 9 | char *code; 10 | }; 11 | 12 | struct argument { 13 | enum { 14 | arg_expr, arg_string, arg_both, arg_bool, arg_menu, 15 | arg_sprite, arg_sound, arg_background, arg_path, arg_script, arg_object, 16 | arg_room, arg_font, arg_color, arg_timeline, arg_fontstr 17 | } kind; 18 | char *val; 19 | unsigned int resource; 20 | }; 21 | 22 | struct action_type { 23 | int id, parent; 24 | 25 | enum { 26 | act_normal, act_begin, act_end, act_else, act_exit, act_repeat, act_variable, 27 | act_code, act_placeholder, act_separator, act_label 28 | } kind; 29 | 30 | bool question, relative; 31 | 32 | enum { exec_none, exec_function, exec_code } exec; 33 | char *code; 34 | 35 | unsigned int nargs; 36 | int *args; // argument_type 37 | }; 38 | 39 | struct action { 40 | action_type *type; 41 | 42 | bool relative, inv; 43 | 44 | enum { self = -1, other = -2, all = -3, noone = -4, global = -5, local = -6 }; 45 | int target; 46 | 47 | unsigned int nargs; 48 | argument *args; 49 | }; 50 | 51 | struct event { 52 | unsigned int main_id, sub_id; 53 | unsigned int nactions; 54 | action *actions; 55 | }; 56 | 57 | struct object { 58 | unsigned int id; 59 | char *name; 60 | 61 | int sprite, mask, parent; 62 | bool solid, visible, persistent; 63 | int depth; 64 | 65 | unsigned int nevents; 66 | event *events; 67 | }; 68 | 69 | struct game { 70 | int version; 71 | char *name; 72 | 73 | unsigned int nactions; 74 | action_type *actions; 75 | 76 | unsigned int nscripts; 77 | script *scripts; 78 | 79 | unsigned int nobjects; 80 | object *objects; 81 | }; 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /plugin/org/dejavu/ProgressPane.java: -------------------------------------------------------------------------------- 1 | package org.dejavu; 2 | 3 | import org.dejavu.backend.build_log; 4 | import org.lateralgm.main.LGM; 5 | import javax.swing.*; 6 | import javax.swing.text.*; 7 | import java.awt.*; 8 | 9 | public class ProgressPane extends JPanel { 10 | private JTextPane text; 11 | private JProgressBar progress; 12 | 13 | public ProgressPane() { 14 | super(new BorderLayout()); 15 | 16 | text = new JTextPane(); 17 | text.setEditable(false); 18 | add(new JScrollPane( 19 | text, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED 20 | ), BorderLayout.CENTER); 21 | 22 | progress = new JProgressBar(); 23 | progress.setStringPainted(true); 24 | progress.setString(null); 25 | add(progress, BorderLayout.PAGE_END); 26 | } 27 | 28 | public void reset() { 29 | percent(0); 30 | message(null); 31 | } 32 | 33 | public void append(String line) { 34 | StyledDocument doc = text.getStyledDocument(); 35 | AttributeSet style = null; 36 | 37 | try { 38 | doc.insertString(doc.getLength(), line, style); 39 | } 40 | catch (BadLocationException e) {} 41 | 42 | text.setCaretPosition(doc.getLength()); 43 | } 44 | 45 | public void clear() { 46 | text.setText(null); 47 | } 48 | 49 | public void message(String msg) { 50 | progress.setStringPainted(msg != null); 51 | progress.setString(msg); 52 | } 53 | 54 | public void percent(int pos) { 55 | progress.setValue(pos); 56 | } 57 | 58 | // this is to get around Java's lack of MI and/or SWIG's lack of interface generation 59 | public class Log extends build_log { 60 | public void append(String line) { ProgressPane.this.append(line); } 61 | public void message(String msg) { ProgressPane.this.message(msg); } 62 | public void percent(int pos) { ProgressPane.this.percent(pos); } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /include/dejavu/system/string.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_H 2 | #define STRING_H 3 | 4 | #include 5 | #include 6 | 7 | class string_pool; 8 | 9 | struct string final { 10 | string() = delete; 11 | string(const string&) = delete; 12 | string &operator=(const string&) = delete; 13 | 14 | string(size_t l) : length(l) {} 15 | string(size_t l, const char *d); 16 | static void *operator new(size_t s, int len = 0) { 17 | return ::operator new(s + len); 18 | } 19 | 20 | void retain() { refcount++; } 21 | void release(); 22 | 23 | static size_t compute_hash(size_t l, const char *data); 24 | 25 | size_t refcount = 0; 26 | string_pool *pool; 27 | 28 | size_t hash; 29 | size_t length; 30 | char data[]; 31 | }; 32 | 33 | template<> 34 | struct hash { 35 | size_t operator()(const string *s) const { return s->hash; } 36 | }; 37 | 38 | template<> 39 | struct equal { 40 | size_t operator()(const string *a, const string *b) const { 41 | return a == b; 42 | } 43 | }; 44 | 45 | class string_pool { 46 | friend struct string; 47 | 48 | struct empty {}; 49 | 50 | struct equal { 51 | bool operator()(const string *a, const string *b) { 52 | return 53 | a->hash == b->hash && a->length == b->length && 54 | memcmp(a->data, b->data, a->length) == 0; 55 | } 56 | }; 57 | 58 | typedef table, equal> string_table; 59 | 60 | public: 61 | string *intern(const char *str) { 62 | return intern(str, strlen(str)); 63 | } 64 | string *intern(const char *str, size_t len) { 65 | return intern(new (len) string(len, str)); 66 | } 67 | string *intern(string *str); 68 | 69 | size_t size() { return pool.size(); } 70 | bool empty() { return pool.empty(); } 71 | 72 | private: 73 | string_table pool; 74 | }; 75 | 76 | inline void string::release() { 77 | if (--refcount == 0) { 78 | pool->pool.remove(this); 79 | delete this; 80 | } 81 | } 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /include/dejavu/compiler/tokens.tbl: -------------------------------------------------------------------------------- 1 | #ifndef TOK 2 | #define TOK(X) 3 | #endif 4 | 5 | #ifndef OPERATOR 6 | #define OPERATOR(X, Y) TOK(X) 7 | #endif 8 | 9 | #ifndef KEYWORD 10 | #define KEYWORD(X) TOK(kw_ ## X) 11 | #endif 12 | 13 | TOK(eof) 14 | TOK(unexpected) 15 | 16 | TOK(v_name) 17 | TOK(v_real) 18 | TOK(v_string) 19 | 20 | OPERATOR(l_brace, "{") 21 | OPERATOR(r_brace, "}") 22 | OPERATOR(l_paren, "(") 23 | OPERATOR(r_paren, ")") 24 | OPERATOR(l_square, "[") 25 | OPERATOR(r_square, "]") 26 | 27 | OPERATOR(equals, "=") 28 | 29 | OPERATOR(less, "<") 30 | OPERATOR(less_equals, "<=") 31 | OPERATOR(is_equals, "==") 32 | OPERATOR(not_equals, "!=") 33 | OPERATOR(greater_equals, ">=") 34 | OPERATOR(greater, ">") 35 | 36 | OPERATOR(plus_equals, "+=") 37 | OPERATOR(minus_equals, "-=") 38 | OPERATOR(times_equals, "*=") 39 | OPERATOR(div_equals, "/=") 40 | OPERATOR(and_equals, "&=") 41 | OPERATOR(or_equals, "|=") 42 | OPERATOR(xor_equals, "^=") 43 | 44 | OPERATOR(comma, ",") 45 | OPERATOR(dot, ".") 46 | OPERATOR(colon, ":") 47 | OPERATOR(semicolon, ";") 48 | 49 | OPERATOR(plus, "+") 50 | OPERATOR(minus, "-") 51 | OPERATOR(times, "*") 52 | OPERATOR(divide, "/") 53 | 54 | OPERATOR(exclaim, "!") 55 | OPERATOR(tilde, "~") 56 | 57 | OPERATOR(ampamp, "&&") 58 | OPERATOR(pipepipe, "||") 59 | OPERATOR(caretcaret, "^^") 60 | 61 | OPERATOR(bit_and, "&") 62 | OPERATOR(bit_or, "|") 63 | OPERATOR(bit_xor, "^") 64 | OPERATOR(shift_left, "<<") 65 | OPERATOR(shift_right, ">>") 66 | 67 | KEYWORD(div) 68 | KEYWORD(mod) 69 | 70 | KEYWORD(true) 71 | KEYWORD(false) 72 | 73 | KEYWORD(self) 74 | KEYWORD(other) 75 | KEYWORD(all) 76 | KEYWORD(noone) 77 | KEYWORD(global) 78 | KEYWORD(local) 79 | 80 | KEYWORD(globalvar) 81 | KEYWORD(var) 82 | 83 | KEYWORD(if) 84 | KEYWORD(then) 85 | KEYWORD(else) 86 | KEYWORD(repeat) 87 | KEYWORD(while) 88 | KEYWORD(do) 89 | KEYWORD(until) 90 | KEYWORD(for) 91 | KEYWORD(switch) 92 | KEYWORD(with) 93 | KEYWORD(case) 94 | KEYWORD(default) 95 | KEYWORD(break) 96 | KEYWORD(continue) 97 | KEYWORD(exit) 98 | KEYWORD(return) 99 | 100 | #undef KEYWORD 101 | #undef OPERATOR 102 | #undef TOK 103 | -------------------------------------------------------------------------------- /plugin/driver.cc: -------------------------------------------------------------------------------- 1 | #include "driver.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | class error_printer : public error_stream { 14 | public: 15 | error_printer(build_log &log) : log(log) {} 16 | 17 | void set_context(const std::string &c) { context = c; } 18 | int count() { return errors; } 19 | 20 | void error(const unexpected_token_error &e) { 21 | std::ostringstream s; 22 | s << context << ":" << e.unexpected.row << ":" << e.unexpected.col 23 | << ": error: unexpected '" << e.unexpected << "'; expected "; 24 | if (e.expected) s << e.expected; 25 | else s << e.expected_token; 26 | s << "\n"; 27 | 28 | log.append(s.str().c_str()); 29 | errors++; 30 | } 31 | 32 | void error(const redefinition_error &e) { 33 | std::ostringstream s; 34 | s << context << ": error: redefinition of " << e.name << "\n"; 35 | log.append(s.str().c_str()); 36 | errors++; 37 | } 38 | 39 | void error(const unsupported_error &e) { 40 | std::ostringstream s; 41 | s << context << ":" << e.position.row << ":" << e.position.col 42 | << ": error: feature is unsupported (" << e.name << ")\n"; 43 | 44 | log.append(s.str().c_str()); 45 | errors++; 46 | } 47 | 48 | void error(const std::string &e) { 49 | log.append(e.c_str()); 50 | errors++; 51 | } 52 | 53 | void progress(int i, const std::string &n = "") { 54 | log.percent(i); 55 | if (!n.empty()) log.message(n.c_str()); 56 | } 57 | 58 | private: 59 | build_log &log; 60 | int errors = 0; 61 | 62 | std::string context = ""; 63 | }; 64 | 65 | llvm::llvm_shutdown_obj y; 66 | 67 | // todo: replace debug with configuration struct 68 | bool compile( 69 | const char *output, const char *target, 70 | game &source, build_log &log, bool debug 71 | ) { 72 | error_printer errors(log); 73 | 74 | llvm::InitializeNativeTarget(); 75 | 76 | // we need a new context for every compilation or LLVM chokes on types 77 | llvm::LLVMContext context; 78 | 79 | return linker( 80 | output, source, errors, 81 | llvm::sys::getDefaultTargetTriple(), context 82 | ).build(target, debug); 83 | } 84 | -------------------------------------------------------------------------------- /include/dejavu/compiler/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSER_H 2 | #define PARSER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class parser { 14 | friend class symbol_table; 15 | 16 | public: 17 | parser(token_stream& l, arena &allocator, error_stream& e); 18 | node *getprogram(); 19 | 20 | private: 21 | // expressions 22 | expression *getexpression(int prec = 0); 23 | 24 | expression *id_nud(token t); 25 | expression *name_nud(token t); 26 | expression *prefix_nud(token t); 27 | expression *paren_nud(token t); 28 | 29 | expression *null_nud(token t) { return error_expr(unexpected_token_error(t, "expression")); } 30 | 31 | expression *infix_led(token t, expression *left); 32 | expression *dot_led(token t, expression *left); 33 | expression *square_led(token t, expression *left); 34 | expression *paren_led(token t, expression *left); 35 | 36 | // statements 37 | statement *getstatement(); 38 | 39 | statement *expr_std(); 40 | statement *var_std(); 41 | statement *brace_std(); 42 | 43 | statement *if_std(); 44 | statement *while_std(); 45 | statement *do_std(); 46 | statement *repeat_std(); 47 | statement *for_std(); 48 | statement *switch_std(); 49 | statement *with_std(); 50 | 51 | statement *jump_std(); 52 | statement *return_std(); 53 | statement *case_std(); 54 | 55 | statement *null_std() { return error_stmt(unexpected_token_error(current, "statement")); } 56 | 57 | // utilities 58 | token advance(); 59 | token advance(token_type t); 60 | 61 | statement_error *error_stmt(const unexpected_token_error&); 62 | expression_error *error_expr(const unexpected_token_error&); 63 | 64 | token_stream& lexer; 65 | token current; 66 | 67 | arena &allocator; 68 | error_stream& errors; 69 | }; 70 | 71 | typedef statement *(parser::*std_parser)(); 72 | typedef expression *(parser::*nud_parser)(token); 73 | typedef expression *(parser::*led_parser)(token, expression*); 74 | 75 | struct symbol { 76 | int precedence; 77 | std_parser std; 78 | nud_parser nud; 79 | led_parser led; 80 | }; 81 | 82 | class symbol_table : public std::map { 83 | public: 84 | symbol_table(); 85 | 86 | private: 87 | void prefix(token_type t, nud_parser nud = &parser::prefix_nud); 88 | void infix(token_type t, int prec, led_parser led = &parser::infix_led); 89 | }; 90 | 91 | extern symbol_table symbols; 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DejaVu Game Maker Compiler 2 | ========================== 3 | 4 | DejaVu is an in-progress LLVM-based GML and D&D compiler, mostly compatible with [GameMaker](http://yoyogames.com/gamemaker). It currently exists as a C++ library, and as a plugin to [LateralGM](http://lateralgm.org). It is capable of compiling a game's scripts and object events. Eventually it will be able to produce fullly compiled executables. 5 | 6 | Build Dependencies 7 | ------------------ 8 | 9 | As a work in progress, DejaVu does not currently distribute compiled binaries. To build it from source requires several tools and libraries that should be available from your package manager or from their respective websites: 10 | 11 | * [LLVM](http://llvm.org) - the compiler uses LLVM to generate code 12 | * [Clang](http://clang.llvm.org) - Clang is required to build the language runtime 13 | * [GNU Make](http://www.gnu.org/software/make/) - the compiler's Makefiles are based on GNU Make 14 | * [SWIG](http://www.swig.org) - SWIG is used to generate the bridge between the plugin and compiler 15 | * [Java Developmen Kit](http://www.oracle.com/technetwork/java/javase/downloads/index.html) - the LateralGM plugin is written in Java 16 | * [Ant](http://ant.apache.org/) - Ant is used to compile the LateralGM plugin 17 | 18 | ### Windows 19 | 20 | Currently, DejaVu is not tested on Windows, but there is nothing inherently preventing it from being built or running on that platform. The [MinGW](http://mingw.org) toolchain should be able to support the required dependencies, although some modifications to the Makefiles and source code may be necessary. Contributions would be welcome. 21 | 22 | Runtime Dependencies 23 | -------------------- 24 | 25 | DejaVu itself does not currently have any runtime dependencies. However, it currently reads game data through LateralGM: 26 | 27 | * [Java Runtime Environment](http://www.java.com) 28 | * [LateralGM](http://lateralgm.org) 29 | 30 | Building and Installing 31 | ----------------------- 32 | 33 | Once prerequisites are installed, DejaVu can be built by running `make`. This should produce three files: `dejavu.jar`, `dejavu.so`, and `runtime.bc`. The first two need to be in a directory next to LateralGM named `plugins` and the third needs to be in its working directory. 34 | 35 | Running 36 | ------- 37 | 38 | Running LateralGM normally will load the DejaVu plugin, adding a menu and buttons that invoke DejaVu's compiler on the loaded game. The resulting file is an optimized LLVM bitcode module containing the generated code for the game's scripts and objects' events, including D&D actions. 39 | 40 | Contact Information 41 | ------------------- 42 | 43 | DejaVu is available on GitHub, at [github.com/rpjohnst/dejavu](https://github.com/rpjohnst/dejavu). Feel free to file bugs, submit pull requests, or fork the repository. It is available under the terms in `LICENSE` (University of Illinois/NCSA Open Source License); the runtime is available under the terms in `runtime/LICENSE` (MIT License). 44 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # top-level commands 2 | 3 | TARGETS := dejavu.jar dejavu.so runtime.bc t 4 | 5 | .PHONY: all 6 | all: $(filter-out t,$(TARGETS)) 7 | 8 | .PHONY: test 9 | test: t 10 | ./t 11 | 12 | .PHONY: clean 13 | clean: 14 | $(RM) $(TARGETS) $(interface_OBJECTS) $(interface_DEPENDS) $(library_OBJECTS) $(library_DEPENDS) $(runtime_OBJECTS) $(runtime_DEPENDS) $(t_OBJECTS) $(t_DEPENDS) 15 | (cd plugin && ant clean) 16 | 17 | # toolchain configuration 18 | 19 | CXX := clang++ 20 | CXXFLAGS := -Wall -Wextra -Wno-unused-parameter -g 21 | LLVM_PREFIX := 22 | 23 | # build the interface 24 | 25 | interface_SOURCES := $(wildcard plugin/*.i) 26 | interface_OBJECTS := $(wildcard plugin/*_wrap.*) $(wildcard plugin/org/dejavu/backend/*.java) 27 | interface_DEPENDS := $(interface_SOURCES:.i=.d) 28 | 29 | %_wrap.cc: %.i | plugin/org/dejavu/backend 30 | swig -Wall -MMD -MF $*.d -O -Iinclude -c++ -java -package org.dejavu.backend -outdir plugin/org/dejavu/backend -o $@ $< 31 | 32 | plugin/org/dejavu/backend: 33 | mkdir $@ 34 | 35 | # build the plugin 36 | 37 | plugin_SOURCES := $(shell find plugin -name '*.java') 38 | 39 | dejavu.jar: $(plugin_SOURCES) plugin/dejavu_wrap.cc 40 | cd plugin && ant 41 | 42 | # build the library 43 | 44 | library_SOURCES := $(shell find compiler linker system plugin -name '*.cc') plugin/dejavu_wrap.cc 45 | library_OBJECTS := $(library_SOURCES:.cc=.o) 46 | library_DEPENDS := $(library_SOURCES:.cc=.d) 47 | 48 | library_CXXFLAGS := -fpic 49 | library_CPPFLAGS := $(shell $(LLVM_PREFIX)llvm-config --cppflags) -I$(JAVA_HOME)/include{,/linux} 50 | library_LDFLAGS := -shared $(shell $(LLVM_PREFIX)llvm-config --ldflags) 51 | library_LDLIBS := $(shell $(LLVM_PREFIX)llvm-config --libs core native scalaropts ipo linker bitreader bitwriter irreader) 52 | 53 | dejavu.so: $(library_OBJECTS) 54 | $(CXX) $(library_LDFLAGS) -o $@ $^ $(library_LDLIBS) 55 | 56 | %.o: %.cc 57 | $(CXX) -c -std=c++14 -Iinclude -MMD -MP $(CXXFLAGS) $(library_CXXFLAGS) $(library_CPPFLAGS) -o $@ $< 58 | 59 | # build the runtime 60 | 61 | runtime_SOURCES := $(shell find runtime system -name '*.cc') 62 | runtime_OBJECTS := $(runtime_SOURCES:.cc=.bc) 63 | runtime_DEPENDS := $(runtime_SOURCES:.cc=.d) 64 | 65 | runtime_CXXFLAGS := -fno-exceptions 66 | 67 | runtime.bc: $(runtime_OBJECTS) 68 | $(LLVM_PREFIX)llvm-link -o $@ $^ 69 | 70 | %.bc: %.cc 71 | $(CXX) -c -emit-llvm -std=c++14 -Iinclude $(DEPFLAGS) $(CXXFLAGS) $(runtime_CXXFLAGS) -o $@ $< 72 | 73 | # build the tests 74 | 75 | t_SOURCES := $(shell find system test -name '*.cc') 76 | t_OBJECTS := $(t_SOURCES:.cc=.o) 77 | t_DEPENDS := $(t_SOURCES:.cc=.d) 78 | 79 | t_LDLIBS := -lgtest -lgtest_main 80 | 81 | test/%.o: test/%.cc 82 | $(CXX) -c -std=c++14 -Iinclude -MMD -MP $(CXXFLAGS) $(t_CXXFLAGS) $(t_CPPFLAGS) -o $@ $< 83 | 84 | t: $(t_OBJECTS) 85 | $(CXX) $(t_LDFLAGS) -o $@ $^ $(t_LDLIBS) 86 | 87 | # include dependencies 88 | 89 | ifeq ($(filter clean, $(MAKECMDGOALS)),) 90 | -include $(interface_DEPENDS) $(library_DEPENDS) $(runtime_DEPENDS) $(t_DEPENDS) 91 | endif 92 | -------------------------------------------------------------------------------- /include/dejavu/system/table.h: -------------------------------------------------------------------------------- 1 | #ifndef TABLE_H 2 | #define TABLE_H 3 | 4 | #include 5 | #include 6 | 7 | template 8 | struct hash; 9 | 10 | template 11 | struct equal; 12 | 13 | /* 14 | * Lua-style hash table- chained scatter table with Brent's variation 15 | * Brent's variation avoids coalescing by relocating colliding keys that are 16 | * not in their main position 17 | */ 18 | template < 19 | class key, class value, class hash = hash, class equal = equal 20 | > 21 | class table { 22 | public: 23 | struct node { 24 | key k; 25 | value v; 26 | node *next; 27 | }; 28 | 29 | table(size_t s = 1) { resize(s); } 30 | ~table() { delete[] contents; } 31 | 32 | value &operator[](const key &k) { 33 | node *p = find(k); 34 | if (p != end()) return p->v; 35 | else return insert(k); 36 | } 37 | 38 | // don't insert an already-existing node 39 | value &insert(const key &k) { 40 | node *main = main_position(k); 41 | 42 | if (!is_empty(main)) { 43 | node *free = find_free(); 44 | if (free == end()) { 45 | resize(length * 2); 46 | return insert(k); 47 | } 48 | 49 | node *other = main_position(main->k); 50 | if (other != main) { 51 | while (other->next != main) other = other->next; 52 | other->next = free; 53 | *free = *main; 54 | main->next = nullptr; 55 | } 56 | else { 57 | free->next = main->next; 58 | main->next = free; 59 | main = free; 60 | } 61 | } 62 | else { 63 | main->next = nullptr; 64 | } 65 | 66 | count++; 67 | main->k = k; 68 | main->v = value(); 69 | return main->v; 70 | } 71 | 72 | node *find(const key &k) { 73 | node *n = main_position(k); 74 | 75 | if (is_empty(n)) 76 | return end(); 77 | 78 | do { 79 | if (equal()(k, n->k)) 80 | return n; 81 | else 82 | n = n->next; 83 | } while (n); 84 | 85 | return end(); 86 | } 87 | 88 | void remove(const key &k) { 89 | node *n = find(k); 90 | if (n == end()) 91 | return; 92 | 93 | if (n->next) { 94 | node *next = n->next; 95 | *n = *next; 96 | 97 | next->next = end(); 98 | if (next > lastfree) 99 | lastfree = next + 1; 100 | } 101 | else { 102 | n->next = end(); 103 | } 104 | 105 | count--; 106 | } 107 | 108 | node *end() { 109 | return contents + length; 110 | } 111 | 112 | size_t size() { return count; } 113 | bool empty() { return size() == 0; } 114 | size_t capacity() { return length; } 115 | 116 | private: 117 | void resize(size_t s) { 118 | assert(s > 0); 119 | 120 | node *old_contents = contents; 121 | size_t old_length = length; 122 | 123 | length = s; 124 | contents = new node[length]; 125 | lastfree = end(); 126 | for (size_t i = 0; i < length; i++) { 127 | contents[i].next = end(); 128 | } 129 | 130 | size_t old_count = count; 131 | for (size_t i = 0; i < old_length; i++) { 132 | node *old = &old_contents[i]; 133 | if (!is_empty(old)) { 134 | (*this)[old->k] = old->v; 135 | } 136 | } 137 | count = old_count; 138 | 139 | delete[] old_contents; 140 | } 141 | 142 | node *main_position(const key &k) { 143 | return &contents[hash()(k) % length]; 144 | } 145 | 146 | bool is_empty(node *n) { 147 | return n->next == end(); 148 | } 149 | 150 | node *find_free() { 151 | while (lastfree > contents) { 152 | lastfree--; 153 | if (is_empty(lastfree)) 154 | return lastfree; 155 | } 156 | return end(); 157 | } 158 | 159 | node *contents = nullptr; 160 | size_t length = 0; 161 | 162 | node *lastfree; 163 | size_t count = 0; 164 | }; 165 | 166 | #endif 167 | -------------------------------------------------------------------------------- /include/dejavu/compiler/codegen.h: -------------------------------------------------------------------------------- 1 | #ifndef CODEGEN_H 2 | #define CODEGEN_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class node_codegen : public node_visitor { 14 | public: 15 | node_codegen(const llvm::Module &runtime, error_stream &e); 16 | llvm::Function *add_function( 17 | node*, const char *name, size_t nargs, bool var 18 | ); 19 | llvm::Module &get_module() { return module; } 20 | 21 | void register_script(const std::string &name); 22 | 23 | // really should be private 24 | llvm::Value *visit_value(value *v); 25 | llvm::Value *visit_unary(unary *u); 26 | llvm::Value *visit_binary(binary *b); 27 | llvm::Value *visit_subscript(subscript *s); 28 | llvm::Value *visit_call(call *c); 29 | 30 | llvm::Value *visit_assignment(assignment *a); 31 | llvm::Value *visit_invocation(invocation* i); 32 | llvm::Value *visit_declaration(declaration *d); 33 | llvm::Value *visit_block(block *b); 34 | 35 | llvm::Value *visit_ifstatement(ifstatement *i); 36 | llvm::Value *visit_whilestatement(whilestatement *w); 37 | llvm::Value *visit_dostatement(dostatement *d); 38 | llvm::Value *visit_repeatstatement(repeatstatement *r); 39 | llvm::Value *visit_forstatement(forstatement *f); 40 | llvm::Value *visit_switchstatement(switchstatement *s); 41 | llvm::Value *visit_withstatement(withstatement *w); 42 | 43 | llvm::Value *visit_jump(jump *j); 44 | llvm::Value *visit_returnstatement(returnstatement *r); 45 | llvm::Value *visit_casestatement(casestatement *c); 46 | 47 | private: 48 | llvm::Function *get_function(llvm::StringRef name, int args, bool var); 49 | llvm::Function *get_operator(llvm::StringRef name, int args); 50 | 51 | llvm::Value *get_real(double val); 52 | llvm::Value *get_real(llvm::Value *val); 53 | llvm::Value *get_string(llvm::StringRef val); 54 | 55 | llvm::Value *to_bool(node *val); 56 | llvm::Value *is_equal(llvm::Value *a, llvm::Value *b); 57 | 58 | llvm::Value *make_local(llvm::StringRef name, llvm::Value *value); 59 | llvm::Value *make_local( 60 | llvm::StringRef name, llvm::Value *x, llvm::Value *y, 61 | llvm::Value *values 62 | ); 63 | 64 | llvm::AllocaInst *alloc(llvm::Type*, const llvm::Twine&); 65 | llvm::AllocaInst *alloc(llvm::Type*, llvm::Value*, const llvm::Twine&); 66 | 67 | llvm::Value *do_lookup(llvm::Value *left, llvm::Value *right, bool lvalue); 68 | llvm::Value *do_lookup_default( 69 | llvm::Value *right, bool lvalue 70 | ); 71 | 72 | const llvm::Module &runtime; 73 | const llvm::DataLayout dl; 74 | 75 | llvm::IRBuilder<> builder; 76 | llvm::Module module; 77 | 78 | llvm::StringMap string_literals; 79 | 80 | // todo: resolve namespace issues by mapping to llvm::Function*s 81 | std::unordered_set scripts; 82 | 83 | // runtime types 84 | llvm::PointerType *scope_type; 85 | llvm::StructType *var_type; 86 | llvm::StructType *variant_type; 87 | llvm::StructType *ret_type; 88 | llvm::Type *real_type; 89 | llvm::Type *string_type; 90 | int union_diff; 91 | 92 | // runtime functions 93 | llvm::Function *to_real; 94 | llvm::Function *to_string; 95 | 96 | llvm::Function *intern; 97 | 98 | llvm::Function *insert_globalvar; 99 | llvm::Function *lookup; 100 | llvm::Function *lookup_default; 101 | llvm::Function *access; 102 | 103 | llvm::Function *retain; 104 | llvm::Function *release; 105 | llvm::Function *retain_var; 106 | llvm::Function *release_var; 107 | 108 | llvm::Function *with_begin; 109 | llvm::Function *with_inc; 110 | 111 | // scope handling 112 | std::unordered_map scope; 113 | llvm::Instruction *alloca_point = 0; 114 | llvm::Value *return_value = 0; 115 | llvm::Value *self_scope = 0; 116 | llvm::Value *other_scope = 0; 117 | 118 | llvm::BasicBlock *current_loop = 0; 119 | llvm::BasicBlock *current_end = 0; 120 | 121 | llvm::Function::iterator current_cond = 0; 122 | llvm::BasicBlock *current_default = 0; 123 | llvm::Value *current_switch = 0; 124 | 125 | bool lvalue = false; 126 | 127 | error_stream& errors; 128 | }; 129 | 130 | inline void node_codegen::register_script(const std::string &name) { 131 | scripts.insert(name); 132 | } 133 | 134 | inline llvm::AllocaInst *node_codegen::alloc( 135 | llvm::Type *type, const llvm::Twine &name = "" 136 | ) { 137 | return alloc(type, NULL, name); 138 | } 139 | inline llvm::AllocaInst *node_codegen::alloc( 140 | llvm::Type *type, llvm::Value *n, const llvm::Twine &name = "" 141 | ) { 142 | return new llvm::AllocaInst(type, n, name, alloca_point); 143 | } 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /include/dejavu/compiler/node.h: -------------------------------------------------------------------------------- 1 | #ifndef NODE_H 2 | #define NODE_H 3 | 4 | #include 5 | #include 6 | 7 | enum node_type { 8 | #define NODE(X) X ## _node, 9 | #include 10 | }; 11 | 12 | struct node { 13 | explicit node(node_type type) : type(type) {} 14 | 15 | node_type type; 16 | }; 17 | 18 | struct expression : public node { 19 | expression(node_type type) : node(type) {} 20 | }; 21 | 22 | struct expression_error : public expression { 23 | expression_error() : expression(expression_error_node) {} 24 | }; 25 | 26 | struct value : public expression { 27 | value(token t) : expression(value_node), t(t) {} 28 | token t; 29 | }; 30 | 31 | struct unary : public expression { 32 | unary(token_type op, expression *right) : 33 | expression(unary_node), op(op), right(right) {} 34 | 35 | token_type op; 36 | expression *right; 37 | }; 38 | 39 | // todo: so much special handling for . - should it be its own node type? 40 | struct binary : public expression { 41 | binary(token_type op, expression *left, expression *right) : 42 | expression(binary_node), op(op), left(left), right(right) {} 43 | 44 | token_type op; 45 | expression *left, *right; 46 | }; 47 | 48 | struct subscript : public expression { 49 | subscript(expression *array, std::vector& indices) : 50 | expression(subscript_node), array(array), indices(indices) {} 51 | 52 | expression *array; 53 | std::vector indices; 54 | }; 55 | 56 | struct call : public expression { 57 | call(value *function, std::vector& args) : 58 | expression(call_node), function(function), args(args) {} 59 | 60 | value *function; 61 | std::vector args; 62 | }; 63 | 64 | struct statement : public node { 65 | statement(node_type type) : node(type) {} 66 | }; 67 | 68 | struct statement_error : public statement { 69 | statement_error() : statement(statement_error_node) {} 70 | }; 71 | 72 | struct assignment : public statement { 73 | assignment(token_type op, expression *lvalue, expression *rvalue) : 74 | statement(assignment_node), op(op), lvalue(lvalue), rvalue(rvalue) {} 75 | 76 | token_type op; 77 | expression *lvalue, *rvalue; 78 | }; 79 | 80 | struct invocation : public statement { 81 | invocation(call *c) : statement(invocation_node), c(c) {} 82 | 83 | call *c; 84 | }; 85 | 86 | struct declaration : public statement { 87 | declaration(token type, std::vector& names) : 88 | statement(declaration_node), type(type), names(names) {} 89 | 90 | token type; 91 | std::vector names; 92 | }; 93 | 94 | struct block : public statement { 95 | block(std::vector& stmts) : 96 | statement(block_node), stmts(stmts) {} 97 | 98 | std::vector stmts; 99 | }; 100 | 101 | struct ifstatement : public statement { 102 | ifstatement( 103 | expression *cond, 104 | statement *branch_true, 105 | statement *branch_false 106 | ) : 107 | statement(ifstatement_node), 108 | cond(cond), 109 | branch_true(branch_true), 110 | branch_false(branch_false) {} 111 | 112 | expression *cond; 113 | statement *branch_true, *branch_false; 114 | }; 115 | 116 | struct whilestatement : public statement { 117 | whilestatement(expression *cond, statement *stmt) : 118 | statement(whilestatement_node), cond(cond), stmt(stmt) {} 119 | 120 | expression *cond; 121 | statement *stmt; 122 | }; 123 | 124 | struct dostatement : public statement { 125 | dostatement(expression *cond, statement *stmt) : 126 | statement(dostatement_node), cond(cond), stmt(stmt) {} 127 | 128 | expression *cond; 129 | statement *stmt; 130 | }; 131 | 132 | struct repeatstatement : public statement { 133 | repeatstatement(expression *expr, statement *stmt) : 134 | statement(repeatstatement_node), expr(expr), stmt(stmt) {} 135 | 136 | expression *expr; 137 | statement *stmt; 138 | }; 139 | 140 | struct forstatement : public statement { 141 | forstatement( 142 | statement *init, 143 | expression *cond, 144 | statement *inc, 145 | statement *stmt 146 | ) : 147 | statement(forstatement_node), 148 | init(init), 149 | cond(cond), 150 | inc(inc), 151 | stmt(stmt) {} 152 | 153 | statement *init; 154 | expression *cond; 155 | statement *inc; 156 | statement *stmt; 157 | }; 158 | 159 | struct switchstatement : public statement { 160 | switchstatement(expression *expr, block *stmts) : 161 | statement(switchstatement_node), expr(expr), stmts(stmts) {} 162 | 163 | expression *expr; 164 | block *stmts; 165 | }; 166 | 167 | struct withstatement : public statement { 168 | withstatement(expression *expr, statement *stmt) : 169 | statement(withstatement_node), expr(expr), stmt(stmt) {} 170 | 171 | expression *expr; 172 | statement *stmt; 173 | }; 174 | 175 | struct jump : public statement { 176 | jump(token_type type) : statement(jump_node), type(type) {} 177 | 178 | token_type type; 179 | }; 180 | 181 | struct returnstatement : public statement { 182 | returnstatement(expression *expr) : 183 | statement(returnstatement_node), expr(expr) {} 184 | 185 | expression *expr; 186 | }; 187 | 188 | struct casestatement : public statement { 189 | casestatement(expression *expr) : 190 | statement(casestatement_node), expr(expr) {} 191 | 192 | expression *expr; 193 | }; 194 | 195 | #endif 196 | -------------------------------------------------------------------------------- /compiler/printer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void print_token(const token& t) { 6 | switch (t.type) { 7 | case unexpected: 8 | printf("%.*s", (int)t.string.length, t.string.data); 9 | break; 10 | 11 | case v_name: 12 | printf("%.*s", (int)t.string.length, t.string.data); 13 | break; 14 | 15 | case v_real: 16 | printf("%g", t.real); 17 | break; 18 | 19 | case v_string: 20 | printf("\"%.*s\"", (int)t.string.length, t.string.data); 21 | break; 22 | 23 | # define KEYWORD(X) case kw_ ## X: printf(#X); break; 24 | # include "dejavu/compiler/tokens.tbl" 25 | 26 | # define OPERATOR(X, Y) case X: printf(Y); break; 27 | # include "dejavu/compiler/tokens.tbl" 28 | 29 | default: /* do nothing */; 30 | } 31 | } 32 | 33 | void node_printer::visit_expression_error(expression_error*) { 34 | printf(""); 35 | } 36 | 37 | void node_printer::visit_value(value *v) { 38 | if (precedence >= 80 && v->t.type == v_real) printf("("); 39 | print_token(v->t); 40 | if (precedence >= 80 && v->t.type == v_real) printf(")"); 41 | } 42 | 43 | void node_printer::visit_unary(unary *u) { 44 | print_token(token(u->op, 0, 0)); 45 | 46 | int p = precedence; 47 | precedence = 70; 48 | 49 | visit(u->right); 50 | 51 | precedence = p; 52 | } 53 | 54 | void node_printer::visit_binary(binary *b) { 55 | if (symbols[b->op].precedence < precedence) { 56 | printf("("); 57 | } 58 | int p = precedence; 59 | precedence = symbols[b->op].precedence; 60 | 61 | visit(b->left); 62 | if (b->op != dot) printf(" "); 63 | print_token(token(b->op, 0, 0)); 64 | if (b->op != dot) printf(" "); 65 | visit(b->right); 66 | 67 | precedence = p; 68 | if (symbols[b->op].precedence < precedence) { 69 | printf(")"); 70 | } 71 | } 72 | 73 | void node_printer::visit_subscript(subscript *s) { 74 | visit(s->array); 75 | printf("["); 76 | 77 | int p = precedence; 78 | precedence = 0; 79 | 80 | print_list(s->indices.begin(), s->indices.end()); 81 | 82 | precedence = p; 83 | 84 | printf("]"); 85 | } 86 | 87 | void node_printer::visit_call(call *c) { 88 | visit(c->function); 89 | printf("("); 90 | print_list(c->args.begin(), c->args.end()); 91 | printf(")"); 92 | } 93 | 94 | void node_printer::visit_statement_error(statement_error*) { 95 | printf(""); 96 | } 97 | 98 | void node_printer::visit_assignment(assignment *a) { 99 | visit(a->lvalue); printf(" "); 100 | print_token(token(a->op, 0, 0)); printf(" "); 101 | visit(a->rvalue); printf(";"); 102 | } 103 | 104 | void node_printer::visit_invocation(invocation* i) { 105 | visit(i->c); printf(";"); 106 | } 107 | 108 | void node_printer::visit_declaration(declaration *d) { 109 | printf("var "); 110 | print_list(d->names.begin(), d->names.end()); 111 | printf(";"); 112 | } 113 | 114 | void node_printer::visit_block(block *b) { 115 | printf("{\n"); scope++; 116 | for ( 117 | std::vector::iterator it = b->stmts.begin(); 118 | it != b->stmts.end(); ++it 119 | ) { 120 | if ((*it)->type == casestatement_node) scope--; 121 | indent(); visit(*it); printf("\n"); 122 | if ((*it)->type == casestatement_node) scope++; 123 | }; 124 | scope--; indent(); printf("}"); 125 | } 126 | 127 | void node_printer::visit_ifstatement(ifstatement *i) { 128 | printf("if ("); visit(i->cond); printf(")"); 129 | print_branch(i->branch_true); 130 | if (i->branch_false) { 131 | printf("\n"); 132 | indent(); printf("else"); 133 | 134 | if (i->branch_false->type != ifstatement_node) { 135 | printf("\n"); print_branch(i->branch_false); 136 | } 137 | else { 138 | printf(" "); visit(i->branch_false); 139 | } 140 | } 141 | } 142 | 143 | void node_printer::visit_whilestatement(whilestatement *w) { 144 | printf("while ("); visit(w->cond); printf(")"); 145 | print_branch(w->stmt); 146 | } 147 | 148 | void node_printer::visit_dostatement(dostatement *d) { 149 | printf("do"); 150 | print_branch(d->stmt); 151 | printf(" until ("); visit(d->cond); printf(");"); 152 | } 153 | 154 | void node_printer::visit_repeatstatement(repeatstatement *r) { 155 | printf("repeat ("); visit(r->expr); printf(")"); 156 | print_branch(r->stmt); 157 | } 158 | 159 | void node_printer::visit_forstatement(forstatement *f) { 160 | printf("for ("); 161 | visit(f->init); printf(" "); 162 | visit(f->cond); printf("; "); 163 | visit(f->inc); printf("\b"); 164 | printf(")"); 165 | print_branch(f->stmt); 166 | } 167 | 168 | void node_printer::visit_switchstatement(switchstatement *s) { 169 | printf("switch ("); visit(s->expr); printf(")"); 170 | print_branch(s->stmts); 171 | } 172 | 173 | void node_printer::visit_withstatement(withstatement *w) { 174 | printf("with ("); visit(w->expr); printf(")"); 175 | print_branch(w->stmt); 176 | } 177 | 178 | void node_printer::visit_jump(jump *j) { 179 | print_token(token(j->type, 0, 0)); printf(";"); 180 | } 181 | 182 | void node_printer::visit_returnstatement(returnstatement *r) { 183 | printf("return "); visit(r->expr); printf(";"); 184 | } 185 | 186 | void node_printer::visit_casestatement(casestatement *c) { 187 | if (c->expr) { 188 | printf("case "); visit(c->expr); 189 | } 190 | else { 191 | printf("default"); 192 | } 193 | 194 | printf(":"); 195 | } 196 | 197 | void node_printer::indent() { 198 | for (size_t i = 0; i < scope; i++) 199 | printf(" "); 200 | } 201 | 202 | void node_printer::print_branch(statement *s) { 203 | if (s->type == block_node) { 204 | printf(" "); visit(static_cast(s)); 205 | } 206 | else { 207 | printf("\n"); 208 | scope++; 209 | indent(); visit(s); 210 | scope--; 211 | } 212 | } 213 | 214 | template 215 | void node_printer::print_list(I begin, I end) { 216 | for (I it = begin; it != end; ++it) { 217 | if (it != begin) printf(", "); 218 | visit(*it); 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /plugin/org/dejavu/Writer.java: -------------------------------------------------------------------------------- 1 | package org.dejavu; 2 | 3 | import org.dejavu.backend.*; 4 | import org.lateralgm.main.LGM; 5 | import org.lateralgm.file.*; 6 | import org.lateralgm.resources.*; 7 | import org.lateralgm.resources.GmObject.*; 8 | import org.lateralgm.resources.sub.*; 9 | import org.lateralgm.resources.library.*; 10 | import static org.lateralgm.main.Util.deRef; 11 | import java.util.List; 12 | import java.util.HashMap; 13 | 14 | public class Writer { 15 | private GmFile file; 16 | private game out; 17 | private ProgressPane log; 18 | 19 | public Writer(GmFile f, ProgressPane l) { 20 | file = f; 21 | out = new game(); 22 | log = l; 23 | } 24 | 25 | // todo: use JNI directly to avoid all this excessive copying 26 | public game write() { 27 | out.setVersion(file.format != null ? file.format.getVersion() : -1); 28 | out.setName(file.uri != null ? file.uri.toString() : ""); 29 | 30 | writeLibraries(); 31 | 32 | writeScripts(); 33 | writeObjects(); 34 | 35 | return out; 36 | } 37 | 38 | // todo: do this on-demand, eventually keep libs compiled on installation 39 | private HashMap actionTypes = new HashMap(); 40 | private void writeLibraries() { 41 | int actionCount = 0; 42 | for (Library lib : LibManager.libs) { 43 | actionCount += lib.libActions.size(); 44 | } 45 | 46 | actionTypeArray actionsOut = new actionTypeArray(actionCount); 47 | int i = 0; 48 | for (Library lib : LibManager.libs) { 49 | for (LibAction act : lib.libActions) { 50 | action_type a = new action_type(); 51 | a.setId(act.id); 52 | a.setParent(act.parentId); 53 | a.setKind(act.actionKind); 54 | a.setQuestion(act.question); 55 | a.setRelative(act.allowRelative); 56 | a.setExec(act.execType); 57 | a.setCode(act.execInfo); 58 | 59 | argumentTypeArray argsOut = new argumentTypeArray( 60 | act.libArguments.length 61 | ); 62 | int j = 0; 63 | for (LibArgument arg : act.libArguments) { 64 | argsOut.setitem(j, arg.kind); 65 | j++; 66 | } 67 | a.setNargs(act.libArguments.length); 68 | a.setArgs(argsOut.cast()); 69 | 70 | actionsOut.setitem(i, a); 71 | actionTypes.put(act, a); 72 | i++; 73 | } 74 | } 75 | out.setNactions(actionCount); 76 | out.setActions(actionsOut.move()); 77 | } 78 | 79 | private void writeScripts() { 80 | ResourceList