lower: 슬라이싱

x[a..b] 는 인덱스가 아니라 포인터와 길이를 만든다. 양쪽 끝을 -- 서로에 대해,
그리고 있는 것에 대해 -- 검사한 뒤에 포인터를 만든다. 유효한 범위의 빈
슬라이스는 괜찮고 끝보다 늦게 시작하는 것은 아니다.

파서가 x[a] 와 x[a..] 를 구분하지 못했다. 둘 다 b 만 있고 c 가 없어서
모양이 같았다. '..' 가 있었으면 노드에 표시한다.

정수 출력이 된다: fizz 12345 -678
This commit is contained in:
2026-08-17 06:20:17 +09:00
parent 0de10f37b5
commit eba6f63530
4 changed files with 71 additions and 3 deletions
+3
View File
@@ -44,6 +44,9 @@ struct FeNode {
#define FE_NODE_PUB 0x8U
#define FE_NODE_COMPTIME 0x10U
#define FE_NODE_EXTERN 0x20U
/* An index expression that had `..` in it, so it makes a slice rather than
reaching an element. `x[a]` and `x[a..]` are otherwise the same shape. */
#define FE_NODE_SLICE 0x40U
typedef struct FeAst {
FeArena arena;
+46 -1
View File
@@ -62,6 +62,8 @@ static void lower_stmt(Lower *L, FeNode *n);
static void store_into(Lower *L, FeIrPlace dst, Slot value, FeNode *n,
unsigned long size);
static void lower_for(Lower *L, FeNode *n);
static Slot lower_slice(Lower *L, FeNode *n);
static void guard(Lower *L, unsigned ok, FeIrTrap reason, unsigned long line);
static void lower_match(Lower *L, FeNode *n);
static int enum_has_payload(const FeType *t);
static void lower_global(Lower *L, FeNode *n);
@@ -673,7 +675,7 @@ static Slot lower_expr_core(Lower *L, FeNode *n)
unsigned scale;
unsigned offset;
unsigned addr;
if (n->c || !n->b) { fail(L, "a slice expression", n); return slot_void(); }
if (n->flags & FE_NODE_SLICE) return lower_slice(L, n);
base = lower_expr(L, n->a);
indexable_parts(L, base, bt, &data, &length, n);
index = as_value(L, lower_expr(L, n->b), n->b);
@@ -973,6 +975,49 @@ static void lower_while(Lower *L, FeNode *n)
L->b = done;
}
/* `x[a..b]` makes a pointer and a length out of part of something indexable.
Both ends are checked -- against each other and against what is there --
before the pointer is formed. An empty slice of a valid range is fine; one
that starts past its end is not. */
static Slot lower_slice(Lower *L, FeNode *n)
{
FeType *bt = n->a ? n->a->sem_type : 0;
FeType *elem = bt ? bt->elem : 0;
FeType *t = n->sem_type;
Slot base = lower_expr(L, n->a);
unsigned data;
unsigned length;
unsigned from;
unsigned to;
unsigned local;
unsigned scale;
unsigned off;
unsigned at;
unsigned count;
indexable_parts(L, base, bt, &data, &length, n);
from = n->b ? as_value(L, lower_expr(L, n->b), n->b)
: fe_ir_const(L->m, L->b, FE_IR_I32, 0);
to = n->c ? as_value(L, lower_expr(L, n->c), n->c) : length;
if (!L->c->no_checks) {
unsigned ordered = fe_ir_binary(L->m, L->b, FE_IR_LE, FE_IR_I32,
from, to, 1);
unsigned within;
guard(L, ordered, FE_TRAP_BOUNDS, n->loc.line);
within = fe_ir_binary(L->m, L->b, FE_IR_LE, FE_IR_I32, to, length, 1);
guard(L, within, FE_TRAP_BOUNDS, n->loc.line);
}
scale = fe_ir_const(L->m, L->b, FE_IR_I32, (long)ir_size(elem));
off = fe_ir_binary(L->m, L->b, FE_IR_MUL, FE_IR_I32, from, scale, 1);
at = fe_ir_binary(L->m, L->b, FE_IR_ADD, FE_IR_PTR, data, off, 1);
count = fe_ir_binary(L->m, L->b, FE_IR_SUB, FE_IR_I32, to, from, 1);
local = scratch(L, t, "slice");
fe_ir_store(L->m, L->b, fe_ir_at_local(local, SLICE_PTR_OFFSET), at,
FE_IR_PTR);
fe_ir_store(L->m, L->b, fe_ir_at_local(local, SLICE_LEN_OFFSET), count,
FE_IR_I32);
return slot_place(fe_ir_at_local(local, 0), FE_IR_MEM, ir_size(t));
}
/* Three shapes share the keyword.
for i in a..b { } counts
+2 -2
View File
@@ -124,8 +124,8 @@ static FeNode *postfix(FeParser *p)
if(eat(p,FE_TOK_LPAREN)) { m=toknode(p,FE_N_CALL,t); m->a=n; while(!is(p,FE_TOK_RPAREN)&&!is(p,FE_TOK_EOF)){fe_node_add(m,delimited_expr(p));if(!eat(p,FE_TOK_COMMA))break;} want(p,FE_TOK_RPAREN,"expected ')' after call"); n=m; }
else if(eat(p,FE_TOK_LBRACKET)) {
m=toknode(p,FE_N_INDEX,t);m->a=n;
if(is(p,FE_TOK_DOTDOT)) m->b=0; else m->b=delimited_expr(p);
if(eat(p,FE_TOK_DOTDOT)) { if(!is(p,FE_TOK_RBRACKET)) m->c=delimited_expr(p); }
if(is(p,FE_TOK_DOTDOT)) { m->b=0; m->flags|=FE_NODE_SLICE; } else m->b=delimited_expr(p);
if(eat(p,FE_TOK_DOTDOT)) { m->flags|=FE_NODE_SLICE; if(!is(p,FE_TOK_RBRACKET)) m->c=delimited_expr(p); }
want(p,FE_TOK_RBRACKET,"expected ']' after index");n=m;
}
else if(eat(p,FE_TOK_DOT)) {