Add more operators.
This commit is contained in:
parent
bcccaa09bf
commit
851d3df8cd
1
chunk.h
1
chunk.h
@ -56,6 +56,7 @@ typedef enum {
|
||||
OP_DUP,
|
||||
OP_SWAP,
|
||||
OP_KWARGS,
|
||||
OP_POW,
|
||||
|
||||
OP_BITOR,
|
||||
OP_BITXOR,
|
||||
|
75
compiler.c
75
compiler.c
@ -52,15 +52,15 @@ typedef enum {
|
||||
PREC_TERNARY,
|
||||
PREC_OR, /* or */
|
||||
PREC_AND, /* and */
|
||||
PREC_COMPARISON, /* < > <= >= in 'not in' */
|
||||
PREC_BITOR, /* | */
|
||||
PREC_BITXOR, /* ^ */
|
||||
PREC_BITAND, /* & */
|
||||
PREC_EQUALITY, /* == != in */
|
||||
PREC_COMPARISON, /* < > <= >= */
|
||||
PREC_SHIFT, /* << >> */
|
||||
PREC_TERM, /* + - */
|
||||
PREC_FACTOR, /* * / % */
|
||||
PREC_UNARY, /* ! - not */
|
||||
PREC_EXPONENT, /* ** */
|
||||
PREC_CALL, /* . () */
|
||||
PREC_PRIMARY
|
||||
} Precedence;
|
||||
@ -225,8 +225,9 @@ static void advance() {
|
||||
|
||||
#ifdef ENABLE_SCAN_TRACING
|
||||
if (vm.flags & KRK_ENABLE_SCAN_TRACING) {
|
||||
fprintf(stderr, "[%s %d:%d '%.*s'] ",
|
||||
fprintf(stderr, "[%s<%d> %d:%d '%.*s'] ",
|
||||
getRule(parser.current.type)->name,
|
||||
(int)parser.current.type,
|
||||
(int)parser.current.line,
|
||||
(int)parser.current.col,
|
||||
(int)parser.current.length,
|
||||
@ -451,6 +452,7 @@ static void binary(int canAssign) {
|
||||
case TOKEN_PLUS: emitByte(OP_ADD); break;
|
||||
case TOKEN_MINUS: emitByte(OP_SUBTRACT); break;
|
||||
case TOKEN_ASTERISK: emitByte(OP_MULTIPLY); break;
|
||||
case TOKEN_POW: emitByte(OP_POW); break;
|
||||
case TOKEN_SOLIDUS: emitByte(OP_DIVIDE); break;
|
||||
case TOKEN_MODULO: emitByte(OP_MODULO); break;
|
||||
case TOKEN_IN: emitByte(OP_EQUAL); break;
|
||||
@ -459,8 +461,7 @@ static void binary(int canAssign) {
|
||||
}
|
||||
|
||||
static int matchAssignment(void) {
|
||||
return match(TOKEN_EQUAL) || match(TOKEN_PLUS_EQUAL) || match(TOKEN_MINUS_EQUAL) ||
|
||||
match(TOKEN_PLUS_PLUS) || match(TOKEN_MINUS_MINUS);
|
||||
return (parser.current.type >= TOKEN_EQUAL && parser.current.type <= TOKEN_MODULO_EQUAL) ? (advance(), 1) : 0;
|
||||
}
|
||||
|
||||
static int matchEndOfDel(void) {
|
||||
@ -468,23 +469,29 @@ static int matchEndOfDel(void) {
|
||||
}
|
||||
|
||||
static void assignmentValue(void) {
|
||||
switch (parser.previous.type) {
|
||||
case TOKEN_PLUS_EQUAL:
|
||||
expression();
|
||||
emitByte(OP_ADD);
|
||||
break;
|
||||
case TOKEN_MINUS_EQUAL:
|
||||
expression();
|
||||
emitByte(OP_SUBTRACT);
|
||||
break;
|
||||
case TOKEN_PLUS_PLUS:
|
||||
emitConstant(INTEGER_VAL(1));
|
||||
emitByte(OP_ADD);
|
||||
break;
|
||||
case TOKEN_MINUS_MINUS:
|
||||
emitConstant(INTEGER_VAL(1));
|
||||
emitByte(OP_SUBTRACT);
|
||||
break;
|
||||
KrkTokenType type = parser.previous.type;
|
||||
if (type == TOKEN_PLUS_PLUS || type == TOKEN_MINUS_MINUS) {
|
||||
emitConstant(INTEGER_VAL(1));
|
||||
} else {
|
||||
expression();
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case TOKEN_PIPE_EQUAL: emitByte(OP_BITOR); break;
|
||||
case TOKEN_CARET_EQUAL: emitByte(OP_BITXOR); break;
|
||||
case TOKEN_AMP_EQUAL: emitByte(OP_BITAND); break;
|
||||
case TOKEN_LSHIFT_EQUAL: emitByte(OP_SHIFTLEFT); break;
|
||||
case TOKEN_RSHIFT_EQUAL: emitByte(OP_SHIFTRIGHT); break;
|
||||
|
||||
case TOKEN_PLUS_EQUAL: emitByte(OP_ADD); break;
|
||||
case TOKEN_PLUS_PLUS: emitByte(OP_ADD); break;
|
||||
case TOKEN_MINUS_EQUAL: emitByte(OP_SUBTRACT); break;
|
||||
case TOKEN_MINUS_MINUS: emitByte(OP_SUBTRACT); break;
|
||||
case TOKEN_ASTERISK_EQUAL: emitByte(OP_MULTIPLY); break;
|
||||
case TOKEN_POW_EQUAL: emitByte(OP_POW); break;
|
||||
case TOKEN_SOLIDUS_EQUAL: emitByte(OP_DIVIDE); break;
|
||||
case TOKEN_MODULO_EQUAL: emitByte(OP_MODULO); break;
|
||||
|
||||
default:
|
||||
error("Unexpected operand in assignment");
|
||||
break;
|
||||
@ -881,8 +888,8 @@ static void function(FunctionType type, size_t blockWidth) {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (match(TOKEN_ASTERISK)) {
|
||||
if (match(TOKEN_ASTERISK)) {
|
||||
if (match(TOKEN_ASTERISK) || check(TOKEN_POW)) {
|
||||
if (match(TOKEN_POW)) {
|
||||
if (hasCollectors == 2) {
|
||||
error("Duplicate ** in parameter list.");
|
||||
return;
|
||||
@ -2106,11 +2113,12 @@ ParseRule krk_parseRules[] = {
|
||||
RULE(TOKEN_SEMICOLON, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_SOLIDUS, NULL, binary, PREC_FACTOR),
|
||||
RULE(TOKEN_ASTERISK, NULL, binary, PREC_FACTOR),
|
||||
RULE(TOKEN_POW, NULL, binary, PREC_EXPONENT),
|
||||
RULE(TOKEN_MODULO, NULL, binary, PREC_FACTOR),
|
||||
RULE(TOKEN_BANG, unary, NULL, PREC_NONE),
|
||||
RULE(TOKEN_BANG_EQUAL, NULL, binary, PREC_EQUALITY),
|
||||
RULE(TOKEN_BANG_EQUAL, NULL, binary, PREC_COMPARISON),
|
||||
RULE(TOKEN_EQUAL, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_EQUAL_EQUAL, NULL, binary, PREC_EQUALITY),
|
||||
RULE(TOKEN_EQUAL_EQUAL, NULL, binary, PREC_COMPARISON),
|
||||
RULE(TOKEN_GREATER, NULL, binary, PREC_COMPARISON),
|
||||
RULE(TOKEN_GREATER_EQUAL, NULL, binary, PREC_COMPARISON),
|
||||
RULE(TOKEN_LESS, NULL, binary, PREC_COMPARISON),
|
||||
@ -2141,6 +2149,8 @@ ParseRule krk_parseRules[] = {
|
||||
RULE(TOKEN_WHILE, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_BREAK, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_CONTINUE, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_IMPORT, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_RAISE, NULL, NULL, PREC_NONE),
|
||||
|
||||
RULE(TOKEN_AT, NULL, NULL, PREC_NONE),
|
||||
|
||||
@ -2155,6 +2165,14 @@ ParseRule krk_parseRules[] = {
|
||||
RULE(TOKEN_MINUS_EQUAL, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_PLUS_PLUS, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_MINUS_MINUS, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_CARET_EQUAL, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_PIPE_EQUAL, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_LSHIFT_EQUAL, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_RSHIFT_EQUAL, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_AMP_EQUAL, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_SOLIDUS_EQUAL, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_ASTERISK_EQUAL,NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_MODULO_EQUAL, NULL, NULL, PREC_NONE),
|
||||
|
||||
RULE(TOKEN_LAMBDA, lambda, NULL, PREC_NONE),
|
||||
|
||||
@ -2163,6 +2181,7 @@ ParseRule krk_parseRules[] = {
|
||||
RULE(TOKEN_ERROR, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_EOL, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_EOF, NULL, NULL, PREC_NONE),
|
||||
RULE(TOKEN_RETRY, NULL, NULL, PREC_NONE),
|
||||
};
|
||||
|
||||
static void actualTernary(size_t count, KrkScanner oldScanner, Parser oldParser) {
|
||||
@ -2300,9 +2319,9 @@ static void call(int canAssign) {
|
||||
size_t argCount = 0, specialArgs = 0, keywordArgs = 0, seenKeywordUnpacking = 0;
|
||||
if (!check(TOKEN_RIGHT_PAREN)) {
|
||||
do {
|
||||
if (match(TOKEN_ASTERISK)) {
|
||||
if (match(TOKEN_ASTERISK) || check(TOKEN_POW)) {
|
||||
specialArgs++;
|
||||
if (match(TOKEN_ASTERISK)) {
|
||||
if (match(TOKEN_POW)) {
|
||||
seenKeywordUnpacking = 1;
|
||||
emitBytes(OP_EXPAND_ARGS, 2); /* Outputs something special */
|
||||
expression(); /* Expect dict */
|
||||
|
1
debug.c
1
debug.c
@ -121,6 +121,7 @@ size_t krk_disassembleInstruction(FILE * f, KrkFunction * func, size_t offset) {
|
||||
SIMPLE(OP_SWAP)
|
||||
SIMPLE(OP_FINALIZE)
|
||||
SIMPLE(OP_IS)
|
||||
SIMPLE(OP_POW)
|
||||
OPERANDB(OP_DUP,(void)0)
|
||||
OPERANDB(OP_EXPAND_ARGS,EXPAND_ARGS_MORE)
|
||||
CONSTANT(OP_DEFINE_GLOBAL,(void)0)
|
||||
|
24
scanner.c
24
scanner.c
@ -337,21 +337,21 @@ KrkToken krk_scanToken() {
|
||||
case ',': return makeToken(TOKEN_COMMA);
|
||||
case '.': return makeToken(TOKEN_DOT);
|
||||
case ';': return makeToken(TOKEN_SEMICOLON);
|
||||
case '/': return makeToken(TOKEN_SOLIDUS);
|
||||
case '*': return makeToken(TOKEN_ASTERISK);
|
||||
case '%': return makeToken(TOKEN_MODULO);
|
||||
case '@': return makeToken(TOKEN_AT);
|
||||
case '~': return makeToken(TOKEN_TILDE);
|
||||
case '^': return makeToken(TOKEN_CARET);
|
||||
case '|': return makeToken(TOKEN_PIPE);
|
||||
case '&': return makeToken(TOKEN_AMPERSAND);
|
||||
|
||||
case '!': return makeToken(match('=') ? TOKEN_BANG_EQUAL : TOKEN_BANG);
|
||||
case '=': return makeToken(match('=') ? TOKEN_EQUAL_EQUAL : TOKEN_EQUAL);
|
||||
case '<': return makeToken(match('=') ? TOKEN_LESS_EQUAL : (match('<') ? TOKEN_LEFT_SHIFT : TOKEN_LESS));
|
||||
case '>': return makeToken(match('=') ? TOKEN_GREATER_EQUAL : (match('>') ? TOKEN_RIGHT_SHIFT : TOKEN_GREATER));
|
||||
case '-': return makeToken(match('=') ? TOKEN_MINUS_EQUAL : (match('-') ? TOKEN_MINUS_MINUS : TOKEN_MINUS));
|
||||
case '+': return makeToken(match('=') ? TOKEN_PLUS_EQUAL : (match('+') ? TOKEN_PLUS_PLUS : TOKEN_PLUS));
|
||||
case '!': return makeToken(match('=') ? TOKEN_BANG_EQUAL : TOKEN_BANG);
|
||||
case '=': return makeToken(match('=') ? TOKEN_EQUAL_EQUAL : TOKEN_EQUAL);
|
||||
case '<': return makeToken(match('=') ? TOKEN_LESS_EQUAL : (match('<') ? (match('=') ? TOKEN_LSHIFT_EQUAL : TOKEN_LEFT_SHIFT) : TOKEN_LESS));
|
||||
case '>': return makeToken(match('=') ? TOKEN_GREATER_EQUAL : (match('>') ? (match('=') ? TOKEN_RSHIFT_EQUAL : TOKEN_RIGHT_SHIFT) : TOKEN_GREATER));
|
||||
case '-': return makeToken(match('=') ? TOKEN_MINUS_EQUAL : (match('-') ? TOKEN_MINUS_MINUS : TOKEN_MINUS));
|
||||
case '+': return makeToken(match('=') ? TOKEN_PLUS_EQUAL : (match('+') ? TOKEN_PLUS_PLUS : TOKEN_PLUS));
|
||||
case '^': return makeToken(match('=') ? TOKEN_CARET_EQUAL : TOKEN_CARET);
|
||||
case '|': return makeToken(match('=') ? TOKEN_PIPE_EQUAL : TOKEN_PIPE);
|
||||
case '&': return makeToken(match('=') ? TOKEN_AMP_EQUAL : TOKEN_AMPERSAND);
|
||||
case '/': return makeToken(match('=') ? TOKEN_SOLIDUS_EQUAL : TOKEN_SOLIDUS);
|
||||
case '*': return makeToken(match('=') ? TOKEN_ASTERISK_EQUAL: (match('*') ? (match('=') ? TOKEN_POW_EQUAL : TOKEN_POW) : TOKEN_ASTERISK));
|
||||
case '%': return makeToken(match('=') ? TOKEN_MODULO_EQUAL : TOKEN_MODULO);
|
||||
|
||||
case '"': return string('"');
|
||||
case '\'': return string('\'');
|
||||
|
33
scanner.h
33
scanner.h
@ -12,6 +12,7 @@ typedef enum {
|
||||
TOKEN_SEMICOLON,
|
||||
TOKEN_SOLIDUS,
|
||||
TOKEN_ASTERISK,
|
||||
TOKEN_POW,
|
||||
TOKEN_MODULO,
|
||||
TOKEN_AT,
|
||||
TOKEN_CARET, /* ^ (xor) */
|
||||
@ -20,15 +21,31 @@ typedef enum {
|
||||
TOKEN_TILDE, /* ~ (negate) */
|
||||
TOKEN_LEFT_SHIFT, /* << */
|
||||
TOKEN_RIGHT_SHIFT,/* >> */
|
||||
TOKEN_PLUS_EQUAL, /* += */
|
||||
TOKEN_MINUS_EQUAL,/* -= */
|
||||
TOKEN_PLUS_PLUS, /* ++ */
|
||||
TOKEN_MINUS_MINUS,/* -- */
|
||||
TOKEN_BANG,
|
||||
TOKEN_GREATER,
|
||||
TOKEN_LESS,
|
||||
|
||||
TOKEN_BANG, TOKEN_BANG_EQUAL,
|
||||
TOKEN_EQUAL, TOKEN_EQUAL_EQUAL,
|
||||
TOKEN_GREATER, TOKEN_GREATER_EQUAL,
|
||||
TOKEN_LESS, TOKEN_LESS_EQUAL,
|
||||
/* Comparisons */
|
||||
TOKEN_GREATER_EQUAL,
|
||||
TOKEN_LESS_EQUAL,
|
||||
TOKEN_BANG_EQUAL,
|
||||
TOKEN_EQUAL_EQUAL,
|
||||
|
||||
/* Assignments */
|
||||
TOKEN_EQUAL,
|
||||
TOKEN_LSHIFT_EQUAL, /* <<= */
|
||||
TOKEN_RSHIFT_EQUAL, /* >>= */
|
||||
TOKEN_PLUS_EQUAL, /* += */
|
||||
TOKEN_MINUS_EQUAL, /* -= */
|
||||
TOKEN_PLUS_PLUS, /* ++ */
|
||||
TOKEN_MINUS_MINUS, /* -- */
|
||||
TOKEN_CARET_EQUAL,
|
||||
TOKEN_PIPE_EQUAL,
|
||||
TOKEN_AMP_EQUAL,
|
||||
TOKEN_SOLIDUS_EQUAL,
|
||||
TOKEN_ASTERISK_EQUAL,
|
||||
TOKEN_POW_EQUAL,
|
||||
TOKEN_MODULO_EQUAL,
|
||||
|
||||
TOKEN_STRING,
|
||||
TOKEN_BIG_STRING,
|
||||
|
@ -205,6 +205,13 @@ KrkValue krk_module_onload_math(void) {
|
||||
bind(isnan);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Maybe the math library should be a core one, but I'm not sure if I want
|
||||
* to have to depend on -lm in the main interpreter, so instead if we have
|
||||
* imported math, we'll just quietly give floats a __pow__ method...
|
||||
*/
|
||||
krk_defineNative(&vm.baseClasses.floatClass->methods, "__pow__", _math_pow);
|
||||
|
||||
krk_attachNamedValue(&module->fields, "pi", FLOATING_VAL(M_PI));
|
||||
#ifndef __toaru__
|
||||
/* TODO: Add these to toaru... */
|
||||
|
31
test/testOperators.krk
Normal file
31
test/testOperators.krk
Normal file
@ -0,0 +1,31 @@
|
||||
import math
|
||||
# Import is needed or we don't have pow. Dunno if I care to fix that.
|
||||
|
||||
let x = 1.27
|
||||
print(x ** 2.7)
|
||||
x **= 2.7
|
||||
print(x)
|
||||
|
||||
let x = 123
|
||||
print(x << 1)
|
||||
x <<= 1
|
||||
print(x)
|
||||
|
||||
x >>= 1
|
||||
print(x)
|
||||
|
||||
x |= 321
|
||||
print(x)
|
||||
x ^= 321
|
||||
print(x)
|
||||
x ^= 321
|
||||
print(x)
|
||||
|
||||
x++
|
||||
print(x)
|
||||
x+=2
|
||||
print(x)
|
||||
x--
|
||||
print(x)
|
||||
|
||||
|
11
test/testOperators.krk.expect
Normal file
11
test/testOperators.krk.expect
Normal file
@ -0,0 +1,11 @@
|
||||
1.90665
|
||||
1.90665
|
||||
246
|
||||
246
|
||||
123
|
||||
379
|
||||
58
|
||||
379
|
||||
380
|
||||
382
|
||||
381
|
8
vm.c
8
vm.c
@ -3536,6 +3536,13 @@ MAKE_BIN_OP(sub,-)
|
||||
MAKE_BIN_OP(mul,*)
|
||||
MAKE_BIN_OP(div,/)
|
||||
|
||||
#define MAKE_UNOPTIMIZED_BIN_OP(name,operator) \
|
||||
static KrkValue operator_ ## name (KrkValue a, KrkValue b) { \
|
||||
return tryBind("__" #name "__", a, b, "unsupported operand types for " #operator ": '%s' and '%s'"); \
|
||||
}
|
||||
|
||||
MAKE_UNOPTIMIZED_BIN_OP(pow,**)
|
||||
|
||||
/* Bit ops are invalid on doubles in C, so we can't use the same set of macros for them;
|
||||
* they should be invalid in Kuroko as well. */
|
||||
#define MAKE_BIT_OP(name,operator) \
|
||||
@ -4091,6 +4098,7 @@ static KrkValue run() {
|
||||
case OP_BITAND: BINARY_OP(and)
|
||||
case OP_SHIFTLEFT: BINARY_OP(lshift)
|
||||
case OP_SHIFTRIGHT: BINARY_OP(rshift)
|
||||
case OP_POW: BINARY_OP(pow)
|
||||
case OP_BITNEGATE: {
|
||||
KrkValue value = krk_pop();
|
||||
if (IS_INTEGER(value)) krk_push(INTEGER_VAL(~AS_INTEGER(value)));
|
||||
|
Loading…
x
Reference in New Issue
Block a user