Permalink
Browse files

my god

  • Loading branch information...
1 parent abd28d9 commit ea6193cac2d156e6c86636c2831e041efe643585 @txus committed Dec 23, 2012
View
4 Makefile
@@ -1,5 +1,5 @@
CC=clang
-CFLAGS=-g -O3 -Wall -Werror -Isrc -DNDEBUG $(OPTFLAGS)
+CFLAGS=-g -std=c11 -O3 -Wall -Werror -Isrc -DNDEBUG $(OPTFLAGS)
LIBS=$(OPTLIBS)
PREFIX?=/usr/local
VPATH=vendor
@@ -20,7 +20,7 @@ SO_TARGET=$(patsubst %.a,%.so,$(TARGET))
# The Target Build
all: $(TARGET) $(SO_TARGET) tests $(PROGRAMS)
-dev: CFLAGS=-g -Wall -Isrc -Wall -Werror $(OPTFLAGS)
+dev: CFLAGS=-g -std=c11 -Wall -Isrc -Wall -Werror $(OPTFLAGS)
dev: all
$(TARGET): CFLAGS += -fPIC $(LIBS)
View
1 compiler/examples/functions.rb
@@ -0,0 +1 @@
+-> { 3 }
View
2 compiler/examples/objects.rb
@@ -1,4 +1,4 @@
-parent = Object.clone()
+parent = Object.new
parent.age = 50
parent.money = 1000
child = parent.clone()
View
4 compiler/kernel/prelude.rb
@@ -1 +1,3 @@
-Object.prelude_ran = true
+def new
+ VM.new_object
+end
View
4 compiler/lib/terror.rb
@@ -8,6 +8,8 @@ def self.parse_file(file, verbose=false)
visitor = Terror::Visitor.new
ast.lazy_visit(visitor, ast)
puts visitor.generator.disassemble if verbose
- puts visitor.finalize
+ # Always return nil at the end of a script
+ visitor.generator.pushnil
+ puts visitor.finalize(:main)
end
end
View
11 compiler/lib/terror/generator.rb
@@ -19,12 +19,10 @@ def disassemble
instructions.map(&:to_s).join "\n"
end
- def encode
- # Always return nil at the end of a script
- pushnil
+ def encode(name)
ret
- output = "_main\n"
+ output = "_#{name}\n"
output << ":%i:%i\n" % [
@literals.size,
@ip
@@ -112,6 +110,11 @@ def send_message(msg, argc)
_send literal(msg), argc
end
+ def defn(name)
+ @ip += 1
+ _defn literal(name)
+ end
+
def ret
@ip += 1
_ret
View
13 compiler/lib/terror/instructions.rb
@@ -10,7 +10,8 @@ class << base; attr_accessor :value; end
#
# Returns a String encoded in hexadecimal format.
def encode
- [self.class.value].tap do |ary|
+ val = "#{self.class.value} #{name}"
+ [val].tap do |ary|
ary.push(a) if respond_to?(:a)
ary.push(b) if respond_to?(:b)
end
@@ -20,15 +21,18 @@ def encode
#
# Returns a readable String representing the instruction and its operands.
def to_s
- name = self.class.name.split('::').last
output = [
- name.upcase,
+ name,
# self.class.value
] + operands
output.join " "
end
+ def name
+ self.class.name.split('::').last.upcase
+ end
+
def inspect
to_s
end
@@ -115,8 +119,6 @@ def emit(instruction)
op :pushlocal, 0x20, 1
op :setlocal, 0x21, 1
- op :add, 0x22, 0
-
op :jmp, 0x30, 1
op :jif, 0x31, 1
op :jit, 0x32, 1
@@ -125,6 +127,7 @@ def emit(instruction)
op :setslot, 0x41, 1
op :pop, 0x42, 0
+ op :defn, 0x43, 1
op :send, 0x80, 2
op :ret, 0x90, 0
View
22 compiler/lib/terror/visitor.rb
@@ -7,9 +7,14 @@ class Visitor
def initialize(g=Generator.new)
@generator = g
@slots = {}
+ @fns = []
end
alias_method :g, :generator
+ def name
+ "block_#{hash}"
+ end
+
def fixnum_literal(node, parent)
g.push node.value
end
@@ -50,10 +55,21 @@ def send(node, parent)
return slot_retrieval(node, parent)
end
+ if node.name == :lambda && node.block
+ return defn(node.block)
+ end
+
node.receiver.lazy_visit self, node
g.send_message node.name, 0
end
+ def defn(block)
+ visitor = Visitor.new
+ block.body.lazy_visit(visitor)
+ @fns << visitor
+ g.defn visitor.name
+ end
+
def send_with_arguments(node, parent)
node.receiver.lazy_visit self, node
argc = node.arguments.array.count
@@ -147,8 +163,10 @@ def constant_access(node, parent)
g.getslot node.name
end
- def finalize
- g.encode
+ def finalize(name)
+ out = g.encode(name)
+ fns = @fns.map { |fn| fn.finalize(fn.name) }.join("\n")
+ [out, fns].join("\n")
end
end
end
View
9 compiler/test/terror/visitor_test.rb
@@ -153,5 +153,14 @@ def compiles(code, &block)
end
end
end
+
+ describe 'functions' do
+ it 'are compiled' do
+ compiles("a = -> { 3 }") do
+ _defn 0
+ _setlocal 0
+ end
+ end
+ end
end
end
View
14 examples/functions.fx
@@ -0,0 +1,14 @@
+_main
+:1:3
+"block_472
+67
+0
+20
+144
+_block_472
+:1:2
+3
+17
+0
+144
+
View
39 examples/numbers.fx
@@ -0,0 +1,39 @@
+_main
+:8:13
+3
+1
+"-
+9
+"/
+"*
+"+
+"puts
+16
+17
+0
+17
+1
+128
+2
+1
+17
+0
+17
+3
+17
+0
+128
+4
+1
+128
+5
+1
+128
+6
+1
+128
+7
+1
+20
+144
+
View
1 src/forkix/bootstrap.c
@@ -30,6 +30,7 @@ State_bootstrap(STATE state)
Hashmap *fns = state->functions;
+ // Load all files.
for(int i=0; i < count; i++) {
bstring filename = (bstring)DArray_at(filenames, i);
debug("[BOOTSTRAP] Loading %s...", bdata(filename));
View
27 src/forkix/function.c
@@ -1,10 +1,37 @@
#include <forkix/function.h>
+#include <forkix/value.h>
Function*
Function_new(int *code, DArray *literals)
{
Function *fn = calloc(1, sizeof(Function));
fn->code = code;
fn->literals = literals;
+ fn->c_fn = NULL;
return fn;
}
+
+Function*
+Function_native_new(native_fn c_fn)
+{
+ Function *fn = calloc(1, sizeof(Function));
+ fn->code = NULL;
+ fn->literals = NULL;
+ fn->c_fn = c_fn;
+ return fn;
+}
+
+VALUE
+Function_native_call(Function *fn, VALUE receiver, DArray *locals)
+{
+ VALUE result = NULL;
+ if (DArray_at(locals, 1)) {
+ result = fn->c_fn(receiver, DArray_at(locals, 0), DArray_at(locals, 1));
+ } else if (DArray_at(locals, 0)) {
+ result = fn->c_fn(receiver, DArray_at(locals, 0), NULL);
+ } else {
+ result =fn->c_fn(receiver, NULL, NULL);
+ }
+
+ return result;
+}
View
6 src/forkix/function.h
@@ -3,12 +3,18 @@
#include <forkix/darray.h>
+struct val_s;
+typedef struct val_s* (*native_fn)(void*, void*, void*);
+
struct function_s {
int *code;
DArray *literals;
+ native_fn c_fn;
};
typedef struct function_s Function;
Function* Function_new(int*, DArray*);
+Function* Function_native_new(native_fn);
+struct val_s* Function_native_call(Function *fn, struct val_s*, DArray *locals);
#endif
View
5 src/forkix/opcode.h
@@ -13,16 +13,15 @@ typedef enum {
PUSHLOCAL = 0x20, // 32
SETLOCAL, // 33
- ADD, // 34
-
JMP = 0x30, // 48
JIF, // 49
JIT, // 50
GETSLOT = 0x40, // 64
SETSLOT, // 65
- POP,
+ POP, // 66
+ DEFN, // 67
SEND = 0x80, // 128
RET = 0x90, // 144
View
78 src/forkix/primitives.c
@@ -0,0 +1,78 @@
+#include <forkix/primitives.h>
+#include <forkix/runtime.h>
+#include <assert.h>
+
+/*
+ * Generic primitives
+ */
+
+VALUE
+Primitive_print(void *_, void *b, void *__)
+{
+ Value_print((VALUE)b);
+ return NilObject;
+}
+
+VALUE
+Primitive_puts(void *a, void *b, void *c)
+{
+ Primitive_print(a, b, c);
+ printf("\n");
+ return NilObject;
+}
+
+
+/*
+ * Integer primitives
+ */
+
+VALUE
+Primitive_Integer_add(void *a, void *b, void *_)
+{
+ VALUE left = (VALUE)a;
+ VALUE right = (VALUE)b;
+
+ CHECK_TYPE(left, IntegerType);
+ CHECK_TYPE(right, IntegerType);
+
+ return Integer_new(VAL2INT(left) + VAL2INT(right));
+}
+
+VALUE
+Primitive_Integer_sub(void *a, void *b, void *_)
+{
+ VALUE left = (VALUE)a;
+ VALUE right = (VALUE)b;
+
+ CHECK_TYPE(left, IntegerType);
+ CHECK_TYPE(right, IntegerType);
+
+ return Integer_new(VAL2INT(left) - VAL2INT(right));
+}
+
+VALUE
+Primitive_Integer_mul(void *a, void *b, void *_)
+{
+ VALUE left = (VALUE)a;
+ VALUE right = (VALUE)b;
+
+ CHECK_TYPE(left, IntegerType);
+ CHECK_TYPE(right, IntegerType);
+
+ return Integer_new(VAL2INT(left) * VAL2INT(right));
+}
+
+VALUE
+Primitive_Integer_div(void *a, void *b, void *_)
+{
+ VALUE left = (VALUE)a;
+ VALUE right = (VALUE)b;
+
+ CHECK_TYPE(left, IntegerType);
+ CHECK_TYPE(right, IntegerType);
+
+ assert(VAL2INT(right) != 0 && "Cannot divide by zero");
+
+ return Integer_new(VAL2INT(left) / VAL2INT(right));
+}
+
View
19 src/forkix/primitives.h
@@ -0,0 +1,19 @@
+#ifndef _fx_primitives_h_
+#define _fx_primitives_h_
+
+#include <forkix/value.h>
+#include <assert.h>
+
+#define CHECK_TYPE(O, T) assert((O)->type == (T) && "Type mismatch in primitive operation")
+
+// Generic primitive methods
+VALUE Primitive_print(void*, void*, void*);
+VALUE Primitive_puts(void*, void*, void*);
+
+// Integer primitive methods
+VALUE Primitive_Integer_add(void*, void*, void*);
+VALUE Primitive_Integer_sub(void*, void*, void*);
+VALUE Primitive_Integer_mul(void*, void*, void*);
+VALUE Primitive_Integer_div(void*, void*, void*);
+
+#endif
View
21 src/forkix/value.c
@@ -2,6 +2,7 @@
#include <forkix/value.h>
#include <forkix/bstrlib.h>
#include <forkix/runtime.h>
+#include <forkix/primitives.h>
#include <forkix/gc.h>
VALUE NilObject;
@@ -49,18 +50,30 @@ Value_print(VALUE o)
printf("#<Main %p>\n", o);
break;
}
+ case ClosureType: {
+ printf("#<Closure %p>\n", o);
+ break;
+ }
default: {
printf("#<Object %p>\n", o);
break;
}
}
}
+#define DEFNATIVE(V, N, F) Value_set((V), (N), Closure_new(Function_native_new((F))))
+
VALUE
Integer_new(int num)
{
VALUE val = Value_new(IntegerType);
val->data.as_int = num;
+
+ DEFNATIVE(val, "+", Primitive_Integer_add);
+ DEFNATIVE(val, "-", Primitive_Integer_sub);
+ DEFNATIVE(val, "*", Primitive_Integer_mul);
+ DEFNATIVE(val, "/", Primitive_Integer_div);
+
return val;
}
@@ -72,6 +85,14 @@ String_new(char* value)
return val;
}
+VALUE
+Closure_new(Function *fn)
+{
+ VALUE val = Value_new(ClosureType);
+ val->data.as_data = fn;
+ return val;
+}
+
void
Value_set(VALUE receiver, char *key, VALUE value)
{
View
4 src/forkix/value.h
@@ -3,6 +3,7 @@
#include <forkix/value_type.h>
#include <forkix/gc_header.h>
+#include <forkix/function.h>
#include <forkix/hashmap.h>
struct val_s {
@@ -29,6 +30,9 @@ VALUE Integer_new(int);
VALUE String_new(char*);
#define VAL2STR(o) (o->data.as_str)
+VALUE Closure_new(Function*);
+#define VAL2FN(o) ((Function*)(o->data.as_data))
+
void Value_set(VALUE receiver, char *key, VALUE value);
VALUE Value_get(VALUE receiver, char *key);
View
1 src/forkix/value_type.h
@@ -3,6 +3,7 @@
typedef enum {
IntegerType = 0,
+ ObjectType,
StringType,
ArrayType,
HashType,
View
52 src/forkix/vm.c
@@ -45,7 +45,9 @@ void VM_start(BytecodeFile *file)
State_bootstrap(state);
Stack *frames = Stack_create();
+
CallFrame *top_frame = CallFrame_new(main, STATE_FN("main"), NULL);
+
Stack_push(frames, top_frame);
VM_run(state, frames);
@@ -146,13 +148,12 @@ VALUE VM_run(STATE state, Stack *frames)
Stack_push(stack, value); // push the rhs back to the stack
break;
}
- case ADD: {
- debug("ADD");
- VALUE op1 = Stack_pop(stack);
- VALUE op2 = Stack_pop(stack);
- int result = VAL2INT(op1) + VAL2INT(op2);
-
- Stack_push(stack, Integer_new(result));
+ case DEFN: {
+ ip++;
+ debug("DEFN %i", *ip);
+ VALUE fn_name = LITERAL(*ip);
+ VALUE closure = Closure_new(STATE_FN(VAL2STR(fn_name)));
+ Stack_push(stack, closure);
break;
}
case SEND: {
@@ -161,25 +162,42 @@ VALUE VM_run(STATE state, Stack *frames)
ip++;
int op2 = *ip;
+ debug("SEND %i %i", op1, op2);
+
VALUE name = LITERAL(op1);
int argcount = op2;
- Function *fn = STATE_FN(VAL2STR(name));
- CallFrame *new_frame = CallFrame_new(NULL, fn, ip++);
-
+ DArray *locals = DArray_create(sizeof(VALUE), 10);
while(argcount--) {
- DArray_push(new_frame->locals, Stack_pop(stack));
+ DArray_push(locals, Stack_pop(stack));
}
+ VALUE receiver = Stack_pop(stack);
- new_frame->self = Stack_pop(stack);
+ VALUE closure = Value_get(receiver, VAL2STR(name));
+ if (op2 == 0 && closure->type != ClosureType) {
+ // GETSLOT
+ Stack_push(stack, closure);
+ break;
+ }
+ check(closure->type == ClosureType, "Cannot find function %s.", VAL2STR(name));
+ Function *fn = VAL2FN(closure);
- Stack_push(frames, new_frame);
+ if(fn->c_fn) {
+ // Native function dispatch
+ VALUE result = Function_native_call(fn, receiver, locals);
+ Value_print(result);
+ Stack_push(stack, result);
+ } else {
+ CallFrame *new_frame = CallFrame_new(receiver, fn, ip++);
+ new_frame->locals = locals;
- current_frame = (CallFrame*)(Stack_peek(frames));
- ip = current_frame->fn->code;
- ip--;
+ Stack_push(frames, new_frame);
- debug("SEND %i %i", op1, op2);
+ current_frame = (CallFrame*)(Stack_peek(frames));
+
+ ip = current_frame->fn->code;
+ ip--;
+ }
break;
}
case PUSHSELF: {
View
64 tests/vm_tests.c
@@ -273,25 +273,73 @@ char *test_send()
SETUP();
DEFN(
+ "echo",
+ PUSHLOCAL, 0,
+ RET
+ );
+
+ PUSH_LITERAL(Integer_new(1), a);
+ PUSH_LITERAL(String_new("echo"), method);
+
+ RUN(
+ PUSHSELF,
+ DEFN, 1,
+ SETSLOT, 1,
+
+ PUSHSELF,
+ PUSH, 0,
+ SEND, 1, 1,
+ RET
+ );
+
+ mu_assert(VAL2INT(result) == 1, "Send failed.");
+
+ TEARDOWN();
+}
+
+char *test_send_getslot()
+{
+ SETUP();
+
+ PUSH_LITERAL(Integer_new(1), a);
+ PUSH_LITERAL(String_new("value"), slot);
+
+ RUN(
+ PUSHSELF,
+ PUSH, 0,
+ SETSLOT, 1,
+ POP,
+
+ PUSHSELF,
+ SEND, 1, 0,
+ RET
+ )
+
+ mu_assert(VAL2INT(result) == 1, "Send didn't fall back to getslot.");
+
+ TEARDOWN();
+}
+
+char *test_defn()
+{
+ SETUP();
+
+ DEFN(
"add",
PUSHSELF,
PUSHLOCAL, 0,
- ADD,
RET
);
- PUSH_LITERAL(Integer_new(1), a);
- PUSH_LITERAL(Integer_new(2), b);
PUSH_LITERAL(String_new("add"), method);
RUN(
- PUSH, 0,
- PUSH, 1,
- SEND, 2, 1,
+ DEFN, 0,
RET
);
- mu_assert(VAL2INT(result) == 3, "Send failed.");
+ mu_assert(result->type == ClosureType, "Defn failed.");
+ mu_assert(*(VAL2FN(result)->code) == PUSHSELF, "Defn failed.");
TEARDOWN();
}
@@ -314,6 +362,8 @@ char *all_tests() {
mu_run_test(test_setslot);
mu_run_test(test_pop);
mu_run_test(test_send);
+ mu_run_test(test_send_getslot);
+ mu_run_test(test_defn);
return NULL;
}

0 comments on commit ea6193c

Please sign in to comment.