about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--boot/lex.c21
-rw-r--r--boot/parse.c39
-rw-r--r--boot/tree.c64
3 files changed, 120 insertions, 4 deletions
diff --git a/boot/lex.c b/boot/lex.c
index 37eabcd..30f4071 100644
--- a/boot/lex.c
+++ b/boot/lex.c
@@ -122,6 +122,10 @@ enum Token_Kind
     TOKEN_STAR,
     TOKEN_SLASH,
 
+    TOKEN_PLUS_PLUS,
+    TOKEN_MINUS_MINUS,
+    TOKEN_STAR_STAR,
+
     TOKEN_AND,
     TOKEN_OR,
     TOKEN_EQUAL,
@@ -239,6 +243,13 @@ token_kind_to_string(enum Token_Kind kind)
     case TOKEN_SLASH:
         return "SLASH";
 
+    case TOKEN_PLUS_PLUS:
+        return "PLUS_PLUS";
+    case TOKEN_MINUS_MINUS:
+        return "MINUS_MINUS";
+    case TOKEN_STAR_STAR:
+        return "STAR_STAR";
+
     case TOKEN_AND:
         return "AND";
     case TOKEN_OR:
@@ -582,20 +593,28 @@ lexer_symbol_token(struct Lexer* l, struct Lexer_Char current)
         if (a.got_match) RET{ TOKEN_ASSIGN_CARET, 2 };
         RET{ TOKEN_CARET, 1 };
     }
-    // todo: increment, decrement, power
     case '+': {
         a = lexer_match_char(l, '=');
         if (a.got_match) RET{ TOKEN_ASSIGN_PLUS, 2 };
+
+        a = lexer_match_char(l, '+');
+        if (a.got_match) RET{ TOKEN_PLUS_PLUS, 2 };
         RET{ TOKEN_PLUS, 1 };
     }
     case '-': {
         a = lexer_match_char(l, '=');
         if (a.got_match) RET{ TOKEN_ASSIGN_MINUS, 2 };
+
+        a = lexer_match_char(l, '-');
+        if (a.got_match) RET{ TOKEN_MINUS_MINUS, 2 };
         RET{ TOKEN_MINUS, 1 };
     }
     case '*': {
         a = lexer_match_char(l, '=');
         if (a.got_match) RET{ TOKEN_ASSIGN_STAR, 2 };
+
+        a = lexer_match_char(l, '*');
+        if (a.got_match) RET{ TOKEN_STAR_STAR, 2 };
         RET{ TOKEN_STAR, 1 };
     }
     case '/': {
diff --git a/boot/parse.c b/boot/parse.c
index 07b6e58..1c42352 100644
--- a/boot/parse.c
+++ b/boot/parse.c
@@ -439,14 +439,31 @@ parser_expression_postfix(struct Parser* p, struct Parser_Error* error)
 {
     struct Expression* expression = CHECK(parser_expression_member(p, error));
 
-    switch (parser_peek(p).kind) {
+    struct Token token = parser_peek(p);
+    switch (token.kind) {
     case TOKEN_ROUND_OPEN:
         return parser_expression_postfix_call(p, expression, error);
     case TOKEN_SQUARE_OPEN:
         return parser_expression_postfix_subscript(p, expression, error);
-    default:
-        return expression;
+    default:;
+    }
+
+    enum Increment_Decrement_Operation inc_dec_op =
+        increment_decrement_operation_from_token(&token);
+    if (inc_dec_op) {
+        parser_next(p);
+        struct Expression_Increment_Decrement inc_dec = {
+            .prefix = false,
+            .subject = expression,
+            .operation = inc_dec_op,
+        };
+
+        struct Span span = span_merge(expression->span, token.span);
+        union Expression_Value value = { .increment_decrement = inc_dec };
+        return expression_new(EXPRESSION_INCREMENT_DECREMENT, value, span, token.location);
     }
+
+    return expression;
 }
 
 struct Expression*
@@ -463,6 +480,22 @@ parser_expression_unary_operation(struct Parser* p, struct Parser_Error* error)
         return expression_new(EXPRESSION_UNARY_OPERATION, value, span, token.location);
     }
 
+    enum Increment_Decrement_Operation inc_dec_op =
+        increment_decrement_operation_from_token(&token);
+    if (inc_dec_op) {
+        parser_next(p);
+        struct Expression* subject = CHECK(parser_expression_unary_operation(p, error));
+        struct Expression_Increment_Decrement inc_dec = {
+            .prefix = true,
+            .subject = subject,
+            .operation = inc_dec_op,
+        };
+
+        struct Span span = span_merge(token.span, inc_dec.subject->span);
+        union Expression_Value value = { .increment_decrement = inc_dec };
+        return expression_new(EXPRESSION_INCREMENT_DECREMENT, value, span, token.location);
+    }
+
     return parser_expression_postfix(p, error);
 }
 
diff --git a/boot/tree.c b/boot/tree.c
index 3ae90b8..2d49a2c 100644
--- a/boot/tree.c
+++ b/boot/tree.c
@@ -54,6 +54,7 @@ enum Binary_Operation
     BINARY_MULTIPLY,
     BINARY_DIVIDE,
     BINARY_MODULO,
+    BINARY_POWER,
 
     BINARY_EQUAL,
     BINARY_NOT_EQUAL,
@@ -99,6 +100,8 @@ binary_operation_from_token(const struct Token* token)
         return BINARY_DIVIDE;
     case TOKEN_PERCENT:
         return BINARY_MODULO;
+    case TOKEN_STAR_STAR:
+        return BINARY_POWER;
 
     case TOKEN_EQUAL:
         return BINARY_EQUAL;
@@ -210,6 +213,8 @@ binary_operation_precedence(enum Binary_Operation operation)
     case BINARY_DIVIDE:
     case BINARY_MODULO:
         return 11;
+    case BINARY_POWER:
+        return 12;
         // strongest
 
     default:
@@ -241,6 +246,7 @@ binary_operation_associativity(enum Binary_Operation operation)
     case BINARY_ASSIGN_BITWISE_OR:
     case BINARY_ASSIGN_BITWISE_XOR:
     case BINARY_ASSIGN_BITWISE_LEFT_SHIFT:
+    case BINARY_POWER:
         return BINARY_ASSOCIATIVITY_RIGHT;
     default:
         return BINARY_ASSOCIATIVITY_LEFT;
@@ -261,6 +267,8 @@ binary_operation_to_string(enum Binary_Operation operation)
         return "/";
     case BINARY_MODULO:
         return "%";
+    case BINARY_POWER:
+        return "**";
 
     case BINARY_EQUAL:
         return "==";
@@ -323,6 +331,43 @@ binary_operation_to_string(enum Binary_Operation operation)
     }
 }
 
+enum Increment_Decrement_Operation
+{
+    INCREMENT_DECREMENT_NONE,
+    INCREMENT_DECREMENT_INCREMENT,
+    INCREMENT_DECREMENT_DECREMENT,
+};
+
+enum Increment_Decrement_Operation
+increment_decrement_operation_from_token(const struct Token* token)
+{
+    switch (token->kind) {
+    case TOKEN_PLUS_PLUS:
+        return INCREMENT_DECREMENT_INCREMENT;
+    case TOKEN_MINUS_MINUS:
+        return INCREMENT_DECREMENT_DECREMENT;
+
+    default:
+        return INCREMENT_DECREMENT_NONE;
+    }
+}
+
+const ascii*
+increment_decrement_operation_to_string(enum Increment_Decrement_Operation operation)
+{
+    switch (operation) {
+    case INCREMENT_DECREMENT_INCREMENT:
+        return "++";
+    case INCREMENT_DECREMENT_DECREMENT:
+        return "--";
+
+    default:
+        failure("unexpected increment/decrement operation passed to "
+                "`increment_decrement_operation_to_string`");
+        return nil;
+    }
+}
+
 // nodes are parts of the syntax tree that are reused often
 // and in different places.
 
@@ -372,6 +417,7 @@ enum Expression_Kind
     EXPRESSION_CALL,
     EXPRESSION_SUBSCRIPT,
     EXPRESSION_MEMBER,
+    EXPRESSION_INCREMENT_DECREMENT,
 
     EXPRESSION_FUNCTION,
 };
@@ -437,6 +483,14 @@ struct Expression_Member
     struct String name;
 };
 
+struct Expression_Increment_Decrement
+{
+    // whether the increment/decrement is a prefix or postfix operation.
+    bool prefix;
+    struct Expression* subject;
+    enum Increment_Decrement_Operation operation;
+};
+
 #define EXPRESSION_FUNCTION_MAX_PARAMS 32
 
 struct Expression_Function
@@ -465,6 +519,7 @@ union Expression_Value
     struct Expression_Call call;
     struct Expression_Subscript subscript;
     struct Expression_Member member;
+    struct Expression_Increment_Decrement increment_decrement;
     struct Expression_Function function;
 };
 
@@ -563,6 +618,15 @@ expression_print(const struct Expression* expression)
         expression_print(expression->value.member.subject);
         printf(")");
         break;
+    case EXPRESSION_INCREMENT_DECREMENT: {
+        const struct Expression_Increment_Decrement* inc_dec =
+            &expression->value.increment_decrement;
+        const ascii* prefix_or_postfix = inc_dec->prefix ? "prefix" : "postfix";
+        printf("(increment/decrement %s %s ",
+               increment_decrement_operation_to_string(inc_dec->operation), prefix_or_postfix);
+        expression_print(inc_dec->subject);
+        break;
+    }
     case EXPRESSION_FUNCTION: {
         const struct Expression_Function* fun = &expression->value.function;
         printf("(function");