mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-19 16:54:08 +10:00
Type casting is working:
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user