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: rework type system
|
||||||
DONE: var decl with a type, but no value
|
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: increment & decrement operators
|
||||||
TODO: a = b = c = 1;
|
TODO: a = b = c = 1;
|
||||||
TODO: are compounds shallow or deep copies?
|
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
|
//push the store to the cache, tweaking the type
|
||||||
Literal lit = TO_ARRAY_LITERAL(store);
|
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);
|
return pushLiteralArray(literalCache, lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,8 +463,20 @@ unsigned char* collateCompiler(Compiler* compiler, int* size) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_TYPE: {
|
case LITERAL_TYPE: {
|
||||||
|
//push a raw type
|
||||||
emitByte(&collation, &capacity, &count, LITERAL_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
|
LiteralArray* ptr = AS_ARRAY(compiler->literalCache.literals[i]); //used an array for storage above
|
||||||
|
|
||||||
//the base literal
|
//the base literal
|
||||||
|
|||||||
@@ -361,6 +361,80 @@ static bool execVarAssign(Interpreter* interpreter) {
|
|||||||
return true;
|
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
|
//the heart of toy
|
||||||
static void execInterpreter(Interpreter* interpreter) {
|
static void execInterpreter(Interpreter* interpreter) {
|
||||||
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
||||||
@@ -433,6 +507,12 @@ static void execInterpreter(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP_TYPE_CAST:
|
||||||
|
if (!execValCast(interpreter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("Unknown opcode found %d, terminating\n", opcode);
|
printf("Unknown opcode found %d, terminating\n", opcode);
|
||||||
printLiteralArray(&interpreter->stack, "\n");
|
printLiteralArray(&interpreter->stack, "\n");
|
||||||
@@ -602,6 +682,24 @@ void runInterpreter(Interpreter* interpreter, unsigned char* bytecode, int lengt
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case LITERAL_TYPE: {
|
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
|
//what the literal represents
|
||||||
LiteralType literalType = (LiteralType)readByte(interpreter->bytecode, &interpreter->count);
|
LiteralType literalType = (LiteralType)readByte(interpreter->bytecode, &interpreter->count);
|
||||||
unsigned char constant = 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) {
|
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) {
|
Literal _toStringLiteral(char* str) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ typedef enum {
|
|||||||
//these are meta-level types
|
//these are meta-level types
|
||||||
LITERAL_IDENTIFIER,
|
LITERAL_IDENTIFIER,
|
||||||
LITERAL_TYPE,
|
LITERAL_TYPE,
|
||||||
|
LITERAL_TYPE_INTERMEDIATE, //used to process types in the compiler only
|
||||||
LITERAL_ANY, //used by the type system only
|
LITERAL_ANY, //used by the type system only
|
||||||
} LiteralType;
|
} LiteralType;
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ typedef enum Opcode {
|
|||||||
|
|
||||||
OP_VAR_ASSIGN, //assign to a literal
|
OP_VAR_ASSIGN, //assign to a literal
|
||||||
|
|
||||||
|
OP_TYPE_CAST, //temporarily change a type of an atomic value
|
||||||
|
|
||||||
//meta
|
//meta
|
||||||
OP_SECTION_END,
|
OP_SECTION_END,
|
||||||
//TODO: add more
|
//TODO: add more
|
||||||
|
|||||||
@@ -266,12 +266,6 @@ static Opcode grouping(Parser* parser, Node** nodeHandle) {
|
|||||||
parsePrecedence(parser, &tmpNode, PREC_TERNARY);
|
parsePrecedence(parser, &tmpNode, PREC_TERNARY);
|
||||||
consume(parser, TOKEN_PAREN_RIGHT, "Expected ')' at end of grouping");
|
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
|
//process the result without optimisations
|
||||||
emitNodeGrouping(nodeHandle);
|
emitNodeGrouping(nodeHandle);
|
||||||
nodeHandle = &((*nodeHandle)->unary.child); //re-align after append
|
nodeHandle = &((*nodeHandle)->unary.child); //re-align after append
|
||||||
@@ -424,13 +418,72 @@ static Opcode identifier(Parser* parser, Node** nodeHandle) {
|
|||||||
return OP_EOF;
|
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
|
ParseRule parseRules[] = { //must match the token types
|
||||||
//types
|
//types
|
||||||
{atomic, NULL, PREC_PRIMARY},// TOKEN_NULL,
|
{atomic, NULL, PREC_PRIMARY},// TOKEN_NULL,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_BOOLEAN,
|
{castingPrefix, NULL, PREC_CALL},// TOKEN_BOOLEAN,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_INTEGER,
|
{castingPrefix, NULL, PREC_CALL},// TOKEN_INTEGER,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_FLOAT,
|
{castingPrefix, NULL, PREC_CALL},// TOKEN_FLOAT,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_STRING,
|
{castingPrefix, NULL, PREC_CALL},// TOKEN_STRING,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_ARRAY,
|
{NULL, NULL, PREC_NONE},// TOKEN_ARRAY,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_DICTIONARY,
|
{NULL, NULL, PREC_NONE},// TOKEN_DICTIONARY,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_FUNCTION,
|
{NULL, NULL, PREC_NONE},// TOKEN_FUNCTION,
|
||||||
@@ -459,12 +512,12 @@ ParseRule parseRules[] = { //must match the token types
|
|||||||
{NULL, NULL, PREC_NONE},// TOKEN_WHILE,
|
{NULL, NULL, PREC_NONE},// TOKEN_WHILE,
|
||||||
|
|
||||||
//literal values
|
//literal values
|
||||||
{identifier, NULL, PREC_PRIMARY},// TOKEN_IDENTIFIER,
|
{identifier, castingInfix, PREC_PRIMARY},// TOKEN_IDENTIFIER,
|
||||||
{atomic, NULL, PREC_PRIMARY},// TOKEN_LITERAL_TRUE,
|
{atomic, castingInfix, PREC_PRIMARY},// TOKEN_LITERAL_TRUE,
|
||||||
{atomic, NULL, PREC_PRIMARY},// TOKEN_LITERAL_FALSE,
|
{atomic, castingInfix, PREC_PRIMARY},// TOKEN_LITERAL_FALSE,
|
||||||
{atomic, NULL, PREC_PRIMARY},// TOKEN_LITERAL_INTEGER,
|
{atomic, castingInfix, PREC_PRIMARY},// TOKEN_LITERAL_INTEGER,
|
||||||
{atomic, NULL, PREC_PRIMARY},// TOKEN_LITERAL_FLOAT,
|
{atomic, castingInfix, PREC_PRIMARY},// TOKEN_LITERAL_FLOAT,
|
||||||
{string, NULL, PREC_PRIMARY},// TOKEN_LITERAL_STRING,
|
{string, castingInfix, PREC_PRIMARY},// TOKEN_LITERAL_STRING,
|
||||||
|
|
||||||
//math operators
|
//math operators
|
||||||
{NULL, binary, PREC_TERM},// TOKEN_PLUS,
|
{NULL, binary, PREC_TERM},// TOKEN_PLUS,
|
||||||
|
|||||||
Reference in New Issue
Block a user