Type casting is working:

This commit is contained in:
2022-08-19 19:24:07 +01:00
parent 9365541c8f
commit 4f0aebc32f
9 changed files with 236 additions and 25 deletions

View File

@@ -1,7 +1,10 @@
DONE: rework type system
DONE: var decl with a type, but no value
DONE: type casting
TODO: type casting
TODO: string concat with the + operator
TODO: empty string as falsy?
TODO: remove optimization option
TODO: increment & decrement operators
TODO: a = b = c = 1;
TODO: are compounds shallow or deep copies?

30
scripts/casting.toy Normal file
View File

@@ -0,0 +1,30 @@
//boolean origin
var b: bool = true;
print (int)b;
print (float)b;
print (string)b;
//integer origin
var i: int = 42;
print (bool)i;
print (float)i;
print (string)i;
//float origin
var f: float = 3.14;
print (bool)f;
print (int)f;
print (string)f;
//string origin
var s: string = "78.9";
print (bool)s;
print (int)s;
print (float)s;

View File

@@ -1,6 +0,0 @@
var arr : [int] = [1, 2, 3, 42];
var dict : [string, int] = ["hello": 1, "world":2];
print arr;
print dict;

View File

@@ -140,7 +140,7 @@ static int writeLiteralTypeToCache(LiteralArray* literalCache, Literal literal)
//push the store to the cache, tweaking the type
Literal lit = TO_ARRAY_LITERAL(store);
lit.type = LITERAL_TYPE; //NOTE: tweaking the type usually isn't a good idea
lit.type = LITERAL_TYPE_INTERMEDIATE; //NOTE: tweaking the type usually isn't a good idea
return pushLiteralArray(literalCache, lit);
}
@@ -463,8 +463,20 @@ unsigned char* collateCompiler(Compiler* compiler, int* size) {
break;
case LITERAL_TYPE: {
//push a raw type
emitByte(&collation, &capacity, &count, LITERAL_TYPE);
Literal typeLiteral = compiler->literalCache.literals[i];
//what type this literal represents
emitByte(&collation, &capacity, &count, AS_TYPE(typeLiteral).typeOf);
emitByte(&collation, &capacity, &count, AS_TYPE(typeLiteral).constant); //if it's constant
}
break;
case LITERAL_TYPE_INTERMEDIATE: {
emitByte(&collation, &capacity, &count, LITERAL_TYPE_INTERMEDIATE);
LiteralArray* ptr = AS_ARRAY(compiler->literalCache.literals[i]); //used an array for storage above
//the base literal

View File

@@ -361,6 +361,80 @@ static bool execVarAssign(Interpreter* interpreter) {
return true;
}
static bool execValCast(Interpreter* interpreter) {
Literal value = popLiteralArray(&interpreter->stack);
Literal type = popLiteralArray(&interpreter->stack);
parseIdentifierToValue(interpreter, &value);
Literal result = TO_NULL_LITERAL;
//cast the rhs to the type represented by lhs
switch(AS_TYPE(type).typeOf) {
case LITERAL_BOOLEAN:
result = TO_BOOLEAN_LITERAL(IS_TRUTHY(value));
break;
case LITERAL_INTEGER:
if (IS_BOOLEAN(value)) {
result = TO_INTEGER_LITERAL(AS_BOOLEAN(value) ? 1 : 0);
}
if (IS_FLOAT(value)) {
result = TO_INTEGER_LITERAL(AS_FLOAT(value));
}
if (IS_STRING(value)) {
int val = 0;
sscanf(AS_STRING(value), "%d", &val);
result = TO_INTEGER_LITERAL(val);
}
break;
case LITERAL_FLOAT:
if (IS_BOOLEAN(value)) {
result = TO_FLOAT_LITERAL(AS_BOOLEAN(value) ? 1 : 0);
}
if (IS_INTEGER(value)) {
result = TO_FLOAT_LITERAL(AS_INTEGER(value));
}
if (IS_STRING(value)) {
float val = 0;
sscanf(AS_STRING(value), "%f", &val);
result = TO_FLOAT_LITERAL(val);
}
break;
case LITERAL_STRING:
if (IS_BOOLEAN(value)) {
result = TO_STRING_LITERAL(AS_BOOLEAN(value) ? "true" : "false");
}
if (IS_INTEGER(value)) {
char buffer[128];
snprintf(buffer, 128, "%d", AS_INTEGER(value));
result = TO_STRING_LITERAL(buffer);
}
if (IS_FLOAT(value)) {
char buffer[128];
snprintf(buffer, 128, "%g", AS_FLOAT(value));
result = TO_STRING_LITERAL(buffer);
}
break;
default:
printf("Unknown cast type found %d, terminating\n", AS_TYPE(type).typeOf);
return false;
}
//leave the new value on the stack
pushLiteralArray(&interpreter->stack, result);
return true;
}
//the heart of toy
static void execInterpreter(Interpreter* interpreter) {
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
@@ -433,6 +507,12 @@ static void execInterpreter(Interpreter* interpreter) {
}
break;
case OP_TYPE_CAST:
if (!execValCast(interpreter)) {
return;
}
break;
default:
printf("Unknown opcode found %d, terminating\n", opcode);
printLiteralArray(&interpreter->stack, "\n");
@@ -602,6 +682,24 @@ void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int lengt
break;
case LITERAL_TYPE: {
//what the literal is
LiteralType literalType = (LiteralType)readByte(interpreter->bytecode, &interpreter->count);
unsigned char constant = readByte(interpreter->bytecode, &interpreter->count);
Literal typeLiteral = TO_TYPE_LITERAL(literalType, constant);
//save the type
pushLiteralArray(&interpreter->literalCache, typeLiteral);
if (command.verbose) {
printf("(type ");
printLiteral(typeLiteral);
printf(")\n");
}
}
break;
case LITERAL_TYPE_INTERMEDIATE: {
//what the literal represents
LiteralType literalType = (LiteralType)readByte(interpreter->bytecode, &interpreter->count);
unsigned char constant = readByte(interpreter->bytecode, &interpreter->count);

View File

@@ -322,7 +322,25 @@ void freeLiteral(Literal literal) {
}
bool _isTruthy(Literal x) {
return (IS_NULL(x) || (IS_BOOLEAN(x) && AS_BOOLEAN(x)) || (IS_INTEGER(x) && AS_INTEGER(x) != 0) || (IS_FLOAT(x) && AS_FLOAT(x) != 0));
if (IS_NULL(x)) {
return false;
}
if (IS_BOOLEAN(x)) {
return AS_BOOLEAN(x);
}
if (IS_INTEGER(x)) {
return AS_INTEGER(x) != 0;
}
if (IS_FLOAT(x)) {
return AS_FLOAT(x) != 0;
}
//TODO: empty string as falsy?
return true;
}
Literal _toStringLiteral(char* str) {

View File

@@ -17,6 +17,7 @@ typedef enum {
//these are meta-level types
LITERAL_IDENTIFIER,
LITERAL_TYPE,
LITERAL_TYPE_INTERMEDIATE, //used to process types in the compiler only
LITERAL_ANY, //used by the type system only
} LiteralType;

View File

@@ -33,6 +33,8 @@ typedef enum Opcode {
OP_VAR_ASSIGN, //assign to a literal
OP_TYPE_CAST, //temporarily change a type of an atomic value
//meta
OP_SECTION_END,
//TODO: add more

View File

@@ -266,12 +266,6 @@ static Opcode grouping(Parser* parser, Node** nodeHandle) {
parsePrecedence(parser, &tmpNode, PREC_TERNARY);
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of grouping");
//if it's just a literal, don't need a grouping
if (command.optimize >= 1 && tmpNode->type == NODE_LITERAL) {
(*nodeHandle) = tmpNode;
return OP_EOF;
}
//process the result without optimisations
emitNodeGrouping(nodeHandle);
nodeHandle = &((*nodeHandle)->unary.child); //re-align after append
@@ -424,13 +418,72 @@ static Opcode identifier(Parser* parser, Node** nodeHandle) {
return OP_EOF;
}
static Opcode castingPrefix(Parser* parser, Node** nodeHandle) {
switch(parser->previous.type) {
case TOKEN_BOOLEAN:
emitNodeLiteral(nodeHandle, TO_TYPE_LITERAL(LITERAL_BOOLEAN, false));
break;
case TOKEN_INTEGER:
emitNodeLiteral(nodeHandle, TO_TYPE_LITERAL(LITERAL_INTEGER, false));
break;
case TOKEN_FLOAT:
emitNodeLiteral(nodeHandle, TO_TYPE_LITERAL(LITERAL_FLOAT, false));
break;
case TOKEN_STRING:
emitNodeLiteral(nodeHandle, TO_TYPE_LITERAL(LITERAL_STRING, false));
break;
default:
error(parser, parser->previous, "Unexpected token passed to casting precedence rule");
return OP_EOF;
}
return OP_EOF;
}
static Opcode castingInfix(Parser* parser, Node** nodeHandle) {
advance(parser);
switch(parser->previous.type) {
case TOKEN_IDENTIFIER:
identifier(parser, nodeHandle);
break;
case TOKEN_LITERAL_TRUE:
case TOKEN_LITERAL_FALSE:
atomic(parser, nodeHandle);
break;
case TOKEN_LITERAL_INTEGER:
atomic(parser, nodeHandle);
break;
case TOKEN_LITERAL_FLOAT:
atomic(parser, nodeHandle);
break;
case TOKEN_LITERAL_STRING:
atomic(parser, nodeHandle);
break;
default:
error(parser, parser->previous, "Unexpected token passed to casting infix precedence rule");
return OP_EOF;
}
return OP_TYPE_CAST;
}
ParseRule parseRules[] = { //must match the token types
//types
{atomic, NULL, PREC_PRIMARY},// TOKEN_NULL,
{NULL, NULL, PREC_NONE},// TOKEN_BOOLEAN,
{NULL, NULL, PREC_NONE},// TOKEN_INTEGER,
{NULL, NULL, PREC_NONE},// TOKEN_FLOAT,
{NULL, NULL, PREC_NONE},// TOKEN_STRING,
{castingPrefix, NULL, PREC_CALL},// TOKEN_BOOLEAN,
{castingPrefix, NULL, PREC_CALL},// TOKEN_INTEGER,
{castingPrefix, NULL, PREC_CALL},// TOKEN_FLOAT,
{castingPrefix, NULL, PREC_CALL},// TOKEN_STRING,
{NULL, NULL, PREC_NONE},// TOKEN_ARRAY,
{NULL, NULL, PREC_NONE},// TOKEN_DICTIONARY,
{NULL, NULL, PREC_NONE},// TOKEN_FUNCTION,
@@ -459,12 +512,12 @@ ParseRule parseRules[] = { //must match the token types
{NULL, NULL, PREC_NONE},// TOKEN_WHILE,
//literal values
{identifier, NULL, PREC_PRIMARY},// TOKEN_IDENTIFIER,
{atomic, NULL, PREC_PRIMARY},// TOKEN_LITERAL_TRUE,
{atomic, NULL, PREC_PRIMARY},// TOKEN_LITERAL_FALSE,
{atomic, NULL, PREC_PRIMARY},// TOKEN_LITERAL_INTEGER,
{atomic, NULL, PREC_PRIMARY},// TOKEN_LITERAL_FLOAT,
{string, NULL, PREC_PRIMARY},// TOKEN_LITERAL_STRING,
{identifier, castingInfix, PREC_PRIMARY},// TOKEN_IDENTIFIER,
{atomic, castingInfix, PREC_PRIMARY},// TOKEN_LITERAL_TRUE,
{atomic, castingInfix, PREC_PRIMARY},// TOKEN_LITERAL_FALSE,
{atomic, castingInfix, PREC_PRIMARY},// TOKEN_LITERAL_INTEGER,
{atomic, castingInfix, PREC_PRIMARY},// TOKEN_LITERAL_FLOAT,
{string, castingInfix, PREC_PRIMARY},// TOKEN_LITERAL_STRING,
//math operators
{NULL, binary, PREC_TERM},// TOKEN_PLUS,