More keyword paring and migration in runtime, docs, code modes.

This commit is contained in:
Graydon Hoare 2012-06-27 13:14:04 -07:00
parent f0565be49a
commit d3c6119a7a
11 changed files with 116 additions and 110 deletions

View File

@ -23,8 +23,10 @@ Version 0.3 (June 2012) - not yet!
* Type reflection
* Removal of various obsolete features
* Keywords: be, prove, syntax, note, mutable, do, bind
* Constructs: do-while loops, fn binding, resources
* Keywords: 'be', 'prove', 'syntax', 'note', 'mutable',
'bind', 'crust', 'native' (now 'extern')
* Constructs: do-while loops ('do' repurposed),
fn binding, resources
* Compiler reorganization
* Syntax-layer of compiler split into separate crate
@ -39,7 +41,7 @@ Version 0.3 (June 2012) - not yet!
* Extensive work on libuv interface
* Much vector code moved to libraries
* Syntax extensions: #line, #col, #file, #mod,
#stringify, #include, #include_str, #include_bin.
#stringify, #include, #include_str, #include_bin
* Tool improvements
* Cargo automatically resolves dependencies

View File

@ -7,12 +7,12 @@ CodeMirror.defineMode("rust", function() {
"let": "let", "fn": "fn", "for": "for", "alt": "alt", "iface": "iface",
"impl": "impl", "type": "type", "enum": "enum", "mod": "mod",
"as": "op", "true": "atom", "false": "atom", "assert": "op", "check": "op",
"claim": "op", "native": "ignore", "unsafe": "ignore", "import": "else-style",
"claim": "op", "extern": "ignore", "unsafe": "ignore", "import": "else-style",
"export": "else-style", "copy": "op", "log": "op", "log_err": "op",
"use": "op", "bind": "op", "self": "atom"
};
var typeKeywords = function() {
var keywords = {"fn": "fn", "block": "fn", "obj": "obj"};
var keywords = {"fn": "fn"};
var atoms = "bool uint int i8 i16 i32 i64 u8 u16 u32 u64 float f32 f64 str char".split(" ");
for (var i = 0, e = atoms.length; i < e; ++i) keywords[atoms[i]] = "atom";
return keywords;

View File

@ -210,17 +210,16 @@ The keywords in [source files](#source-files) are the following strings:
~~~~~~~~ {.keyword}
alt assert
be break
check claim class const cont copy crust
break
check claim class const cont copy
drop
else enum export
else enum export extern
fail false fn for
if iface impl import
let log loop
mod mut
native new
pure
resource ret
ret
true trait type
unchecked unsafe
while
@ -575,7 +574,7 @@ of [attributes](#attributes) attached to it.
~~~~~~~~ {.ebnf .gram}
item : mod_item | fn_item | type_item | enum_item
| res_item | iface_item | impl_item | native_mod_item ;
| res_item | iface_item | impl_item | foreign_mod_item ;
~~~~~~~~
An _item_ is a component of a crate; some module items can be defined in crate
@ -1039,29 +1038,29 @@ Similarly, [interface](#interfaces) bounds can be specified for type
parameters to allow methods of that interface to be called on values
of that type.
#### Crust functions
#### Extern functions
Crust functions are part of Rust's foreign function interface,
providing the opposite functionality to [native modules](#native-modules).
Whereas native modules allow Rust code to call foreign
code, crust functions allow foreign code to call Rust code. They are
defined the same as any other Rust function, except that they are
prepended with the `crust` keyword.
Extern functions are part of Rust's foreign function interface, providing
the opposite functionality to [foreign modules](#foreign-modules). Whereas
foreign modules allow Rust code to call foreign code, extern functions with
bodies defined in Rust code _can be called by foreign code_. They are defined the
same as any other Rust function, except that they are prepended with the
`extern` keyword.
~~~
crust fn new_vec() -> [int] { [] }
extern fn new_vec() -> [int] { [] }
~~~
Crust functions may not be called from Rust code, but their value
Extern functions may not be called from Rust code, but their value
may be taken as an unsafe `u8` pointer.
~~~
# crust fn new_vec() -> [int] { [] }
# extern fn new_vec() -> [int] { [] }
let fptr: *u8 = new_vec;
~~~
The primary motivation of crust functions is to create callbacks
for native functions that expect to receive function pointers.
The primary motivation of extern functions is to create callbacks
for foreign functions that expect to receive function pointers.
### Type definitions
@ -1298,49 +1297,51 @@ impl of seq<bool> for u32 {
}
~~~~
### Native modules
### Foreign modules
~~~ {.ebnf .gram}
native_mod_item : "native mod" ident '{' native_mod '} ;
native_mod : [ native_fn ] * ;
foreign_mod_item : "extern mod" ident '{' foreign_mod '} ;
foreign_mod : [ foreign_fn ] * ;
~~~
Native modules form the basis for Rust's foreign function interface. A native
module describes functions in external, non-Rust libraries. Functions within
native modules are declared the same as other Rust functions, with the exception
that they may not have a body and are instead terminated by a semi-colon.
Foreign modules form the basis for Rust's foreign function interface. A
foreign module describes functions in external, non-Rust
libraries. Functions within foreign modules are declared the same as other
Rust functions, with the exception that they may not have a body and are
instead terminated by a semi-colon.
~~~
# import libc::{c_char, FILE};
# #[nolink]
native mod c {
extern mod c {
fn fopen(filename: *c_char, mode: *c_char) -> *FILE;
}
~~~
Functions within native modules may be called by Rust code as it would any
Functions within foreign modules may be called by Rust code as it would any
normal function and the Rust compiler will automatically translate between
the Rust ABI and the native ABI.
the Rust ABI and the foreign ABI.
The name of the native module has special meaning to the Rust compiler in
The name of the foreign module has special meaning to the Rust compiler in
that it will treat the module name as the name of a library to link to,
performing the linking as appropriate for the target platform. The name
given for the native module will be transformed in a platform-specific
way to determine the name of the library. For example, on Linux the name
of the native module is prefixed with 'lib' and suffixed with '.so', so
the native mod 'rustrt' would be linked to a library named 'librustrt.so'.
given for the foreign module will be transformed in a platform-specific way
to determine the name of the library. For example, on Linux the name of the
foreign module is prefixed with 'lib' and suffixed with '.so', so the
foreign mod 'rustrt' would be linked to a library named 'librustrt.so'.
A number of [attributes](#attributes) control the behavior of native mods.
A number of [attributes](#attributes) control the behavior of foreign
modules.
By default native mods assume that the library they are calling use
the standard C "cdecl" ABI. Other ABI's may be specified using the `abi`
By default foreign modules assume that the library they are calling use the
standard C "cdecl" ABI. Other ABI's may be specified using the `abi`
attribute as in
~~~{.xfail-test}
// Interface to the Windows API
#[abi = "stdcall"]
native mod kernel32 { }
extern mod kernel32 { }
~~~
The `link_name` attribute allows the default library naming behavior to
@ -1348,13 +1349,13 @@ be overriden by explicitly specifying the name of the library.
~~~{.xfail-test}
#[link_name = "crypto"]
native mod mycrypto { }
extern mod mycrypto { }
~~~
The `nolink` attribute tells the Rust compiler not to perform any linking
for the native module. This is particularly useful for creating native
mods for libc, which tends to not follow standard library naming conventions
and is linked to all Rust programs anyway.
for the foreign module. This is particularly useful for creating foreign
modules for libc, which tends to not follow standard library naming
conventions and is linked to all Rust programs anyway.
## Attributes
@ -1752,8 +1753,8 @@ A type cast expression is denoted with the binary operator `as`.
Executing an `as` expression casts the value on the left-hand side to the type
on the right-hand side.
A numeric value can be cast to any numeric type. A native pointer value can
be cast to or from any integral type or native pointer type. Any other cast
A numeric value can be cast to any numeric type. An unsafe pointer value can
be cast to or from any integral type or unsafe pointer type. Any other cast
is unsupported and will fail to compile.
An example of an `as` expression:

View File

@ -2106,7 +2106,7 @@ OpenSSL libraries installed, it should 'just work'.
~~~~ {.xfail-test}
use std;
native mod crypto {
extern mod crypto {
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
}
@ -2128,20 +2128,23 @@ fn main(args: [str]) {
}
~~~~
## Native modules
## Foreign modules
Before we can call `SHA1`, we have to declare it. That is what this
part of the program is responsible for:
~~~~ {.xfail-test}
native mod crypto {
extern mod crypto {
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
}
~~~~
A `native` module declaration tells the compiler that the program
should be linked with a library by that name, and that the given list
of functions are available in that library.
An `extern` module declaration containing function signatures introduces
the functions listed as _foreign functions_, that are implemented in some
other language (usually C) and accessed through Rust's foreign function
interface (FFI). An extern module like this is called a foreign module, and
implicitly tells the compiler to link with a library with the same name as
the module, and that it will find the foreign functions in that library.
In this case, it'll change the name `crypto` to a shared library name
in a platform-specific way (`libcrypto.so` on Linux, for example), and
@ -2150,38 +2153,38 @@ actual library, you can use the `"link_name"` attribute, like:
~~~~ {.xfail-test}
#[link_name = "crypto"]
native mod something {
extern mod something {
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
}
~~~~
## Native calling conventions
## Foreign calling conventions
Most native C code use the cdecl calling convention, so that is what
Rust uses by default when calling native functions. Some native functions,
most notably the Windows API, use other calling conventions, so Rust
provides a way to hint to the compiler which is expected by using
the `"abi"` attribute:
Most foreign code will be C code, which usually uses the `cdecl` calling
convention, so that is what Rust uses by default when calling foreign
functions. Some foreign functions, most notably the Windows API, use other
calling conventions, so Rust provides a way to hint to the compiler which
is expected by using the `"abi"` attribute:
~~~~
#[cfg(target_os = "win32")]
#[abi = "stdcall"]
native mod kernel32 {
extern mod kernel32 {
fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
}
~~~~
The `"abi"` attribute applies to a native mod (it can not be applied
The `"abi"` attribute applies to a foreign module (it can not be applied
to a single function within a module), and must be either `"cdecl"`
or `"stdcall"`. Other conventions may be defined in the future.
## Unsafe pointers
The native `SHA1` function is declared to take three arguments, and
The foreign `SHA1` function is declared to take three arguments, and
return a pointer.
~~~~ {.xfail-test}
# native mod crypto {
# extern mod crypto {
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
# }
~~~~
@ -2295,7 +2298,7 @@ use std;
type timeval = {mut tv_sec: uint,
mut tv_usec: uint};
#[nolink]
native mod libc {
extern mod libc {
fn gettimeofday(tv: *timeval, tz: *()) -> i32;
}
fn unix_time_in_microseconds() -> u64 unsafe {
@ -2307,8 +2310,8 @@ fn unix_time_in_microseconds() -> u64 unsafe {
# fn main() { assert #fmt("%?", unix_time_in_microseconds()) != ""; }
~~~~
The `#[nolink]` attribute indicates that there's no native library to link
in. The standard C library is already linked with Rust programs.
The `#[nolink]` attribute indicates that there's no foreign library to
link in. The standard C library is already linked with Rust programs.
A `timeval`, in C, is a struct with two 32-bit integers. Thus, we
define a record type with the same contents, and declare

View File

@ -52,21 +52,21 @@
(defvar rust-punc-chars "()[].,{}:;")
(defvar rust-value-keywords
(let ((table (make-hash-table :test 'equal)))
(dolist (word '("mod" "type" "resource" "fn" "enum" "iface" "impl"))
(dolist (word '("mod" "const" "class" "type"
"trait" "fn" "enum" "iface"
"impl"))
(puthash word 'def table))
(dolist (word '("assert"
"be" "break"
"check" "claim" "class" "const" "cont" "copy" "crust"
"break"
"check" "claim" "cont" "copy"
"drop"
"else" "export"
"else" "export" "extern"
"fail" "for"
"if" "import"
"let" "log" "loop"
"mut"
"native" "new"
"new"
"pure"
"ret"
"trait"
"unchecked" "unsafe"
"while"))
(puthash word t table))

View File

@ -14,21 +14,21 @@ if !exists("main_syntax")
let main_syntax='rust'
endif
syn keyword rustKeyword alt as assert be bind break
syn keyword rustKeyword check claim cont const copy else export fail
syn keyword rustKeyword for if impl import in inline lambda let log
syn keyword rustKeyword loop mod mut mutable native note of prove pure
syn keyword rustKeyword ret self syntax to unchecked
syn keyword rustKeyword alt as assert break
syn keyword rustKeyword check claim cont const copy else export extern fail
syn keyword rustKeyword for if impl import in let log
syn keyword rustKeyword loop mod mut of pure
syn keyword rustKeyword ret self to unchecked
syn keyword rustKeyword unsafe use while with
" FIXME: Scoped impl's name is also fallen in this category
syn keyword rustKeyword mod iface resource class enum type nextgroup=rustIdentifier skipwhite
syn keyword rustKeyword mod iface trait class enum type nextgroup=rustIdentifier skipwhite
syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite
syn match rustIdentifier "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
syn match rustFuncName "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
" Reserved words
syn keyword rustKeyword m32 m64 m128 f80 f16 f128 class trait
syn keyword rustKeyword m32 m64 m128 f80 f16 f128
syn keyword rustType any int uint float char bool u8 u16 u32 u64 f32
syn keyword rustType f64 i8 i16 i32 i64 str

View File

@ -285,7 +285,7 @@ fn restricted_keyword_table() -> hashmap<str, ()> {
let keys = [
"alt",
"assert",
"be", "break",
"break",
"check", "claim", "class", "const", "cont", "copy", "crust",
"do", "drop",
"else", "enum", "export", "extern",

View File

@ -1,4 +1,4 @@
/* Native builtins. */
/* Foreign builtins. */
#include "rust_sched_loop.h"
#include "rust_task.h"

View File

@ -10,7 +10,7 @@
* Managing the dynamically resizing list of Rust stack segments
* Switching between running Rust code on the Rust segmented stack and
native C code on large stacks owned by the scheduler
foreign C code on large stacks owned by the scheduler
The lifetime of a rust_task object closely mirrors that of a running Rust
task object, but they are not identical. In particular, the rust_task is an

View File

@ -40,7 +40,7 @@ extern "C" void record_sp_limit(void *limit);
/**********************************************************************
* Switches to the C-stack and invokes |fn_ptr|, passing |args| as argument.
* This is used by the C compiler to call native functions and by other
* This is used by the C compiler to call foreign functions and by other
* upcalls to switch to the C stack. The return value is passed through a
* field in the args parameter. This upcall is specifically for switching
* to the shim functions generated by rustc.
@ -58,7 +58,7 @@ upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
task->call_on_c_stack(args, fn_ptr);
} catch (...) {
// Logging here is not reliable
assert(false && "Native code threw an exception");
assert(false && "Foreign code threw an exception");
}
task->record_stack_limit();

View File

@ -8,11 +8,11 @@
#include "rust_log.h"
#include "uv.h"
// crust fn pointers
typedef void (*crust_async_op_cb)(uv_loop_t* loop, void* data,
// extern fn pointers
typedef void (*extern_async_op_cb)(uv_loop_t* loop, void* data,
uv_async_t* op_handle);
typedef void (*crust_simple_cb)(uint8_t* id_buf, void* loop_data);
typedef void (*crust_close_cb)(uint8_t* id_buf, void* handle,
typedef void (*extern_simple_cb)(uint8_t* id_buf, void* loop_data);
typedef void (*extern_close_cb)(uint8_t* id_buf, void* handle,
void* data);
// data types
@ -20,8 +20,8 @@ typedef void (*crust_close_cb)(uint8_t* id_buf, void* handle,
struct handle_data {
uint8_t id_buf[RUST_UV_HANDLE_LEN];
crust_simple_cb cb;
crust_close_cb close_cb;
extern_simple_cb cb;
extern_close_cb close_cb;
};
// helpers
@ -37,7 +37,7 @@ current_kernel_free(void* ptr) {
}
static handle_data*
new_handle_data_from(uint8_t* buf, crust_simple_cb cb) {
new_handle_data_from(uint8_t* buf, extern_simple_cb cb) {
handle_data* data = (handle_data*)current_kernel_malloc(
sizeof(handle_data),
"handle_data");
@ -48,39 +48,39 @@ new_handle_data_from(uint8_t* buf, crust_simple_cb cb) {
// libuv callback impls
static void
native_crust_async_op_cb(uv_async_t* handle, int status) {
crust_async_op_cb cb = (crust_async_op_cb)handle->data;
foreign_extern_async_op_cb(uv_async_t* handle, int status) {
extern_async_op_cb cb = (extern_async_op_cb)handle->data;
void* loop_data = handle->loop->data;
cb(handle->loop, loop_data, handle);
}
static void
native_async_cb(uv_async_t* handle, int status) {
foreign_async_cb(uv_async_t* handle, int status) {
handle_data* handle_d = (handle_data*)handle->data;
void* loop_data = handle->loop->data;
handle_d->cb(handle_d->id_buf, loop_data);
}
static void
native_timer_cb(uv_timer_t* handle, int status) {
foreign_timer_cb(uv_timer_t* handle, int status) {
handle_data* handle_d = (handle_data*)handle->data;
void* loop_data = handle->loop->data;
handle_d->cb(handle_d->id_buf, loop_data);
}
static void
native_close_cb(uv_handle_t* handle) {
foreign_close_cb(uv_handle_t* handle) {
handle_data* data = (handle_data*)handle->data;
data->close_cb(data->id_buf, handle, handle->loop->data);
}
static void
native_close_op_cb(uv_handle_t* op_handle) {
foreign_close_op_cb(uv_handle_t* op_handle) {
current_kernel_free(op_handle);
// uv_run() should return after this..
}
// native fns bound in rust
// foreign fns bound in rust
extern "C" void
rust_uv_free(void* ptr) {
current_kernel_free(ptr);
@ -122,11 +122,11 @@ rust_uv_loop_set_data(uv_loop_t* loop, void* data) {
}
extern "C" void*
rust_uv_bind_op_cb(uv_loop_t* loop, crust_async_op_cb cb) {
rust_uv_bind_op_cb(uv_loop_t* loop, extern_async_op_cb cb) {
uv_async_t* async = (uv_async_t*)current_kernel_malloc(
sizeof(uv_async_t),
"uv_async_t");
uv_async_init(loop, async, native_crust_async_op_cb);
uv_async_init(loop, async, foreign_extern_async_op_cb);
async->data = (void*)cb;
// decrement the ref count, so that our async bind
// doesn't count towards keeping the loop alive
@ -136,7 +136,7 @@ rust_uv_bind_op_cb(uv_loop_t* loop, crust_async_op_cb cb) {
extern "C" void
rust_uv_stop_op_cb(uv_handle_t* op_handle) {
uv_close(op_handle, native_close_op_cb);
uv_close(op_handle, foreign_close_op_cb);
}
extern "C" void
@ -150,10 +150,10 @@ rust_uv_close(uv_handle_t* handle, uv_close_cb cb) {
}
extern "C" void
rust_uv_hilvl_close(uv_handle_t* handle, crust_close_cb cb) {
rust_uv_hilvl_close(uv_handle_t* handle, extern_close_cb cb) {
handle_data* data = (handle_data*)handle->data;
data->close_cb = cb;
uv_close(handle, native_close_cb);
uv_close(handle, foreign_close_cb);
}
extern "C" void
@ -181,12 +181,12 @@ rust_uv_async_init(uv_loop_t* loop_handle,
}
extern "C" void*
rust_uv_hilvl_async_init(uv_loop_t* loop, crust_simple_cb cb,
rust_uv_hilvl_async_init(uv_loop_t* loop, extern_simple_cb cb,
uint8_t* buf) {
uv_async_t* async = (uv_async_t*)current_kernel_malloc(
sizeof(uv_async_t),
"uv_async_t");
uv_async_init(loop, async, native_async_cb);
uv_async_init(loop, async, foreign_async_cb);
handle_data* data = new_handle_data_from(buf, cb);
async->data = data;
@ -194,7 +194,7 @@ rust_uv_hilvl_async_init(uv_loop_t* loop, crust_simple_cb cb,
}
extern "C" void*
rust_uv_hilvl_timer_init(uv_loop_t* loop, crust_simple_cb cb,
rust_uv_hilvl_timer_init(uv_loop_t* loop, extern_simple_cb cb,
uint8_t* buf) {
uv_timer_t* new_timer = (uv_timer_t*)current_kernel_malloc(
sizeof(uv_timer_t),
@ -209,7 +209,7 @@ rust_uv_hilvl_timer_init(uv_loop_t* loop, crust_simple_cb cb,
extern "C" void
rust_uv_hilvl_timer_start(uv_timer_t* the_timer, uint32_t timeout,
uint32_t repeat) {
uv_timer_start(the_timer, native_timer_cb, timeout, repeat);
uv_timer_start(the_timer, foreign_timer_cb, timeout, repeat);
}
extern "C" int