Permalink
Browse files

Make arithmetic operators just primitive calls.

This also means multi-argument primitives now work.
  • Loading branch information...
1 parent d475606 commit a28634b46c933fb1a2973de7dd4fbc2583ca2644 @munificent committed Jun 19, 2012
View
@@ -224,4 +224,23 @@ namespace magpie
T* items_;
};
+ template <class T>
+ class ArrayView
+ {
+ public:
+ ArrayView(Array<T>& array, int start)
+ : array_(array),
+ start_(start)
+ {}
+
+ // Gets the item at the given index.
+ inline T& operator[] (int index)
+ {
+ return array_[start_ + index];
+ }
+
+ private:
+ Array<T>& array_;
+ int start_;
+ };
}
View
@@ -53,52 +53,48 @@ namespace magpie
// index of the exported variable in that module to load. Stores the value
// in slot C.
OP_GET_MODULE = 0x07,
-
- OP_ADD = 0x08, // R(C) = RC(A) + RC(B)
- OP_SUBTRACT = 0x09, // R(C) = RC(A) - RC(B)
- OP_MULTIPLY = 0x0a, // R(C) = RC(A) * RC(B)
- OP_DIVIDE = 0x0b, // R(C) = RC(A) / RC(B)
- OP_EQUAL = 0x0c, // R(C) = RC(A) == RC(B)
- OP_LESS_THAN = 0x0d, // R(C) = RC(A) < RC(B)
- OP_GREATER_THAN = 0x0e, // R(C) = RC(A) > RC(B)
- OP_NOT = 0x0f, // R(C) = RC(A) + RC(B)
+
+ OP_EQUAL = 0x08, // R(C) = RC(A) == RC(B)
+ OP_LESS_THAN = 0x09, // R(C) = RC(A) < RC(B)
+ OP_GREATER_THAN = 0x0a, // R(C) = RC(A) > RC(B)
+ OP_NOT = 0x0b, // R(C) = RC(A) + RC(B)
// Tests if the value in slot A is an instance of the type in slot B.
// Stores the result in slot C.
- OP_IS = 0x10,
+ OP_IS = 0x0c,
// Performs an unconditional jump. If A is 1, then the instruction pointer
// is moved forward by B. Otherwise, it is moved back by that amount.
- OP_JUMP = 0x11,
+ OP_JUMP = 0x0d,
- OP_JUMP_IF_FALSE = 0x12, // R(A) = test slot, B = offset
- OP_JUMP_IF_TRUE = 0x13, // R(A) = test slot, B = offset
+ OP_JUMP_IF_FALSE = 0x0e, // R(A) = test slot, B = offset
+ OP_JUMP_IF_TRUE = 0x0f, // R(A) = test slot, B = offset
// Invokes a top-level method. The index of the method in the global table
// is A. The arguments to the method are laid out in sequential slots
// starting at B. The number of slots needed is determined by the
// signature, so is not explicitly passed. The result will be stored in
// slot C when the method returns.
// TODO(bob): Tweak operands so that we can support more than 256 methods.
- OP_CALL = 0x14,
+ OP_CALL = 0x10,
// Exits the current method, returning slot A.
- OP_RETURN = 0x15,
+ OP_RETURN = 0x11,
// Throws the error object in slot A.
- OP_THROW = 0x16,
+ OP_THROW = 0x12,
// Registers a new catch handler. If an error is thrown before the
// subsequent OP_EXIT_TRY, then execution will jump to the associated catch
// block. Its code location is the location of the OP_ENTER_TRY + A.
- OP_ENTER_TRY = 0x17,
+ OP_ENTER_TRY = 0x13,
// Discards the previous OP_ENTER_TRY handler. This occurs when execution
// has proceeded past the block containing a catch clause.
- OP_EXIT_TRY = 0x18,
+ OP_EXIT_TRY = 0x14,
// Throws a NoMatchError if slot A is false.
- OP_TEST_MATCH = 0x19
+ OP_TEST_MATCH = 0x15
};
enum BuiltIn
@@ -202,10 +202,6 @@ namespace magpie
bool negate = false;
switch (expr.type())
{
- case TOKEN_PLUS: op = OP_ADD; break;
- case TOKEN_MINUS: op = OP_SUBTRACT; break;
- case TOKEN_STAR: op = OP_MULTIPLY; break;
- case TOKEN_SLASH: op = OP_DIVIDE; break;
case TOKEN_EQEQ: op = OP_EQUAL; break;
case TOKEN_NEQ: op = OP_EQUAL; negate = true; break;
case TOKEN_LT: op = OP_LESS_THAN; break;
View
@@ -36,11 +36,11 @@ namespace magpie
{ NULL, &Parser::binaryOp, PRECEDENCE_COMPARISON }, // TOKEN_GT
{ NULL, &Parser::binaryOp, PRECEDENCE_COMPARISON }, // TOKEN_LTE
{ NULL, &Parser::binaryOp, PRECEDENCE_COMPARISON }, // TOKEN_GTE
- { NULL, &Parser::binaryOp, PRECEDENCE_TERM }, // TOKEN_PLUS
- { NULL, &Parser::binaryOp, PRECEDENCE_TERM }, // TOKEN_MINUS
- { NULL, &Parser::binaryOp, PRECEDENCE_PRODUCT }, // TOKEN_STAR
- { NULL, &Parser::binaryOp, PRECEDENCE_PRODUCT }, // TOKEN_SLASH
- { NULL, &Parser::binaryOp, PRECEDENCE_PRODUCT }, // TOKEN_PERCENT
+ { NULL, &Parser::infixCall, PRECEDENCE_TERM }, // TOKEN_PLUS
+ { NULL, &Parser::infixCall, PRECEDENCE_TERM }, // TOKEN_MINUS
+ { NULL, &Parser::infixCall, PRECEDENCE_PRODUCT }, // TOKEN_STAR
+ { NULL, &Parser::infixCall, PRECEDENCE_PRODUCT }, // TOKEN_SLASH
+ { NULL, &Parser::infixCall, PRECEDENCE_PRODUCT }, // TOKEN_PERCENT
// Keywords.
{ NULL, &Parser::and_, PRECEDENCE_LOGICAL }, // TOKEN_AND
@@ -498,7 +498,16 @@ namespace magpie
// TODO(bob): Better position.
return new CallExpr(token->pos(), left, token->text(), right);
}
-
+
+ gc<Expr> Parser::infixCall(gc<Expr> left, gc<Token> token)
+ {
+ // TODO(bob): Support right-associative infix. Needs to do precedence
+ // - 1 here, to be right-assoc.
+ gc<Expr> right = parsePrecedence(expressions_[token->type()].precedence);
+
+ return new CallExpr(token->pos(), left, token->text(), right);
+ }
+
gc<Expr> Parser::infixRecord(gc<Expr> left, gc<Token> token)
{
Array<Field> fields;
View
@@ -65,6 +65,7 @@ namespace magpie
gc<Expr> assignment(gc<Expr> left, gc<Token> token);
gc<Expr> binaryOp(gc<Expr> left, gc<Token> token);
gc<Expr> call(gc<Expr> left, gc<Token> token);
+ gc<Expr> infixCall(gc<Expr> left, gc<Token> token);
gc<Expr> infixRecord(gc<Expr> left, gc<Token> token);
gc<Expr> is(gc<Expr> left, gc<Token> token);
gc<Expr> or_(gc<Expr> left, gc<Token> token);
View
@@ -144,54 +144,6 @@ namespace magpie
break;
}
- case OP_ADD:
- {
- gc<Object> a = loadSlotOrConstant(frame, GET_A(ins));
- gc<Object> b = loadSlotOrConstant(frame, GET_B(ins));
-
- // TODO(bob): Handle non-number types.
- double c = a->toNumber() + b->toNumber();
- gc<Object> num = new NumberObject(c);
- store(frame, GET_C(ins), num);
- break;
- }
-
- case OP_SUBTRACT:
- {
- gc<Object> a = loadSlotOrConstant(frame, GET_A(ins));
- gc<Object> b = loadSlotOrConstant(frame, GET_B(ins));
-
- // TODO(bob): Handle non-number types.
- double c = a->toNumber() - b->toNumber();
- gc<Object> num = new NumberObject(c);
- store(frame, GET_C(ins), num);
- break;
- }
-
- case OP_MULTIPLY:
- {
- gc<Object> a = loadSlotOrConstant(frame, GET_A(ins));
- gc<Object> b = loadSlotOrConstant(frame, GET_B(ins));
-
- // TODO(bob): Handle non-number types.
- double c = a->toNumber() * b->toNumber();
- gc<Object> num = new NumberObject(c);
- store(frame, GET_C(ins), num);
- break;
- }
-
- case OP_DIVIDE:
- {
- gc<Object> a = loadSlotOrConstant(frame, GET_A(ins));
- gc<Object> b = loadSlotOrConstant(frame, GET_B(ins));
-
- // TODO(bob): Handle non-number types.
- double c = a->toNumber() / b->toNumber();
- gc<Object> num = new NumberObject(c);
- store(frame, GET_C(ins), num);
- break;
- }
-
case OP_EQUAL:
{
gc<Object> a = loadSlotOrConstant(frame, GET_A(ins));
@@ -337,9 +289,8 @@ namespace magpie
Primitive primitive = method->primitive();
if (primitive != NULL) {
- // TODO(bob): Hack. Support multi-arg primitives.
- gc<Object> arg = load(frame, firstArg);
- gc<Object> result = primitive(arg);
+ ArrayView<gc<Object> > args(stack_, frame.stackStart + firstArg);
+ gc<Object> result = primitive(args);
store(frame, GET_C(ins), result);
} else {
int stackStart = frame.stackStart + firstArg;
View
@@ -70,23 +70,7 @@ namespace magpie
case OP_GET_MODULE:
cout << "GET_MODULE import " << GET_A(ins) << ", var " << GET_B(ins) << " -> " << GET_C(ins);
break;
-
- case OP_ADD:
- cout << "ADD " << GET_A(ins) << " + " << GET_B(ins) << " -> " << GET_C(ins);
- break;
-
- case OP_SUBTRACT:
- cout << "SUBTRACT " << GET_A(ins) << " - " << GET_B(ins) << " -> " << GET_C(ins);
- break;
-
- case OP_MULTIPLY:
- cout << "MULTIPLY " << GET_A(ins) << " - " << GET_B(ins) << " -> " << GET_C(ins);
- break;
-
- case OP_DIVIDE:
- cout << "DIVIDE " << GET_A(ins) << " - " << GET_B(ins) << " -> " << GET_C(ins);
- break;
-
+
case OP_EQUAL:
cout << "EQUAL " << GET_A(ins) << " == " << GET_B(ins) << " -> " << GET_C(ins);
break;
View
@@ -11,7 +11,7 @@ namespace magpie
class Module;
class Object;
- typedef gc<Object> (*Primitive)(gc<Object> arg);
+ typedef gc<Object> (*Primitive)(ArrayView<gc<Object> >& args);
class Method : public Managed
{
View
@@ -5,9 +5,36 @@ namespace magpie
{
PRIMITIVE(print)
{
- std::cout << arg << std::endl;
- // TODO(bob): Is this what print() should return?
- return arg;
+ std::cout << args[0] << std::endl;
+ return args[0];
+ }
+
+ PRIMITIVE(add)
+ {
+ // TODO(bob): Handle non-number types.
+ double c = args[0]->toNumber() + args[1]->toNumber();
+ return new NumberObject(c);
+ }
+
+ PRIMITIVE(subtract)
+ {
+ // TODO(bob): Handle non-number types.
+ double c = args[0]->toNumber() - args[1]->toNumber();
+ return new NumberObject(c);
+ }
+
+ PRIMITIVE(multiply)
+ {
+ // TODO(bob): Handle non-number types.
+ double c = args[0]->toNumber() * args[1]->toNumber();
+ return new NumberObject(c);
+ }
+
+ PRIMITIVE(divide)
+ {
+ // TODO(bob): Handle non-number types.
+ double c = args[0]->toNumber() / args[1]->toNumber();
+ return new NumberObject(c);
}
}
View
@@ -7,10 +7,14 @@
#include "Method.h"
#include "RootSource.h"
-#define PRIMITIVE(name) gc<Object> name##Primitive(gc<Object> arg)
+#define PRIMITIVE(name) gc<Object> name##Primitive(ArrayView<gc<Object> >& args)
namespace magpie
{
PRIMITIVE(print);
+ PRIMITIVE(add);
+ PRIMITIVE(subtract);
+ PRIMITIVE(multiply);
+ PRIMITIVE(divide);
}
View
@@ -21,6 +21,10 @@ namespace magpie
fiber_ = new Fiber(*this);
DEF_PRIMITIVE(print, "print 0:");
+ DEF_PRIMITIVE(add, "0: + 0:");
+ DEF_PRIMITIVE(subtract, "0: - 0:");
+ DEF_PRIMITIVE(multiply, "0: * 0:");
+ DEF_PRIMITIVE(divide, "0: / 0:");
coreModule_ = new Module();
@@ -0,0 +1,3 @@
+print(0 + 0) // expect: 0
+print(1234 + 7654) // expect: 8888
+print(3 + 4) // expect: 7
@@ -0,0 +1,4 @@
+print(10 / 2) // expect: 5
+print(1234 / 1) // expect: 1234
+
+// TODO(bob): Division by zero, floating point.
@@ -0,0 +1,3 @@
+print(0 * 0) // expect: 0
+print(0 * 123) // expect: 0
+print(3 * 4) // expect: 12
@@ -0,0 +1,5 @@
+print(0 - 0) // expect: 0
+print(4 - 3) // expect: 1
+print(3 - 4) // expect: -1
+
+// TODO(bob): How should it handle "3-4"?

0 comments on commit a28634b

Please sign in to comment.