Skip to content

Commit 405bcc7

Browse files
gh-192: Make POP use STR.
Closes #192.
1 parent bb8a513 commit 405bcc7

9 files changed

Lines changed: 42 additions & 38 deletions

File tree

docs/SPECIFICATION.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,7 @@
968968
{"n":"ParForStatement","loc":<loc>,"counter":"<identifier>","target_expr":<Expr>,"block":<Stmt>}
969969
{"n":"FuncDef","loc":<loc>,"name":"<identifier>","params":[{"n":"Param","type":"<TYPE>","coerced":<bool>,"name":"<identifier>","default":<Expr-or-null>},...],"return_type":"<TYPE>","body":<Stmt>}
970970
{"n":"ReturnStatement","loc":<loc>,"expression":<Expr-or-null>}
971-
{"n":"PopStatement","loc":<loc>,"expression":{"n":"Identifier","loc":<loc>,"name":"<identifier>"}}
971+
{"n":"PopStatement","loc":<loc>,"expression":{"n":"Literal","loc":<loc>,"value":"<string>","literal_type":"STR"}}
972972
{"n":"BreakStatement","loc":<loc>,"expression":<Expr>}
973973
{"n":"GotoStatement","loc":<loc>,"expression":<Expr>}
974974
{"n":"GotopointStatement","loc":<loc>,"expression":<Expr>}
@@ -1074,7 +1074,7 @@
10741074

10751075
The statement `RETURN(expression)` MUST terminate the innermost enclosing function immediately and produce the supplied value as that function's result. The returned value MUST satisfy the function's declared return type, and using `RETURN` outside a function MUST raise a runtime error.
10761076

1077-
The statement `POP(SYMBOL name)` MUST be valid only inside a function body. It MUST retrieve the current value bound to `name`, delete that binding from the environment, and then return the retrieved value as though `RETURN(name)` had executed immediately before the deletion. Using `POP` outside a function, or applying it to an unreadable binding, MUST raise a runtime error.
1077+
The statement `POP(STR name)` MUST be valid only inside a function body. The `name` expression MUST evaluate to a `STR` whose contents are the identifier name to operate on. `POP` MUST retrieve the current value bound to the named identifier, delete that binding from the environment, and then return the retrieved value as though `RETURN(<that identifier>)` had executed immediately before the deletion. Using `POP` outside a function, or applying it when the `name` expression does not evaluate to a `STR`, or when the named binding is unreadable, MUST raise a runtime error.
10781078

10791079
---
10801080

lib/std/image/init.pre

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ FUNC TNS FLIP_H(TNS img){
8282
FUNC TNS INVERT(TNS img){
8383
TNS return = M-(TNS(SHAPE(img), 0xFF), img)
8484
return[# , # , 0d4] = img[# , # , 0d4] ! Preserve alpha
85-
POP(return)
85+
POP("return")
8686
}
8787

8888
FUNC TNS RECT(TNS img, INT x, INT y, INT width, INT height, TNS color, INT fill, INT thickness){

lib/std/path.pre

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ FUNC STR BASEPATH(STR path){ ! returns directory portion of path
1515
RETURN("")
1616
}
1717
STR dir = REPLACE(npath, JOIN("/", base), "")
18-
POP(dir)
18+
POP("dir")
1919
}
2020

2121
FUNC STR BASENAME(STR path){ ! returns filename portion of path
2222
TNS tpath = SPLIT(NORMALIZE_PATH(path), "/")
2323
STR basename = tpath[MAX(TLEN(tpath, 0d1), 0d1)]
2424
DEL(tpath)
25-
POP(basename)
25+
POP("basename")
2626
}
2727

2828
FUNC TNS SPLITEXT(STR path){ ! returns [name without ext, ext]
@@ -34,7 +34,7 @@ FUNC TNS SPLITEXT(STR path){ ! returns [name without ext, ext]
3434
IF(EQ(TLEN(parts, 0d1), 0d1)){
3535
DEL(base)
3636
TNS result = [npath, ""]
37-
POP(result)
37+
POP("result")
3838
}
3939
! Extension is the last segment (1-based indexing)
4040
STR ext = parts[ TLEN(parts, 0d1) ]
@@ -54,7 +54,7 @@ FUNC TNS SPLITEXT(STR path){ ! returns [name without ext, ext]
5454
DEL(dir)
5555
DEL(name)
5656
TNS result = [delex, ext]
57-
POP(result)
57+
POP("result")
5858
}
5959

6060
FUNC STR EXTNAME(STR path){ ! returns extension portion of path
@@ -77,7 +77,7 @@ FUNC STR TEMPFILE(STR local_path){
7777
}
7878
STR final_path = JOIN(temp, local_path)
7979
DEL(temp)
80-
POP(final_path)
80+
POP("final_path")
8181
}
8282

8383
STR interpreter = ARGV()[0d1]

src/ast.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,12 +306,12 @@ Stmt *stmt_return(Expr *value, int line, int column) {
306306
return stmt;
307307
}
308308

309-
Stmt *stmt_pop(char *name, int line, int column) {
309+
Stmt *stmt_pop(Expr *expr, int line, int column) {
310310
Stmt *stmt = ast_alloc(sizeof(Stmt));
311311
stmt->type = STMT_POP;
312312
stmt->line = line;
313313
stmt->column = column;
314-
stmt->as.pop_stmt.name = name;
314+
stmt->as.pop_stmt.expr = expr;
315315
return stmt;
316316
}
317317

@@ -533,7 +533,7 @@ void free_stmt(Stmt *stmt) {
533533
free_expr(stmt->as.return_stmt.value);
534534
break;
535535
case STMT_POP:
536-
free(stmt->as.pop_stmt.name);
536+
free_expr(stmt->as.pop_stmt.expr);
537537
break;
538538
case STMT_BREAK:
539539
free_expr(stmt->as.break_stmt.value);

src/ast.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ struct Stmt {
207207
Expr *target;
208208
} goto_stmt;
209209
struct {
210-
char *name;
210+
Expr *expr;
211211
} pop_stmt;
212212
struct {
213213
Expr *target;
@@ -244,7 +244,7 @@ Stmt *stmt_for(char *counter, Expr *target, Stmt *body, int line, int column);
244244
Stmt *stmt_parfor(char *counter, Expr *target, Stmt *body, int line, int column);
245245
Stmt *stmt_func(char *name, DeclType ret, Stmt *body, int line, int column);
246246
Stmt *stmt_return(Expr *value, int line, int column);
247-
Stmt *stmt_pop(char *name, int line, int column);
247+
Stmt *stmt_pop(Expr *expr, int line, int column);
248248
Stmt *stmt_break(Expr *value, int line, int column);
249249
Stmt *stmt_continue(int line, int column);
250250
Stmt *stmt_thr(char *name, Stmt *body, int line, int column);

src/builtins.c

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2630,15 +2630,7 @@ static void ser_stmt(JsonBuf *jb, SerCtx *ctx, Interpreter *interp, Stmt *stmt)
26302630
json_obj_field(jb, &first, "loc");
26312631
ser_loc(jb, stmt->line, stmt->column);
26322632
json_obj_field(jb, &first, "expression");
2633-
jb_append_char(jb, '{');
2634-
bool ef = true;
2635-
json_obj_field(jb, &ef, "n");
2636-
jb_append_json_string(jb, "Identifier");
2637-
json_obj_field(jb, &ef, "loc");
2638-
ser_loc(jb, stmt->line, stmt->column);
2639-
json_obj_field(jb, &ef, "name");
2640-
jb_append_json_string(jb, stmt->as.pop_stmt.name ? stmt->as.pop_stmt.name : "");
2641-
jb_append_char(jb, '}');
2633+
ser_expr(jb, ctx, interp, stmt->as.pop_stmt.expr);
26422634
jb_append_char(jb, '}');
26432635
return;
26442636
}
@@ -3464,13 +3456,8 @@ static Stmt *deser_stmt(JsonValue *obj, UnserCtx *ctx, Interpreter *interp, cons
34643456
return stmt_return(ex, line, col);
34653457
}
34663458
if (strcmp(name, "PopStatement") == 0) {
3467-
JsonValue *ex = json_obj_get(obj, "expression");
3468-
if (ex && ex->type == JSON_OBJ) {
3469-
JsonValue *nm = json_obj_get(ex, "name");
3470-
const char *name_s = (nm && nm->type == JSON_STR) ? nm->as.str : "";
3471-
return stmt_pop(strdup(name_s), line, col);
3472-
}
3473-
return stmt_pop(strdup(""), line, col);
3459+
Expr *ex = deser_expr(json_obj_get(obj, "expression"), ctx, interp, err);
3460+
return stmt_pop(ex, line, col);
34743461
}
34753462
if (strcmp(name, "BreakStatement") == 0) {
34763463
Expr *ex = deser_expr(json_obj_get(obj, "expression"), ctx, interp, err);

src/interpreter.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3287,25 +3287,44 @@ static ExecResult exec_stmt(Interpreter *interp, Stmt *stmt, Env *env, LabelMap
32873287
}
32883288

32893289
case STMT_POP: {
3290-
// POP: retrieve identifier value, delete binding, and return the value
3291-
const char *name = stmt->as.pop_stmt.name;
3290+
// POP: evaluate expression that yields the symbol name (STR),
3291+
// delete the binding with that name, and return the retrieved value.
32923292
// POP is only valid inside a function (env != global_env)
32933293
if (env == interp->global_env) {
32943294
return make_error("POP used outside function", stmt->line, stmt->column);
32953295
}
32963296

3297+
Value name_val = eval_expr(interp, stmt->as.pop_stmt.expr, env);
3298+
if (interp->error) {
3299+
ExecResult err = make_error(interp->error, interp->error_line, interp->error_col);
3300+
clear_error(interp);
3301+
return err;
3302+
}
3303+
3304+
if (name_val.type != VAL_STR) {
3305+
value_free(name_val);
3306+
return make_error("POP requires a STR argument", stmt->line, stmt->column);
3307+
}
3308+
3309+
const char *name_c = name_val.as.s ? name_val.as.s : "";
3310+
char *name = strdup(name_c);
3311+
value_free(name_val);
3312+
32973313
Value v;
32983314
DeclType dtype;
32993315
bool initialized = false;
33003316
if (!env_get(env, name, &v, &dtype, &initialized) || !initialized) {
3317+
free(name);
33013318
return make_error("Cannot POP undefined or uninitialized identifier", stmt->line, stmt->column);
33023319
}
33033320

33043321
if (!env_delete(env, name)) {
3322+
free(name);
33053323
value_free(v);
33063324
return make_error("Failed to delete identifier during POP", stmt->line, stmt->column);
33073325
}
33083326

3327+
free(name);
33093328
ExecResult res;
33103329
res.status = EXEC_RETURN;
33113330
res.value = v; // transfer ownership to caller

src/parser.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,14 +1187,12 @@ static Stmt *parse_statement(Parser *parser) {
11871187
Token tok = parser->current_token;
11881188
advance(parser);
11891189
consume(parser, TOKEN_LPAREN, "Expected '(' after POP");
1190-
if (parser->current_token.type != TOKEN_IDENT) {
1191-
report_error(parser, "POP expects an identifier");
1190+
Expr *expr = parse_expression(parser);
1191+
if (!expr) {
11921192
return NULL;
11931193
}
1194-
char *name = parser->current_token.literal;
1195-
advance(parser);
1196-
consume(parser, TOKEN_RPAREN, "Expected ')' after POP identifier");
1197-
return stmt_pop(name, tok.line, tok.column);
1194+
consume(parser, TOKEN_RPAREN, "Expected ')' after POP expression");
1195+
return stmt_pop(expr, tok.line, tok.column);
11981196
}
11991197
case TOKEN_BREAK: {
12001198
Token tok = parser->current_token;

tests/cases/passing/func-pop.pre

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
INT pop_target = 0d8
22

33
FUNC INT take_and_delete(){
4-
POP(pop_target)
4+
POP("pop_target")
55
}
66

77
ASSERT(EQ(take_and_delete(), 0d8))

0 commit comments

Comments
 (0)