Lisp_Object Qbackquote, Qcomma, Qcomma_at, Qcomma_dot, Qfunction;
Lisp_Object Qinhibit_file_name_operation;
Lisp_Object Qeval_buffer_list;
+Lisp_Object Qlexical_binding;
Lisp_Object Qfile_truename, Qdo_after_load_evaluation; /* ACM 2006/5/16 */
/* Used instead of Qget_file_char while loading *.elc files compiled
static Lisp_Object Qload_force_doc_strings;
+extern Lisp_Object Qinternal_interpreter_environment;
+
static Lisp_Object Qload_in_progress;
/* The association list of objects read with the #n=object form.
static int read_emacs_mule_char (int, int (*) (int, Lisp_Object),
Lisp_Object);
-static void readevalloop (Lisp_Object, FILE*, Lisp_Object,
- Lisp_Object (*) (Lisp_Object), int,
+static void readevalloop (Lisp_Object, FILE*, Lisp_Object, int,
Lisp_Object, Lisp_Object,
Lisp_Object, Lisp_Object);
static Lisp_Object load_unwind (Lisp_Object);
if (pt_byte >= BUF_ZV_BYTE (inbuffer))
return -1;
- if (! NILP (inbuffer->enable_multibyte_characters))
+ if (! NILP (BVAR (inbuffer, enable_multibyte_characters)))
{
/* Fetch the character code from the buffer. */
unsigned char *p = BUF_BYTE_ADDRESS (inbuffer, pt_byte);
if (bytepos >= BUF_ZV_BYTE (inbuffer))
return -1;
- if (! NILP (inbuffer->enable_multibyte_characters))
+ if (! NILP (BVAR (inbuffer, enable_multibyte_characters)))
{
/* Fetch the character code from the buffer. */
unsigned char *p = BUF_BYTE_ADDRESS (inbuffer, bytepos);
else if (BUFFERP (readcharfun))
{
struct buffer *b = XBUFFER (readcharfun);
+ EMACS_INT charpos = BUF_PT (b);
EMACS_INT bytepos = BUF_PT_BYTE (b);
- BUF_PT (b)--;
- if (! NILP (b->enable_multibyte_characters))
+ if (! NILP (BVAR (b, enable_multibyte_characters)))
BUF_DEC_POS (b, bytepos);
else
bytepos--;
- BUF_PT_BYTE (b) = bytepos;
+ SET_BUF_PT_BOTH (b, charpos - 1, bytepos);
}
else if (MARKERP (readcharfun))
{
EMACS_INT bytepos = XMARKER (readcharfun)->bytepos;
XMARKER (readcharfun)->charpos--;
- if (! NILP (b->enable_multibyte_characters))
+ if (! NILP (BVAR (b, enable_multibyte_characters)))
BUF_DEC_POS (b, bytepos);
else
bytepos--;
return val;
}
-DEFUN ("read-char", Fread_char, Sread_char, 0, 3, 0,
+DEFUE ("read-char", Fread_char, Sread_char, 0, 3, 0,
doc: /* Read a character from the command input (keyboard or macro).
It is returned as a number.
If the character has modifiers, they are resolved and reflected to the
: make_number (char_resolve_modifier_mask (XINT (val))));
}
-DEFUN ("read-event", Fread_event, Sread_event, 0, 3, 0,
+DEFUE ("read-event", Fread_event, Sread_event, 0, 3, 0,
doc: /* Read an event object from the input stream.
If the optional argument PROMPT is non-nil, display that as a prompt.
If the optional argument INHERIT-INPUT-METHOD is non-nil and some
\f
+
+/* Return true if the lisp code read using READCHARFUN defines a non-nil
+ `lexical-binding' file variable. After returning, the stream is
+ positioned following the first line, if it is a comment, otherwise
+ nothing is read. */
+
+static int
+lisp_file_lexically_bound_p (Lisp_Object readcharfun)
+{
+ int ch = READCHAR;
+ if (ch != ';')
+ /* The first line isn't a comment, just give up. */
+ {
+ UNREAD (ch);
+ return 0;
+ }
+ else
+ /* Look for an appropriate file-variable in the first line. */
+ {
+ int rv = 0;
+ enum {
+ NOMINAL, AFTER_FIRST_DASH, AFTER_ASTERIX,
+ } beg_end_state = NOMINAL;
+ int in_file_vars = 0;
+
+#define UPDATE_BEG_END_STATE(ch) \
+ if (beg_end_state == NOMINAL) \
+ beg_end_state = (ch == '-' ? AFTER_FIRST_DASH : NOMINAL); \
+ else if (beg_end_state == AFTER_FIRST_DASH) \
+ beg_end_state = (ch == '*' ? AFTER_ASTERIX : NOMINAL); \
+ else if (beg_end_state == AFTER_ASTERIX) \
+ { \
+ if (ch == '-') \
+ in_file_vars = !in_file_vars; \
+ beg_end_state = NOMINAL; \
+ }
+
+ /* Skip until we get to the file vars, if any. */
+ do
+ {
+ ch = READCHAR;
+ UPDATE_BEG_END_STATE (ch);
+ }
+ while (!in_file_vars && ch != '\n' && ch != EOF);
+
+ while (in_file_vars)
+ {
+ char var[100], val[100];
+ unsigned i;
+
+ ch = READCHAR;
+
+ /* Read a variable name. */
+ while (ch == ' ' || ch == '\t')
+ ch = READCHAR;
+
+ i = 0;
+ while (ch != ':' && ch != '\n' && ch != EOF)
+ {
+ if (i < sizeof var - 1)
+ var[i++] = ch;
+ UPDATE_BEG_END_STATE (ch);
+ ch = READCHAR;
+ }
+
+ while (i > 0 && (var[i - 1] == ' ' || var[i - 1] == '\t'))
+ i--;
+ var[i] = '\0';
+
+ if (ch == ':')
+ {
+ /* Read a variable value. */
+ ch = READCHAR;
+
+ while (ch == ' ' || ch == '\t')
+ ch = READCHAR;
+
+ i = 0;
+ while (ch != ';' && ch != '\n' && ch != EOF && in_file_vars)
+ {
+ if (i < sizeof val - 1)
+ val[i++] = ch;
+ UPDATE_BEG_END_STATE (ch);
+ ch = READCHAR;
+ }
+ if (! in_file_vars)
+ /* The value was terminated by an end-marker, which
+ remove. */
+ i -= 3;
+ while (i > 0 && (val[i - 1] == ' ' || val[i - 1] == '\t'))
+ i--;
+ val[i] = '\0';
+
+ if (strcmp (var, "lexical-binding") == 0)
+ /* This is it... */
+ {
+ rv = (strcmp (val, "nil") != 0);
+ break;
+ }
+ }
+ }
+
+ while (ch != '\n' && ch != EOF)
+ ch = READCHAR;
+
+ return rv;
+ }
+}
+\f
/* Value is a version number of byte compiled code if the file
associated with file descriptor FD is a compiled Lisp file that's
safe to load. Only files compiled with Emacs are safe to load.
if (i == 4)
version = buf[i];
- if (i == nbytes
+ if (i >= nbytes
|| fast_c_string_match_ignore_case (Vbytecomp_version_regexp,
buf + i) < 0)
safe_p = 0;
return Qnil;
}
-DEFUN ("get-load-suffixes", Fget_load_suffixes, Sget_load_suffixes, 0, 0, 0,
+DEFUE ("get-load-suffixes", Fget_load_suffixes, Sget_load_suffixes, 0, 0, 0,
doc: /* Return the suffixes that `load' should try if a suffix is \
required.
This uses the variables `load-suffixes' and `load-file-rep-suffixes'. */)
return Fnreverse (lst);
}
-DEFUN ("load", Fload, Sload, 1, 5, 0,
+DEFUE ("load", Fload, Sload, 1, 5, 0,
doc: /* Execute a file of Lisp code named FILE.
First try FILE with `.elc' appended, then try with `.el',
then try FILE unmodified (the exact suffixes in the exact order are
Also, just loading a file recursively is not always an error in
the general case; the second load may do something different. */
{
- int count = 0;
+ int load_count = 0;
Lisp_Object tem;
for (tem = Vloads_in_progress; CONSP (tem); tem = XCDR (tem))
- if (!NILP (Fequal (found, XCAR (tem))) && (++count > 3))
+ if (!NILP (Fequal (found, XCAR (tem))) && (++load_count > 3))
{
if (fd >= 0)
emacs_close (fd);
Vloads_in_progress = Fcons (found, Vloads_in_progress);
}
+ /* All loads are by default dynamic, unless the file itself specifies
+ otherwise using a file-variable in the first line. This is bound here
+ so that it takes effect whether or not we use
+ Vload_source_file_function. */
+ specbind (Qlexical_binding, Qnil);
+
/* Get the name for load-history. */
hist_file_name = (! NILP (Vpurify_flag)
? Fconcat (2, (tmp[0] = Ffile_name_directory (file),
load_descriptor_list
= Fcons (make_number (fileno (stream)), load_descriptor_list);
specbind (Qload_in_progress, Qt);
+
+ instream = stream;
+ if (lisp_file_lexically_bound_p (Qget_file_char))
+ Fset (Qlexical_binding, Qt);
+
if (! version || version >= 22)
readevalloop (Qget_file_char, stream, hist_file_name,
- Feval, 0, Qnil, Qnil, Qnil, Qnil);
+ 0, Qnil, Qnil, Qnil, Qnil);
else
{
/* We can't handle a file which was compiled with
byte-compile-dynamic by older version of Emacs. */
specbind (Qload_force_doc_strings, Qt);
- readevalloop (Qget_emacs_mule_file_char, stream, hist_file_name, Feval,
+ readevalloop (Qget_emacs_mule_file_char, stream, hist_file_name,
0, Qnil, Qnil, Qnil, Qnil);
}
unbind_to (count, Qnil);
file name when searching.
If non-nil, PREDICATE is used instead of `file-readable-p'.
PREDICATE can also be an integer to pass to the access(2) function,
-in which case file-name-handlers are ignored. */)
+in which case file-name-handlers are ignored.
+This function will normally skip directories, so if you want it to find
+directories, make sure the PREDICATE function returns `dir-ok' for them. */)
(Lisp_Object filename, Lisp_Object path, Lisp_Object suffixes, Lisp_Object predicate)
{
Lisp_Object file;
return file;
}
+static Lisp_Object Qdir_ok;
/* Search for a file whose name is STR, looking in directories
in the Lisp list PATH, and trying suffixes from SUFFIX.
/* Of course, this could conceivably lose if luser sets
default-directory to be something non-absolute... */
{
- filename = Fexpand_file_name (filename, current_buffer->directory);
+ filename = Fexpand_file_name (filename, BVAR (current_buffer, directory));
if (!complete_filename_p (filename))
/* Give up on this path element! */
continue;
if (NILP (predicate))
exists = !NILP (Ffile_readable_p (string));
else
- exists = !NILP (call1 (predicate, string));
- if (exists && !NILP (Ffile_directory_p (string)))
- exists = 0;
+ {
+ Lisp_Object tmp = call1 (predicate, string);
+ exists = !NILP (tmp)
+ && (EQ (tmp, Qdir_ok)
+ || NILP (Ffile_directory_p (string)));
+ }
if (exists)
{
encoded_fn = ENCODE_FILE (string);
pfn = SSDATA (encoded_fn);
- exists = (stat (pfn, &st) >= 0
- && (st.st_mode & S_IFMT) != S_IFDIR);
+ exists = (stat (pfn, &st) == 0 && ! S_ISDIR (st.st_mode));
if (exists)
{
/* Check that we can access or open it. */
readevalloop (Lisp_Object readcharfun,
FILE *stream,
Lisp_Object sourcename,
- Lisp_Object (*evalfun) (Lisp_Object),
int printflag,
Lisp_Object unibyte, Lisp_Object readfun,
Lisp_Object start, Lisp_Object end)
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
struct buffer *b = 0;
int continue_reading_p;
+ Lisp_Object lex_bound;
/* Nonzero if reading an entire buffer. */
int whole_buffer = 0;
/* 1 on the first time around. */
record_unwind_protect (readevalloop_1, load_convert_to_unibyte ? Qt : Qnil);
load_convert_to_unibyte = !NILP (unibyte);
+ /* If lexical binding is active (either because it was specified in
+ the file's header, or via a buffer-local variable), create an empty
+ lexical environment, otherwise, turn off lexical binding. */
+ lex_bound = find_symbol_value (Qlexical_binding);
+ specbind (Qinternal_interpreter_environment,
+ NILP (lex_bound) || EQ (lex_bound, Qunbound)
+ ? Qnil : Fcons (Qt, Qnil));
+
GCPRO4 (sourcename, readfun, start, end);
/* Try to ensure sourcename is a truename, except whilst preloading. */
{
int count1 = SPECPDL_INDEX ();
- if (b != 0 && NILP (b->name))
+ if (b != 0 && NILP (BVAR (b, name)))
error ("Reading from killed buffer");
if (!NILP (start))
to a different value when evaluated. */
if (BUFFERP (readcharfun))
{
- struct buffer *b = XBUFFER (readcharfun);
- if (BUF_PT (b) == BUF_ZV (b))
+ struct buffer *buf = XBUFFER (readcharfun);
+ if (BUF_PT (buf) == BUF_ZV (buf))
continue_reading_p = 0;
}
}
unbind_to (count1, Qnil);
/* Now eval what we just read. */
- val = (*evalfun) (val);
+ val = eval_sub (val);
if (printflag)
{
tem = printflag;
if (NILP (filename))
- filename = XBUFFER (buf)->filename;
+ filename = BVAR (XBUFFER (buf), filename);
specbind (Qeval_buffer_list, Fcons (buf, Veval_buffer_list));
specbind (Qstandard_output, tem);
record_unwind_protect (save_excursion_restore, save_excursion_save ());
BUF_TEMP_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf)));
- readevalloop (buf, 0, filename, Feval,
+ specbind (Qlexical_binding, lisp_file_lexically_bound_p (buf) ? Qt : Qnil);
+ readevalloop (buf, 0, filename,
!NILP (printflag), unibyte, Qnil, Qnil, Qnil);
unbind_to (count, Qnil);
This function does not move point. */)
(Lisp_Object start, Lisp_Object end, Lisp_Object printflag, Lisp_Object read_function)
{
+ /* FIXME: Do the eval-sexp-add-defvars danse! */
int count = SPECPDL_INDEX ();
Lisp_Object tem, cbuf;
specbind (Qeval_buffer_list, Fcons (cbuf, Veval_buffer_list));
/* readevalloop calls functions which check the type of start and end. */
- readevalloop (cbuf, 0, XBUFFER (cbuf)->filename, Feval,
+ readevalloop (cbuf, 0, BVAR (XBUFFER (cbuf), filename),
!NILP (printflag), Qnil, read_function,
start, end);
}
\f
-DEFUN ("read", Fread, Sread, 0, 1, 0,
+DEFUE ("read", Fread, Sread, 0, 1, 0,
doc: /* Read one Lisp expression as text from STREAM, return as Lisp object.
If STREAM is nil, use the value of `standard-input' (which see).
STREAM or the value of `standard-input' may be:
return read_internal_start (stream, Qnil, Qnil);
}
-DEFUN ("read-from-string", Fread_from_string, Sread_from_string, 1, 3, 0,
+DEFUE ("read-from-string", Fread_from_string, Sread_from_string, 1, 3, 0,
doc: /* Read one Lisp expression which is represented as text by STRING.
Returns a cons: (OBJECT-READ . FINAL-STRING-INDEX).
START and END optionally delimit a substring of STRING from which to read;
read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
{
register int c;
- int uninterned_symbol = 0;
+ unsigned uninterned_symbol = 0;
int multibyte;
*pch = 0;
{
char *p = read_buffer;
char *end = read_buffer + read_buffer_size;
- register int c;
+ register int ch;
/* Nonzero if we saw an escape sequence specifying
a multibyte character. */
int force_multibyte = 0;
int cancel = 0;
int nchars = 0;
- while ((c = READCHAR) >= 0
- && c != '\"')
+ while ((ch = READCHAR) >= 0
+ && ch != '\"')
{
if (end - p < MAX_MULTIBYTE_LENGTH)
{
end = read_buffer + read_buffer_size;
}
- if (c == '\\')
+ if (ch == '\\')
{
int modifiers;
- c = read_escape (readcharfun, 1);
+ ch = read_escape (readcharfun, 1);
- /* C is -1 if \ newline has just been seen */
- if (c == -1)
+ /* CH is -1 if \ newline has just been seen */
+ if (ch == -1)
{
if (p == read_buffer)
cancel = 1;
continue;
}
- modifiers = c & CHAR_MODIFIER_MASK;
- c = c & ~CHAR_MODIFIER_MASK;
+ modifiers = ch & CHAR_MODIFIER_MASK;
+ ch = ch & ~CHAR_MODIFIER_MASK;
- if (CHAR_BYTE8_P (c))
+ if (CHAR_BYTE8_P (ch))
force_singlebyte = 1;
- else if (! ASCII_CHAR_P (c))
+ else if (! ASCII_CHAR_P (ch))
force_multibyte = 1;
- else /* i.e. ASCII_CHAR_P (c) */
+ else /* i.e. ASCII_CHAR_P (ch) */
{
/* Allow `\C- ' and `\C-?'. */
if (modifiers == CHAR_CTL)
{
- if (c == ' ')
- c = 0, modifiers = 0;
- else if (c == '?')
- c = 127, modifiers = 0;
+ if (ch == ' ')
+ ch = 0, modifiers = 0;
+ else if (ch == '?')
+ ch = 127, modifiers = 0;
}
if (modifiers & CHAR_SHIFT)
{
/* Shift modifier is valid only with [A-Za-z]. */
- if (c >= 'A' && c <= 'Z')
+ if (ch >= 'A' && ch <= 'Z')
modifiers &= ~CHAR_SHIFT;
- else if (c >= 'a' && c <= 'z')
- c -= ('a' - 'A'), modifiers &= ~CHAR_SHIFT;
+ else if (ch >= 'a' && ch <= 'z')
+ ch -= ('a' - 'A'), modifiers &= ~CHAR_SHIFT;
}
if (modifiers & CHAR_META)
/* Move the meta bit to the right place for a
string. */
modifiers &= ~CHAR_META;
- c = BYTE8_TO_CHAR (c | 0x80);
+ ch = BYTE8_TO_CHAR (ch | 0x80);
force_singlebyte = 1;
}
}
/* Any modifiers remaining are invalid. */
if (modifiers)
error ("Invalid modifier in string");
- p += CHAR_STRING (c, (unsigned char *) p);
+ p += CHAR_STRING (ch, (unsigned char *) p);
}
else
{
- p += CHAR_STRING (c, (unsigned char *) p);
- if (CHAR_BYTE8_P (c))
+ p += CHAR_STRING (ch, (unsigned char *) p);
+ if (CHAR_BYTE8_P (ch))
force_singlebyte = 1;
- else if (! ASCII_CHAR_P (c))
+ else if (! ASCII_CHAR_P (ch))
force_multibyte = 1;
}
nchars++;
}
- if (c < 0)
+ if (ch < 0)
end_of_file_error ();
/* If purifying, and string starts with \ newline,
p = read_buffer + nchars;
}
else
- /* Otherwise, READ_BUFFER contains only ASCII. */
- ;
+ {
+ /* Otherwise, READ_BUFFER contains only ASCII. */
+ }
/* We want readchar_count to be the number of characters, not
bytes. Hence we adjust for multibyte characters in the
: make_string (str, len));
}
\f
-DEFUN ("intern", Fintern, Sintern, 1, 2, 0,
+DEFUE ("intern", Fintern, Sintern, 1, 2, 0,
doc: /* Return the canonical symbol whose name is STRING.
If there is none, one is created by this function and returned.
A second optional argument specifies the obarray to use;
return sym;
}
-DEFUN ("intern-soft", Fintern_soft, Sintern_soft, 1, 2, 0,
+DEFUE ("intern-soft", Fintern_soft, Sintern_soft, 1, 2, 0,
doc: /* Return the canonical symbol named NAME, or nil if none exists.
NAME may be a string or a symbol. If it is a symbol, that exact
symbol is searched for.
return tem;
}
\f
-DEFUN ("unintern", Funintern, Sunintern, 1, 2, 0,
+DEFUE ("unintern", Funintern, Sunintern, 1, 2, 0,
doc: /* Delete the symbol named NAME, if any, from OBARRAY.
The value is t if a symbol was found and deleted, nil otherwise.
NAME may be a string or a symbol. If it is a symbol, that symbol
sym = intern_c_string (namestring);
i_fwd->type = Lisp_Fwd_Int;
i_fwd->intvar = address;
+ XSYMBOL (sym)->declared_special = 1;
XSYMBOL (sym)->redirect = SYMBOL_FORWARDED;
SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)i_fwd);
}
sym = intern_c_string (namestring);
b_fwd->type = Lisp_Fwd_Bool;
b_fwd->boolvar = address;
+ XSYMBOL (sym)->declared_special = 1;
XSYMBOL (sym)->redirect = SYMBOL_FORWARDED;
SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)b_fwd);
Vbyte_boolean_vars = Fcons (sym, Vbyte_boolean_vars);
sym = intern_c_string (namestring);
o_fwd->type = Lisp_Fwd_Obj;
o_fwd->objvar = address;
+ XSYMBOL (sym)->declared_special = 1;
XSYMBOL (sym)->redirect = SYMBOL_FORWARDED;
SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)o_fwd);
}
sym = intern_c_string (namestring);
ko_fwd->type = Lisp_Fwd_Kboard_Obj;
ko_fwd->offset = offset;
+ XSYMBOL (sym)->declared_special = 1;
XSYMBOL (sym)->redirect = SYMBOL_FORWARDED;
SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)ko_fwd);
}
Vbytecomp_version_regexp
= make_pure_c_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
+ Qlexical_binding = intern ("lexical-binding");
+ staticpro (&Qlexical_binding);
+ DEFVAR_LISP ("lexical-binding", Vlexical_binding,
+ doc: /* If non-nil, use lexical binding when evaluating code.
+This only applies to code evaluated by `eval-buffer' and `eval-region'.
+This variable is automatically set from the file variables of an interpreted
+ Lisp file read using `load'. */);
+ Fmake_variable_buffer_local (Qlexical_binding);
+
DEFVAR_LISP ("eval-buffer-list", Veval_buffer_list,
doc: /* List of buffers being read from by calls to `eval-buffer' and `eval-region'. */);
Veval_buffer_list = Qnil;
Qfile_truename = intern_c_string ("file-truename");
staticpro (&Qfile_truename) ;
+ Qdir_ok = intern_c_string ("dir-ok");
+ staticpro (&Qdir_ok);
+
Qdo_after_load_evaluation = intern_c_string ("do-after-load-evaluation");
staticpro (&Qdo_after_load_evaluation) ;