static sl_node_base_t* if_expression(sl_parse_state_t* ps) { sl_node_base_t *condition, *if_true, *if_false = NULL; int negate_condition = 0; if(peek_token(ps)->type == SL_TOK_ELSIF) { expect_token(ps, SL_TOK_ELSIF); } else if(peek_token(ps)->type == SL_TOK_UNLESS) { expect_token(ps, SL_TOK_UNLESS); negate_condition = 1; } else { expect_token(ps, SL_TOK_IF); } condition = expression(ps); if(negate_condition) { condition = sl_make_unary_node(ps, condition, SL_NODE_NOT); } if_true = body_expression(ps); if(peek_token(ps)->type == SL_TOK_ELSIF) { if_false = if_expression(ps); } if(peek_token(ps)->type == SL_TOK_ELSE) { next_token(ps); if_false = body_expression(ps); } return sl_make_if_node(ps, condition, if_true, if_false); }
static sl_node_base_t* switch_expression(sl_parse_state_t* ps) { expect_token(ps, SL_TOK_SWITCH); sl_node_base_t* value = expression(ps); expect_token(ps, SL_TOK_OPEN_BRACE); size_t case_count = 0, case_cap = 2; sl_node_switch_case_t* cases = sl_alloc(ps->vm->arena, sizeof(sl_node_switch_case_t) * case_cap); sl_node_base_t* else_body = NULL; while(peek_token(ps)->type != SL_TOK_CLOSE_BRACE) { if(peek_token(ps)->type == SL_TOK_ELSE) { next_token(ps); else_body = body_expression(ps); break; } if(case_count + 1 >= case_cap) { case_cap *= 2; cases = sl_realloc(ps->vm->arena, cases, sizeof(sl_node_switch_case_t) * case_cap); } cases[case_count].value = expression(ps); cases[case_count].body = body_expression(ps); case_count++; } expect_token(ps, SL_TOK_CLOSE_BRACE); return sl_make_switch_node(ps, value, case_count, cases, else_body); }
static sl_node_base_t* for_expression(sl_parse_state_t* ps) { sl_node_base_t *lval, *expr, *body, *else_body = NULL; sl_node_seq_t* seq_lval; sl_token_t* tok; sl_parse_scope_t scope; expect_token(ps, SL_TOK_FOR); /* save current token to allow rewinding and erroring */ tok = peek_token(ps); lval = call_expression(ps); if(!sl_node_is_lval(lval)) { unexpected(ps, tok); } if(peek_token(ps)->type == SL_TOK_COMMA || peek_token(ps)->type == SL_TOK_FAT_COMMA) { seq_lval = sl_make_seq_node(ps); seq_lval->nodes[seq_lval->node_count++] = lval; while(peek_token(ps)->type == SL_TOK_COMMA || peek_token(ps)->type == SL_TOK_FAT_COMMA) { next_token(ps); if(seq_lval->node_count == seq_lval->node_capacity) { seq_lval->node_capacity *= 2; seq_lval->nodes = sl_realloc(ps->vm->arena, seq_lval->nodes, sizeof(sl_node_base_t*) * seq_lval->node_capacity); } tok = peek_token(ps); lval = call_expression(ps); if(!sl_node_is_lval(lval)) { unexpected(ps, tok); } seq_lval->nodes[seq_lval->node_count++] = lval; } lval = sl_make_array_node(ps, seq_lval->node_count, seq_lval->nodes); } expect_token(ps, SL_TOK_IN); expr = expression(ps); scope.prev = ps->scope; scope.flags = scope.prev->flags | SL_PF_CAN_NEXT_LAST; ps->scope = &scope; body = body_expression(ps); ps->scope = scope.prev; if(scope.flags & SL_PF_SCOPE_CLOSURE) { ps->scope->flags |= SL_PF_SCOPE_CLOSURE; } if(peek_token(ps)->type == SL_TOK_ELSE) { next_token(ps); else_body = body_expression(ps); } return sl_make_for_node(ps, lval, expr, body, else_body); }
static sl_node_base_t* while_expression(sl_parse_state_t* ps) { sl_node_base_t *condition, *body; sl_parse_scope_t scope; int until = 0; if(peek_token(ps)->type == SL_TOK_UNTIL) { next_token(ps); until = 1; } else { expect_token(ps, SL_TOK_WHILE); } condition = expression(ps); if(until) { condition = sl_make_unary_node(ps, condition, SL_NODE_NOT); } scope.prev = ps->scope; scope.flags = scope.prev->flags | SL_PF_CAN_NEXT_LAST; ps->scope = &scope; body = body_expression(ps); ps->scope = scope.prev; if(scope.flags & SL_PF_SCOPE_CLOSURE) { ps->scope->flags |= SL_PF_SCOPE_CLOSURE; } return sl_make_while_node(ps, condition, body); }
static sl_node_base_t* try_expression(sl_parse_state_t* ps) { sl_node_base_t *body, *lval = NULL, *catch_body = NULL; sl_token_t* tok; expect_token(ps, SL_TOK_TRY); body = body_expression(ps); expect_token(ps, SL_TOK_CATCH); tok = peek_token(ps); if(tok->type != SL_TOK_OPEN_BRACE) { lval = primary_expression(ps); if(!sl_node_is_lval(lval)) { unexpected(ps, tok); } } catch_body = body_expression(ps); return sl_make_try_node(ps, body, lval, catch_body); }
static sl_node_base_t* class_expression(sl_parse_state_t* ps) { expect_token(ps, SL_TOK_CLASS); sl_token_t* tok = expect_token(ps, SL_TOK_CONSTANT); SLID name = sl_intern2(ps->vm, sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); sl_node_base_t *extends, *body; if(peek_token(ps)->type == SL_TOK_EXTENDS) { next_token(ps); extends = expression(ps); } else { extends = NULL; } body = body_expression(ps); return sl_make_class_node(ps, name, extends, body); }
static sl_node_base_t* lambda_expression(sl_parse_state_t* ps) { sl_node_base_t* body; sl_token_t* tok; size_t arg_count = 0, arg_cap = 2; sl_string_t** args = sl_alloc(ps->vm->arena, sizeof(sl_string_t*) * arg_cap); sl_parse_scope_t scope; expect_token(ps, SL_TOK_LAMBDA); if(peek_token(ps)->type == SL_TOK_IDENTIFIER) { tok = next_token(ps); args[arg_count++] = (sl_string_t*)sl_get_ptr( sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); } else if(peek_token(ps)->type != SL_TOK_OPEN_BRACE && peek_token(ps)->type != SL_TOK_DOT) { expect_token(ps, SL_TOK_OPEN_PAREN); while(peek_token(ps)->type != SL_TOK_CLOSE_PAREN) { if(arg_count >= arg_cap) { arg_cap *= 2; args = sl_realloc(ps->vm->arena, args, sizeof(sl_string_t*) * arg_cap); } tok = expect_token(ps, SL_TOK_IDENTIFIER); args[arg_count++] = (sl_string_t*)sl_get_ptr( sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); if(peek_token(ps)->type != SL_TOK_CLOSE_PAREN) { expect_token(ps, SL_TOK_COMMA); } } expect_token(ps, SL_TOK_CLOSE_PAREN); } scope.prev = ps->scope; scope.flags = SL_PF_CAN_RETURN; ps->scope = &scope; if(peek_token(ps)->type == SL_TOK_DOT) { next_token(ps); body = expression(ps); } else { body = body_expression(ps); } ps->scope = scope.prev; ps->scope->flags |= SL_PF_SCOPE_CLOSURE; return sl_make_lambda_node(ps, arg_count, args, body); }
static sl_node_base_t* def_expression(sl_parse_state_t* ps) { SLID name; sl_node_base_t* on = NULL; sl_node_base_t* body; sl_token_t* tok; size_t req_arg_count = 0, req_arg_cap = 2; sl_string_t** req_args = sl_alloc(ps->vm->arena, sizeof(sl_string_t*) * req_arg_cap); size_t opt_arg_count = 0, opt_arg_cap = 2; sl_node_opt_arg_t* opt_args = sl_alloc(ps->vm->arena, sizeof(sl_node_opt_arg_t) * opt_arg_cap); sl_parse_scope_t scope; expect_token(ps, SL_TOK_DEF); switch(peek_token(ps)->type) { case SL_TOK_IDENTIFIER: if(peek_token_n(ps, 2)->type == SL_TOK_DOT) { on = sl_make_var_node(ps, SL_NODE_VAR, next_token(ps)->str); next_token(ps); name = def_expression_method_name(ps); } else { on = NULL; name = def_expression_method_name(ps); } break; case SL_TOK_SELF: case SL_TOK_IVAR: case SL_TOK_CVAR: case SL_TOK_CONSTANT: on = primary_expression(ps); expect_token(ps, SL_TOK_DOT); name = def_expression_method_name(ps); break; default: name = def_expression_method_name(ps); } if(peek_token(ps)->type == SL_TOK_EQUALS) { next_token(ps); name = sl_intern2(ps->vm, sl_string_concat(ps->vm, sl_id_to_string(ps->vm, name), sl_make_cstring(ps->vm, "="))); } int at_opt_args = 0; if(peek_token(ps)->type != SL_TOK_OPEN_BRACE) { expect_token(ps, SL_TOK_OPEN_PAREN); if(peek_token(ps)->type == SL_TOK_SELF) { error(ps, sl_make_cstring(ps->vm, "not a chance"), peek_token(ps)); } while(peek_token(ps)->type != SL_TOK_CLOSE_PAREN) { tok = expect_token(ps, SL_TOK_IDENTIFIER); if(peek_token(ps)->type == SL_TOK_EQUALS) { at_opt_args = 1; } if(at_opt_args) { expect_token(ps, SL_TOK_EQUALS); if(opt_arg_count >= opt_arg_cap) { opt_arg_cap *= 2; opt_args = sl_realloc(ps->vm->arena, opt_args, sizeof(sl_node_opt_arg_t) * opt_arg_cap); } opt_args[opt_arg_count].name = (sl_string_t*)sl_get_ptr( sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); opt_args[opt_arg_count++].default_value = expression(ps); } else { if(req_arg_count >= req_arg_cap) { req_arg_cap *= 2; req_args = sl_realloc(ps->vm->arena, req_args, sizeof(sl_string_t*) * req_arg_cap); } req_args[req_arg_count++] = (sl_string_t*)sl_get_ptr( sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len)); } if(peek_token(ps)->type != SL_TOK_CLOSE_PAREN) { expect_token(ps, SL_TOK_COMMA); } } expect_token(ps, SL_TOK_CLOSE_PAREN); } scope.prev = ps->scope; scope.flags = SL_PF_CAN_RETURN; ps->scope = &scope; body = body_expression(ps); ps->scope = scope.prev; ps->scope->flags |= SL_PF_SCOPE_CLOSURE; return sl_make_def_node(ps, name, on, req_arg_count, req_args, opt_arg_count, opt_args, body); }