|
|
@ -43,16 +43,25 @@ void fatal(char *fmt, ...) |
|
|
|
# endif |
|
|
|
#endif |
|
|
|
|
|
|
|
#define indexableSize(A) (sizeof(A) / sizeof(*(A))) |
|
|
|
|
|
|
|
typedef union Object Object, *oop; |
|
|
|
|
|
|
|
#define YYSTYPE oop |
|
|
|
|
|
|
|
#define _do_types(_) \ |
|
|
|
_(Undefined) _(Input) _(Integer) _(Float) _(Symbol) _(Pair) _(String) _(Array) \ |
|
|
|
_(Closure) _(Call) \ |
|
|
|
_(Block) _(Unary) _(Binary) _(Cast) _(While) _(For) _(If) _(Return) _(Continue) _(Break) \ |
|
|
|
_(Type) _(Struct) \ |
|
|
|
_(VarDecls) _(FunDefn) \ |
|
|
|
_(Scope) _(TypeName) _(Variable) _(Constant) _(Function) _(Primitive) |
|
|
|
|
|
|
|
|
|
|
|
typedef enum { |
|
|
|
Undefined, Input, Integer, Float, Symbol, Pair, String, Array, |
|
|
|
Primitive, Closure, Function, Call, |
|
|
|
Block, Unary, Binary, Cast, While, For, If, Return, Continue, Break, |
|
|
|
Type, Struct, |
|
|
|
VarDecls, FunDefn, |
|
|
|
# define _(X) X, |
|
|
|
_do_types(_) |
|
|
|
# undef _ |
|
|
|
} type_t; |
|
|
|
|
|
|
|
typedef enum { NEG, NOT, COM, DEREF, REF, PREINC, PREDEC, POSTINC, POSTDEC } unary_t; |
|
|
@ -75,9 +84,7 @@ struct Symbol { type_t _type; char *name; oop value; }; |
|
|
|
struct Pair { type_t _type; oop head, tail; }; |
|
|
|
struct String { type_t _type; int size; char *elements; }; |
|
|
|
struct Array { type_t _type; int size; oop *elements; }; |
|
|
|
struct Primitive { type_t _type; prim_t function; char *name; }; |
|
|
|
struct Closure { type_t _type; oop function, environment; }; |
|
|
|
struct Function { type_t _type; oop parameters, body, *code; }; |
|
|
|
struct Call { type_t _type; oop function, arguments; }; |
|
|
|
struct Block { type_t _type; oop statements; }; |
|
|
|
struct Unary { type_t _type; unary_t operator; oop rhs; }; |
|
|
@ -96,6 +103,13 @@ struct Struct { type_t _type; oop tag, members; }; |
|
|
|
struct VarDecls { type_t _type; oop type, declarations, variables; }; |
|
|
|
struct FunDefn { type_t _type; oop type, name, parameters, body; }; |
|
|
|
|
|
|
|
struct Scope { type_t _type; oop names, types, values; }; |
|
|
|
struct TypeName { type_t _type; oop name, type; }; |
|
|
|
struct Variable { type_t _type; oop name, type, value; }; |
|
|
|
struct Constant { type_t _type; oop name, type, value; }; |
|
|
|
struct Function { type_t _type; oop name, type, parameters, body, *code; }; |
|
|
|
struct Primitive { type_t _type; oop name; prim_t function; }; |
|
|
|
|
|
|
|
union Object |
|
|
|
{ |
|
|
|
type_t _type; |
|
|
@ -108,7 +122,6 @@ union Object |
|
|
|
struct Array Array; |
|
|
|
struct Primitive Primitive; |
|
|
|
struct Closure Closure; |
|
|
|
struct Function Function; |
|
|
|
struct Call Call; |
|
|
|
struct Block Block; |
|
|
|
struct Unary Unary; |
|
|
@ -124,6 +137,11 @@ union Object |
|
|
|
struct Struct Struct; |
|
|
|
struct VarDecls VarDecls; |
|
|
|
struct FunDefn FunDefn; |
|
|
|
struct Scope Scope; |
|
|
|
struct TypeName TypeName; |
|
|
|
struct Variable Variable; |
|
|
|
struct Constant Constant; |
|
|
|
struct Function Function; |
|
|
|
}; |
|
|
|
|
|
|
|
int opt_O = 0; // optimise (use VM) |
|
|
@ -145,6 +163,45 @@ oop _new(size_t size, type_t type) |
|
|
|
|
|
|
|
#define new(TYPE) _new(sizeof(struct TYPE), TYPE) |
|
|
|
|
|
|
|
#define CTOR0(Type) \ |
|
|
|
oop new##Type(void) { \ |
|
|
|
return new(Type); \ |
|
|
|
} |
|
|
|
|
|
|
|
#define CTOR1(Type, A) \ |
|
|
|
oop new##Type(oop A) { \ |
|
|
|
oop obj = new(Type); \ |
|
|
|
obj->Type.A = A; \ |
|
|
|
return obj; \ |
|
|
|
} |
|
|
|
|
|
|
|
#define CTOR2(Type, A, B) \ |
|
|
|
oop new##Type(oop A, oop B) { \ |
|
|
|
oop obj = new(Type); \ |
|
|
|
obj->Type.A = A; \ |
|
|
|
obj->Type.B = B; \ |
|
|
|
return obj; \ |
|
|
|
} |
|
|
|
|
|
|
|
#define CTOR3(Type, A, B, C) \ |
|
|
|
oop new##Type(oop A, oop B, oop C) { \ |
|
|
|
oop obj = new(Type); \ |
|
|
|
obj->Type.A = A; \ |
|
|
|
obj->Type.B = B; \ |
|
|
|
obj->Type.C = C; \ |
|
|
|
return obj; \ |
|
|
|
} |
|
|
|
|
|
|
|
#define CTOR4(Type, A, B, C, D) \ |
|
|
|
oop new##Type(oop A, oop B, oop C, oop D) { \ |
|
|
|
oop obj = new(Type); \ |
|
|
|
obj->Type.A = A; \ |
|
|
|
obj->Type.B = B; \ |
|
|
|
obj->Type.C = C; \ |
|
|
|
obj->Type.D = D; \ |
|
|
|
return obj; \ |
|
|
|
} |
|
|
|
|
|
|
|
oop newInteger(long value) |
|
|
|
{ |
|
|
|
# if TAGINT |
|
|
@ -173,6 +230,17 @@ oop newFloat(double value) |
|
|
|
# endif |
|
|
|
} |
|
|
|
|
|
|
|
char *typeName(type_t type) |
|
|
|
{ |
|
|
|
static char *typeNames[] = { |
|
|
|
# define _(X) #X, |
|
|
|
_do_types(_) |
|
|
|
# undef _ |
|
|
|
}; |
|
|
|
if (type < 0 || type >= indexableSize(typeNames)) fatal("unknown type %d", type); |
|
|
|
return typeNames[type]; |
|
|
|
} |
|
|
|
|
|
|
|
type_t getType(oop obj) |
|
|
|
{ |
|
|
|
# if TAGINT |
|
|
@ -184,6 +252,8 @@ type_t getType(oop obj) |
|
|
|
return obj->_type; |
|
|
|
} |
|
|
|
|
|
|
|
char *getTypeName(oop obj) { return typeName(getType(obj)); } |
|
|
|
|
|
|
|
int is(type_t type, oop obj) { return type == getType(obj); } |
|
|
|
|
|
|
|
oop _check(oop obj, type_t type, char *file, int line) |
|
|
@ -280,13 +350,7 @@ oop intern(char *name) |
|
|
|
return sym; |
|
|
|
} |
|
|
|
|
|
|
|
oop newPair(oop head, oop tail) |
|
|
|
{ |
|
|
|
oop obj = new(Pair); |
|
|
|
obj->Pair.head = head; |
|
|
|
obj->Pair.tail = tail; |
|
|
|
return obj; |
|
|
|
} |
|
|
|
CTOR2(Pair, head, tail); |
|
|
|
|
|
|
|
oop head(oop pair) { return get(pair, Pair,head); } |
|
|
|
oop tail(oop pair) { return get(pair, Pair,tail); } |
|
|
@ -345,53 +409,43 @@ oop Array_append(oop array, oop element) |
|
|
|
return elements[size] = element; |
|
|
|
} |
|
|
|
|
|
|
|
oop Array_set(oop array, int index, oop element) |
|
|
|
oop newArrayWith(oop a) |
|
|
|
{ |
|
|
|
oop *elements = get(array, Array,elements); |
|
|
|
int size = get(array, Array,size); |
|
|
|
if (index >= size) fatal("array index %d out of bounds %d", index, size); |
|
|
|
return elements[index] = element; |
|
|
|
} |
|
|
|
|
|
|
|
oop newPrimitive(prim_t function, char *name) |
|
|
|
{ |
|
|
|
oop obj = new(Primitive); |
|
|
|
obj->Primitive.function = function; |
|
|
|
obj->Primitive.name = name; |
|
|
|
oop obj = newArray(); |
|
|
|
Array_append(obj, a); |
|
|
|
return obj; |
|
|
|
} |
|
|
|
|
|
|
|
oop newClosure(oop function, oop environment) |
|
|
|
oop Array_last(oop array) |
|
|
|
{ |
|
|
|
oop obj = new(Closure); |
|
|
|
obj->Closure.function = function; |
|
|
|
obj->Closure.environment = environment; |
|
|
|
return obj; |
|
|
|
int size = get(array, Array,size); |
|
|
|
oop *elts = get(array, Array,elements); |
|
|
|
assert(size > 0); |
|
|
|
return elts[size - 1]; |
|
|
|
} |
|
|
|
|
|
|
|
oop newFunction(oop parameters, oop body) |
|
|
|
oop Array_popLast(oop array) |
|
|
|
{ |
|
|
|
oop obj = new(Function); |
|
|
|
obj->Function.parameters = parameters; |
|
|
|
obj->Function.body = body; |
|
|
|
obj->Function.code = 0; |
|
|
|
return obj; |
|
|
|
int size = get(array, Array,size); |
|
|
|
oop *elts = get(array, Array,elements); |
|
|
|
assert(size > 0); |
|
|
|
oop last = elts[--size]; |
|
|
|
elts[size] = nil; |
|
|
|
set(array, Array,size, size); |
|
|
|
return last; |
|
|
|
} |
|
|
|
|
|
|
|
oop newCall(oop function, oop arguments) |
|
|
|
oop Array_set(oop array, int index, oop element) |
|
|
|
{ |
|
|
|
oop obj = new(Call); |
|
|
|
obj->Call.function = function; |
|
|
|
obj->Call.arguments = arguments; |
|
|
|
return obj; |
|
|
|
oop *elements = get(array, Array,elements); |
|
|
|
int size = get(array, Array,size); |
|
|
|
if (index >= size) fatal("array index %d out of bounds %d", index, size); |
|
|
|
return elements[index] = element; |
|
|
|
} |
|
|
|
|
|
|
|
oop newBlock(oop statements) |
|
|
|
{ |
|
|
|
oop obj = new(Block); |
|
|
|
obj->Block.statements = statements; |
|
|
|
return obj; |
|
|
|
} |
|
|
|
CTOR2(Closure, function, environment); |
|
|
|
CTOR2(Call, function, arguments); |
|
|
|
CTOR1(Block, statements); |
|
|
|
|
|
|
|
oop newUnary(unary_t operator, oop operand) |
|
|
|
{ |
|
|
@ -410,107 +464,120 @@ oop newBinary(binary_t operator, oop lhs, oop rhs) |
|
|
|
return obj; |
|
|
|
} |
|
|
|
|
|
|
|
oop newCast(oop type, oop declarator, oop rhs) |
|
|
|
{ |
|
|
|
oop obj = new(Cast); |
|
|
|
obj->Cast.type = type; |
|
|
|
obj->Cast.declarator = declarator; |
|
|
|
obj->Cast.rhs = rhs; |
|
|
|
return obj; |
|
|
|
} |
|
|
|
CTOR3(Cast, type, declarator, rhs); |
|
|
|
CTOR2(While, condition, expression); |
|
|
|
CTOR4(For, initialiser, condition, update, body); |
|
|
|
CTOR3(If, condition, consequent, alternate); |
|
|
|
CTOR1(Return, value); |
|
|
|
CTOR0(Continue); |
|
|
|
CTOR1(Break, value); |
|
|
|
|
|
|
|
void println(oop obj); |
|
|
|
|
|
|
|
oop newWhile(oop condition, oop expression) |
|
|
|
oop newType(char *name) |
|
|
|
{ |
|
|
|
oop obj = new(While); |
|
|
|
obj->While.condition = condition; |
|
|
|
obj->While.expression = expression; |
|
|
|
oop obj = new(Type); |
|
|
|
obj->Type.name = name; |
|
|
|
return obj; |
|
|
|
} |
|
|
|
|
|
|
|
oop newFor(oop initialiser, oop condition, oop update, oop body) |
|
|
|
oop Type_void = 0; |
|
|
|
oop Type_char = 0; |
|
|
|
oop Type_int = 0; |
|
|
|
|
|
|
|
CTOR2(Struct, tag, members); |
|
|
|
|
|
|
|
oop newVarDecls(oop type, oop declaration) |
|
|
|
{ |
|
|
|
oop obj = new(For); |
|
|
|
obj->For.initialiser = initialiser; |
|
|
|
obj->For.condition = condition; |
|
|
|
obj->For.update = update; |
|
|
|
obj->For.body = body; |
|
|
|
oop obj = new(VarDecls); |
|
|
|
obj->VarDecls.type = type; |
|
|
|
obj->VarDecls.declarations = newArray(); |
|
|
|
obj->VarDecls.variables = newArray(); |
|
|
|
Array_append(obj->VarDecls.declarations, declaration); |
|
|
|
return obj; |
|
|
|
} |
|
|
|
|
|
|
|
oop newIf(oop condition, oop consequent, oop alternate) |
|
|
|
void VarDecls_append(oop vd, oop declaration) |
|
|
|
{ |
|
|
|
oop obj = new(If); |
|
|
|
obj->If.condition = condition; |
|
|
|
obj->If.consequent = consequent; |
|
|
|
obj->If.alternate = alternate; |
|
|
|
return obj; |
|
|
|
Array_append(get(vd, VarDecls,declarations), declaration); |
|
|
|
} |
|
|
|
|
|
|
|
oop newReturn(oop value) |
|
|
|
CTOR4(FunDefn, type, name, parameters, body); |
|
|
|
|
|
|
|
oop newScope(void) |
|
|
|
{ |
|
|
|
oop obj = new(Return); |
|
|
|
obj->Return.value = value; |
|
|
|
oop obj = new(Scope); |
|
|
|
obj->Scope.names = newArray(); |
|
|
|
obj->Scope.types = newArray(); |
|
|
|
obj->Scope.values = newArray(); |
|
|
|
return obj; |
|
|
|
} |
|
|
|
|
|
|
|
oop newContinue(void) |
|
|
|
int Scope_find(oop scope, oop name) |
|
|
|
{ |
|
|
|
return new(Continue); |
|
|
|
oop names = get(scope, Scope,names); |
|
|
|
int size = get(names, Array,size); |
|
|
|
oop *elts = get(names, Array,elements); |
|
|
|
for (int i = 0; i < size; ++i) |
|
|
|
if (name == elts[i]) |
|
|
|
return i; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
oop newBreak(oop value) |
|
|
|
oop scopes = 0; |
|
|
|
|
|
|
|
void Scope_begin(void) |
|
|
|
{ |
|
|
|
oop obj = new(Break); |
|
|
|
obj->Break.value = value; |
|
|
|
return obj; |
|
|
|
Array_append(scopes, newScope()); |
|
|
|
} |
|
|
|
|
|
|
|
void println(oop obj); |
|
|
|
|
|
|
|
oop newType(char *name) |
|
|
|
void Scope_end(void) |
|
|
|
{ |
|
|
|
oop obj = new(Type); |
|
|
|
obj->Type.name = name; |
|
|
|
return obj; |
|
|
|
Array_popLast(scopes); |
|
|
|
} |
|
|
|
|
|
|
|
oop Type_void = 0; |
|
|
|
oop Type_char = 0; |
|
|
|
oop Type_int = 0; |
|
|
|
|
|
|
|
oop newStruct(oop tag, oop members) |
|
|
|
oop Scope_lookup(oop name) |
|
|
|
{ |
|
|
|
oop obj = new(Struct); |
|
|
|
obj->Struct.tag = tag; |
|
|
|
obj->Struct.members = members; |
|
|
|
return obj; |
|
|
|
int n = get(scopes, Array,size); |
|
|
|
oop *elts = get(scopes, Array,elements); |
|
|
|
while (n--) { |
|
|
|
oop scope = elts[n]; |
|
|
|
int i = Scope_find(scope, name); |
|
|
|
if (i >= 0) return get(get(scope, Scope,values), Array,elements)[i]; |
|
|
|
} |
|
|
|
return 0; // NOTE: 0 means undefined (rather than nil, which means uninitialised) |
|
|
|
} |
|
|
|
|
|
|
|
oop newVarDecls(oop type, oop declaration) |
|
|
|
CTOR2(TypeName, name, type); |
|
|
|
CTOR3(Variable, name, type, value); |
|
|
|
CTOR3(Constant, name, type, value); |
|
|
|
|
|
|
|
oop newFunction(oop name, oop type, oop parameters, oop body) |
|
|
|
{ |
|
|
|
oop obj = new(VarDecls); |
|
|
|
obj->VarDecls.type = type; |
|
|
|
obj->VarDecls.declarations = newArray(); |
|
|
|
obj->VarDecls.variables = newArray(); |
|
|
|
Array_append(obj->VarDecls.declarations, declaration); |
|
|
|
oop obj = new(Function); |
|
|
|
obj->Function.name = name; |
|
|
|
obj->Function.type = type; |
|
|
|
obj->Function.parameters = parameters; |
|
|
|
obj->Function.body = body; |
|
|
|
obj->Function.code = 0; |
|
|
|
return obj; |
|
|
|
} |
|
|
|
|
|
|
|
void VarDecls_append(oop vd, oop declaration) |
|
|
|
oop newPrimitive(oop name, prim_t function) |
|
|
|
{ |
|
|
|
Array_append(get(vd, VarDecls,declarations), declaration); |
|
|
|
} |
|
|
|
oop obj = new(Primitive); |
|
|
|
obj->Primitive.name = name; |
|
|
|
obj->Primitive.function = function; |
|
|
|
|
|
|
|
oop newFunDefn(oop type, oop name, oop parameters, oop body) |
|
|
|
{ |
|
|
|
oop obj = new(FunDefn); |
|
|
|
obj->FunDefn.type = type; |
|
|
|
obj->FunDefn.name = name; |
|
|
|
obj->FunDefn.parameters = parameters; |
|
|
|
obj->FunDefn.body = body; |
|
|
|
return obj; |
|
|
|
} |
|
|
|
|
|
|
|
#undef CTOR4 |
|
|
|
#undef CTOR3 |
|
|
|
#undef CTOR2 |
|
|
|
#undef CTOR1 |
|
|
|
#undef CTOR0 |
|
|
|
|
|
|
|
void printiln(oop obj, int indent) |
|
|
|
{ |
|
|
|
printf("%*s", indent*2, ""); |
|
|
@ -551,7 +618,7 @@ void printiln(oop obj, int indent) |
|
|
|
break; |
|
|
|
} |
|
|
|
case Primitive: { |
|
|
|
printf("PRIMITIVE<%s>\n", get(obj, Primitive,name)); |
|
|
|
printf("PRIMITIVE<%s>\n", symbolName(get(obj, Primitive,name))); |
|
|
|
break; |
|
|
|
} |
|
|
|
case Closure: { |
|
|
@ -559,15 +626,9 @@ void printiln(oop obj, int indent) |
|
|
|
printiln(get(obj, Closure,function), indent+1); |
|
|
|
break; |
|
|
|
} |
|
|
|
case Function: { |
|
|
|
printf("FUNCTION\n"); |
|
|
|
printiln(get(obj, Function,parameters), indent+1); |
|
|
|
printiln(get(obj, Function,body), indent+1); |
|
|
|
break; |
|
|
|
} |
|
|
|
case Call: { |
|
|
|
printf("CALL\n"); |
|
|
|
printiln(get(obj, Call,function), indent+1); |
|
|
|
printiln(get(obj, Call,function ), indent+1); |
|
|
|
printiln(get(obj, Call,arguments), indent+1); |
|
|
|
break; |
|
|
|
} |
|
|
@ -661,7 +722,7 @@ void printiln(oop obj, int indent) |
|
|
|
break; |
|
|
|
} |
|
|
|
case Type: { |
|
|
|
printf("Type %s\n", get(obj, Type,name)); |
|
|
|
printf("<%s>\n", get(obj, Type,name)); |
|
|
|
break; |
|
|
|
} |
|
|
|
case Struct: { |
|
|
@ -685,6 +746,38 @@ void printiln(oop obj, int indent) |
|
|
|
printiln(get(obj, FunDefn,body ), indent+1); |
|
|
|
break; |
|
|
|
} |
|
|
|
case Scope: { |
|
|
|
printf("SCOPE\n"); |
|
|
|
printiln(get(obj, Scope,names), indent+1); |
|
|
|
break; |
|
|
|
} |
|
|
|
case TypeName: { |
|
|
|
printf("TypeName\n"); |
|
|
|
printiln(get(obj, TypeName,name), indent+1); |
|
|
|
printiln(get(obj, TypeName,type), indent+1); |
|
|
|
break; |
|
|
|
} |
|
|
|
case Variable: { |
|
|
|
printf("Variable\n"); |
|
|
|
printiln(get(obj, Variable,name ), indent+1); |
|
|
|
printiln(get(obj, Variable,type ), indent+1); |
|
|
|
printiln(get(obj, Variable,value), indent+1); |
|
|
|
break; |
|
|
|
} |
|
|
|
case Constant: { |
|
|
|
printf("Constant\n"); |
|
|
|
printiln(get(obj, Constant,name ), indent+1); |
|
|
|
printiln(get(obj, Constant,type ), indent+1); |
|
|
|
printiln(get(obj, Constant,value), indent+1); |
|
|
|
break; |
|
|
|
}; |
|
|
|
case Function: { |
|
|
|
printf("Function\n"); |
|
|
|
printiln(get(obj, Function,type ), indent+1); |
|
|
|
printiln(get(obj, Function,parameters), indent+1); |
|
|
|
printiln(get(obj, Function,body ), indent+1); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -752,7 +845,8 @@ void expected(oop where, char *what) |
|
|
|
|
|
|
|
%} |
|
|
|
|
|
|
|
start = - ( include { yysval = 0 } |
|
|
|
start = - ( interp { yysval = 0 } |
|
|
|
| include { yysval = 0 } |
|
|
|
| x:tldecl { yysval = x } |
|
|
|
| !. { yysval = 0 } |
|
|
|
| e:error { expected(e, "declaration") } |
|
|
@ -760,6 +854,8 @@ start = - ( include { yysval = 0 } |
|
|
|
|
|
|
|
error = < (![\n\r] .)* > { $$ = newStringWith(yytext) } |
|
|
|
|
|
|
|
interp = HASH PLING (![\n\r] .)* |
|
|
|
|
|
|
|
include = HASH INCLUDE ( |
|
|
|
'<' < [a-zA-Z0-9_.]* > '>' @{ pushInput(yytext, sysOpen(yytext)) } |
|
|
|
| '"' < [a-zA-Z0-9_.]* > '"' @{ pushInput(yytext, usrOpen(yytext)) } |
|
|
@ -798,9 +894,9 @@ ddector = ( LPAREN d:decltor RPAREN |
|
|
|
)* { $$ = d } |
|
|
|
|
|
|
|
params = LPAREN a:mkArray |
|
|
|
( p:pdecl { Array_append(a, p) } |
|
|
|
( COMMA p:pdecl { Array_append(a, p) } |
|
|
|
)* )? RPAREN { $$ = a } |
|
|
|
( p:pdecl { Array_append(a, p) } |
|
|
|
( COMMA p:pdecl { Array_append(a, p) } |
|
|
|
)* )? RPAREN { $$ = a } |
|
|
|
|
|
|
|
pdecl = t:tname d:decltor { $$ = newVarDecls(t, d) } |
|
|
|
|
|
|
@ -1045,14 +1141,6 @@ oop nlrPop(void) |
|
|
|
|
|
|
|
#define nlrReturn(TYPE, VAL) ((nlrValue = (VAL), longjmp(nlrStack[nlrCount-1], TYPE))) |
|
|
|
|
|
|
|
oop define(oop lhs, oop rhs, oop env) |
|
|
|
{ |
|
|
|
oop kv = assoc(env, lhs); |
|
|
|
if (nil != kv) return set(kv, Pair,tail, rhs); // local |
|
|
|
if (!is(Symbol, lhs)) fatal("cannot assign to non-symbol type %d", getType(lhs)); |
|
|
|
return set(lhs, Symbol,value, rhs); |
|
|
|
} |
|
|
|
|
|
|
|
#define IBINOP(L, OP, R) newInteger(integerValue(L) OP integerValue(R)) |
|
|
|
#define IRELOP(L, OP, R) (integerValue(L) OP integerValue(R) ? true : false) |
|
|
|
|
|
|
@ -1067,9 +1155,10 @@ oop eval(oop exp, oop env); |
|
|
|
|
|
|
|
oop apply(oop function, oop arguments, oop env) |
|
|
|
{ |
|
|
|
// printf("APPLY "); println(function); |
|
|
|
switch (getType(function)) { |
|
|
|
default: { |
|
|
|
fatal("object type %d is not callable", getType(function)); |
|
|
|
fatal("type %s is not callable", getTypeName(function)); |
|
|
|
} |
|
|
|
case Primitive: { |
|
|
|
return get(function, Primitive,function) |
|
|
@ -1077,54 +1166,156 @@ oop apply(oop function, oop arguments, oop env) |
|
|
|
get(arguments, Array,elements), |
|
|
|
env ); |
|
|
|
} |
|
|
|
case Closure: { |
|
|
|
oop env2 = get(function, Closure,environment); |
|
|
|
function = get(function, Closure,function); |
|
|
|
case Function: { |
|
|
|
oop parameters = get(function, Function,parameters); |
|
|
|
int nParams = get(parameters, Array,size); |
|
|
|
int nArgs = get(arguments, Array,size); |
|
|
|
oop body = get(function, Function,body); |
|
|
|
int nParams = get(parameters, Array,size); |
|
|
|
int nArgs = get(arguments, Array,size); |
|
|
|
if (nParams != nArgs) |
|
|
|
fatal("wrong number of arguments, expected %d got %d", nParams, nArgs); |
|
|
|
oop *params = get(parameters, Array,elements); |
|
|
|
oop *args = get(arguments, Array,elements); |
|
|
|
for (int i = nArgs; i--;) { |
|
|
|
oop key = params[i]; |
|
|
|
oop val = eval(args[i], env); |
|
|
|
env2 = newPair(newPair(key, val), env2); |
|
|
|
} |
|
|
|
oop body = get(function, Function,body); |
|
|
|
oop result = nil; |
|
|
|
Scope_begin(); |
|
|
|
switch (nlrPush()) { // longjmp occurred |
|
|
|
case NLR_INIT: break; |
|
|
|
case NLR_RETURN: return nlrPop(); |
|
|
|
case NLR_CONTINUE: fatal("continue outside loop"); |
|
|
|
case NLR_BREAK: fatal("break outside loop"); |
|
|
|
} |
|
|
|
result = eval(body, env2); |
|
|
|
oop result = eval(body, nil); |
|
|
|
nlrPop(); |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
oop makeType(oop base, oop decl); |
|
|
|
|
|
|
|
oop makeTypes(oop declarations) |
|
|
|
{ |
|
|
|
int size = get(declarations, Array,size); |
|
|
|
oop *elts = get(declarations, Array,elements); |
|
|
|
oop types = newArray(); |
|
|
|
// printf("MAKE TYPES\n"); |
|
|
|
for (int i = 0; i < size; ++i) { |
|
|
|
oop vdecl = elts[i]; |
|
|
|
oop type = get(vdecl, VarDecls,type); |
|
|
|
oop decls = get(vdecl, VarDecls,declarations); |
|
|
|
int dsize = get(decls, Array,size); |
|
|
|
oop *delts = get(decls, Array,elements); |
|
|
|
for (int j = 0; j < dsize; ++j) |
|
|
|
Array_append(types, makeType(type, delts[j])); |
|
|
|
} |
|
|
|
return types; |
|
|
|
} |
|
|
|
|
|
|
|
oop makeType(oop base, oop decl) |
|
|
|
{ |
|
|
|
// printf("MAKE TYPE "); println(base); |
|
|
|
// printf(" "); println(decl); |
|
|
|
switch (getType(decl)) { |
|
|
|
case Undefined: |
|
|
|
case Symbol: return base; |
|
|
|
case Unary: { |
|
|
|
switch (get(decl, Unary,operator)) { |
|
|
|
case DEREF: return newUnary(DEREF, makeType(base, get(decl, Unary,rhs))); |
|
|
|
default: break; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case Call: { |
|
|
|
oop func = get(decl, Call,function); |
|
|
|
oop params = get(decl, Call,arguments); |
|
|
|
return newCall(makeType(base, func), makeTypes(params)); |
|
|
|
} |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
printf("cannot make type from delcaration: "); |
|
|
|
println(decl); |
|
|
|
exit(1); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
oop makeName(oop decl) |
|
|
|
{ |
|
|
|
// printf("MAKE NAME "); println(decl); |
|
|
|
switch (getType(decl)) { |
|
|
|
case Undefined: |
|
|
|
case Symbol: return decl; |
|
|
|
case Unary: { |
|
|
|
switch (get(decl, Unary,operator)) { |
|
|
|
case DEREF: return makeName(get(decl, Unary,rhs)); |
|
|
|
default: break; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case Call: { |
|
|
|
return makeName(get(decl, Call,function)); |
|
|
|
} |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
printf("cannot make name from delcaration: "); |
|
|
|
println(decl); |
|
|
|
exit(1); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void define(oop name, oop value) |
|
|
|
{ |
|
|
|
oop scope = Array_last(scopes); |
|
|
|
int index = Scope_find(scope, name); |
|
|
|
if (index >= 0) fatal("name '%s' redefined\n", get(name, Symbol,name)); |
|
|
|
Array_append(get(scope, Scope,names ), name ); |
|
|
|
Array_append(get(scope, Scope,values), value); |
|
|
|
// printf("NAME = " ); println(name); |
|
|
|
// printf("VALU = " ); println(value); |
|
|
|
// printf(" => "); println(scope); |
|
|
|
} |
|
|
|
|
|
|
|
void defineTypeName(oop name, oop type) |
|
|
|
{ |
|
|
|
define(name, newTypeName(name, type)); |
|
|
|
} |
|
|
|
|
|
|
|
void defineVariable(oop name, oop type, oop value) |
|
|
|
{ |
|
|
|
define(name, newVariable(name, type, value)); |
|
|
|
} |
|
|
|
|
|
|
|
void defineConstant(oop name, oop type, oop value) |
|
|
|
{ |
|
|
|
define(name, newConstant(name, type, value)); |
|
|
|
} |
|
|
|
|
|
|
|
void defineFunction(oop name, oop type, oop parameters, oop body) |
|
|
|
{ |
|
|
|
define(name, newFunction(name, type, parameters, body)); |
|
|
|
} |
|
|
|
|
|
|
|
void definePrimitive(oop name, prim_t function) |
|
|
|
{ |
|
|
|
define(name, newPrimitive(name, function)); |
|
|
|
} |
|
|
|
|
|
|
|
oop eval(oop exp, oop env) |
|
|
|
{ |
|
|
|
// printf("EVAL "); println(exp); |
|
|
|
switch (getType(exp)) { |
|
|
|
case Undefined: assert(!"this cannot happen"); |
|
|
|
case Input: assert(!"this cannot happen"); |
|
|
|
case Integer: return exp; |
|
|
|
case Float: return exp; |
|
|
|
case Symbol: { |
|
|
|
oop kv = assoc(env, exp); |
|
|
|
if (nil == kv) return get(exp, Symbol,value); // global value stored in symbol |
|
|
|
return tail(kv); // local value stored in association |
|
|
|
oop value = Scope_lookup(exp); |
|
|
|
if (!value) fatal("'%s' is undefined\n", get(exp, Symbol,name)); |
|
|
|
if (isNil(value)) fatal("'%s' is uninitialised\n", get(exp, Symbol,name)); |
|
|
|
return value; |
|
|
|
} |
|
|
|
case Pair: assert(!"this cannot happen"); |
|
|
|
case String: return exp; |
|
|
|
case Array: assert(!"this cannot happen"); |
|
|
|
case Primitive: return exp; |
|
|
|
case Closure: return exp; |
|
|
|
case Function: return newClosure(exp, env); |
|
|
|
case Call: { |
|
|
|
oop fun = eval(get(exp, Call,function), env); |
|
|
|
oop args = get(exp, Call,arguments); |
|
|
@ -1164,8 +1355,8 @@ oop eval(oop exp, oop env) |
|
|
|
case LAND: return isFalse(eval(lhs, env)) ? false : eval(rhs, env); |
|
|
|
case LOR: return isTrue (eval(lhs, env)) ? true : eval(rhs, env); |
|
|
|
case ASSIGN: { |
|
|
|
rhs = eval(rhs, env); |
|
|
|
return define(lhs, rhs, env); |
|
|
|
assert(!"unimplemented"); |
|
|
|
return nil; |
|
|
|
} |
|
|
|
default: { |
|
|
|
lhs = eval(lhs, env); |
|
|
@ -1270,7 +1461,20 @@ oop eval(oop exp, oop env) |
|
|
|
case Type: assert(!"unimplemented"); break; |
|
|
|
case Struct: assert(!"unimplemented"); break; |
|
|
|
case VarDecls: assert(!"unimplemented"); break; |
|
|
|
case FunDefn: assert(!"unimplemented"); break; |
|
|
|
case FunDefn: { |
|
|
|
oop type = get(exp, FunDefn,type ); |
|
|
|
oop name = get(exp, FunDefn,name ); |
|
|
|
oop parameters = get(exp, FunDefn,parameters); |
|
|
|
oop body = get(exp, FunDefn,body ); |
|
|
|
type = makeType(type, newCall(name, parameters)); |
|
|
|
defineFunction(name, type, parameters, body); |
|
|
|
return nil; |
|
|
|
} |
|
|
|
case Scope: break; |
|
|
|
case TypeName: break; |
|
|
|
case Variable: break; |
|
|
|
case Constant: break; |
|
|
|
case Function: return newClosure(exp, env); |
|
|
|
} |
|
|
|
assert(!"this cannot happen"); |
|
|
|
return 0; |
|
|
@ -1278,23 +1482,20 @@ oop eval(oop exp, oop env) |
|
|
|
|
|
|
|
// primitive functions |
|
|
|
|
|
|
|
oop prim_print(int argc, oop *argv, oop env) // array |
|
|
|
oop prim_printf(int argc, oop *argv, oop env) // array |
|
|
|
{ |
|
|
|
oop result = nil; |
|
|
|
for (int i = 0; i < argc; ++i) { |
|
|
|
result = eval(argv[i], env); |
|
|
|
println(result); |
|
|
|
if (argc < 1) fatal("printf: no format string"); |
|
|
|
oop format = argv[0]; |
|
|
|
if (!is(String, format)) fatal("printf: format is not a string"); |
|
|
|
char *fmt = get(format, String,elements); |
|
|
|
int size = get(format, String,size); |
|
|
|
int n = 0; |
|
|
|
for (int i = 0; i < size; ++i) { |
|
|
|
putchar(fmt[i]); |
|
|
|
++n; |
|
|
|
} |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
#include <sys/resource.h> |
|
|
|
|
|
|
|
oop prim_memsize(int argc, oop *argv, oop env) // array |
|
|
|
{ |
|
|
|
struct rusage ru; |
|
|
|
if (getrusage(RUSAGE_SELF, &ru) < 0) return nil; |
|
|
|
return newInteger(ru.ru_maxrss); |
|
|
|
return newInteger(n); |
|
|
|
} |
|
|
|
|
|
|
|
enum opcode_t { iHALT = 0, iPUSH, iPOP, |
|
|
@ -1574,13 +1775,6 @@ void compileOn(oop exp, oop program, oop cs, oop bs) |
|
|
|
case Array: assert(!"unimplemented"); |
|
|
|
case Primitive: EMITio(iPUSH, exp); return; |
|
|
|
case Closure: EMITio(iPUSH, exp); return; |
|
|
|
case Function: { |
|
|
|
assert(0 == get(exp, Function,code)); |
|
|
|
oop prog2 = compileFunction(get(exp, Function,body)); |
|
|
|
set(exp, Function,code, get(prog2, Array,elements)); |
|
|
|
EMITio(iCLOSE, exp); |
|
|
|
return; |
|
|
|
} |
|
|
|
case Call: { |
|
|
|
Object *args = get(exp, Call,arguments); |
|
|
|
int argc = get(args, Array,size); |
|
|
@ -1726,10 +1920,21 @@ void compileOn(oop exp, oop program, oop cs, oop bs) |
|
|
|
Array_append(bs, newInteger(L1)); |
|
|
|
return; |
|
|
|
} |
|
|
|
case Type: assert(!"unimplemented"); return; |
|
|
|
case Struct: assert(!"unimplemented"); return; |
|
|
|
case VarDecls: assert(!"unimplemented"); return; |
|
|
|
case FunDefn: assert(!"unimplemented"); return; |
|
|
|
case Type: assert(!"unimplemented"); return; |
|
|
|
case Struct: assert(!"unimplemented"); return; |
|
|
|
case VarDecls: assert(!"unimplemented"); return; |
|
|
|
case FunDefn: assert(!"unimplemented"); return; |
|
|
|
case Scope: assert(!"this cannot happen"); return; |
|
|
|
case TypeName: assert(!"unimplemented"); return; |
|
|
|
case Variable: assert(!"unimplemented"); return; |
|
|
|
case Constant: assert(!"unimplemented"); return; |
|
|
|
case Function: { |
|
|
|
assert(0 == get(exp, Function,code)); |
|
|
|
oop prog2 = compileFunction(get(exp, Function,body)); |
|
|
|
set(exp, Function,code, get(prog2, Array,elements)); |
|
|
|
EMITio(iCLOSE, exp); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -1758,7 +1963,7 @@ void replFile(char *name, FILE *file) |
|
|
|
while (input) { |
|
|
|
if (yyparse() && yysval) { |
|
|
|
if (opt_v > 1) println(yysval); |
|
|
|
if (0*!opt_x) { |
|
|
|
if (!opt_x) { |
|
|
|
oop result = nil; |
|
|
|
if (opt_O) { |
|
|
|
oop program = compile(yysval); |
|
|
@ -1797,8 +2002,10 @@ int main(int argc, char **argv) |
|
|
|
Type_char = newType("char"); |
|
|
|
Type_int = newType("int"); |
|
|
|
|
|
|
|
define(intern("print" ), newPrimitive(prim_print, "print" ), nil); |
|
|
|
define(intern("memsize"), newPrimitive(prim_memsize, "memsize"), nil); |
|
|
|
scopes = newArray(); |
|
|
|
Scope_begin(); |
|
|
|
|
|
|
|
definePrimitive(intern("printf"), prim_printf); |
|
|
|
|
|
|
|
int repls = 0; |
|
|
|
|
|
|
@ -1822,5 +2029,17 @@ int main(int argc, char **argv) |
|
|
|
|
|
|
|
if (!repls) replFile("stdin", stdin); |
|
|
|
|
|
|
|
return 0; |
|
|
|
oop args = newArray(); |
|
|
|
Array_append(args, newInteger(1)); |
|
|
|
Array_append(args, newStringWith("main")); |
|
|
|
|
|
|
|
oop result = eval(newCall(intern("main"), args), nil); |
|
|
|
|
|
|
|
if (!is(Integer, result)) { |
|
|
|
printf("\n=> "); |
|
|
|
println(result); |
|
|
|
fatal("main did not return an integer"); |
|
|
|
} |
|
|
|
|
|
|
|
return _integerValue(result); |
|
|
|
} |