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* send_with_args_expression(sl_parse_state_t* ps, sl_node_base_t* recv, SLID id) { size_t argc = 0, cap = 2; sl_node_base_t** argv = sl_alloc(ps->vm->arena, sizeof(sl_node_base_t*) * cap); bool splat_last = false; expect_token(ps, SL_TOK_OPEN_PAREN); while(peek_token(ps)->type != SL_TOK_CLOSE_PAREN) { if(argc >= cap) { cap *= 2; argv = sl_realloc(ps->vm->arena, argv, sizeof(sl_node_base_t*) * cap); } if(peek_token(ps)->type == SL_TOK_TIMES) { next_token(ps); splat_last = true; argv[argc++] = expression(ps); break; } argv[argc++] = expression(ps); if(peek_token(ps)->type != SL_TOK_CLOSE_PAREN) { expect_token(ps, SL_TOK_COMMA); } } expect_token(ps, SL_TOK_CLOSE_PAREN); return sl_make_send_node(ps, recv, id, argc, argv, splat_last); }
static sl_node_base_t* statement(sl_parse_state_t* ps) { sl_node_base_t* node; switch(peek_token(ps)->type) { case SL_TOK_CLOSE_TAG: next_token(ps); node = inline_raw(ps); if(peek_token(ps)->type != SL_TOK_END) { expect_token(ps, SL_TOK_OPEN_TAG); } return node; case SL_TOK_SEMICOLON: next_token(ps); return NULL; case SL_TOK_IF: case SL_TOK_UNLESS: return if_expression(ps); case SL_TOK_FOR: return for_expression(ps); case SL_TOK_WHILE: case SL_TOK_UNTIL: return while_expression(ps); default: node = expression(ps); if(peek_token(ps)->type != SL_TOK_CLOSE_TAG && peek_token(ps)->type != SL_TOK_CLOSE_BRACE && token(ps)->type != SL_TOK_CLOSE_BRACE && peek_token(ps)->type != SL_TOK_END) { expect_token(ps, SL_TOK_SEMICOLON); } return node; } }
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); }
enum internal_ret parse_instruction(struct assembler *a, const struct inst_generic *inst, void (*handler) (struct assembler *, const struct inst_generic *, struct inst_reg *)) { int i; struct lexer_link *link = a->link; struct inst_reg r[4]; memset(r, 0, sizeof(struct inst_reg) * 4); for (i = 0; i < inst->reg_count; i++) { link = get_next_link(a, link); switch (inst->rs[i]) { case REG_REGISTER: expect_token(a, link, TOK_REGISTER); r[i].val = link->lex.val; break; case REG_IMMEDIATE: if (link->tok == TOK_INTEGER) { r[i].val = link->lex.val; } else if (link->tok == TOK_IDENT) { r[i].val = 0; r[i].ident = strdup(link->lex.ident); } else { a->err_tok = link; return RET_UNEXPECTED; } break; case REG_ADDRESS: if (link->tok == TOK_INTEGER) { r[i].val = link->lex.val >> 2; } else if (link->tok == TOK_IDENT) { r[i].val = 0; r[i].ident = strdup(link->lex.ident); } else { a->err_tok = link; return RET_UNEXPECTED; } break; case REG_DEREF_REG: expect_token(a, link, TOK_INTEGER); r[i].val = link->lex.val; link = get_next_link(a, link); expect_token(a, link, TOK_LPAREN); link = get_next_link(a, link); expect_token(a, link, TOK_REGISTER); r[i + 1].val = link->lex.val; i++; link = get_next_link(a, link); expect_token(a, link, TOK_RPAREN); break; }
static sl_node_base_t* regexp_expression(sl_parse_state_t* ps) { sl_token_t* re = expect_token(ps, SL_TOK_REGEXP); sl_token_t* opts = expect_token(ps, SL_TOK_REGEXP_OPTS); return sl_make_immediate_node(ps, sl_make_regexp(ps->vm, re->as.str.buff, re->as.str.len, opts->as.str.buff, opts->as.str.len)); }
static sl_node_base_t* echo_tag(sl_parse_state_t* ps) { sl_node_base_t* expr; expect_token(ps, SL_TOK_OPEN_ECHO_TAG); expr = expression(ps); expect_token(ps, SL_TOK_CLOSE_TAG); return sl_make_echo_node(ps, expr); }
static sl_node_base_t* bracketed_expression(sl_parse_state_t* ps) { sl_node_base_t* node; expect_token(ps, SL_TOK_OPEN_PAREN); node = expression(ps); expect_token(ps, SL_TOK_CLOSE_PAREN); return node; }
static sl_node_base_t* call_expression(sl_parse_state_t* ps) { sl_node_base_t* left = primary_expression(ps); sl_node_base_t** nodes; size_t node_len; size_t node_cap; sl_token_t* tok; if(left->type == SL_NODE_VAR && peek_token(ps)->type == SL_TOK_OPEN_PAREN) { left = send_with_args_expression(ps, sl_make_self_node(ps), sl_intern2(ps->vm, sl_make_ptr((sl_object_t*)((sl_node_var_t*)left)->name))); } while(1) { tok = peek_token(ps); switch(tok->type) { case SL_TOK_DOT: next_token(ps); left = send_expression(ps, left); break; case SL_TOK_COLON: next_token(ps); left = sl_make_bind_method_node(ps, left, def_expression_method_name(ps)); break; case SL_TOK_PAAMAYIM_NEKUDOTAYIM: next_token(ps); tok = expect_token(ps, SL_TOK_CONSTANT); left = sl_make_const_node(ps, left, sl_intern2(ps->vm, sl_make_string(ps->vm, tok->as.str.buff, tok->as.str.len))); break; case SL_TOK_OPEN_BRACKET: next_token(ps); node_cap = 1; node_len = 0; nodes = sl_alloc(ps->vm->arena, sizeof(SLVAL) * node_cap); while(peek_token(ps)->type != SL_TOK_CLOSE_BRACKET) { if(node_len >= node_cap) { node_cap *= 2; nodes = sl_realloc(ps->vm->arena, nodes, sizeof(SLVAL) * node_cap); } nodes[node_len++] = expression(ps); if(peek_token(ps)->type != SL_TOK_CLOSE_BRACKET) { expect_token(ps, SL_TOK_COMMA); } } expect_token(ps, SL_TOK_CLOSE_BRACKET); left = sl_make_send_node(ps, left, sl_intern(ps->vm, "[]"), node_len, nodes); break; default: return left; } } }
static sl_node_base_t* assignment_expression(sl_parse_state_t* ps) { sl_node_base_t* left = range_expression(ps); sl_token_t* tok = peek_token(ps); char* op_method; switch(tok->type) { case SL_TOK_EQUALS: op_method = NULL; break; case SL_TOK_ASSIGN_PLUS: op_method = "+"; break; case SL_TOK_ASSIGN_MINUS: op_method = "-"; break; case SL_TOK_ASSIGN_POW: op_method = "**"; break; case SL_TOK_ASSIGN_TIMES: op_method = "*"; break; case SL_TOK_ASSIGN_DIVIDE: op_method = "/"; break; case SL_TOK_ASSIGN_MOD: op_method = "%"; break; case SL_TOK_ASSIGN_PIPE: op_method = "|"; break; case SL_TOK_ASSIGN_AMP: op_method = "&"; break; case SL_TOK_ASSIGN_CARET: op_method = "^"; break; case SL_TOK_ASSIGN_OR: op_method = "||"; break; case SL_TOK_ASSIGN_AND: op_method = "&&"; break; case SL_TOK_ASSIGN_SHIFT_LEFT: op_method = "<<"; break; case SL_TOK_ASSIGN_SHIFT_RIGHT: op_method = ">>"; break; default: return left; } switch(left->type) { case SL_NODE_VAR: case SL_NODE_IVAR: case SL_NODE_CVAR: next_token(ps); left = sl_make_simple_assign_node(ps, (sl_node_var_t*)left, assignment_expression(ps), op_method); break; case SL_NODE_SEND: next_token(ps); left = sl_make_assign_send_node(ps, (sl_node_send_t*)left, assignment_expression(ps), op_method); break; case SL_NODE_CONST: /* compound assignment makes no sense on constants, so error if the assignment operator is anything except '=': */ expect_token(ps, SL_TOK_EQUALS); left = sl_make_assign_const_node(ps, (sl_node_const_t*)left, assignment_expression(ps)); break; case SL_NODE_ARRAY: /* compound assignment makes no sense on arrays, so error if the assignment operator is anything except '=': */ expect_token(ps, SL_TOK_EQUALS); left = sl_make_assign_array_node(ps, (sl_node_array_t*)left, assignment_expression(ps)); break; default: break; } return left; }
/* * Read the configuration from the config file. */ static void read_config(struct config_s *config) { // Copy the default configuration values: memmove(config, &config_default, sizeof(struct config_s)); // Find a configuration file: const char *filename = CONFIG_FILENAME; FILE *file = fopen(filename, "r"); if (file == NULL) { warning("unable to open configuration file \"%s\" for reading; " "will use backup configuration file", filename); filename = CONFIG_BAK_FILENAME; file = fopen(filename, "r"); if (file == NULL) { warning("unable to open backup configuration file \"%s\" for " "reading", filename); return; } } // Parse the configuration file: struct http_user_vars_s vars; http_user_vars_init(&vars); char var[MAX_TOKEN_LENGTH+1]; char val[MAX_TOKEN_LENGTH+1]; bool success; while (true) { token_t t = expect_token(filename, file, var, TOKEN_VAR, true); if (t == TOKEN_END) { success = true; break; } if (t != TOKEN_VAR || TOKEN_EQ != expect_token(filename, file, NULL, TOKEN_EQ, false) || TOKEN_VAL != expect_token(filename, file, val, TOKEN_VAL, false)) { success = false; break; } http_user_var_insert(&vars, var, val); } fclose(file); // Load the configuration: load_config(&vars, config); http_user_vars_free(&vars); }
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* body_expression(sl_parse_state_t* ps) { sl_node_seq_t* seq = sl_make_seq_node(ps); sl_node_base_t* node; expect_token(ps, SL_TOK_OPEN_BRACE); while(peek_token(ps)->type != SL_TOK_CLOSE_BRACE) { node = statement(ps); if(node) { sl_seq_node_append(ps, seq, node); } } expect_token(ps, SL_TOK_CLOSE_BRACE); return (sl_node_base_t*)seq; }
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* 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 int parse_end_sequence(struct TestFile *tf, const char *kind, const char *name, size_t name_len) { char message[32] = "end "; char *tok; size_t len; strncpy(message + 4, kind, sizeof(message) - 4); if (expect_token(tf, "end", message)) return -1; // expect kind tok = next_token(tf, &len); assert(tok != NULL); if (tok == END_OF_LINE) { syntax_error(tf); return -1; } if (!same_token(kind, strlen(kind), tok, len)) { vfail(tf, tf->read_pos, "expected \"end %s\"", kind); return -1; } // check end name if given and present if (name) { tok = next_name(tf, &len); assert(tok != NULL); if (tok != END_OF_LINE && !same_token(name, name_len, tok, len)) { vfail(tf, tf->read_pos, "mismatched %s name", kind); return -1; } } return expect_eol(tf); }
static sl_node_base_t* bracketed_expression(sl_parse_state_t* ps) { sl_node_base_t* node; expect_token(ps, SL_TOK_OPEN_PAREN); node = expression(ps); if(peek_token(ps)->type == SL_TOK_SEMICOLON) { sl_node_seq_t* seq = sl_make_seq_node(ps); sl_seq_node_append(ps, seq, node); while(peek_token(ps)->type == SL_TOK_SEMICOLON) { next_token(ps); sl_seq_node_append(ps, seq, expression(ps)); } node = (sl_node_base_t*)seq; } expect_token(ps, SL_TOK_CLOSE_PAREN); return node; }
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); }
TEST(terminal_read_test, read_mouse_command_yields_mouse_report) { expect_token( "\x1B[M @B", terminalpp::ansi::mouse::report { terminalpp::ansi::mouse::report::LEFT_BUTTON_DOWN, 31, 33 }); }
static sl_node_base_t* array_expression(sl_parse_state_t* ps) { size_t count = 0, cap = 2; sl_node_base_t** nodes = sl_alloc(ps->vm->arena, sizeof(sl_node_base_t*) * cap); expect_token(ps, SL_TOK_OPEN_BRACKET); while(peek_token(ps)->type != SL_TOK_CLOSE_BRACKET) { if(count >= cap) { cap *= 2; nodes = sl_realloc(ps->vm->arena, nodes, sizeof(sl_node_base_t*) * cap); } nodes[count++] = expression(ps); if(peek_token(ps)->type != SL_TOK_CLOSE_BRACKET) { expect_token(ps, SL_TOK_COMMA); } } expect_token(ps, SL_TOK_CLOSE_BRACKET); return sl_make_array_node(ps, count, nodes); }
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); }
TEST(terminal_read_test, read_character_yields_virtual_key) { expect_token( "z", terminalpp::virtual_key{ terminalpp::vk::lowercase_z, terminalpp::vk_modifier::none, 1, { 'z' } }); }
TEST(terminal_read_test, read_non_mouse_similar_command_yields_command) { expect_token( "\x1B?M", terminalpp::ansi::control_sequence { '?', 'M', false, { "" } }); }
TEST(terminal_read_test, read_meta_command_yields_meta_command) { expect_token( "\x1B\x1B[S", terminalpp::ansi::control_sequence { '[', 'S', true, { "" } }); }
TEST(terminal_read_test, read_command_with_arguments_yields_command_with_arguments) { expect_token( "\x1B[22;33S", terminalpp::ansi::control_sequence { '[', 'S', false, { "22", "33" } }); }
TEST(terminal_read_test, read_8bit_command_yields_command) { expect_token( "\x9B""22;33S", terminalpp::ansi::control_sequence { '[', 'S', false, { "22", "33" } }); }
TEST(terminal_read_test, read_uppercase_character_yields_character_without_modifier) { // We consider uppercase letters to be entirely different keypresses. expect_token( "Z", terminalpp::virtual_key{ terminalpp::vk::uppercase_z, terminalpp::vk_modifier::none, 1, { 'Z' } }); }
TEST(terminal_read_test, read_bang_extended_command_yields_extended_command) { expect_token( "\x1B[!p", terminalpp::ansi::control_sequence { '[', 'p', false, { "" }, '!' }); }
TEST(terminal_read_test, read_gt_extended_command_yields_extended_command) { expect_token( "\x1B[>5c", terminalpp::ansi::control_sequence { '[', 'c', false, { "5" }, '>' }); }
TEST(terminal_read_test, read_query_extended_command_yields_extended_command) { expect_token( "\x1B[?6n", terminalpp::ansi::control_sequence { '[', 'n', false, { "6" }, '?' }); }