static void _syx_parser_parse_body (SyxParser *self) { SyxToken token = syx_lexer_get_last_token (self->lexer); while (TRUE) { while (token.type == SYX_TOKEN_CLOSING) { if (self->_in_block && token.value.character == ']') return; if (token.value.character == '.') { token = syx_lexer_next_token (self->lexer); /* Do not pop from the stack multiple times */ if (token.type != SYX_TOKEN_CLOSING && token.type != SYX_TOKEN_END) syx_bytecode_pop_top (self->bytecode); } else token = syx_lexer_next_token (self->lexer); } if (token.type == SYX_TOKEN_END) break; _syx_parser_parse_statement (self); token = syx_lexer_get_last_token (self->lexer); } if (self->_in_block) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected ] after block body")); }
static void _syx_parser_parse_expression (SyxParser *self) { SyxToken token = syx_lexer_get_last_token (self->lexer); syx_string assign_name; syx_bool super_term = FALSE; if (token.type == SYX_TOKEN_NAME_CONST) { assign_name = syx_strdup (token.value.string); syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (token.type == SYX_TOKEN_BINARY && (!strcmp (token.value.string, ":=") || !strcmp (token.value.string, "<-"))) { syx_token_free (token); syx_lexer_next_token (self->lexer); _syx_parser_parse_assignment (self, assign_name); } else /* Not an assignment, let it be a name term then */ super_term = _syx_parser_parse_name_term (self, assign_name); syx_free (assign_name); } else super_term = _syx_parser_parse_term (self); /* After we got the initial object, we can do message continuation on it specifying if 'super' has been requested instead of self */ _syx_parser_do_continuation (self, super_term); }
static void _syx_parser_parse_temporaries (SyxParser *self) { SyxToken token = syx_lexer_get_last_token (self->lexer); SyxParserScope *scope = self->_temporary_scopes + self->_temporary_scopes_top; if (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, "|")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); while (token.type == SYX_TOKEN_NAME_CONST) { scope->stack[scope->top++] = syx_strdup (token.value.string); syx_token_free (token); token = syx_lexer_next_token (self->lexer); } if (! (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, "|"))) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Temporary list not terminated by bar")); syx_token_free (token); syx_lexer_next_token (self->lexer); } /* we choose the maximum number so we can hold all the temporaries without forgetting previous parsed optimized blocks. */ if (SYX_IS_NIL (SYX_CODE_TEMPORARIES_COUNT (self->method)) || scope->top > SYX_SMALL_INTEGER (SYX_CODE_TEMPORARIES_COUNT (self->method))) SYX_CODE_TEMPORARIES_COUNT(self->method) = syx_small_integer_new (scope->top); }
static void _syx_parser_parse_temporaries (SyxParser *self) { SyxToken token = syx_lexer_get_last_token (self->lexer); SyxParserScope scope; scope.start = self->_temporary_names_top; scope.end = self->_temporary_names_top; if (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, "|")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); while (token.type == SYX_TOKEN_NAME_CONST) { self->_temporary_names[self->_temporary_names_top++] = token.value.string; scope.end++; token = syx_lexer_next_token (self->lexer); } if (! (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, "|"))) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Temporary list not terminated by bar")); syx_token_free (token); syx_lexer_next_token (self->lexer); } self->_temporary_scopes.stack[(syx_int32) self->_temporary_scopes.top++] = scope; }
static void _syx_parser_parse_block_message_pattern (SyxParser *self) { SyxToken token = syx_lexer_get_last_token (self->lexer); SyxParserScope *scope = self->_argument_scopes + self->_argument_scopes_top; if (! (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, ":"))) { SYX_CODE_ARGUMENTS_COUNT(self->method) = syx_small_integer_new (0); return; } while (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, ":")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); assert (token.type == SYX_TOKEN_NAME_CONST); scope->stack[scope->top++] = syx_strdup (token.value.string); syx_token_free (token); token = syx_lexer_next_token (self->lexer); } if (! (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, "|"))) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected | after block message pattern\n")); syx_token_free (token); syx_lexer_next_token (self->lexer); SYX_CODE_ARGUMENTS_COUNT(self->method) = syx_small_integer_new (scope->top); return; }
static void _syx_parser_parse_method_message_pattern (SyxParser *self) { SyxToken token = syx_lexer_get_last_token (self->lexer); syx_char selector[256] = {0}; SyxParserScope scope; scope.start = self->_argument_names_top; scope.end = self->_argument_names_top; switch (token.type) { case SYX_TOKEN_NAME_CONST: /* Unary message pattern */ SYX_METHOD_SELECTOR(self->method) = syx_symbol_new (token.value.string); syx_token_free (token); syx_lexer_next_token (self->lexer); break; case SYX_TOKEN_BINARY: /* Binary message pattern */ SYX_METHOD_SELECTOR(self->method) = syx_symbol_new (token.value.string); syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (token.type != SYX_TOKEN_NAME_CONST) syx_error ("Expected name constant for argument name\n"); self->_argument_names[self->_argument_names_top++] = token.value.string; scope.end++; syx_lexer_next_token (self->lexer); break; case SYX_TOKEN_NAME_COLON: /* Keyword message pattern */ while (token.type == SYX_TOKEN_NAME_COLON) { strcat (selector, token.value.string); syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (token.type != SYX_TOKEN_NAME_CONST) syx_error ("Expected name constant for argument name\n"); self->_argument_names[self->_argument_names_top++] = token.value.string; scope.end++; token = syx_lexer_next_token (self->lexer); } SYX_METHOD_SELECTOR(self->method) = syx_symbol_new (selector); break; default: syx_error ("Invalid message pattern\n"); } self->_argument_scopes.stack[(syx_int32) self->_argument_scopes.top++] = scope; SYX_CODE_ARGUMENT_COUNT(self->method) = syx_small_integer_new (scope.end - scope.start); }
static void _syx_parser_parse_method_message_pattern (SyxParser *self) { SyxToken token = syx_lexer_get_last_token (self->lexer); syx_char selector[0xFF] = {0}; SyxParserScope *scope = self->_argument_scopes + self->_argument_scopes_top; switch (token.type) { case SYX_TOKEN_NAME_CONST: /* Unary message pattern */ SYX_METHOD_SELECTOR(self->method) = syx_symbol_new (token.value.string); syx_token_free (token); syx_lexer_next_token (self->lexer); break; case SYX_TOKEN_BINARY: /* Binary message pattern */ SYX_METHOD_SELECTOR(self->method) = syx_symbol_new (token.value.string); syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (token.type != SYX_TOKEN_NAME_CONST) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected name constant for argument name\n")); scope->stack[scope->top++] = syx_strdup (token.value.string); syx_token_free (token); syx_lexer_next_token (self->lexer); break; case SYX_TOKEN_NAME_COLON: /* Keyword message pattern */ while (token.type == SYX_TOKEN_NAME_COLON) { strcat (selector, token.value.string); syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (token.type != SYX_TOKEN_NAME_CONST) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected name constant for argument name\n")); scope->stack[scope->top++] = syx_strdup (token.value.string); syx_token_free (token); token = syx_lexer_next_token (self->lexer); } SYX_METHOD_SELECTOR(self->method) = syx_symbol_new (selector); break; default: syx_signal (SYX_ERROR_INTERP, syx_string_new ("Invalid message pattern\n")); } SYX_CODE_ARGUMENTS_COUNT(self->method) = syx_small_integer_new (scope->top); }
static SyxOop _syx_parser_parse_literal_array (SyxParser *self) { SyxOop elements[256]; syx_varsize top = 0; SyxToken token; token = syx_lexer_next_token (self->lexer); while (! (token.type == SYX_TOKEN_END || (token.type == SYX_TOKEN_CLOSING && token.value.character == ')'))) { switch (token.type) { case SYX_TOKEN_ARRAY_BEGIN: elements[top++] = _syx_parser_parse_literal_array (self); break; case SYX_TOKEN_INT_CONST: elements[top++] = syx_small_integer_new (token.value.integer); break; case SYX_TOKEN_BINARY: if (!strcmp (token.value.string, "(")) { elements[top++] = _syx_parser_parse_literal_array (self); syx_token_free (token); break; } case SYX_TOKEN_NAME_CONST: case SYX_TOKEN_NAME_COLON: case SYX_TOKEN_SYM_CONST: elements[top++] = syx_symbol_new (token.value.string); syx_token_free (token); break; case SYX_TOKEN_STR_CONST: elements[top++] = syx_string_new (token.value.string); syx_token_free (token); break; case SYX_TOKEN_CHAR_CONST: elements[top++] = syx_character_new (token.value.character); break; default: syx_signal (SYX_ERROR_INTERP, syx_string_new ("Illegal text in literal array\n")); break; } token = syx_lexer_next_token (self->lexer); } return syx_array_new_ref (top, elements); }
static syx_bool _syx_parser_do_binary_continuation (SyxParser *self, syx_bool super_receiver, syx_bool do_cascade) { syx_string selector; SyxToken token; syx_bool super_term; super_receiver = _syx_parser_do_unary_continuation (self, super_receiver, do_cascade); token = syx_lexer_get_last_token (self->lexer); while (token.type == SYX_TOKEN_BINARY) { selector = syx_strdup (token.value.string); if (do_cascade) { self->_duplicate_indexes[self->_duplicate_indexes_top - 1] = self->bytecode->code_top; do_cascade = FALSE; } syx_token_free (token); syx_lexer_next_token (self->lexer); super_term = _syx_parser_parse_term (self); _syx_parser_do_unary_continuation (self, super_term, FALSE); token = syx_lexer_get_last_token (self->lexer); syx_bytecode_gen_message (self->bytecode, super_receiver, 1, selector); syx_free (selector); } return super_receiver; }
static syx_varsize _syx_parser_parse_optimized_block (SyxParser *self, SyxBytecodeSpecial branch_type, syx_bool do_pop) { syx_int8 scope_top; syx_uint16 jump; syx_bool block_state; SyxToken token; syx_int32 i; syx_bytecode_do_special (self->bytecode, branch_type); syx_bytecode_gen_code (self->bytecode, 0); jump = self->bytecode->code_top - 1; if (do_pop) syx_bytecode_pop_top (self->bytecode); block_state = self->_in_block; self->_in_block = TRUE; token = syx_lexer_get_last_token (self->lexer); if (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, "[")) { syx_token_free (token); syx_lexer_next_token (self->lexer); /* we need to restore the current scope after the optimized block has been parsed */ scope_top = self->_temporary_scopes[self->_temporary_scopes_top].top; _syx_parser_parse_temporaries (self); _syx_parser_parse_body (self); for (i=scope_top; i < self->_temporary_scopes[self->_temporary_scopes_top].top; i++) syx_free (self->_temporary_scopes[self->_temporary_scopes_top].stack[i]); self->_temporary_scopes[self->_temporary_scopes_top].top = scope_top; token = syx_lexer_next_token (self->lexer); } else { /* a variable or such has been used, like ifTrue: trueBlock */ _syx_parser_do_binary_continuation (self, _syx_parser_parse_term (self), FALSE); syx_bytecode_gen_message (self->bytecode, FALSE, 0, "value"); } self->_in_block = block_state; self->bytecode->code[jump] = SYX_COMPAT_SWAP_16 (self->bytecode->code_top); return jump; }
static void _syx_parser_parse_array (SyxParser *self) { syx_varsize num_elements = 0; SyxToken token = syx_lexer_get_last_token (self->lexer); syx_token_free (token); token = syx_lexer_next_token (self->lexer); while (! (token.type == SYX_TOKEN_END || (token.type == SYX_TOKEN_CLOSING && token.value.character == '}'))) { _syx_parser_parse_expression (self); num_elements++; token = syx_lexer_get_last_token (self->lexer); if (token.type == SYX_TOKEN_CLOSING && token.value.character == '.') token = syx_lexer_next_token (self->lexer); } syx_bytecode_push_array (self->bytecode, num_elements); }
/*! Parse simple declarations like classes and methods. \return TRUE if no error has occurred */ syx_bool syx_cold_parse (SyxLexer *lexer) { SyxToken token; syx_bool parseOk = TRUE; token = syx_lexer_next_token (lexer); while (parseOk && token.type != SYX_TOKEN_END) { if (_IS_EXL_MARK (token)) parseOk = syx_cold_parse_methods (lexer); else parseOk = _syx_cold_parse_class (lexer); syx_token_free (token); token = syx_lexer_next_token (lexer); } syx_token_free (token); return parseOk; }
/*! Do parse. \return TRUE if parsing was successful, otherwise FALSE */ syx_bool syx_parser_parse (SyxParser *self, syx_bool skip_message_pattern) { SyxToken token; SyxParserScope scope; token = syx_lexer_next_token (self->lexer); if (token.type == SYX_TOKEN_END) return TRUE; if (skip_message_pattern) { scope.start = self->_argument_names_top; scope.end = self->_argument_names_top; self->_argument_scopes.stack[(syx_int32) self->_argument_scopes.top++] = scope; } else _syx_parser_parse_message_pattern (self); if (!self->_in_block) _syx_parser_parse_primitive (self); _syx_parser_parse_temporaries (self); if (self->_in_block) syx_bytecode_push_constant (self->bytecode, SYX_BYTECODE_CONST_NIL); _syx_parser_parse_body (self); syx_bytecode_do_special (self->bytecode, SYX_BYTECODE_SELF_RETURN); SYX_CODE_BYTECODES(self->method) = syx_byte_array_new_ref (self->bytecode->code_top * sizeof (syx_uint16), (syx_uint8 *)self->bytecode->code); SYX_CODE_LITERALS(self->method) = syx_array_new_ref (self->bytecode->literals_top, self->bytecode->literals); if (self->_in_block) SYX_BLOCK_ARGUMENT_STACK_TOP(self->method) = syx_small_integer_new (self->_argument_scopes.stack[self->_argument_scopes.top-1].start); else { SYX_METHOD_ARGUMENT_STACK_SIZE(self->method) = syx_small_integer_new (self->_argument_names_top); SYX_METHOD_TEMPORARY_STACK_SIZE(self->method) = syx_small_integer_new (self->_temporary_names_top); } SYX_CODE_STACK_SIZE(self->method) = syx_small_integer_new (self->bytecode->stack_size + 1); SYX_CODE_TEXT(self->method) = syx_string_new (self->lexer->text + syx_find_first_non_whitespace (self->lexer->text)); SYX_CODE_CLASS(self->method) = self->klass; return TRUE; }
static syx_varsize _syx_parser_parse_optimized_block (SyxParser *self, SyxBytecodeSpecial branch_type, syx_bool do_pop) { syx_uint16 jump; syx_bool block_state; SyxToken token; syx_bytecode_do_special (self->bytecode, branch_type); syx_bytecode_gen_code (self->bytecode, 0); jump = self->bytecode->code_top - 1; if (do_pop) syx_bytecode_pop_top (self->bytecode); block_state = self->_in_block; self->_in_block = TRUE; token = syx_lexer_get_last_token (self->lexer); if (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, "[")) { syx_token_free (token); syx_lexer_next_token (self->lexer); _syx_parser_parse_temporaries (self); _syx_parser_parse_body (self); self->_temporary_scopes.top--; token = syx_lexer_next_token (self->lexer); } else { _syx_parser_do_binary_continuation (self, _syx_parser_parse_term (self), FALSE); syx_bytecode_gen_message (self->bytecode, FALSE, 0, "value"); } self->_in_block = block_state; self->bytecode->code[jump] = SYX_COMPAT_SWAP_16 (self->bytecode->code_top); return jump; }
static SyxOop _syx_cold_parse_vars (SyxLexer *lexer, syx_bool capitalized) { SyxOop vars; SyxOop vars_raw[256]; syx_varsize vars_size; SyxToken token; /* Fetch variable names using the lexer */ token = syx_lexer_next_token (lexer); for (vars_size=0; token.type != SYX_TOKEN_END; vars_size++) { if (token.type != SYX_TOKEN_NAME_CONST) { syx_token_free (token); syx_error ("Expected names for variables\n"); } if (capitalized && !isupper (token.value.string[0])) { syx_token_free (token); syx_error ("First letter must be uppercase\n"); } vars_raw[vars_size] = syx_symbol_new (token.value.string); syx_token_free (token); token = syx_lexer_next_token (lexer); } /* Create the array */ vars = syx_array_new_size (vars_size); /* Copy out of the stack */ memcpy (SYX_OBJECT_DATA (vars), vars_raw, sizeof (SyxOop ) * vars_size); return vars; }
static void _syx_parser_parse_statement (SyxParser *self) { SyxToken token = syx_lexer_get_last_token (self->lexer); if (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, "^")) { syx_token_free (token); syx_lexer_next_token (self->lexer); _syx_parser_parse_expression (self); syx_bytecode_do_special (self->bytecode, SYX_BYTECODE_STACK_RETURN); } else _syx_parser_parse_expression (self); }
static void _syx_parser_parse_block_message_pattern (SyxParser *self) { SyxToken token = syx_lexer_get_last_token (self->lexer); SyxParserScope scope; scope.start = self->_argument_names_top; scope.end = self->_argument_names_top; if (! (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, ":"))) { self->_argument_scopes.stack[(syx_int32) self->_argument_scopes.top++] = scope; SYX_CODE_ARGUMENT_COUNT(self->method) = syx_small_integer_new (0); return; } while (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, ":")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); assert (token.type == SYX_TOKEN_NAME_CONST); self->_argument_names[self->_argument_names_top++] = token.value.string; scope.end++; token = syx_lexer_next_token (self->lexer); } if (! (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, "|"))) syx_error ("Expected | after block message pattern\n"); syx_token_free (token); syx_lexer_next_token (self->lexer); self->_argument_scopes.stack[(syx_int32) self->_argument_scopes.top++] = scope; SYX_CODE_ARGUMENT_COUNT(self->method) = syx_small_integer_new (scope.end - scope.start); return; }
/*! Do parse. \return TRUE if parsing was successful, otherwise FALSE */ syx_bool syx_parser_parse (SyxParser *self, syx_bool skip_message_pattern) { SyxToken token; token = syx_lexer_next_token (self->lexer); if (token.type == SYX_TOKEN_END) return TRUE; self->_temporary_scopes[self->_temporary_scopes_top].top = 0; self->_argument_scopes[self->_argument_scopes_top].top = 0; if (!skip_message_pattern) _syx_parser_parse_message_pattern (self); if (!self->_in_block) _syx_parser_parse_primitive (self); _syx_parser_parse_temporaries (self); if (self->_in_block) syx_bytecode_push_constant (self->bytecode, SYX_BYTECODE_CONST_NIL); _syx_parser_parse_body (self); syx_bytecode_do_special (self->bytecode, SYX_BYTECODE_SELF_RETURN); SYX_CODE_BYTECODES(self->method) = syx_byte_array_new_ref (self->bytecode->code_top * sizeof (syx_uint16), (syx_uint8 *)self->bytecode->code); SYX_CODE_LITERALS(self->method) = syx_array_new_ref (self->bytecode->literals_top, self->bytecode->literals); SYX_CODE_STACK_SIZE(self->method) = syx_small_integer_new (self->bytecode->stack_size + 1); SYX_CODE_TEXT(self->method) = syx_string_new (self->lexer->text + syx_find_first_non_whitespace (self->lexer->text)); SYX_CODE_CLASS(self->method) = self->klass; /* Free arguments and temporaries of this scope */ _syx_parser_free_arguments (self); _syx_parser_free_temporaries (self); return TRUE; }
static syx_bool _syx_parser_do_unary_continuation (SyxParser *self, syx_bool super_receiver, syx_bool do_cascade) { SyxToken token = syx_lexer_get_last_token (self->lexer); while (token.type == SYX_TOKEN_NAME_CONST) { if (do_cascade) self->_duplicate_indexes[self->_duplicate_indexes_top - 1] = self->bytecode->code_top; syx_bytecode_gen_message (self->bytecode, super_receiver, 0, token.value.string); syx_token_free (token); token = syx_lexer_next_token (self->lexer); super_receiver = FALSE; } return super_receiver; }
static void _syx_parser_do_continuation (SyxParser *self, syx_bool super_receiver) { SyxToken token; self->_duplicate_indexes_top++; super_receiver = _syx_parser_do_key_continuation (self, super_receiver); token = syx_lexer_get_last_token (self->lexer); while (token.type == SYX_TOKEN_CLOSING && token.value.character == ';') { syx_bytecode_duplicate_at (self->bytecode, self->_duplicate_indexes[self->_duplicate_indexes_top - 1]); syx_bytecode_pop_top (self->bytecode); syx_token_free (token); syx_lexer_next_token (self->lexer); _syx_parser_do_key_continuation (self, super_receiver); token = syx_lexer_get_last_token (self->lexer); } self->_duplicate_indexes_top--; }
static syx_bool _syx_parser_parse_term (SyxParser *self) { SyxToken token = syx_lexer_get_last_token (self->lexer); syx_bool super_term = FALSE; switch (token.type) { case SYX_TOKEN_NAME_CONST: super_term = _syx_parser_parse_name_term (self, token.value.string); syx_token_free (token); break; case SYX_TOKEN_STR_CONST: syx_bytecode_push_literal (self->bytecode, syx_string_new (token.value.string)); syx_token_free (token); break; case SYX_TOKEN_INT_CONST: syx_bytecode_push_literal (self->bytecode, syx_small_integer_new (token.value.integer)); syx_token_free (token); break; #ifdef HAVE_LIBGMP case SYX_TOKEN_LARGE_INT_CONST: syx_bytecode_push_literal (self->bytecode, syx_large_integer_new_mpz (token.value.large_integer)); syx_token_free (token); break; #endif case SYX_TOKEN_FLOAT_CONST: syx_bytecode_push_literal (self->bytecode, syx_float_new (token.value.floating)); syx_token_free (token); break; case SYX_TOKEN_SYM_CONST: syx_bytecode_push_literal (self->bytecode, syx_symbol_new (token.value.string)); syx_token_free (token); break; case SYX_TOKEN_CHAR_CONST: syx_bytecode_push_literal (self->bytecode, syx_character_new (token.value.character)); syx_token_free (token); break; case SYX_TOKEN_ARRAY_BEGIN: syx_bytecode_push_literal (self->bytecode, _syx_parser_parse_literal_array (self)); syx_token_free (token); break; case SYX_TOKEN_BINARY: if (!strcmp (token.value.string, "(")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); _syx_parser_parse_expression (self); token = syx_lexer_get_last_token (self->lexer); if (! (token.type == SYX_TOKEN_CLOSING && token.value.character == ')')) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected ) after sub expression")); break; } else if (!strcmp (token.value.string, "[")) { _syx_parser_parse_block (self); break; } else if (!strcmp (token.value.string, "{")) { _syx_parser_parse_array (self); break; } else if (!strcmp (token.value.string, "-")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (token.type == SYX_TOKEN_INT_CONST) syx_bytecode_push_literal (self->bytecode, syx_small_integer_new (-token.value.integer)); #ifdef HAVE_LIBGMP else if (token.type == SYX_TOKEN_LARGE_INT_CONST) { mpz_neg (*token.value.large_integer, *token.value.large_integer); syx_bytecode_push_literal (self->bytecode, syx_large_integer_new_mpz (token.value.large_integer)); } #endif /* HAVE_LIBGMP */ else if (token.type == SYX_TOKEN_FLOAT_CONST) syx_bytecode_push_literal (self->bytecode, syx_float_new (-token.value.floating)); else syx_signal(SYX_ERROR_INTERP, syx_string_new ("Negation not followed by number")); syx_token_free (token); break; } /* We continue here because of weird binary token used as expression start */ default: switch (token.type) { case SYX_TOKEN_END: syx_signal (SYX_ERROR_INTERP, syx_string_new ("Unexpected end of input")); break; case SYX_TOKEN_STRING_ENTRY: syx_signal (SYX_ERROR_INTERP, syx_string_new ("Invalid expression start: %s", token.value.string)); syx_token_free (token); break; case SYX_TOKEN_CLOSING: syx_signal (SYX_ERROR_INTERP, syx_string_new ("Unexpected closing: %c", token.value.character)); break; default: syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected expression")); break; } } syx_lexer_next_token (self->lexer); return super_term; }
static syx_bool _syx_cold_parse_class (SyxLexer *lexer) { SyxToken token = syx_lexer_get_last_token (lexer); SyxOop superclass, subclass; syx_string subclass_name; syx_bool existing_class = TRUE; SyxOop inst_vars, class_vars; SyxLexer *inst_vars_lexer, *class_vars_lexer; syx_varsize super_inst_vars_size; syx_int32 i; if (token.type != SYX_TOKEN_NAME_CONST) { syx_error ("Expected a name constant\n"); syx_token_free (token); return FALSE; } if (!strcmp (token.value.string, "nil")) superclass = syx_nil; else superclass = syx_globals_at (token.value.string); token = syx_lexer_next_token (lexer); if (!(token.type == SYX_TOKEN_NAME_COLON && !strcmp (token.value.string, "subclass:"))) { syx_token_free (token); syx_error ("Expected #subclass:\n"); return FALSE; } syx_token_free (token); token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_SYM_CONST) { syx_token_free (token); syx_error ("Expected a symbol constant\n"); return FALSE; } subclass_name = syx_strdup (token.value.string); syx_token_free (token); subclass = syx_globals_at_if_absent (subclass_name, syx_nil); if (strcmp (subclass_name, "Object")) { if (SYX_IS_NIL (subclass)) existing_class = FALSE; else { existing_class = TRUE; if (SYX_OOP_NE (SYX_CLASS_SUPERCLASS(subclass), superclass)) { syx_array_remove (SYX_CLASS_SUBCLASSES (SYX_CLASS_SUPERCLASS (subclass)), subclass); SYX_CLASS_SUPERCLASS(subclass) = superclass; syx_array_add (SYX_CLASS_SUBCLASSES (superclass), subclass, TRUE); syx_array_remove (SYX_CLASS_SUBCLASSES (SYX_CLASS_SUPERCLASS(syx_object_get_class (subclass))), syx_object_get_class (subclass)); SYX_CLASS_SUPERCLASS(syx_object_get_class (subclass)) = syx_object_get_class (superclass); syx_array_add (SYX_CLASS_SUBCLASSES (syx_object_get_class (superclass)), syx_object_get_class (subclass), TRUE); } } } token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_NAME_COLON) { syx_token_free (token); syx_error ("Expected #instanceVariableNames:\n"); return FALSE; } syx_token_free (token); token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_STR_CONST) { syx_token_free (token); syx_error ("Expected a string as argument for #instanceVariableNames:\n"); return FALSE; } inst_vars_lexer = syx_lexer_new (token.value.string); token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_NAME_COLON) { syx_token_free (token); syx_error ("Expected #classVariableNames:\n"); return FALSE; } syx_token_free (token); token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_STR_CONST) { syx_token_free (token); syx_error ("Expected a string as argument for #classVariableNames:\n"); return FALSE; } class_vars_lexer = syx_lexer_new (token.value.string); token = syx_lexer_next_token (lexer); if (!_IS_EXL_MARK (token)) { syx_token_free (token); syx_error ("Class definition must terminate with an exlamation mark\n"); return FALSE; } syx_token_free (token); if (!existing_class) { subclass = syx_class_new (superclass); SYX_CLASS_NAME(subclass) = syx_symbol_new (subclass_name); syx_globals_at_put (SYX_CLASS_NAME(subclass), subclass); } syx_free (subclass_name); /* Parse instance variables */ inst_vars = _syx_cold_parse_vars (inst_vars_lexer, FALSE); syx_lexer_free (inst_vars_lexer, TRUE); /* Fetch superclass instanceSize */ if (SYX_IS_NIL (superclass)) super_inst_vars_size = 0; else super_inst_vars_size = SYX_SMALL_INTEGER (SYX_CLASS_INSTANCE_SIZE (superclass)); SYX_CLASS_INSTANCE_VARIABLES(subclass) = inst_vars; SYX_CLASS_INSTANCE_SIZE(subclass) = syx_small_integer_new (super_inst_vars_size + SYX_OBJECT_DATA_SIZE (inst_vars)); /* Now parse class variables */ class_vars = _syx_cold_parse_vars (class_vars_lexer, TRUE); syx_lexer_free (class_vars_lexer, TRUE); SYX_CLASS_CLASS_VARIABLES(subclass) = syx_dictionary_new (SYX_OBJECT_DATA_SIZE (class_vars) + 10); /* translate from array to dictionary */ for (i=0; i < SYX_OBJECT_DATA_SIZE(class_vars); i++) syx_dictionary_at_symbol_put (SYX_CLASS_CLASS_VARIABLES(subclass), SYX_OBJECT_DATA(class_vars)[i], syx_nil); /* get rid of this */ syx_object_free (class_vars); return TRUE; }
static syx_bool _syx_parser_do_key_continuation (SyxParser *self, syx_bool super_receiver) { SyxToken token; syx_char selector[256] = {0}; syx_int8 num_args; syx_bool super_term; syx_uint16 jump, conditionJump, loopJump; SyxBytecodeSpecial branchType; super_receiver = _syx_parser_do_binary_continuation (self, super_receiver, TRUE); token = syx_lexer_get_last_token (self->lexer); if (token.type == SYX_TOKEN_NAME_COLON) { self->_duplicate_indexes[self->_duplicate_indexes_top - 1] = self->bytecode->code_top; if (!strcmp (token.value.string, "ifTrue:")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); jump = _syx_parser_parse_optimized_block (self, SYX_BYTECODE_BRANCH_IF_TRUE, FALSE); token = syx_lexer_get_last_token (self->lexer); if (token.type == SYX_TOKEN_NAME_COLON && !strcmp (token.value.string, "ifFalse:")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); /* skip ifFalse: block if condition is true */ syx_bytecode_do_special (self->bytecode, SYX_BYTECODE_BRANCH); syx_bytecode_gen_code (self->bytecode, 0); conditionJump = self->bytecode->code_top - 1; /* jump here if condition is false */ self->bytecode->code[jump] = SYX_COMPAT_SWAP_16 (self->bytecode->code_top); jump = _syx_parser_parse_optimized_block (self, SYX_BYTECODE_BRANCH, TRUE); /* We don't need any jump after ifFalse: */ self->bytecode->code[jump] = 0; /* jump here if condition was true */ self->bytecode->code[conditionJump] = SYX_COMPAT_SWAP_16 (self->bytecode->code_top); } return FALSE; } else if (!strcmp (token.value.string, "ifFalse:")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); jump = _syx_parser_parse_optimized_block (self, SYX_BYTECODE_BRANCH_IF_FALSE, FALSE); token = syx_lexer_get_last_token (self->lexer); if (token.type == SYX_TOKEN_NAME_COLON && !strcmp (token.value.string, "ifTrue:")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); /* skip ifTrue: block if condition is false */ syx_bytecode_do_special (self->bytecode, SYX_BYTECODE_BRANCH); syx_bytecode_gen_code (self->bytecode, 0); conditionJump = self->bytecode->code_top - 1; /* jump here if condition is true */ self->bytecode->code[jump] = SYX_COMPAT_SWAP_16 (self->bytecode->code_top); jump = _syx_parser_parse_optimized_block (self, SYX_BYTECODE_BRANCH, TRUE); /* We don't need any jump after ifFalse: */ self->bytecode->code[jump] = 0; /* jump here if condition was false */ self->bytecode->code[conditionJump] = SYX_COMPAT_SWAP_16 (self->bytecode->code_top); } return FALSE; } else if (!strcmp (token.value.string, "whileTrue:") || !strcmp (token.value.string, "whileFalse:")) { if (!strcmp (token.value.string, "whileTrue:")) branchType = SYX_BYTECODE_BRANCH_IF_TRUE; else branchType = SYX_BYTECODE_BRANCH_IF_FALSE; syx_token_free (token); token = syx_lexer_next_token (self->lexer); loopJump = self->bytecode->code_top; syx_bytecode_do_special (self->bytecode, SYX_BYTECODE_DUPLICATE); syx_bytecode_gen_message (self->bytecode, FALSE, 0, "value"); conditionJump = _syx_parser_parse_optimized_block (self, branchType, FALSE); syx_bytecode_pop_top (self->bytecode); syx_bytecode_do_special (self->bytecode, SYX_BYTECODE_BRANCH); syx_bytecode_gen_code (self->bytecode, loopJump); self->bytecode->code[conditionJump] = SYX_COMPAT_SWAP_16 (self->bytecode->code_top); syx_bytecode_pop_top (self->bytecode); return FALSE; } num_args = 0; while (token.type == SYX_TOKEN_NAME_COLON) { strcat (selector, token.value.string); num_args++; syx_token_free (token); syx_lexer_next_token (self->lexer); super_term = _syx_parser_parse_term (self); _syx_parser_do_binary_continuation (self, super_term, FALSE); token = syx_lexer_get_last_token (self->lexer); } syx_bytecode_gen_message (self->bytecode, super_receiver, num_args, selector); return FALSE; } return super_receiver; }
syx_bool syx_cold_parse_methods (SyxLexer *lexer) { SyxToken token; SyxOop klass; SyxParser *parser; SyxLexer *method_lexer; /*syx_symbol category; */ syx_string chunk; SyxLexer saved_lexer = *lexer; token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_NAME_CONST) { *lexer = saved_lexer; return FALSE; } klass = syx_globals_at (token.value.string); syx_token_free (token); if (SYX_IS_NIL (klass)) return FALSE; token = syx_lexer_next_token (lexer); if (token.type == SYX_TOKEN_NAME_CONST && !strcmp (token.value.string, "class")) { klass = syx_object_get_class (klass); syx_token_free (token); token = syx_lexer_next_token (lexer); } if (! (token.type == SYX_TOKEN_NAME_COLON && !strcmp (token.value.string, "methodsFor:"))) { *lexer = saved_lexer; return FALSE; } syx_token_free (token); token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_STR_CONST) { *lexer = saved_lexer; return FALSE; } /* category = syx_strdup (token.value.string); */ syx_token_free (token); token = syx_lexer_next_token (lexer); if (!_IS_EXL_MARK (token)) { *lexer = saved_lexer; return FALSE; } syx_token_free (token); if (SYX_IS_NIL (SYX_CLASS_METHODS (klass))) { SYX_CLASS_METHODS(klass) = syx_dictionary_new (50); } while (TRUE) { chunk = syx_lexer_next_chunk (lexer); method_lexer = syx_lexer_new (chunk); if (!method_lexer) break; parser = syx_parser_new (method_lexer, syx_method_new (), klass); syx_parser_parse (parser, FALSE); syx_dictionary_at_symbol_put (SYX_CLASS_METHODS(klass), SYX_METHOD_SELECTOR(parser->method), parser->method); syx_parser_free (parser, TRUE); } return TRUE; }
int SYX_CDECL main (int argc, char *argv[]) { SyxLexer *lexer; SyxToken token; syx_init (0, NULL, ".."); #ifdef HAVE_LIBGMP lexer = syx_lexer_new ("nameconst 123 16r123 16rFFFFFFFF 123.321 1e2 1.3e-2 $c $ #symbol #(aaa) \"comment\" 'string' + := -> !!"); #else lexer = syx_lexer_new ("nameconst 123 16r123 123.321 1e2 1.3e-2 $c $ #symbol #(aaa) \"comment\" 'string' + := -> !!"); #endif token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_NAME_CONST); assert (!strcmp (token.value.string, "nameconst")); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_INT_CONST); assert (token.value.integer == 123); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_INT_CONST); assert (token.value.integer == 0x123); #ifdef HAVE_LIBGMP token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_LARGE_INT_CONST); assert (mpz_cmp_si (*token.value.large_integer, 0xFFFFFFFF) == 0); #endif token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_FLOAT_CONST); assert (token.value.floating == 123.321); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_FLOAT_CONST); assert (token.value.floating == 100.0); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_FLOAT_CONST); assert (token.value.floating == 0.013); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_CHAR_CONST); assert (token.value.character == 'c'); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_CHAR_CONST); assert (token.value.character == ' '); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_SYM_CONST); assert (!strcmp (token.value.string, "symbol")); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_ARRAY_BEGIN); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_NAME_CONST); assert (!strcmp (token.value.string, "aaa")); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_CLOSING); assert (token.value.character == ')'); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_STR_CONST); assert (!strcmp (token.value.string, "string")); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_BINARY); assert (!strcmp (token.value.string, "+")); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_BINARY); assert (!strcmp (token.value.string, ":=")); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_BINARY); assert (!strcmp (token.value.string, "->")); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_BINARY); assert (!strcmp (token.value.string, "!")); syx_token_free (token); token = syx_lexer_next_token (lexer); assert (token.type == SYX_TOKEN_BINARY); assert (!strcmp (token.value.string, "!")); syx_token_free (token); syx_lexer_free (lexer, FALSE); return 0; }
static void _syx_parser_parse_primitive (SyxParser *self) { SyxToken token = syx_lexer_get_last_token (self->lexer); syx_int32 prim_index; SYX_METHOD_PRIMITIVE(self->method) = syx_small_integer_new (-1); if (! (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, "<"))) return; syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (token.type != SYX_TOKEN_NAME_COLON) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected name colon")); if (!strcmp (token.value.string, "primitive:")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (token.type != SYX_TOKEN_STR_CONST) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected a string containing the primitive to be called")); prim_index = syx_primitive_get_index (token.value.string); if (prim_index < 0) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Unknown primitive named", token.value.string)); syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (! (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, ">"))) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected >")); syx_token_free (token); SYX_METHOD_PRIMITIVE (self->method) = syx_small_integer_new (prim_index); syx_lexer_next_token (self->lexer); } else if (!strcmp (token.value.string, "cCall:")) { syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (token.type != SYX_TOKEN_STR_CONST) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected a string containing the primitive to be called")); syx_bytecode_gen_literal (self->bytecode, syx_symbol_new (token.value.string)); syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, ">")) { syx_token_free (token); syx_bytecode_gen_literal (self->bytecode, syx_nil); SYX_METHOD_PRIMITIVE (self->method) = syx_small_integer_new (-2); syx_lexer_next_token (self->lexer); return; } if (! (token.type == SYX_TOKEN_NAME_COLON && !strcmp (token.value.string, "plugin:"))) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected plugin:")); syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (token.type != SYX_TOKEN_STR_CONST) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected a string containing the plugin name")); syx_bytecode_gen_literal (self->bytecode, syx_symbol_new (token.value.string)); syx_token_free (token); token = syx_lexer_next_token (self->lexer); if (! (token.type == SYX_TOKEN_BINARY && !strcmp (token.value.string, ">"))) syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected >")); syx_token_free (token); syx_lexer_next_token (self->lexer); SYX_METHOD_PRIMITIVE(self->method) = syx_small_integer_new (-2); } else syx_signal (SYX_ERROR_INTERP, syx_string_new ("Expected primitive or cCall")); return; }