diff --git a/docs/TODO.txt b/docs/TODO.txt index 2834bd0..79e21b4 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -10,8 +10,8 @@ DONE: while-then DONE: for-then DONE: break and continue statements DONE: truthiness rethink +DONE: string concat with the + operator -TODO: string concat with the + operator TODO: increment & decrement operators TODO: a = b = c = 1; TODO: are compounds shallow or deep copies? diff --git a/docs/spec.md b/docs/spec.md index 069f625..6f4b2f7 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -357,7 +357,7 @@ export hello as world; ## String -Strings are a series of characters, and are created by surrounding said characters with a pair of double quotation marks `"`. Strings cannot exceed 4096 bytes in length. +Strings are a series of characters, and are created by surrounding said characters with a pair of double quotation marks `"`. Strings cannot exceed 4096 bytes in length (this amount can be tweaked in the source). ``` var greeting: string = "Hello world"; diff --git a/source/interpreter.c b/source/interpreter.c index ab9edd9..af7344f 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -230,6 +230,22 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) { parseIdentifierToValue(interpreter, &rhs); parseIdentifierToValue(interpreter, &lhs); + //special case for string concatenation ONLY + if (IS_STRING(lhs) && IS_STRING(rhs)) { + //check for overflow + if (STRLEN(lhs) + STRLEN(rhs) > MAX_STRING_LENGTH) { + printf("Can't concatenate these strings (result is too long)\n"); + return false; + } + + //concat the strings + char buffer[MAX_STRING_LENGTH]; + snprintf(buffer, MAX_STRING_LENGTH, "%s%s", AS_STRING(lhs), AS_STRING(rhs)); + pushLiteralArray(&interpreter->stack, TO_STRING_LITERAL(buffer)); + + return true; + } + //type coersion if (IS_FLOAT(lhs) && IS_INTEGER(rhs)) { rhs = TO_FLOAT_LITERAL(AS_INTEGER(rhs)); diff --git a/source/literal.c b/source/literal.c index a185e64..1fddebc 100644 --- a/source/literal.c +++ b/source/literal.c @@ -81,12 +81,12 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) { break; case LITERAL_STRING: { - char buffer[4096]; + char buffer[MAX_STRING_LENGTH]; if (!quotes) { - snprintf(buffer, 4096, "%.*s", STRLEN(literal), AS_STRING(literal)); + snprintf(buffer, MAX_STRING_LENGTH, "%.*s", STRLEN(literal), AS_STRING(literal)); } else { - snprintf(buffer, 4096, "%c%.*s%c", quotes, STRLEN(literal), AS_STRING(literal), quotes); + snprintf(buffer, MAX_STRING_LENGTH, "%c%.*s%c", quotes, STRLEN(literal), AS_STRING(literal), quotes); } printFn(buffer); } diff --git a/source/literal.h b/source/literal.h index 7649267..61241a0 100644 --- a/source/literal.h +++ b/source/literal.h @@ -92,6 +92,7 @@ void freeLiteral(Literal literal); #define IS_TRUTHY(x) _isTruthy(x) +#define MAX_STRING_LENGTH 4096 #define STRLEN(lit) ((lit).as.string.length) #define STRLEN_I(lit) ((lit).as.identifier.length) #define HASH_I(lit) ((lit).as.identifier.hash) diff --git a/source/parser.c b/source/parser.c index 2123e99..4744e99 100644 --- a/source/parser.c +++ b/source/parser.c @@ -241,9 +241,11 @@ static Opcode string(Parser* parser, Node** nodeHandle) { int length = parser->previous.length; //for safety - if (length > 4096) { - length = 4096; - error(parser, parser->previous, "Strings can only be a maximum of 4096 characters long"); + if (length > MAX_STRING_LENGTH) { + length = MAX_STRING_LENGTH; + char buffer[256]; + snprintf(buffer, 256, "Strings can only be a maximum of %d characters long", MAX_STRING_LENGTH); + error(parser, parser->previous, buffer); } emitNodeLiteral(nodeHandle, TO_STRING_LITERAL(copyString(parser->previous.lexeme, length)));