Skip to content

Commit

Permalink
my god
Browse files Browse the repository at this point in the history
  • Loading branch information
Josep M. Bach committed Dec 23, 2012
1 parent abd28d9 commit ea6193c
Show file tree
Hide file tree
Showing 22 changed files with 358 additions and 43 deletions.
4 changes: 2 additions & 2 deletions 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
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions compiler/examples/functions.rb
@@ -0,0 +1 @@
-> { 3 }
2 changes: 1 addition & 1 deletion compiler/examples/objects.rb
@@ -1,4 +1,4 @@
parent = Object.clone()
parent = Object.new
parent.age = 50
parent.money = 1000
child = parent.clone()
Expand Down
4 changes: 3 additions & 1 deletion compiler/kernel/prelude.rb
@@ -1 +1,3 @@
Object.prelude_ran = true
def new
VM.new_object
end
4 changes: 3 additions & 1 deletion compiler/lib/terror.rb
Expand Up @@ -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
11 changes: 7 additions & 4 deletions compiler/lib/terror/generator.rb
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
13 changes: 8 additions & 5 deletions compiler/lib/terror/instructions.rb
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
22 changes: 20 additions & 2 deletions compiler/lib/terror/visitor.rb
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
9 changes: 9 additions & 0 deletions compiler/test/terror/visitor_test.rb
Expand Up @@ -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
14 changes: 14 additions & 0 deletions examples/functions.fx
@@ -0,0 +1,14 @@
_main
:1:3
"block_472
67
0
20
144
_block_472
:1:2
3
17
0
144
39 changes: 39 additions & 0 deletions 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
1 change: 1 addition & 0 deletions src/forkix/bootstrap.c
Expand Up @@ -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));
Expand Down
27 changes: 27 additions & 0 deletions 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;
}
6 changes: 6 additions & 0 deletions src/forkix/function.h
Expand Up @@ -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
5 changes: 2 additions & 3 deletions src/forkix/opcode.h
Expand Up @@ -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
Expand Down
78 changes: 78 additions & 0 deletions 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));
}

0 comments on commit ea6193c

Please sign in to comment.