Add string type support: literals, concatenation, println, and if eval
- Implement string literal tokenization and parsing (lexer + parser) - Add string concatenation with + operator in evaluator - Add println keyword for printing with newline - Add NODE_IF evaluation in VM - Fix null terminator bug in string concat buffer
This commit is contained in:
12
projects/str.j
Normal file
12
projects/str.j
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
x = 0
|
||||||
|
while x < 10:
|
||||||
|
x = x + 1
|
||||||
|
|
||||||
|
if x > 9:
|
||||||
|
println "fin"
|
||||||
|
|
||||||
|
|
||||||
|
x = "a"
|
||||||
|
y = x * 1
|
||||||
|
z = y + 2
|
||||||
|
println "a" + z
|
||||||
3
projects/test.j
Normal file
3
projects/test.j
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
x = 5
|
||||||
|
z = x > 2
|
||||||
|
print x + z
|
||||||
@@ -16,6 +16,7 @@ typedef enum {
|
|||||||
// Identificadores y keywords
|
// Identificadores y keywords
|
||||||
TOK_ID, // x, foo, mi_var
|
TOK_ID, // x, foo, mi_var
|
||||||
TOK_PRINT, // print
|
TOK_PRINT, // print
|
||||||
|
TOK_PRINTLN, // println
|
||||||
TOK_IF, // if
|
TOK_IF, // if
|
||||||
TOK_WHILE, // while
|
TOK_WHILE, // while
|
||||||
|
|
||||||
@@ -117,6 +118,14 @@ Token *tokenize(const char *source, int *token_count) {
|
|||||||
} else if (c == ':') {
|
} else if (c == ':') {
|
||||||
tokens[count++] = make_token(TOK_COLON, ":");
|
tokens[count++] = make_token(TOK_COLON, ":");
|
||||||
pos++;
|
pos++;
|
||||||
|
} else if (c == '"') {
|
||||||
|
// Leer todo hasta el proximo '"'
|
||||||
|
pos++; // consumir '"'
|
||||||
|
int start = pos;
|
||||||
|
while (source[pos] != '"')
|
||||||
|
pos++;
|
||||||
|
tokens[count++] = make_token(TOK_STRING, substr(source, start, pos));
|
||||||
|
pos++; // consumir '"'
|
||||||
} else if (c >= '0' && c <= '9') {
|
} else if (c >= '0' && c <= '9') {
|
||||||
// Leer todos los digitos consecutivos
|
// Leer todos los digitos consecutivos
|
||||||
int start = pos;
|
int start = pos;
|
||||||
@@ -137,6 +146,8 @@ Token *tokenize(const char *source, int *token_count) {
|
|||||||
tokens[count++] = make_token(TOK_WHILE, word);
|
tokens[count++] = make_token(TOK_WHILE, word);
|
||||||
} else if (strcmp(word, "if") == 0) {
|
} else if (strcmp(word, "if") == 0) {
|
||||||
tokens[count++] = make_token(TOK_IF, word);
|
tokens[count++] = make_token(TOK_IF, word);
|
||||||
|
} else if (strcmp(word, "println") == 0) {
|
||||||
|
tokens[count++] = make_token(TOK_PRINTLN, word);
|
||||||
} else {
|
} else {
|
||||||
tokens[count++] = make_token(TOK_ID, word);
|
tokens[count++] = make_token(TOK_ID, word);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ typedef enum {
|
|||||||
NODE_ASSIGN, // asignacion: x = expr
|
NODE_ASSIGN, // asignacion: x = expr
|
||||||
NODE_BINOP, // operacion binaria: a + b
|
NODE_BINOP, // operacion binaria: a + b
|
||||||
NODE_PRINT, // print(expr)
|
NODE_PRINT, // print(expr)
|
||||||
|
NODE_PRINTLN,
|
||||||
NODE_IF, // if cond: bloque
|
NODE_IF, // if cond: bloque
|
||||||
NODE_WHILE, // while cond: bloque
|
NODE_WHILE, // while cond: bloque
|
||||||
NODE_BLOCK, // secuencia de statements
|
NODE_BLOCK, // secuencia de statements
|
||||||
@@ -64,6 +65,11 @@ ASTNode *parse_term(Token *tokens) {
|
|||||||
node->data.int_val = atoi(tokens[pos].value);
|
node->data.int_val = atoi(tokens[pos].value);
|
||||||
pos++;
|
pos++;
|
||||||
return node;
|
return node;
|
||||||
|
} else if (tokens[pos].type == TOK_STRING) {
|
||||||
|
ASTNode *node = make_node(NODE_STRING_LIT);
|
||||||
|
node->data.string_val = tokens[pos].value;
|
||||||
|
pos++;
|
||||||
|
return node;
|
||||||
} else if (tokens[pos].type == TOK_ID) {
|
} else if (tokens[pos].type == TOK_ID) {
|
||||||
ASTNode *node = make_node(NODE_VAR);
|
ASTNode *node = make_node(NODE_VAR);
|
||||||
node->data.string_val = tokens[pos].value;
|
node->data.string_val = tokens[pos].value;
|
||||||
@@ -79,7 +85,7 @@ ASTNode *parse_term(Token *tokens) {
|
|||||||
neg->data.binop.right = term;
|
neg->data.binop.right = term;
|
||||||
return neg;
|
return neg;
|
||||||
}
|
}
|
||||||
printf("ERROR: esperaba INT o ID, encontré tipo %d\n", tokens[pos].type);
|
printf("ERROR: esperaba INT o ID, encontre tipo %d\n", tokens[pos].type);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +129,15 @@ ASTNode *parse_statement(Token *tokens) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tokens[pos].type == TOK_PRINTLN) {
|
||||||
|
pos++; // consumir "println"
|
||||||
|
ASTNode *expr = parse_expr(tokens);
|
||||||
|
|
||||||
|
ASTNode *node = make_node(NODE_PRINTLN);
|
||||||
|
node->data.print.expr = expr;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
if (tokens[pos].type == TOK_WHILE) {
|
if (tokens[pos].type == TOK_WHILE) {
|
||||||
pos++; // consumir while
|
pos++; // consumir while
|
||||||
ASTNode *cond = parse_expr(tokens);
|
ASTNode *cond = parse_expr(tokens);
|
||||||
@@ -247,6 +262,11 @@ void ast_print(ASTNode *node, const char *prefix, int is_last) {
|
|||||||
ast_print(node->data.print.expr, new_prefix, 1);
|
ast_print(node->data.print.expr, new_prefix, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_PRINTLN:
|
||||||
|
printf("NODE_PRINTLN\n");
|
||||||
|
ast_print(node->data.print.expr, new_prefix, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
case NODE_BLOCK:
|
case NODE_BLOCK:
|
||||||
printf("NODE_BLOCK\n");
|
printf("NODE_BLOCK\n");
|
||||||
for (int i = 0; i < node->data.block.count; i++) {
|
for (int i = 0; i < node->data.block.count; i++) {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ int main(int argc, char **argv) {
|
|||||||
eval(block, &env, allocPtr, 0, 1);
|
eval(block, &env, allocPtr, 0, 1);
|
||||||
|
|
||||||
printf("heapSize=%zu\n", allocPtr->size);
|
printf("heapSize=%zu\n", allocPtr->size);
|
||||||
// JLANG_visualize(allocPtr);
|
JLANG_visualize(allocPtr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -54,6 +54,8 @@ size_t eval(ASTNode *node, Environment *env, void *allocator, int debug,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
|
case NODE_STRING_LIT:
|
||||||
|
return obj_new_string(allocator, node->data.string_val);
|
||||||
case NODE_INT_LIT:
|
case NODE_INT_LIT:
|
||||||
return obj_new_int(allocator, node->data.int_val);
|
return obj_new_int(allocator, node->data.int_val);
|
||||||
case NODE_VAR:
|
case NODE_VAR:
|
||||||
@@ -73,6 +75,22 @@ size_t eval(ASTNode *node, Environment *env, void *allocator, int debug,
|
|||||||
|
|
||||||
// Operar (ints por ahora)
|
// Operar (ints por ahora)
|
||||||
if (node->data.binop.op == '+') {
|
if (node->data.binop.op == '+') {
|
||||||
|
if (l->type == OBJ_STRING) {
|
||||||
|
int n = l->data.string_val.length + r->data.string_val.length;
|
||||||
|
char *tempBuff = (char *)malloc(n + 1);
|
||||||
|
// Copy left text
|
||||||
|
memcpy(tempBuff, JLANG_RESOLVE(allocator, l->data.string_val.chars),
|
||||||
|
l->data.string_val.length);
|
||||||
|
|
||||||
|
// Copy right text
|
||||||
|
memcpy(tempBuff + l->data.string_val.length, JLANG_RESOLVE(allocator, r->data.string_val.chars),
|
||||||
|
r->data.string_val.length);
|
||||||
|
tempBuff[n] = '\0';
|
||||||
|
|
||||||
|
size_t newObj = obj_new_string(allocator, tempBuff);
|
||||||
|
free(tempBuff);
|
||||||
|
return newObj;
|
||||||
|
}
|
||||||
return obj_new_int(allocator, l->data.int_val + r->data.int_val);
|
return obj_new_int(allocator, l->data.int_val + r->data.int_val);
|
||||||
} else if (node->data.binop.op == '-') {
|
} else if (node->data.binop.op == '-') {
|
||||||
return obj_new_int(allocator, l->data.int_val - r->data.int_val);
|
return obj_new_int(allocator, l->data.int_val - r->data.int_val);
|
||||||
@@ -87,6 +105,11 @@ size_t eval(ASTNode *node, Environment *env, void *allocator, int debug,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case NODE_PRINT: {
|
case NODE_PRINT: {
|
||||||
|
size_t val = eval(node->data.print.expr, env, allocator, debug, gc);
|
||||||
|
obj_print(allocator, val, "");
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
case NODE_PRINTLN: {
|
||||||
size_t val = eval(node->data.print.expr, env, allocator, debug, gc);
|
size_t val = eval(node->data.print.expr, env, allocator, debug, gc);
|
||||||
obj_print(allocator, val, "");
|
obj_print(allocator, val, "");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@@ -113,6 +136,15 @@ size_t eval(ASTNode *node, Environment *env, void *allocator, int debug,
|
|||||||
break;
|
break;
|
||||||
eval(node->data.while_loop.body, env, allocator, debug, gc);
|
eval(node->data.while_loop.body, env, allocator, debug, gc);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
case NODE_IF: {
|
||||||
|
size_t cond = eval(node->data.while_loop.cond, env, allocator, debug, gc);
|
||||||
|
Object *obj = (Object *)JLANG_RESOLVE(allocator, cond);
|
||||||
|
if (obj->data.int_val > 0) {
|
||||||
|
eval(node->data.while_loop.body, env, allocator, debug, gc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user