Skip to content

Commit 6ebe99f

Browse files
committed
Extended parser to recognize list indexing in primary expressions
1 parent 6b22e32 commit 6ebe99f

5 files changed

Lines changed: 121 additions & 20 deletions

File tree

mas/interpreter.c

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,41 @@ static MASObject *builtin_input_num(Interpreter *interp, MASObject **args, int a
427427
case AST_ASSIGN:
428428
{
429429
MASObject *value = evaluate(node->data.assign.value, interp);
430-
symbol_table_set(interp->locals, node->data.assign.name, value);
430+
431+
if (node->data.assign.index == NULL) {
432+
// Plain variable assignment
433+
symbol_table_set(interp->locals, node->data.assign.name, value);
434+
} else {
435+
// Indexed assignment: a[i] = value
436+
437+
// 1. Find the list variable
438+
MASObject *list_obj = symbol_table_get(interp->locals, node->data.assign.name);
439+
if (!list_obj) {
440+
list_obj = symbol_table_get(interp->globals, node->data.assign.name);
441+
}
442+
if (!list_obj || list_obj->type != AST_LIST) {
443+
fprintf(stderr, "Error: '%s' is not a list\n", node->data.assign.name);
444+
exit(1);
445+
}
446+
447+
// 2. Evaluate index
448+
MASObject *index_obj = evaluate(node->data.assign.index, interp);
449+
if (index_obj->type != AST_NUMBER) {
450+
fprintf(stderr, "List index must be a number\n");
451+
exit(1);
452+
}
453+
int idx = (int)index_obj->data.number;
454+
455+
// 3. Bounds check
456+
if (idx < 0 || idx >= list_obj->data.list.count) {
457+
fprintf(stderr, "Index %d out of bounds\n", idx);
458+
exit(1);
459+
}
460+
461+
// 4. Assign (replace item)
462+
// In pure GC, just overwrite — old item may become unreachable
463+
list_obj->data.list.items[idx] = value;
464+
}
431465
return value;
432466
}
433467
case AST_BINOP:
@@ -669,6 +703,36 @@ static MASObject *builtin_input_num(Interpreter *interp, MASObject **args, int a
669703
case AST_FUNCDEF:
670704
interpreter_add_function(interp, node->data.funcdef.name, node);
671705
return create_null();
706+
case AST_INDEX:
707+
{
708+
// Look up the list variable
709+
MASObject *list_obj = symbol_table_get(interp->locals, node->data.index.target);
710+
if (!list_obj) {
711+
list_obj = symbol_table_get(interp->globals, node->data.index.target);
712+
}
713+
if (!list_obj || list_obj->type != AST_LIST) {
714+
fprintf(stderr, "Error: '%s' is not a list (line %d)\n",
715+
node->data.index.target, node->line);
716+
exit(1);
717+
}
718+
719+
// Evaluate index expression
720+
MASObject *index_obj = evaluate(node->data.index.index, interp);
721+
if (index_obj->type != AST_NUMBER) {
722+
fprintf(stderr, "List index must be a number (line %d)\n", node->line);
723+
exit(1);
724+
}
725+
int idx = (int)index_obj->data.number;
726+
727+
// Bounds check
728+
if (idx < 0 || idx >= list_obj->data.list.count) {
729+
fprintf(stderr, "Index %d out of bounds (line %d)\n", idx, node->line);
730+
exit(1);
731+
}
732+
733+
// Return the item (no incref — GC handles it)
734+
return list_obj->data.list.items[idx];
735+
}
672736
default:
673737
fprintf(stderr, "Unknown AST node type: %d\n", node->type);
674738
exit(1);

mas/mas.exe

1 KB
Binary file not shown.

mas/mas.h

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ typedef struct {
3030
// AST Node types
3131
typedef enum {
3232
AST_PROGRAM, AST_ASSIGN, AST_BINOP, AST_UNARYOP, AST_NUMBER, AST_STRING,
33-
AST_BOOLEAN, AST_NULL, AST_VAR, AST_LIST, AST_CALL, AST_IF, AST_LOOP,
33+
AST_BOOLEAN, AST_NULL, AST_VAR, AST_LIST, AST_CALL, AST_IF, AST_LOOP, AST_INDEX,
3434
AST_EACH, AST_FUNCDEF, AST_RETURN, AST_BREAK, AST_CONTINUE, AST_EXPRSTMT
3535
} ASTType;
3636

@@ -40,22 +40,16 @@ typedef struct MASObject MASObject;
4040

4141
// MAS Object system (for GC foundation)
4242
typedef struct MASObject {
43-
int refcount;
4443
ASTType type;
45-
bool marked;
44+
bool marked; // for GC
4645
union {
4746
double number;
4847
char* string;
4948
bool boolean;
5049
struct {
51-
MASObject** items;
50+
struct MASObject** items;
5251
int count;
5352
} list;
54-
struct {
55-
char* name;
56-
ASTNode** args;
57-
int arg_count;
58-
} call;
5953
} data;
6054
}MASObject;
6155

@@ -64,7 +58,7 @@ struct ASTNode {
6458
ASTType type;
6559
int line;
6660
union {
67-
struct { char* name; ASTNode* value; } assign;
61+
struct { char* name; ASTNode* value; ASTNode* index; } assign;
6862
struct { ASTNode* left; char* op; ASTNode* right; } binop;
6963
struct { char* op; ASTNode* operand; } unaryop;
7064
double number;
@@ -75,13 +69,14 @@ struct ASTNode {
7569
struct { char* name; ASTNode** args; int arg_count; } call;
7670
struct { ASTNode* condition; ASTNode** body; int body_count; } loop;
7771
struct {
78-
char* target;
79-
ASTNode* iterable; // for lists
80-
ASTNode* range_start; // for ranges (if not NULL)
81-
ASTNode* range_end; // for ranges
82-
ASTNode** body;
83-
int body_count;
84-
} each;
72+
char* target;
73+
ASTNode* iterable; // for lists
74+
ASTNode* range_start; // for ranges (if not NULL)
75+
ASTNode* range_end; // for ranges
76+
ASTNode** body;
77+
int body_count;
78+
} each;
79+
struct { char* target; ASTNode* index; } index; // ← for AST_INDEX
8580
struct { char* name; char** params; int param_count; ASTNode** body; int body_count; } funcdef;
8681
struct { ASTNode* condition; ASTNode** then_body; int then_body_count; ASTNode** else_body; int else_body_count; } if_stmt;
8782
ASTNode* expr;

mas/parser.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,15 +332,21 @@ ASTNode* parse_comparison() {
332332
// Check for assignment, which has the lowest precedence
333333
if (match(TOK_ASSIGN)) {
334334
advance(); // consume '='
335-
if (expr->type != AST_VAR) {
335+
if (expr->type != AST_VAR && expr->type != AST_INDEX) {
336336
fprintf(stderr, "Parse error at line %d: Invalid assignment target.\n", expr->line);
337337
exit(1);
338338
}
339339
ASTNode* value = parse_expression();
340340
ASTNode* assign = malloc(sizeof(ASTNode));
341341
assign->type = AST_ASSIGN;
342342
assign->line = expr->line;
343-
assign->data.assign.name = expr->data.var_name;
343+
if (expr->type == AST_VAR) {
344+
assign->data.assign.name = expr->data.var_name;
345+
assign->data.assign.index = NULL; // no index
346+
} else { // AST_INDEX
347+
assign->data.assign.name = expr->data.index.target;
348+
assign->data.assign.index = expr->data.index.index; // take ownership
349+
}
344350
assign->data.assign.value = value;
345351
return assign;
346352
}
@@ -553,6 +559,20 @@ ASTNode* parse_primary() {
553559
int line = current_token->line;
554560
advance();
555561

562+
// Check for indexing: a[0]
563+
if (match(TOK_LBRACKET)) {
564+
advance(); // consume '['
565+
ASTNode* index_expr = parse_expression();
566+
consume(TOK_RBRACKET, "Expected ']'");
567+
568+
ASTNode* index_node = malloc(sizeof(ASTNode));
569+
index_node->type = AST_INDEX;
570+
index_node->line = line;
571+
index_node->data.index.target = id_name; // variable name
572+
index_node->data.index.index = index_expr; // index expression
573+
return index_node;
574+
}
575+
556576
// Check if it's a function call
557577
if (match(TOK_LPAREN)) {
558578
advance(); // consume '('
@@ -697,6 +717,11 @@ void print_ast(ASTNode* node, int indent) {
697717
printf("EXPRSTMT\n");
698718
print_ast(node->data.expr, indent + 1);
699719
break;
720+
case AST_INDEX:
721+
printf("INDEX: %s[", node->data.index.target);
722+
print_ast(node->data.index.index, 0); // print index expr inline
723+
printf("]\n");
724+
break;
700725
default:
701726
printf("UNKNOWN AST NODE TYPE: %d\n", node->type);
702727
}

mas/test.mas

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,20 @@ print(number)
4545
x = [1, 2, 3, 4, 5]
4646
x = null
4747
gc()
48+
49+
# Garbage Collector verification(cyclic reference)
50+
def make_cycle():
51+
a = [0]
52+
b = [0]
53+
a[0] = b
54+
b[0] = a # a → b → a (cycle!)
55+
print "Cycle created"
56+
end
57+
58+
make_cycle()
59+
gc()
60+
61+
# List indexing
62+
a = [10, 20]
63+
print a[0] # ->10
64+
a[1] = 30 # update list element

0 commit comments

Comments
 (0)