MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add switch cases

+304 -18
+1 -1
meson.build
··· 41 41 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 42 42 43 43 version_conf = configuration_data() 44 - version_conf.set('ANT_VERSION', '0.0.5.44') 44 + version_conf.set('ANT_VERSION', '0.0.5.45') 45 45 version_conf.set('ANT_GIT_HASH', git_hash) 46 46 version_conf.set('ANT_BUILD_DATE', build_date) 47 47
+220 -17
src/ant.c
··· 85 85 #define F_BREAK 8U // exit the loop 86 86 #define F_RETURN 16U // return has been executed 87 87 #define F_THROW 32U // throw has been executed 88 + #define F_SWITCH 64U // we are inside a switch statement 88 89 jsoff_t clen; // code snippet length 89 90 jsoff_t pos; // current parsing position 90 91 jsoff_t toff; // offset of the last parsed token ··· 181 182 static jsval_t js_do_while(struct js *js); 182 183 static jsval_t js_block_or_stmt(struct js *js); 183 184 static jsval_t js_try(struct js *js); 185 + static jsval_t js_switch(struct js *js); 184 186 static jsval_t do_op(struct js *, uint8_t op, jsval_t l, jsval_t r); 185 187 static jsval_t do_instanceof(struct js *js, jsval_t l, jsval_t r); 186 188 static jsval_t do_in(struct js *js, jsval_t l, jsval_t r); ··· 3747 3749 static jsval_t js_break(struct js *js) { 3748 3750 if (js->flags & F_NOEXEC) { 3749 3751 } else { 3750 - if (!(js->flags & F_LOOP)) return js_mkerr(js, "not in loop"); 3752 + if (!(js->flags & (F_LOOP | F_SWITCH))) return js_mkerr(js, "not in loop or switch"); 3751 3753 js->flags |= F_BREAK | F_NOEXEC; 3752 3754 } 3753 3755 js->consumed = 1; ··· 3782 3784 return res; 3783 3785 } 3784 3786 3787 + static jsval_t js_switch(struct js *js) { 3788 + uint8_t flags = js->flags, exe = !(flags & F_NOEXEC); 3789 + jsval_t res = js_mkundef(); 3790 + 3791 + js->consumed = 1; 3792 + if (!expect(js, TOK_LPAREN, &res)) return res; 3793 + 3794 + jsoff_t switch_expr_start = js->pos; 3795 + uint8_t saved_flags = js->flags; 3796 + js->flags |= F_NOEXEC; 3797 + jsval_t switch_expr = js_expr(js); 3798 + js->flags = saved_flags; 3799 + 3800 + if (is_err(switch_expr)) return switch_expr; 3801 + 3802 + if (!expect(js, TOK_RPAREN, &res)) return res; 3803 + if (!expect(js, TOK_LBRACE, &res)) return res; 3804 + 3805 + typedef struct { 3806 + jsoff_t case_expr_start; 3807 + jsoff_t case_expr_end; 3808 + jsoff_t body_start; 3809 + bool is_default; 3810 + } CaseInfo; 3811 + 3812 + CaseInfo cases[64]; 3813 + int case_count = 0; 3814 + 3815 + js->flags |= F_NOEXEC; 3816 + 3817 + while (next(js) != TOK_RBRACE && next(js) != TOK_EOF && case_count < 64) { 3818 + if (next(js) == TOK_CASE) { 3819 + js->consumed = 1; 3820 + 3821 + cases[case_count].is_default = false; 3822 + cases[case_count].case_expr_start = js->pos; 3823 + 3824 + jsval_t case_val = js_expr(js); 3825 + if (is_err(case_val)) { 3826 + js->flags = flags; 3827 + return case_val; 3828 + } 3829 + 3830 + cases[case_count].case_expr_end = js->pos; 3831 + 3832 + if (!expect(js, TOK_COLON, &res)) { 3833 + js->flags = flags; 3834 + return res; 3835 + } 3836 + 3837 + cases[case_count].body_start = js->pos; 3838 + case_count++; 3839 + 3840 + while (next(js) != TOK_EOF && next(js) != TOK_CASE && next(js) != TOK_DEFAULT && next(js) != TOK_RBRACE) { 3841 + jsval_t stmt = js_stmt(js); 3842 + if (is_err(stmt)) { 3843 + js->flags = flags; 3844 + return stmt; 3845 + } 3846 + } 3847 + 3848 + } else if (next(js) == TOK_DEFAULT) { 3849 + js->consumed = 1; 3850 + 3851 + cases[case_count].is_default = true; 3852 + cases[case_count].case_expr_start = 0; 3853 + cases[case_count].case_expr_end = 0; 3854 + 3855 + if (!expect(js, TOK_COLON, &res)) { 3856 + js->flags = flags; 3857 + return res; 3858 + } 3859 + 3860 + cases[case_count].body_start = js->pos; 3861 + case_count++; 3862 + 3863 + while (next(js) != TOK_EOF && next(js) != TOK_CASE && next(js) != TOK_DEFAULT && next(js) != TOK_RBRACE) { 3864 + jsval_t stmt = js_stmt(js); 3865 + if (is_err(stmt)) { 3866 + js->flags = flags; 3867 + return stmt; 3868 + } 3869 + } 3870 + 3871 + } else { 3872 + break; 3873 + } 3874 + } 3875 + 3876 + if (!expect(js, TOK_RBRACE, &res)) { 3877 + js->flags = flags; 3878 + return res; 3879 + } 3880 + 3881 + jsoff_t end_pos = js->pos; 3882 + 3883 + if (exe) { 3884 + js->pos = switch_expr_start; 3885 + js->consumed = 1; 3886 + js->flags = flags; 3887 + jsval_t switch_val = resolveprop(js, js_expr(js)); 3888 + 3889 + if (is_err(switch_val)) { 3890 + js->pos = end_pos; 3891 + js->flags = flags; 3892 + return switch_val; 3893 + } 3894 + 3895 + int matching_case = -1; 3896 + int default_case = -1; 3897 + 3898 + for (int i = 0; i < case_count; i++) { 3899 + if (cases[i].is_default) { 3900 + default_case = i; 3901 + continue; 3902 + } 3903 + 3904 + js->pos = cases[i].case_expr_start; 3905 + js->consumed = 1; 3906 + js->flags = flags; 3907 + jsval_t case_val = resolveprop(js, js_expr(js)); 3908 + 3909 + if (is_err(case_val)) { 3910 + js->pos = end_pos; 3911 + js->flags = flags; 3912 + return case_val; 3913 + } 3914 + 3915 + bool matches = false; 3916 + if (vtype(switch_val) == vtype(case_val)) { 3917 + if (vtype(switch_val) == T_NUM) { 3918 + matches = tod(switch_val) == tod(case_val); 3919 + } else if (vtype(switch_val) == T_STR) { 3920 + jsoff_t n1, off1 = vstr(js, switch_val, &n1); 3921 + jsoff_t n2, off2 = vstr(js, case_val, &n2); 3922 + matches = n1 == n2 && memcmp(&js->mem[off1], &js->mem[off2], n1) == 0; 3923 + } else if (vtype(switch_val) == T_BOOL) { 3924 + matches = vdata(switch_val) == vdata(case_val); 3925 + } else { 3926 + matches = vdata(switch_val) == vdata(case_val); 3927 + } 3928 + } 3929 + 3930 + if (matches) { 3931 + matching_case = i; 3932 + break; 3933 + } 3934 + } 3935 + 3936 + if (matching_case < 0 && default_case >= 0) matching_case = default_case; 3937 + 3938 + if (matching_case >= 0) { 3939 + js->flags = (flags & ~F_NOEXEC) | F_SWITCH; 3940 + 3941 + for (int i = matching_case; i < case_count; i++) { 3942 + js->pos = cases[i].body_start; 3943 + js->consumed = 1; 3944 + 3945 + while (next(js) != TOK_EOF && next(js) != TOK_CASE && 3946 + next(js) != TOK_DEFAULT && next(js) != TOK_RBRACE && 3947 + !(js->flags & (F_BREAK | F_RETURN | F_THROW))) { 3948 + res = js_stmt(js); 3949 + if (is_err(res)) { 3950 + js->pos = end_pos; 3951 + uint8_t preserve = 0; 3952 + if (js->flags & F_RETURN) { 3953 + preserve = js->flags & (F_RETURN | F_NOEXEC); 3954 + } 3955 + if (js->flags & F_THROW) { 3956 + preserve = js->flags & (F_THROW | F_NOEXEC); 3957 + } 3958 + js->flags = flags | preserve; 3959 + return res; 3960 + } 3961 + } 3962 + 3963 + if (js->flags & F_BREAK) js->flags &= ~F_BREAK; break; 3964 + if (js->flags & (F_RETURN | F_THROW)) break; 3965 + } 3966 + } 3967 + } 3968 + 3969 + js->pos = end_pos; 3970 + js->tok = TOK_SEMICOLON; 3971 + js->consumed = 0; 3972 + 3973 + uint8_t preserve = 0; 3974 + if (js->flags & F_RETURN) { 3975 + preserve = js->flags & (F_RETURN | F_NOEXEC); 3976 + } 3977 + if (js->flags & F_THROW) { 3978 + preserve = js->flags & (F_THROW | F_NOEXEC); 3979 + } 3980 + js->flags = (flags & ~F_SWITCH) | preserve; 3981 + 3982 + return res; 3983 + } 3984 + 3785 3985 static jsval_t js_class_decl(struct js *js) { 3786 3986 uint8_t exe = !(js->flags & F_NOEXEC); 3787 3987 js->consumed = 1; ··· 3964 4164 return js_mkundef(); 3965 4165 } 3966 4166 4167 + static void js_throw_handle(struct js *js, jsval_t *res) { 4168 + js->consumed = 1; 4169 + jsval_t throw_val = js_expr(js); 4170 + if (js->flags & F_NOEXEC) { 4171 + *res = js_mkundef(); 4172 + } else { 4173 + throw_val = resolveprop(js, throw_val); 4174 + if (is_err(throw_val)) { 4175 + *res = throw_val; 4176 + } else { 4177 + *res = js_throw(js, throw_val); 4178 + } 4179 + } 4180 + } 4181 + 3967 4182 static jsval_t js_stmt(struct js *js) { 3968 4183 jsval_t res; 3969 4184 if (js->brk > js->gct) js_gc(js); ··· 3971 4186 switch (next(js)) { 3972 4187 case TOK_CASE: case TOK_CATCH: 3973 4188 case TOK_DEFAULT: case TOK_FINALLY: 3974 - case TOK_SWITCH: 4189 + res = js_mkerr(js, "SyntaxError '%.*s'", (int) js->tlen, js->code + js->toff); 4190 + break; 3975 4191 case TOK_WITH: case TOK_YIELD: 3976 4192 res = js_mkerr(js, "'%.*s' not implemented", (int) js->tlen, js->code + js->toff); 3977 4193 break; 3978 - case TOK_THROW: { 3979 - js->consumed = 1; 3980 - jsval_t throw_val = js_expr(js); 3981 - if (js->flags & F_NOEXEC) { 3982 - res = js_mkundef(); 3983 - } else { 3984 - throw_val = resolveprop(js, throw_val); 3985 - if (is_err(throw_val)) { 3986 - res = throw_val; 3987 - } else { 3988 - res = js_throw(js, throw_val); 3989 - } 3990 - } 3991 - break; 3992 - } 4194 + case TOK_THROW: js_throw_handle(js, &res); break; 3993 4195 case TOK_VAR: 3994 4196 if (!js->var_warning_shown) { 3995 4197 fprintf(stderr, "Warning: 'var' is deprecated, use 'let' or 'const' instead\n"); ··· 3997 4199 } 3998 4200 res = js_let(js); 3999 4201 break; 4202 + case TOK_SWITCH: res = js_switch(js); break; 4000 4203 case TOK_WHILE: res = js_while(js); break; 4001 4204 case TOK_DO: res = js_do_while(js); break; 4002 4205 case TOK_CONTINUE: res = js_continue(js); break;
+9
tests/for_in.js
··· 1 + const person = { 2 + name: 'Alice', 3 + age: 30, 4 + city: 'New York' 5 + }; 6 + 7 + for (let key in person) { 8 + console.log(`${key}: ${person[key]}`); 9 + }
+74
tests/test_switch.cjs
··· 1 + // Test basic switch statement 2 + let x = 2; 3 + let result = 0; 4 + 5 + switch (x) { 6 + case 1: 7 + result = 10; 8 + break; 9 + case 2: 10 + result = 20; 11 + break; 12 + case 3: 13 + result = 30; 14 + break; 15 + default: 16 + result = 99; 17 + } 18 + 19 + console.log('Result:', result); // Should be 20 20 + 21 + // Test switch without break (fall-through) 22 + let y = 1; 23 + let sum = 0; 24 + 25 + switch (y) { 26 + case 1: 27 + sum = sum + 1; 28 + case 2: 29 + sum = sum + 2; 30 + case 3: 31 + sum = sum + 3; 32 + break; 33 + default: 34 + sum = sum + 100; 35 + } 36 + 37 + console.log('Sum:', sum); // Should be 6 (1+2+3) 38 + 39 + // Test switch with string 40 + let fruit = 'apple'; 41 + let color = ''; 42 + 43 + switch (fruit) { 44 + case 'apple': 45 + color = 'red'; 46 + break; 47 + case 'banana': 48 + color = 'yellow'; 49 + break; 50 + case 'grape': 51 + color = 'purple'; 52 + break; 53 + default: 54 + color = 'unknown'; 55 + } 56 + 57 + console.log('Color:', color); // Should be "red" 58 + 59 + // Test switch with default only 60 + let z = 5; 61 + let msg = ''; 62 + 63 + switch (z) { 64 + case 1: 65 + msg = 'one'; 66 + break; 67 + case 2: 68 + msg = 'two'; 69 + break; 70 + default: 71 + msg = 'other'; 72 + } 73 + 74 + console.log('Message:', msg); // Should be "other"