mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Type casting is working:
This commit is contained in:
@@ -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
30
scripts/casting.toy
Normal 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;
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
var arr : [int] = [1, 2, 3, 42];
|
||||
var dict : [string, int] = ["hello": 1, "world":2];
|
||||
|
||||
print arr;
|
||||
print dict;
|
||||
@@ -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