From c23d6a50d786e926d001423f36dc43fe480acbae Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 10 May 2012 17:18:04 -0700 Subject: [PATCH] Preliminary groundwork for intrinsic module, reflection interface. --- src/librustsyntax/codemap.rs | 6 ++ src/librustsyntax/ext/base.rs | 2 + src/librustsyntax/ext/include.rs | 59 ++++++++++++ src/librustsyntax/parse.rs | 12 +++ src/librustsyntax/rustsyntax.rc | 1 + src/rustc/driver/driver.rs | 4 + src/rustc/front/intrinsic.rs | 140 ++++++++++++++++++++++++++++ src/rustc/front/intrinsic_inject.rs | 30 ++++++ src/rustc/middle/trans/native.rs | 23 +++++ src/rustc/middle/typeck.rs | 13 +++ src/rustc/rustc.rc | 1 + 11 files changed, 291 insertions(+) create mode 100644 src/librustsyntax/ext/include.rs create mode 100644 src/rustc/front/intrinsic.rs create mode 100644 src/rustc/front/intrinsic_inject.rs diff --git a/src/librustsyntax/codemap.rs b/src/librustsyntax/codemap.rs index b8579f6733d..e119ae840e6 100644 --- a/src/librustsyntax/codemap.rs +++ b/src/librustsyntax/codemap.rs @@ -12,6 +12,7 @@ export mk_substr_filename; export lookup_char_pos; export adjust_span; export span_to_str; +export span_to_filename; export span_to_lines; export file_lines; export get_line; @@ -170,6 +171,11 @@ fn span_to_str(sp: span, cm: codemap) -> str { type file_lines = {file: filemap, lines: [uint]}; +fn span_to_filename(sp: span, cm: codemap::codemap) -> filename { + let lo = lookup_char_pos(cm, sp.lo); + ret lo.file.name; +} + fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines { let lo = lookup_char_pos(cm, sp.lo); let hi = lookup_char_pos(cm, sp.hi); diff --git a/src/librustsyntax/ext/base.rs b/src/librustsyntax/ext/base.rs index a4ca819d6b6..170ba112e31 100644 --- a/src/librustsyntax/ext/base.rs +++ b/src/librustsyntax/ext/base.rs @@ -31,6 +31,8 @@ fn syntax_expander_table() -> hashmap { syntax_expanders.insert("auto_serialize", item_decorator(ext::auto_serialize::expand)); syntax_expanders.insert("env", builtin(ext::env::expand_syntax_ext)); + syntax_expanders.insert("include_str", + builtin(ext::include::str::expand_syntax_ext)); syntax_expanders.insert("macro", macro_defining(ext::simplext::add_new_extension)); syntax_expanders.insert("concat_idents", diff --git a/src/librustsyntax/ext/include.rs b/src/librustsyntax/ext/include.rs new file mode 100644 index 00000000000..a31d2835e8a --- /dev/null +++ b/src/librustsyntax/ext/include.rs @@ -0,0 +1,59 @@ +/* + * The compiler code necessary to support the #include and #include_str + * extensions. Eventually this should all get sucked into either the compiler + * syntax extension plugin interface. + */ + +import diagnostic::span_handler; +import base::*; +export str; + +// FIXME: implement plain #include, restarting the parser on the included +// file. Currently only implement #include_str. + +mod str { + fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, + _body: ast::mac_body) -> @ast::expr { + let arg = get_mac_arg(cx,sp,arg); + let args: [@ast::expr] = + alt arg.node { + ast::expr_vec(elts, _) { elts } + _ { + cx.span_fatal(sp, "#include_str requires arguments \ + of the form `[...]`.") + } + }; + if vec::len::<@ast::expr>(args) != 1u { + cx.span_fatal(sp, "malformed #include_str call"); + } + let mut path = expr_to_str(cx, args[0], "#include_str requires \ + a string"); + + // NB: relative paths are resolved relative to the compilation unit + if !path::path_is_absolute(path) { + let cu = codemap::span_to_filename(sp, cx.codemap()); + let dir = path::dirname(cu); + path = path::connect(dir, path); + } + + alt io::read_whole_file_str(path) { + result::ok(src) { ret make_new_str(cx, sp, src); } + result::err(e) { + cx.parse_sess().span_diagnostic.handler().fatal(e) + } + } + } +} + +fn make_new_str(cx: ext_ctxt, sp: codemap::span, s: str) -> @ast::expr { + ret make_new_lit(cx, sp, ast::lit_str(s)); +} +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// End: +// diff --git a/src/librustsyntax/parse.rs b/src/librustsyntax/parse.rs index 96fa2dae8b5..ab3fc2072ae 100644 --- a/src/librustsyntax/parse.rs +++ b/src/librustsyntax/parse.rs @@ -8,6 +8,7 @@ export parse_crate_from_file; export parse_crate_from_crate_file; export parse_crate_from_source_str; export parse_expr_from_source_str; +export parse_item_from_source_str; export parse_from_source_str; import parser::parser; @@ -93,6 +94,17 @@ fn parse_expr_from_source_str(name: str, source: @str, cfg: ast::crate_cfg, ret r; } +fn parse_item_from_source_str(name: str, source: @str, cfg: ast::crate_cfg, + +attrs: [ast::attribute], vis: ast::visibility, + sess: parse_sess) -> option<@ast::item> { + let p = new_parser_from_source_str( + sess, cfg, name, codemap::fss_none, source); + let r = parser::parse_item(p, attrs, vis); + sess.chpos = p.reader.chpos; + sess.byte_pos = sess.byte_pos + p.reader.pos; + ret r; +} + fn parse_from_source_str(f: fn (p: parser) -> T, name: str, ss: codemap::file_substr, source: @str, cfg: ast::crate_cfg, diff --git a/src/librustsyntax/rustsyntax.rc b/src/librustsyntax/rustsyntax.rc index 2e560eb01c1..293238aac3c 100644 --- a/src/librustsyntax/rustsyntax.rc +++ b/src/librustsyntax/rustsyntax.rc @@ -63,6 +63,7 @@ mod ext { mod simplext; mod concat_idents; mod ident_to_str; + mod include; mod log_syntax; mod auto_serialize; } diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 6fb525a1346..7f737403da8 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -148,6 +148,10 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, if upto == cu_expand { ret {crate: crate, tcx: none}; } + crate = + time(time_passes, "intrinsic injection", + bind front::intrinsic_inject::inject_intrinsic(sess, crate)); + crate = time(time_passes, "core injection", bind front::core_inject::maybe_inject_libcore_ref(sess, crate)); diff --git a/src/rustc/front/intrinsic.rs b/src/rustc/front/intrinsic.rs new file mode 100644 index 00000000000..e389b30715b --- /dev/null +++ b/src/rustc/front/intrinsic.rs @@ -0,0 +1,140 @@ +// NB: this file is #include_str'ed into the compiler, re-parsed +// and injected into each crate the compiler builds. Keep it small. + +mod intrinsic { + + // import rusti::visit_ty; + // import rusti::visit_val; + // import rusti::visit_val_pair; + + export ty_visitor, val_visitor, val_pair_visitor; + + fn macros() { + // Present for side-effect of defining intrinsic macros. + #macro([#error[f, ...], log(core::error, #fmt[f, ...])]); + #macro([#warn[f, ...], log(core::warn, #fmt[f, ...])]); + #macro([#info[f, ...], log(core::info, #fmt[f, ...])]); + #macro([#debug[f, ...], log(core::debug, #fmt[f, ...])]); + } + + iface ty_visitor { + fn visit_nil(); + fn visit_bool(); + + fn visit_int(); + fn visit_i8(); + fn visit_i16(); + fn visit_i32(); + fn visit_i64(); + + fn visit_uint(); + fn visit_u8(); + fn visit_u16(); + fn visit_u32(); + fn visit_u64(); + + fn visit_float(); + fn visit_f32(); + fn visit_f64(); + fn visit_str(); + + fn visit_vec(cells_mut: bool, + visit_cell: fn(uint, self)); + + fn visit_box(inner_mut: bool, + visit_inner: fn(self)); + + fn visit_uniq(inner_mut: bool, + visit_inner: fn(self)); + + fn visit_ptr(inner_mut: bool, + visit_inner: fn(self)); + + fn visit_rptr(inner_mut: bool, + visit_inner: fn(self)); + + fn visit_rec(n_fields: uint, + field_name: fn(uint) -> str/&, + field_mut: fn(uint) -> bool, + visit_field: fn(uint, self)); + fn visit_tup(n_fields: uint, + visit_field: fn(uint, self)); + fn visit_enum(n_variants: uint, + variant: uint, + variant_name: fn(uint) -> str/&, + visit_variant: fn(uint, self)); + } + + iface val_visitor { + + // Basic types we can visit directly. + fn visit_nil(); + fn visit_bool(b: &bool); + + fn visit_int(i: &int); + fn visit_i8(i: &i8); + fn visit_i16(i: &i16); + fn visit_i32(i: &i32); + fn visit_i64(i: &i64); + + fn visit_uint(u: &uint); + fn visit_u8(i: &i8); + fn visit_u16(i: &i16); + fn visit_u32(i: &i32); + fn visit_u64(i: &i64); + + fn visit_float(f: &float); + fn visit_f32(f: &f32); + fn visit_f64(f: &f64); + + // Vecs and strs we can provide a stub view of. + fn visit_str(repr: &vec::unsafe::vec_repr, + visit_cell: fn(uint,self)); + + fn visit_vec(repr: &vec::unsafe::vec_repr, + cells_mut: bool, + visit_cell: fn(uint, self)); + + fn visit_box(mem: *u8, + inner_mut: bool, + visit_inner: fn(self)); + + fn visit_uniq(mem: *u8, + inner_mut: bool, + visit_inner: fn(self)); + + fn visit_ptr(mem: *u8, + inner_mut: bool, + visit_inner: fn(self)); + + fn visit_rptr(mem: *u8, + inner_mut: bool, + visit_inner: fn(self)); + + // Aggregates we can't really provide anything useful for + // beyond a *u8. You really have to know what you're doing. + fn visit_rec(mem: *u8, + n_fields: uint, + field_name: fn(uint) -> str/&, + field_mut: fn(uint) -> bool, + visit_field: fn(uint, self)); + fn visit_tup(mem: *u8, + n_fields: uint, + visit_field: fn(uint, self)); + fn visit_enum(mem: *u8, + n_variants: uint, + variant: uint, + variant_name: fn(uint) -> str/&, + visit_variant: fn(uint, self)); + } + + iface val_pair_visitor { + } + + #[abi = "rust-intrinsic"] + native mod rusti { + // fn visit_ty(tv: V); + // fn visit_val(v: &T, vv: V); + // fn visit_val_pair(a: &T, b: &T, vpv: &V); + } +} diff --git a/src/rustc/front/intrinsic_inject.rs b/src/rustc/front/intrinsic_inject.rs new file mode 100644 index 00000000000..d2eaf2c8955 --- /dev/null +++ b/src/rustc/front/intrinsic_inject.rs @@ -0,0 +1,30 @@ +import driver::session::session; +import syntax::parse; +import syntax::ast; + +export inject_intrinsic; + +fn inject_intrinsic(sess: session, + crate: @ast::crate) -> @ast::crate { + + // FIXME: upgrade this to #include_str("intrinsic.rs"); + let intrinsic_module = @"mod intrinsic { }"; + + let item = parse::parse_item_from_source_str("intrinsic", + intrinsic_module, + sess.opts.cfg, + [], ast::public, + sess.parse_sess); + let item = + alt item { + some(i) { i } + none { + sess.fatal("no item found in intrinsic module"); + } + }; + + let items = [item] + crate.node.module.items; + + ret @{node: {module: { items: items with crate.node.module } + with crate.node} with *crate } +} diff --git a/src/rustc/middle/trans/native.rs b/src/rustc/middle/trans/native.rs index 77e3a1f3067..4ecbdb7a1c1 100644 --- a/src/rustc/middle/trans/native.rs +++ b/src/rustc/middle/trans/native.rs @@ -834,6 +834,29 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::native_item, Store(bcx, C_bool(ty::type_needs_drop(ccx.tcx, tp_ty)), fcx.llretptr); } + "visit_ty" { + let vp_ty = substs.tys[1], _llvp_ty = type_of::type_of(ccx, vp_ty); + let visitor = get_param(decl, first_real_arg); + // FIXME: implement a proper iface-call. Nontrivial. + Call(bcx, visitor, []); + } + + "visit_val" { + let vp_ty = substs.tys[1], _llvp_ty = type_of::type_of(ccx, vp_ty); + let val = get_param(decl, first_real_arg); + let visitor = get_param(decl, first_real_arg + 1u); + // FIXME: implement a proper iface-call. Nontrivial. + Call(bcx, visitor, [val]); + } + + "visit_val_pair" { + let vp_ty = substs.tys[1], _llvp_ty = type_of::type_of(ccx, vp_ty); + let a = get_param(decl, first_real_arg); + let b = get_param(decl, first_real_arg + 1u); + let visitor = get_param(decl, first_real_arg + 2u); + // FIXME: implement a proper iface-call. Nontrivial. + Call(bcx, visitor, [a, b]); + } } build_return(bcx); finish_fn(fcx, lltop); diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 472a4f43e2c..7e132ffbee6 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -2072,6 +2072,19 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::native_item) { "addr_of" { (1u, [arg(ast::by_ref, param(ccx, 0u))], ty::mk_imm_ptr(tcx, param(ccx, 0u))) } "needs_drop" { (1u, [], ty::mk_bool(tcx)) } + + "visit_ty" { (2u, [arg(ast::by_ref, param(ccx, 1u))], + ty::mk_nil(tcx)) } + + "visit_val" { (2u, [arg(ast::by_ref, param(ccx, 0u)), + arg(ast::by_ref, param(ccx, 1u))], + ty::mk_nil(tcx)) } + + "visit_val_pair" { (2u, [arg(ast::by_ref, param(ccx, 0u)), + arg(ast::by_ref, param(ccx, 0u)), + arg(ast::by_ref, param(ccx, 1u))], + ty::mk_nil(tcx)) } + other { tcx.sess.span_err(it.span, "unrecognized intrinsic function: `" + other + "`"); diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index c50ea26eb15..1f0b7798fe0 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -76,6 +76,7 @@ mod front { mod config; mod test; mod core_inject; + mod intrinsic_inject; } mod back {