/*! Returns a new SyxOop */ SyxOop syx_memory_alloc (void) { SyxOop oop; if (_syx_freed_memory_top == 0) { syx_memory_gc (); if (_syx_freed_memory_top == 0) syx_error ("object memory heap is really full\n"); } oop = _syx_freed_memory[--_syx_freed_memory_top]; /* Prevent the object from being collected */ if (_syx_memory_gc_trans_running) { if (_syx_memory_gc_trans_top == 0x100) syx_error ("transactions can hold up to 256 objects\n"); SYX_OBJECT_IS_MARKED(oop) = TRUE; _syx_memory_gc_trans[_syx_memory_gc_trans_top++] = oop; } else SYX_OBJECT_IS_MARKED(oop) = FALSE; return oop; }
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); }
/*! Parse a declaration file. \return TRUE if no error has occurred */ syx_bool syx_cold_file_in (syx_symbol filename) { SyxLexer *lexer; syx_string buffer; syx_int32 fd, count; syx_size size; #ifdef HAVE_FSTAT struct stat statbuf; #endif if ((fd = open (filename, O_RDONLY)) < 0) { syx_error ("can't open %s\n", filename); return FALSE; } #ifdef HAVE_FSTAT if ((fstat (fd, &statbuf)) < 0) { syx_error ("can't obtain size of %s\n", filename); return FALSE; } size = statbuf.st_size; #else size = 1000000; #endif buffer = (syx_string) syx_malloc (size + 1); count = read (fd, buffer, size); buffer[count - 1] = '\0'; close (fd); lexer = syx_lexer_new (buffer); if (!lexer) { syx_free (buffer); return FALSE; } if (!syx_cold_parse (lexer)) { syx_lexer_free (lexer, TRUE); return FALSE; } syx_lexer_free (lexer, TRUE); return TRUE; }
/*! Create a MethodContext for an arbitrary message ready to enter a Process. \param num_args the number of arguments \param ap a va_list containing all SyxOops */ SyxOop syx_vsend_message (SyxOop receiver, syx_symbol selector, syx_int32 num_args, va_list ap) { syx_varsize i; SyxOop context; SyxOop klass; SyxOop method; SyxOop arguments; if (num_args == 0) return syx_send_unary_message (receiver, selector); klass = syx_object_get_class (receiver); method = syx_class_lookup_method (klass, selector); if (SYX_IS_NIL (method)) syx_error ("Unable to lookup method #%s in class %p (%s)\n", selector, SYX_OOP_CAST_POINTER (klass), SYX_OBJECT_BYTE_ARRAY (SYX_CLASS_NAME(klass))); arguments = syx_array_new_size (num_args); for (i=0; i < num_args; i++) SYX_OBJECT_DATA(arguments)[i] = va_arg (ap, SyxOop); context = syx_method_context_new (method, receiver, arguments); return context; }
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 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_error ("illegal text in literal array\n"); break; } token = syx_lexer_next_token (self->lexer); } return syx_array_new_ref (top, elements); }
/*! Create a MethodContext for a unary message ready to enter a Process */ SyxOop syx_send_unary_message (SyxOop receiver, syx_symbol selector) { SyxOop context; SyxOop klass; SyxOop method; klass = syx_object_get_class (receiver); method = syx_class_lookup_method (klass, selector); if (SYX_IS_NIL (method)) syx_error ("Unable to lookup method #%s in class %p (%s)\n", selector, SYX_OOP_CAST_POINTER (klass), SYX_IS_NIL (SYX_CLASS_NAME(klass)) ? NULL : SYX_OBJECT_STRING (SYX_CLASS_NAME(klass))); context = syx_method_context_new (method, receiver, syx_nil); return context; }
/*! Create a MethodContext for a binary message ready to enter a Process */ SyxOop syx_send_binary_message (SyxOop receiver, syx_symbol selector, SyxOop argument) { SyxOop context; SyxOop klass; SyxOop method; SyxOop arguments; klass = syx_object_get_class (receiver); method = syx_class_lookup_method (klass, selector); if (SYX_IS_NIL (method)) syx_error ("Unable to lookup method #%s in class %p (%s)\n", selector, SYX_OOP_CAST_POINTER (klass), SYX_OBJECT_BYTE_ARRAY (SYX_CLASS_NAME(klass))); arguments = syx_array_new_size (1); SYX_OBJECT_DATA(arguments)[0] = argument; context = syx_method_context_new (method, receiver, arguments); return context; }
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; }
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; }