scripting engine: bitwise operators

This commit is contained in:
nakst 2022-03-04 10:19:47 +00:00
parent 195f53abe1
commit f3dc1fd4bb
1 changed files with 133 additions and 49 deletions

View File

@ -2,7 +2,7 @@
// - Other list operations: insert_many, delete_many.
// - Maps: T[int], T[str].
// - Control flow: break, continue.
// - Other operators: remainder, bitwise shifts, bitwise AND/OR/XOR/NOT, ternary.
// - Other operators: remainder, ternary.
// - Named optional arguments with default values.
// - Accessing structs and functypes from imported modules.
// - inttype and struct inheritance.
@ -52,35 +52,41 @@
#define T_STRING_LITERAL (3)
#define T_NUMERIC_LITERAL (4)
#define T_ADD (40)
#define T_MINUS (41)
#define T_ASTERISK (42)
#define T_SLASH (43)
#define T_NEGATE (44)
#define T_LEFT_ROUND (45)
#define T_RIGHT_ROUND (46)
#define T_LEFT_SQUARE (47)
#define T_RIGHT_SQUARE (48)
#define T_LEFT_FANCY (49)
#define T_RIGHT_FANCY (50)
#define T_COMMA (51)
#define T_EQUALS (52)
#define T_SEMICOLON (53)
#define T_GREATER_THAN (54)
#define T_LESS_THAN (55)
#define T_GT_OR_EQUAL (56)
#define T_LT_OR_EQUAL (57)
#define T_DOUBLE_EQUALS (58)
#define T_NOT_EQUALS (59)
#define T_LOGICAL_AND (60)
#define T_LOGICAL_OR (61)
#define T_ADD_EQUALS (62)
#define T_MINUS_EQUALS (63)
#define T_ASTERISK_EQUALS (64)
#define T_SLASH_EQUALS (65)
#define T_DOT (66)
#define T_COLON (67)
#define T_LOGICAL_NOT (68)
#define T_ADD (20)
#define T_MINUS (21)
#define T_ASTERISK (22)
#define T_SLASH (23)
#define T_NEGATE (24)
#define T_LEFT_ROUND (25)
#define T_RIGHT_ROUND (26)
#define T_LEFT_SQUARE (27)
#define T_RIGHT_SQUARE (28)
#define T_LEFT_FANCY (29)
#define T_RIGHT_FANCY (30)
#define T_COMMA (31)
#define T_EQUALS (32)
#define T_SEMICOLON (33)
#define T_GREATER_THAN (34)
#define T_LESS_THAN (35)
#define T_GT_OR_EQUAL (36)
#define T_LT_OR_EQUAL (37)
#define T_DOUBLE_EQUALS (38)
#define T_NOT_EQUALS (39)
#define T_LOGICAL_AND (40)
#define T_LOGICAL_OR (41)
#define T_ADD_EQUALS (42)
#define T_MINUS_EQUALS (43)
#define T_ASTERISK_EQUALS (44)
#define T_SLASH_EQUALS (45)
#define T_DOT (46)
#define T_COLON (47)
#define T_LOGICAL_NOT (48)
#define T_BIT_SHIFT_LEFT (49)
#define T_BIT_SHIFT_RIGHT (50)
#define T_BITWISE_OR (51)
#define T_BITWISE_AND (52)
#define T_BITWISE_NOT (53)
#define T_BITWISE_XOR (54)
#define T_ROOT (70)
#define T_FUNCBODY (71)
@ -419,6 +425,7 @@ size_t startFunctionBytes = 5;
char **options;
bool *optionsMatched;
size_t optionCount;
int debugBytecodeLevel;
ImportData *importedModules;
ImportData **importedModulesLink = &importedModules;
@ -842,17 +849,23 @@ uint8_t TokenLookupPrecedence(uint8_t t) {
if (t == T_COMMA) return 12;
if (t == T_LOGICAL_OR) return 14;
if (t == T_LOGICAL_AND) return 15;
if (t == T_GREATER_THAN) return 20;
if (t == T_LESS_THAN) return 20;
if (t == T_GT_OR_EQUAL) return 20;
if (t == T_LT_OR_EQUAL) return 20;
if (t == T_BITWISE_OR) return 16;
if (t == T_BITWISE_XOR) return 17;
if (t == T_BITWISE_AND) return 18;
if (t == T_DOUBLE_EQUALS) return 20;
if (t == T_NOT_EQUALS) return 20;
if (t == T_GREATER_THAN) return 25;
if (t == T_LESS_THAN) return 25;
if (t == T_GT_OR_EQUAL) return 25;
if (t == T_LT_OR_EQUAL) return 25;
if (t == T_BIT_SHIFT_LEFT) return 30;
if (t == T_BIT_SHIFT_RIGHT) return 30;
if (t == T_ADD) return 50;
if (t == T_MINUS) return 50;
if (t == T_ASTERISK) return 60;
if (t == T_SLASH) return 60;
if (t == T_LOGICAL_NOT) return 70;
if (t == T_BITWISE_NOT) return 70;
if (t == T_NEGATE) return 70;
if (t == T_NEW) return 75;
if (t == T_DOT) return 80;
@ -907,6 +920,9 @@ Token TokenNext(Tokenizer *tokenizer) {
else if (c == '-' && c1 == '=' && (tokenizer->position += 2)) token.type = T_MINUS_EQUALS;
else if (c == '*' && c1 == '=' && (tokenizer->position += 2)) token.type = T_ASTERISK_EQUALS;
else if (c == '/' && c1 == '=' && (tokenizer->position += 2)) token.type = T_SLASH_EQUALS;
else if (c == '<' && c1 == '<' && (tokenizer->position += 2)) token.type = T_BIT_SHIFT_LEFT;
else if (c == '>' && c1 == '>' && (tokenizer->position += 2)) token.type = T_BIT_SHIFT_RIGHT;
else if (c == '~' && c1 == '|' && (tokenizer->position += 2)) token.type = T_BITWISE_XOR;
else if (c == '+' && ++tokenizer->position) token.type = T_ADD;
else if (c == '-' && ++tokenizer->position) token.type = T_MINUS;
else if (c == '*' && ++tokenizer->position) token.type = T_ASTERISK;
@ -926,6 +942,9 @@ Token TokenNext(Tokenizer *tokenizer) {
else if (c == '.' && ++tokenizer->position) token.type = T_DOT;
else if (c == ':' && ++tokenizer->position) token.type = T_COLON;
else if (c == '!' && ++tokenizer->position) token.type = T_LOGICAL_NOT;
else if (c == '|' && ++tokenizer->position) token.type = T_BITWISE_OR;
else if (c == '&' && ++tokenizer->position) token.type = T_BITWISE_AND;
else if (c == '~' && ++tokenizer->position) token.type = T_BITWISE_NOT;
else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (c >= 0x80) || c == '#') {
token.textBytes = 0;
@ -1315,8 +1334,8 @@ Node *ParseExpression(Tokenizer *tokenizer, bool allowAssignment, uint8_t preced
} else if (node->token.type == T_NUMERIC_LITERAL || node->token.type == T_SUCCESS
|| node->token.type == T_TRUE || node->token.type == T_FALSE || node->token.type == T_NULL) {
node->type = node->token.type;
} else if (node->token.type == T_LOGICAL_NOT || node->token.type == T_MINUS) {
node->type = node->token.type == T_MINUS ? T_NEGATE : T_LOGICAL_NOT;
} else if (node->token.type == T_LOGICAL_NOT || node->token.type == T_MINUS || node->token.type == T_BITWISE_NOT) {
node->type = node->token.type == T_MINUS ? T_NEGATE : node->token.type;
node->firstChild = ParseExpression(tokenizer, false, TokenLookupPrecedence(node->type));
} else if (node->token.type == T_LEFT_ROUND) {
node = ParseExpression(tokenizer, false, 0);
@ -1412,12 +1431,14 @@ Node *ParseExpression(Tokenizer *tokenizer, bool allowAssignment, uint8_t preced
if (!node) return NULL;
node->type = T_COLON;
node->token = operationName;
} else if ((token.type == T_EQUALS || token.type == T_ADD || token.type == T_MINUS
|| token.type == T_ASTERISK || token.type == T_SLASH
|| token.type == T_GREATER_THAN || token.type == T_LESS_THAN
|| token.type == T_LT_OR_EQUAL || token.type == T_GT_OR_EQUAL
|| token.type == T_DOUBLE_EQUALS || token.type == T_NOT_EQUALS
|| token.type == T_LOGICAL_AND || token.type == T_LOGICAL_OR)
} else if ((token.type == T_EQUALS || token.type == T_ADD || token.type == T_MINUS || token.type == T_BITWISE_XOR
|| token.type == T_ASTERISK || token.type == T_SLASH
|| token.type == T_GREATER_THAN || token.type == T_LESS_THAN
|| token.type == T_BIT_SHIFT_LEFT || token.type == T_BIT_SHIFT_RIGHT
|| token.type == T_BITWISE_OR || token.type == T_BITWISE_AND
|| token.type == T_LT_OR_EQUAL || token.type == T_GT_OR_EQUAL
|| token.type == T_DOUBLE_EQUALS || token.type == T_NOT_EQUALS
|| token.type == T_LOGICAL_AND || token.type == T_LOGICAL_OR)
&& TokenLookupPrecedence(token.type) > precedence) {
Node *operation = (Node *) AllocateFixed(sizeof(Node));
operation->token = TokenNext(tokenizer);
@ -2690,6 +2711,12 @@ int64_t ASTEvaluateIntConstant(Tokenizer *tokenizer, Node *node, bool *error) {
return ASTEvaluateIntConstant(tokenizer, node->firstChild, error) - ASTEvaluateIntConstant(tokenizer, node->firstChild->sibling, error);
} else if (node->type == T_ASTERISK) {
return ASTEvaluateIntConstant(tokenizer, node->firstChild, error) * ASTEvaluateIntConstant(tokenizer, node->firstChild->sibling, error);
} else if (node->type == T_BITWISE_OR) {
return ASTEvaluateIntConstant(tokenizer, node->firstChild, error) | ASTEvaluateIntConstant(tokenizer, node->firstChild->sibling, error);
} else if (node->type == T_BITWISE_AND) {
return ASTEvaluateIntConstant(tokenizer, node->firstChild, error) & ASTEvaluateIntConstant(tokenizer, node->firstChild->sibling, error);
} else if (node->type == T_BITWISE_XOR) {
return ASTEvaluateIntConstant(tokenizer, node->firstChild, error) ^ ASTEvaluateIntConstant(tokenizer, node->firstChild->sibling, error);
} else if (node->type == T_SLASH) {
int64_t divisor = ASTEvaluateIntConstant(tokenizer, node->firstChild->sibling, error);
@ -2702,8 +2729,24 @@ int64_t ASTEvaluateIntConstant(Tokenizer *tokenizer, Node *node, bool *error) {
} else {
return ASTEvaluateIntConstant(tokenizer, node->firstChild, error) / divisor;
}
} else if (node->type == T_BIT_SHIFT_LEFT || node->type == T_BIT_SHIFT_RIGHT) {
int64_t shift = ASTEvaluateIntConstant(tokenizer, node->firstChild->sibling, error);
if (*error) {
return 0;
} else if (shift < 0 || shift > 63) {
*error = true;
PrintError2(tokenizer, node, "Shift %d is out of range (0..63).\n", shift);
return 0;
} else if (node->type == T_BIT_SHIFT_LEFT) {
return ASTEvaluateIntConstant(tokenizer, node->firstChild, error) << shift;
} else {
return ASTEvaluateIntConstant(tokenizer, node->firstChild, error) >> shift;
}
} else if (node->type == T_NEGATE) {
return -ASTEvaluateIntConstant(tokenizer, node->firstChild, error);
} else if (node->type == T_BITWISE_NOT) {
return ~ASTEvaluateIntConstant(tokenizer, node->firstChild, error);
} else {
Assert(false);
return 0;
@ -2716,7 +2759,13 @@ bool ASTIsIntegerConstant(Node *node) {
&& node->type != T_MINUS
&& node->type != T_ASTERISK
&& node->type != T_SLASH
&& node->type != T_NEGATE) {
&& node->type != T_NEGATE
&& node->type != T_BIT_SHIFT_LEFT
&& node->type != T_BIT_SHIFT_RIGHT
&& node->type != T_BITWISE_OR
&& node->type != T_BITWISE_AND
&& node->type != T_BITWISE_XOR
&& node->type != T_BITWISE_NOT) {
return false;
}
@ -2803,7 +2852,9 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) {
}
} else if (node->type == T_ADD || node->type == T_MINUS || node->type == T_ASTERISK || node->type == T_SLASH
|| node->type == T_GREATER_THAN || node->type == T_LESS_THAN || node->type == T_LT_OR_EQUAL || node->type == T_GT_OR_EQUAL
|| node->type == T_DOUBLE_EQUALS || node->type == T_NOT_EQUALS || node->type == T_LOGICAL_AND || node->type == T_LOGICAL_OR) {
|| node->type == T_DOUBLE_EQUALS || node->type == T_NOT_EQUALS || node->type == T_LOGICAL_AND || node->type == T_LOGICAL_OR
|| node->type == T_BIT_SHIFT_LEFT || node->type == T_BIT_SHIFT_RIGHT
|| node->type == T_BITWISE_OR || node->type == T_BITWISE_AND || node->type == T_BITWISE_XOR) {
if (!ASTMatching(node->firstChild->expressionType, node->firstChild->sibling->expressionType)) {
PrintError2(tokenizer, node, "The expression on the left and right side of a binary operator must have the same type.\n");
return false;
@ -3317,10 +3368,10 @@ bool ASTSetTypes(Tokenizer *tokenizer, Node *node) {
}
node->expressionType = &globalExpressionTypeBool;
} else if (node->type == T_NEGATE) {
} else if (node->type == T_NEGATE || node->type == T_BITWISE_NOT) {
if (!ASTMatching(node->firstChild->expressionType, &globalExpressionTypeInt)
&& !ASTMatching(node->firstChild->expressionType, &globalExpressionTypeFloat)) {
PrintError2(tokenizer, node, "Expected a int or float for the unary negate '-' operator.\n");
PrintError2(tokenizer, node, "Expected a int or float for the %s operator.\n", node->type == T_NEGATE ? "unary negate '-'" : "bitwise not '~'");
return false;
}
@ -4074,7 +4125,9 @@ bool FunctionBuilderRecurse(Tokenizer *tokenizer, Node *node, FunctionBuilder *b
} else {
FunctionBuilderAppend(builder, &node->type, sizeof(node->type));
}
} else if (node->type == T_ADD || node->type == T_MINUS || node->type == T_ASTERISK || node->type == T_SLASH || node->type == T_NEGATE) {
} else if (node->type == T_ADD || node->type == T_MINUS || node->type == T_ASTERISK || node->type == T_SLASH || node->type == T_NEGATE || node->type == T_BITWISE_NOT
|| node->type == T_BIT_SHIFT_LEFT || node->type == T_BIT_SHIFT_RIGHT
|| node->type == T_BITWISE_OR || node->type == T_BITWISE_AND || node->type == T_BITWISE_XOR) {
uint8_t b = node->expressionType->type == T_FLOAT ? node->type - T_ADD + T_FLOAT_ADD
: node->expressionType->type == T_STR ? T_CONCAT : node->type;
FunctionBuilderAddLineNumber(builder, node);
@ -4518,8 +4571,11 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex
while (true) {
uint8_t command = functionData[instructionPointer++];
// PrintDebug("--> %d, %ld, %ld, %ld\n", command, instructionPointer - 1, context->c->id, context->c->stackPointer);
// PrintBackTrace(context, instructionPointer - 1, context->c, "");
if (debugBytecodeLevel >= 1) {
PrintDebug("--> %d, %ld, %ld, %ld\n", command, instructionPointer - 1, context->c->id, context->c->stackPointer);
if (debugBytecodeLevel >= 2) PrintBackTrace(context, instructionPointer - 1, context->c, "");
}
if (command == T_BLOCK || command == T_FUNCBODY) {
uint16_t newVariableCount = functionData[instructionPointer + 0] + (functionData[instructionPointer + 1] << 8);
@ -4854,6 +4910,26 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex
context->c->stack[context->c->stackPointer - 1] = entry->fields[fieldIndex];
context->c->stackIsManaged[context->c->stackPointer - 1] = isManaged;
} else if (command == T_BIT_SHIFT_LEFT) {
if (context->c->stackPointer < 2) return -1;
context->c->stack[context->c->stackPointer - 2].i = context->c->stack[context->c->stackPointer - 2].i << context->c->stack[context->c->stackPointer - 1].i;
context->c->stackPointer--;
} else if (command == T_BIT_SHIFT_RIGHT) {
if (context->c->stackPointer < 2) return -1;
context->c->stack[context->c->stackPointer - 2].i = context->c->stack[context->c->stackPointer - 2].i >> context->c->stack[context->c->stackPointer - 1].i;
context->c->stackPointer--;
} else if (command == T_BITWISE_OR) {
if (context->c->stackPointer < 2) return -1;
context->c->stack[context->c->stackPointer - 2].i = context->c->stack[context->c->stackPointer - 2].i | context->c->stack[context->c->stackPointer - 1].i;
context->c->stackPointer--;
} else if (command == T_BITWISE_AND) {
if (context->c->stackPointer < 2) return -1;
context->c->stack[context->c->stackPointer - 2].i = context->c->stack[context->c->stackPointer - 2].i & context->c->stack[context->c->stackPointer - 1].i;
context->c->stackPointer--;
} else if (command == T_BITWISE_XOR) {
if (context->c->stackPointer < 2) return -1;
context->c->stack[context->c->stackPointer - 2].i = context->c->stack[context->c->stackPointer - 2].i ^ context->c->stack[context->c->stackPointer - 1].i;
context->c->stackPointer--;
} else if (command == T_ADD) {
if (context->c->stackPointer < 2) return -1;
context->c->stack[context->c->stackPointer - 2].i = context->c->stack[context->c->stackPointer - 2].i + context->c->stack[context->c->stackPointer - 1].i;
@ -4879,6 +4955,9 @@ int ScriptExecuteFunction(uintptr_t instructionPointer, ExecutionContext *contex
} else if (command == T_NEGATE) {
if (context->c->stackPointer < 1) return -1;
context->c->stack[context->c->stackPointer - 1].i = -context->c->stack[context->c->stackPointer - 1].i;
} else if (command == T_BITWISE_NOT) {
if (context->c->stackPointer < 1) return -1;
context->c->stack[context->c->stackPointer - 1].i = ~context->c->stack[context->c->stackPointer - 1].i;
} else if (command == T_FLOAT_ADD) {
if (context->c->stackPointer < 2) return -1;
context->c->stack[context->c->stackPointer - 2].f = context->c->stack[context->c->stackPointer - 2].f + context->c->stack[context->c->stackPointer - 1].f;
@ -7123,6 +7202,11 @@ int main(int argc, char **argv) {
} else if (0 == memcmp(argv[i], "--start=", 8)) {
startFunction = argv[i] + 8;
startFunctionBytes = strlen(argv[i]) - 8;
} else if (0 == memcmp(argv[i], "--debug-bytecode=", 17)) {
debugBytecodeLevel = atoi(argv[i] + 17);
} else {
fprintf(stderr, "Unrecognised engine option: '%s'.\n", argv[i]);
return 1;
}
}