Skip to content

More quasi-quote related fixups #1808

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 15, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/comp/driver/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ fn emit(cmsp: option<(codemap::codemap, span)>,
msg: str, lvl: level) {
alt cmsp {
some((cm, sp)) {
let sp = codemap::adjust_span(cm,sp);
let ss = codemap::span_to_str(sp, cm);
let lines = codemap::span_to_lines(sp, cm);
print_diagnostic(ss, lvl, msg);
Expand Down
61 changes: 51 additions & 10 deletions src/comp/syntax/codemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ type file_pos = {ch: uint, byte: uint};
* compiler.
*/

type file_substr_ = {lo: uint, hi: uint, col: uint, line: uint};
type file_substr = option<file_substr_>;
enum file_substr {
fss_none,
fss_internal(span),
fss_external({filename: str, line: uint, col: uint})
}

type filemap =
@{name: filename, substr: file_substr, src: @str,
Expand All @@ -33,16 +36,14 @@ fn new_filemap_w_substr(filename: filename, substr: file_substr,
fn new_filemap(filename: filename, src: @str,
start_pos_ch: uint, start_pos_byte: uint)
-> filemap {
ret new_filemap_w_substr(filename, none, src,
ret new_filemap_w_substr(filename, fss_none, src,
start_pos_ch, start_pos_byte);
}

fn get_substr_info(cm: codemap, lo: uint, hi: uint)
-> (filename, file_substr_)
fn mk_substr_filename(cm: codemap, sp: span) -> str
{
let pos = lookup_char_pos(cm, lo);
let name = #fmt("<%s:%u:%u>", pos.file.name, pos.line, pos.col);
ret (name, {lo: lo, hi: hi, col: pos.col, line: pos.line});
let pos = lookup_char_pos(cm, sp.lo);
ret #fmt("<%s:%u:%u>", pos.file.name, pos.line, pos.col);
}

fn next_line(file: filemap, chpos: uint, byte_pos: uint) {
Expand Down Expand Up @@ -89,26 +90,66 @@ fn lookup_byte_pos(map: codemap, pos: uint) -> loc {
ret lookup_pos(map, pos, lookup);
}

fn lookup_char_pos_adj(map: codemap, pos: uint)
-> {filename: str, line: uint, col: uint, file: option<filemap>}
{
let loc = lookup_char_pos(map, pos);
alt (loc.file.substr) {
fss_none {
{filename: loc.file.name, line: loc.line, col: loc.col,
file: some(loc.file)}
}
fss_internal(sp) {
lookup_char_pos_adj(map, sp.lo + (pos - loc.file.start_pos.ch))
}
fss_external(eloc) {
{filename: eloc.filename,
line: eloc.line + loc.line - 1u,
col: if loc.line == 1u {eloc.col + loc.col} else {loc.col},
file: none}
}
}
}

fn adjust_span(map: codemap, sp: span) -> span {
fn lookup(pos: file_pos) -> uint { ret pos.ch; }
let line = lookup_line(map, sp.lo, lookup);
alt (line.fm.substr) {
fss_none {sp}
fss_internal(s) {
adjust_span(map, {lo: s.lo + (sp.lo - line.fm.start_pos.ch),
hi: s.lo + (sp.hi - line.fm.start_pos.ch),
expn_info: sp.expn_info})}
fss_external(_) {sp}
}
}

enum expn_info_ {
expanded_from({call_site: span,
callie: {name: str, span: option<span>}})
}
type expn_info = option<@expn_info_>;
type span = {lo: uint, hi: uint, expn_info: expn_info};

fn span_to_str(sp: span, cm: codemap) -> str {
fn span_to_str_no_adj(sp: span, cm: codemap) -> str {
let lo = lookup_char_pos(cm, sp.lo);
let hi = lookup_char_pos(cm, sp.hi);
ret #fmt("%s:%u:%u: %u:%u", lo.file.name,
lo.line, lo.col, hi.line, hi.col)
}

fn span_to_str(sp: span, cm: codemap) -> str {
let lo = lookup_char_pos_adj(cm, sp.lo);
let hi = lookup_char_pos_adj(cm, sp.hi);
ret #fmt("%s:%u:%u: %u:%u", lo.filename,
lo.line, lo.col, hi.line, hi.col)
}

type file_lines = {file: filemap, lines: [uint]};

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);
// FIXME: Check for filemap?
let lines = [];
uint::range(lo.line - 1u, hi.line as uint) {|i| lines += [i]; };
ret @{file: lo.file, lines: lines};
Expand Down
2 changes: 1 addition & 1 deletion src/comp/syntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import std::map::hashmap;
import syntax::ast::{crate, expr_, expr_mac, mac_invoc};
import syntax::fold::*;
import syntax::ext::base::*;
import syntax::ext::qquote::{expand_qquote,qq_helper};
import syntax::ext::qquote::{qq_helper};
import syntax::parse::parser::parse_expr_from_source_str;

import codemap::{span, expanded_from};
Expand Down
49 changes: 27 additions & 22 deletions src/comp/syntax/ext/qquote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,19 +143,6 @@ fn expand_ast(ecx: ext_ctxt, _sp: span,
}
}
let body = get_mac_body(ecx,_sp,body);
fn finish<T: qq_helper>(ecx: ext_ctxt, body: ast::mac_body_,
f: fn (p: parser) -> T)
-> @ast::expr
{
let cm = ecx.session().parse_sess.cm;
let str = @codemap::span_to_snippet(body.span, cm);
let (fname, ss) = codemap::get_substr_info
(cm, body.span.lo, body.span.hi);
let node = parse_from_source_str
(f, fname, some(ss), str,
ecx.session().opts.cfg, ecx.session().parse_sess);
ret expand_qquote(ecx, node.span(), *str, node);
}

ret alt what {
"expr" {finish(ecx, body, parser::parse_expr)}
Expand All @@ -182,23 +169,33 @@ fn parse_item(p: parser) -> @ast::item {
}
}

fn expand_qquote<N: qq_helper>
(ecx: ext_ctxt, sp: span, str: str, node: N)
fn finish<T: qq_helper>
(ecx: ext_ctxt, body: ast::mac_body_, f: fn (p: parser) -> T)
-> @ast::expr
{
let cm = ecx.session().parse_sess.cm;
let str = @codemap::span_to_snippet(body.span, cm);
let fname = codemap::mk_substr_filename(cm, body.span);
let node = parse_from_source_str
(f, fname, codemap::fss_internal(body.span), str,
ecx.session().opts.cfg, ecx.session().parse_sess);
let loc = codemap::lookup_char_pos(cm, body.span.lo);

let sp = node.span();
let qcx = gather_anti_quotes(sp.lo, node);
let cx = qcx;
let prev = 0u;
for {lo: lo, _} in cx.gather {
assert lo > prev;
prev = lo;

// assert that the vector is sorted by position:
uint::range(1u, vec::len(cx.gather)) {|i|
assert cx.gather[i-1u].lo < cx.gather[i].lo;
}

let str2 = "";
enum state {active, skip(uint), blank};
let state = active;
let i = 0u, j = 0u;
let g_len = vec::len(cx.gather);
str::chars_iter(str) {|ch|
str::chars_iter(*str) {|ch|
if (j < g_len && i == cx.gather[j].lo) {
assert ch == '$';
let repl = #fmt("$%u ", j);
Expand Down Expand Up @@ -228,8 +225,12 @@ fn expand_qquote<N: qq_helper>
["syntax", "parse", "parser",
"parse_from_source_str"],
[node.mk_parse_fn(cx,sp),
mk_str(cx,sp, "<anon>"),
mk_path(cx,sp, ["option","none"]),
mk_str(cx,sp, fname),
mk_call(cx,sp,
["syntax","ext","qquote", "mk_file_substr"],
[mk_str(cx,sp, loc.file.name),
mk_uint(cx,sp, loc.line),
mk_uint(cx,sp, loc.col)]),
mk_unary(cx,sp, ast::box(ast::imm),
mk_str(cx,sp, str2)),
mk_access_(cx,sp,
Expand Down Expand Up @@ -306,6 +307,10 @@ fn print_expr(expr: @ast::expr) {
stdout.write_str("\n");
}

fn mk_file_substr(fname: str, line: uint, col: uint) -> codemap::file_substr {
codemap::fss_external({filename: fname, line: line, col: col})
}

// Local Variables:
// mode: rust
// fill-column: 78;
Expand Down
8 changes: 7 additions & 1 deletion src/comp/syntax/parse/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,13 @@ impl reader for reader {
let next = str::char_range_at(*self.src, self.pos);
self.pos = next.next;
self.curr = next.ch;
} else { self.curr = -1 as char; }
} else {
if (self.curr != -1 as char) {
self.col += 1u;
self.chpos += 1u;
self.curr = -1 as char;
}
}
}
fn fatal(m: str) -> ! {
self.span_diagnostic.span_fatal(
Expand Down
9 changes: 6 additions & 3 deletions src/comp/syntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import std::{io, fs};
import either::{left, right};
import std::map::{hashmap, new_str_hash};
import token::can_begin_expr;
import codemap::span;
import codemap::{span,fss_none};
import util::interner;
import ast::{node_id, spanned};
import ast_util::{mk_sp, ident_to_path};
Expand Down Expand Up @@ -2607,7 +2607,7 @@ fn parse_crate_from_source_file(input: str, cfg: ast::crate_cfg,

fn parse_expr_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
sess: parse_sess) -> @ast::expr {
let p = new_parser_from_source_str(sess, cfg, name, none, source);
let p = new_parser_from_source_str(sess, cfg, name, fss_none, source);
let r = parse_expr(p);
sess.chpos = p.reader.chpos;
sess.byte_pos = sess.byte_pos + p.reader.pos;
Expand All @@ -2622,14 +2622,17 @@ fn parse_from_source_str<T>(f: fn (p: parser) -> T,
{
let p = new_parser_from_source_str(sess, cfg, name, ss, source);
let r = f(p);
if !p.reader.is_eof() {
p.reader.fatal("expected end-of-string");
}
sess.chpos = p.reader.chpos;
sess.byte_pos = sess.byte_pos + p.reader.pos;
ret r;
}

fn parse_crate_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
sess: parse_sess) -> @ast::crate {
let p = new_parser_from_source_str(sess, cfg, name, none, source);
let p = new_parser_from_source_str(sess, cfg, name, fss_none, source);
let r = parse_crate_mod(p, cfg);
sess.chpos = p.reader.chpos;
sess.byte_pos = sess.byte_pos + p.reader.pos;
Expand Down
2 changes: 1 addition & 1 deletion src/rustdoc/attr_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ mod test {
mutable byte_pos: 0u
};
let parser = parser::new_parser_from_source_str(
parse_sess, [], "-", none, @source);
parse_sess, [], "-", codemap::fss_none, @source);

parser::parse_outer_attributes(parser)
}
Expand Down
51 changes: 51 additions & 0 deletions src/test/compile-fail/qquote-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// xfail-pretty

use std;
use rustc;

import rustc::*;
import std::io::*;

import rustc::driver::diagnostic;
import rustc::syntax::ast;
import rustc::syntax::codemap;
import rustc::syntax::parse::parser;
import rustc::syntax::print::*;

fn new_parse_sess() -> parser::parse_sess {
fail;
}

iface fake_ext_ctxt {
fn session() -> fake_session;
}

type fake_options = {cfg: ast::crate_cfg};

type fake_session = {opts: @fake_options,
parse_sess: parser::parse_sess};

impl of fake_ext_ctxt for fake_session {
fn session() -> fake_session {self}
}

fn mk_ctxt() -> fake_ext_ctxt {
let opts : fake_options = {cfg: []};
{opts: @opts, parse_sess: new_parse_sess()} as fake_ext_ctxt
}


fn main() {
let ext_cx = mk_ctxt();

let abc = #ast{23};
check_pp(abc, pprust::print_expr, "23");

let expr3 = #ast{2 - $(abcd) + 7}; //! ERROR unresolved name: abcd
check_pp(expr3, pprust::print_expr, "2 - 23 + 7");
}

fn check_pp<T>(expr: T, f: fn(pprust::ps, T), expect: str) {
fail;
}

48 changes: 48 additions & 0 deletions src/test/compile-fail/qquote-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// xfail-pretty

use std;
use rustc;

import rustc::*;
import std::io::*;

import rustc::driver::diagnostic;
import rustc::syntax::ast;
import rustc::syntax::codemap;
import rustc::syntax::parse::parser;
import rustc::syntax::print::*;

fn new_parse_sess() -> parser::parse_sess {
fail;
}

iface fake_ext_ctxt {
fn session() -> fake_session;
}

type fake_options = {cfg: ast::crate_cfg};

type fake_session = {opts: @fake_options,
parse_sess: parser::parse_sess};

impl of fake_ext_ctxt for fake_session {
fn session() -> fake_session {self}
}

fn mk_ctxt() -> fake_ext_ctxt {
let opts : fake_options = {cfg: []};
{opts: @opts, parse_sess: new_parse_sess()} as fake_ext_ctxt
}


fn main() {
let ext_cx = mk_ctxt();

let stmt = #ast(stmt){let x int = 20;}; //! ERROR expected end-of-string
check_pp(*stmt, pprust::print_stmt, "");
}

fn check_pp<T>(expr: T, f: fn(pprust::ps, T), expect: str) {
fail;
}

12 changes: 12 additions & 0 deletions src/test/run-pass/qquote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@ fn main() {

let pat = #ast(pat){some(_)};
check_pp(pat, pprust::print_pat, "some(_)");

// issue #1785
let x = #ast{1};
let test1 = #ast{1+$(x)};
check_pp(test1, pprust::print_expr, "1 + 1");

let test2 = #ast{$(x)+1};
check_pp(test2, pprust::print_expr, "1 + 1");

let y = #ast{2};
let test3 = #ast{$(x) + $(y)};
check_pp(test3, pprust::print_expr, "1 + 2");
}

fn check_pp<T>(expr: T, f: fn(pprust::ps, T), expect: str) {
Expand Down