From c2d9270cf90c6707bd6959bea22328ce7b0ef5ce Mon Sep 17 00:00:00 2001 From: cassowarii Date: Sun, 12 Jul 2026 16:24:19 -0700 Subject: [PATCH] project euler #0 (which exposed a bug in my bigint promotion code!) --- sample/project_euler/pe00.sa | 5 +++++ src/compile/emit.c | 1 + src/data/integer.c | 4 ++-- src/lib/module/list.c | 37 +++++++++++++++++++++++++++++-------- src/parse/lexer.c | 23 ++++++++++------------- 5 files changed, 47 insertions(+), 23 deletions(-) create mode 100644 sample/project_euler/pe00.sa diff --git a/sample/project_euler/pe00.sa b/sample/project_euler/pe00.sa new file mode 100644 index 0000000..a383a86 --- /dev/null +++ b/sample/project_euler/pe00.sa @@ -0,0 +1,5 @@ +list::iota1 130_000 + | _.filter => n { not (n %% 2) } + | _.map => n { n * n } + | _.reduce 0, => a, b { a + b } + | println diff --git a/src/compile/emit.c b/src/compile/emit.c index f7ee340..ccd02e4 100644 --- a/src/compile/emit.c +++ b/src/compile/emit.c @@ -431,6 +431,7 @@ void compile_op(sbVmCompiler *cm, sbAstOp op) { case AST_OP_GT: EMIT(BC_OP_LE, BC_OP_NOT); break; case AST_OP_LE: EMIT(BC_OP_LE); break; case AST_OP_GE: EMIT(BC_OP_LT, BC_OP_NOT); break; + case AST_OP_NOT: EMIT(BC_OP_NOT); break; case AST_OP_AND: EMIT(BC_OP_AND); break; case AST_OP_OR: EMIT(BC_OP_OR); break; case AST_OP_INDEX: EMIT(BC_OP_INDEX); break; diff --git a/src/data/integer.c b/src/data/integer.c index bee7706..b06ed74 100644 --- a/src/data/integer.c +++ b/src/data/integer.c @@ -66,8 +66,8 @@ hInteger sbInteger_new(i64 value) { i->sign_bit = 1; value *= -1; } - i->buf.data[0] = (value % BIGINT_PIECE_MAX); - i->buf.data[1] = (value / BIGINT_PIECE_MAX); + ((piece*)(i->buf.data))[0] = (value % BIGINT_PIECE_MAX); + ((piece*)(i->buf.data))[1] = (value / BIGINT_PIECE_MAX); return i->handle; } diff --git a/src/lib/module/list.c b/src/lib/module/list.c index 5845041..770fc0d 100644 --- a/src/lib/module/list.c +++ b/src/lib/module/list.c @@ -10,9 +10,13 @@ sbLibTable g_list_module; -static void iota(hVm vm, usize argc) { +static void do_iota(hVm vm, usize argc, i32 offset) { if (argc != 1 && argc != 2) { - PANIC("list::iota takes 1 or 2 arguments"); + if (offset == 1) { + PANIC("list::iota1 takes 1 or 2 arguments"); + } else { + PANIC("list::iota takes 1 or 2 arguments"); + } } hV *first = sbVm_pop(vm); @@ -20,17 +24,25 @@ static void iota(hVm vm, usize argc) { hInteger min, max; if (argc == 1) { if (first->type != IT_INTEGER) { - PANIC("list::iota's argument must be an integer!"); + if (offset == 1) { + PANIC("list::iota1's argument must be an integer!"); + } else { + PANIC("list::iota's argument must be an integer!"); + } } - min = 0; - max = first->integer; + min = offset; + max = first->integer + offset; } else { hV *second = sbVm_pop(vm); if (first->type != IT_INTEGER || second->type != IT_INTEGER) { - PANIC("list::iota's arguments must be integers!"); + if (offset == 1) { + PANIC("list::iota1's arguments must be integers!"); + } else { + PANIC("list::iota's arguments must be integers!"); + } } - min = first->integer; - max = second->integer; + min = first->integer + offset; + max = second->integer + offset; } hList result = sbList_new((usize)sbInteger_diff(max, min)); @@ -43,8 +55,17 @@ static void iota(hVm vm, usize argc) { sbVm_push_immediate(vm, &HVLIST(result)); } +static void iota(hVm vm, usize argc) { + do_iota(vm, argc, 0); +} + +static void iota1(hVm vm, usize argc) { + do_iota(vm, argc, 1); +} + void sbLib_loadmodule_list() { sbLibTable_initialize(&g_list_module, 16, FALSE); REGISTER_VALUE(&g_list_module, "iota", &HVBUILTIN(iota)); + REGISTER_VALUE(&g_list_module, "iota1", &HVBUILTIN(iota1)); REGISTER_VALUE(&g_list_module, "convert", &HVSYM(S_OP_TO_LIST)); } diff --git a/src/parse/lexer.c b/src/parse/lexer.c index db364ae..7ec339a 100644 --- a/src/parse/lexer.c +++ b/src/parse/lexer.c @@ -198,8 +198,6 @@ static flag is_closing_bracket(sbTokenType type) { /* header keywords that introduce a block and go until a { */ static flag begins_brace_terminated_state(sbTokenType type) { return type == T_rDEF - || type == T_rIF - || type == T_rUNLESS || type == T_rWHILE || type == T_rUNTIL || type == T_rDO @@ -211,6 +209,12 @@ static flag begins_brace_terminated_state(sbTokenType type) { || type == T_SQUIGARROW; /* squiggle arrow ~> a, b { ... } introduces block header also */ } +/* only starts BTS at start of line, not in middle of line */ +static flag begins_brace_terminated_state_at_line_start(sbTokenType type) { + return type == T_rIF + || type == T_rUNLESS; +} + /* things we can potentially insert a ( after because they may be a call */ static flag can_open_paren_after(sbTokenType type) { return type == T_IDENTIFIER @@ -232,19 +236,11 @@ static flag block_header_can_end_after(sbTokenType type) { || type == T_rDO; } -/* these are operators that look weird if they get captured inside - * of parentheses, and also if and unless in postfix form */ +/* close invisible parentheses before we see this token */ static flag close_invisible_parens_before(sbTokenType type) { - return type == T_rAND - || type == T_rOR + return type == T_SEMICOLON || type == T_rIF || type == T_rUNLESS - || type == T_DOUBLEEQUALS - || type == T_NOTEQUALS - || type == T_LESS - || type == T_GREATER - || type == T_LESSEQUALS - || type == T_GREATEREQUALS || type == T_PIPE; } @@ -394,7 +390,8 @@ static void compute_next_token(hLexer lx) { unstack_all_invisible_parentheses(lx); } - if (begins_brace_terminated_state(token.type)) { + if (begins_brace_terminated_state(token.type) + || (begins_brace_terminated_state_at_line_start(token.type) && lx->last_token_seen.type == ';')) { /* don't start brace-terminated state if we are directly after a '}' (otherwise it gets * confused by things like repeat..until */ if (lx->last_token_seen.type != '}') { -- 1.8.3.1