diff options
| author | Graydon Hoare <[email protected]> | 2010-09-23 15:46:31 -0700 |
|---|---|---|
| committer | Graydon Hoare <[email protected]> | 2010-09-23 15:46:31 -0700 |
| commit | 46e46d0b49de8e245d091f7062dfc28ab71e869e (patch) | |
| tree | 5ca0d7ab10eb2a89b9c2a299ff3490eac912bf5d /src/comp/front | |
| parent | More fleshing-out on rustc.me.trans. Emitting modules and fns corresponding t... (diff) | |
| download | rust-46e46d0b49de8e245d091f7062dfc28ab71e869e.tar.xz rust-46e46d0b49de8e245d091f7062dfc28ab71e869e.zip | |
Translate a bunch of the material (lltrans, llasm, abi) from rustboot to rustc, and move files around.
Diffstat (limited to 'src/comp/front')
| -rw-r--r-- | src/comp/front/ast.rs | 83 | ||||
| -rw-r--r-- | src/comp/front/lexer.rs | 595 | ||||
| -rw-r--r-- | src/comp/front/parser.rs | 265 | ||||
| -rw-r--r-- | src/comp/front/token.rs | 348 |
4 files changed, 1291 insertions, 0 deletions
diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs new file mode 100644 index 00000000..327570d6 --- /dev/null +++ b/src/comp/front/ast.rs @@ -0,0 +1,83 @@ + +import std.util.option; +import std.map.hashmap; +import util.common.span; + +type ident = str; + +type crate = rec(_mod module); + +type block = vec[@stmt]; + +tag stmt { + stmt_block(block); + stmt_decl(@decl); + stmt_ret(option[@lval]); + stmt_log(@atom); +} + + +tag decl { + decl_local(ident, option[ty]); + decl_item(ident, @item); +} + +tag lval { + lval_ident(ident); + lval_ext(@lval, ident); + lval_idx(@lval, @atom); +} + +tag atom { + atom_lit(@lit); + atom_lval(@lval); +} + +tag lit { + lit_char(char); + lit_int(int); + lit_uint(uint); + lit_nil; + lit_bool(bool); +} + +tag ty { + ty_nil; + ty_bool; + ty_int; + ty_uint; + ty_machine(util.common.ty_mach); + ty_char; + ty_str; + ty_box(@ty); +} + +tag mode { + val; + alias; +} + +type slot = rec(ty ty, mode mode); + +type _fn = rec(vec[rec(slot slot, ident ident)] inputs, + slot output, + block body); + +type _mod = hashmap[ident,item]; + +tag item { + item_fn(@_fn); + item_mod(@_mod); +} + + +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: +// diff --git a/src/comp/front/lexer.rs b/src/comp/front/lexer.rs new file mode 100644 index 00000000..d058db4a --- /dev/null +++ b/src/comp/front/lexer.rs @@ -0,0 +1,595 @@ +import std._io.stdio_reader; +import std._str; +import std.map; +import std.map.hashmap; +import util.common; +import util.common.new_str_hash; + +state type reader = state obj { + fn is_eof() -> bool; + fn curr() -> char; + fn next() -> char; + state fn bump(); + state fn mark(); + fn get_filename() -> str; + fn get_mark_pos() -> common.pos; + fn get_curr_pos() -> common.pos; + fn get_keywords() -> hashmap[str,token.token]; + fn get_reserved() -> hashmap[str,()]; +}; + +fn new_reader(stdio_reader rdr, str filename) -> reader +{ + state obj reader(stdio_reader rdr, + str filename, + mutable char c, + mutable char n, + mutable uint mark_line, + mutable uint mark_col, + mutable uint line, + mutable uint col, + hashmap[str,token.token] keywords, + hashmap[str,()] reserved) { + + fn is_eof() -> bool { + ret c == (-1) as char; + } + + fn get_curr_pos() -> common.pos { + ret rec(line=line, col=col); + } + + fn get_mark_pos() -> common.pos { + ret rec(line=mark_line, col=mark_col); + } + + fn get_filename() -> str { + ret filename; + } + + fn curr() -> char { + ret c; + } + + fn next() -> char { + ret n; + } + + state fn bump() { + c = n; + + if (c == (-1) as char) { + ret; + } + + if (c == '\n') { + line += 1u; + col = 1u; + } else { + col += 1u; + } + + n = rdr.getc() as char; + } + + state fn mark() { + mark_line = line; + mark_col = col; + } + + fn get_keywords() -> hashmap[str,token.token] { + ret keywords; + } + + fn get_reserved() -> hashmap[str,()] { + ret reserved; + } + } + + auto keywords = new_str_hash[token.token](); + auto reserved = new_str_hash[()](); + + keywords.insert("mod", token.MOD); + keywords.insert("use", token.USE); + keywords.insert("meta", token.META); + keywords.insert("auth", token.AUTH); + + keywords.insert("syntax", token.SYNTAX); + + keywords.insert("if", token.IF); + keywords.insert("else", token.ELSE); + keywords.insert("while", token.WHILE); + keywords.insert("do", token.DO); + keywords.insert("alt", token.ALT); + keywords.insert("case", token.CASE); + + keywords.insert("for", token.FOR); + keywords.insert("each", token.EACH); + keywords.insert("put", token.PUT); + keywords.insert("ret", token.RET); + keywords.insert("be", token.BE); + + keywords.insert("fail", token.FAIL); + keywords.insert("drop", token.DROP); + + keywords.insert("type", token.TYPE); + keywords.insert("check", token.CHECK); + keywords.insert("claim", token.CLAIM); + keywords.insert("prove", token.PROVE); + + keywords.insert("io", token.IO); + keywords.insert("state", token.STATE); + keywords.insert("unsafe", token.UNSAFE); + + keywords.insert("native", token.NATIVE); + keywords.insert("mutable", token.MUTABLE); + keywords.insert("auto", token.AUTO); + + keywords.insert("fn", token.FN); + keywords.insert("iter", token.ITER); + + keywords.insert("import", token.IMPORT); + keywords.insert("export", token.EXPORT); + + keywords.insert("let", token.LET); + keywords.insert("const", token.CONST); + + keywords.insert("log", token.LOG); + keywords.insert("spawn", token.SPAWN); + keywords.insert("thread", token.THREAD); + keywords.insert("yield", token.YIELD); + keywords.insert("join", token.JOIN); + + keywords.insert("bool", token.BOOL); + + keywords.insert("int", token.INT); + keywords.insert("uint", token.UINT); + keywords.insert("float", token.FLOAT); + + keywords.insert("char", token.CHAR); + keywords.insert("str", token.STR); + + + keywords.insert("rec", token.REC); + keywords.insert("tup", token.TUP); + keywords.insert("tag", token.TAG); + keywords.insert("vec", token.VEC); + keywords.insert("any", token.ANY); + + keywords.insert("obj", token.OBJ); + + keywords.insert("port", token.PORT); + keywords.insert("chan", token.CHAN); + + keywords.insert("task", token.TASK); + + keywords.insert("true", token.LIT_BOOL(true)); + keywords.insert("false", token.LIT_BOOL(false)); + + keywords.insert("in", token.IN); + + keywords.insert("as", token.AS); + keywords.insert("with", token.WITH); + + keywords.insert("bind", token.BIND); + + keywords.insert("u8", token.MACH(common.ty_u8)); + keywords.insert("u16", token.MACH(common.ty_u16)); + keywords.insert("u32", token.MACH(common.ty_u32)); + keywords.insert("u64", token.MACH(common.ty_u64)); + keywords.insert("i8", token.MACH(common.ty_i8)); + keywords.insert("i16", token.MACH(common.ty_i16)); + keywords.insert("i32", token.MACH(common.ty_i32)); + keywords.insert("i64", token.MACH(common.ty_i64)); + keywords.insert("f32", token.MACH(common.ty_f32)); + keywords.insert("f64", token.MACH(common.ty_f64)); + + ret reader(rdr, filename, rdr.getc() as char, rdr.getc() as char, + 1u, 1u, 1u, 1u, keywords, reserved); +} + + + + +fn in_range(char c, char lo, char hi) -> bool { + ret lo <= c && c <= hi; +} + +fn is_alpha(char c) -> bool { + ret in_range(c, 'a', 'z') || + in_range(c, 'A', 'Z'); +} + +fn is_dec_digit(char c) -> bool { + ret in_range(c, '0', '9'); +} + +fn is_hex_digit(char c) -> bool { + ret in_range(c, '0', '9') || + in_range(c, 'a', 'f') || + in_range(c, 'A', 'F'); +} + +fn is_bin_digit(char c) -> bool { + ret c == '0' || c == '1'; +} + +fn dec_digit_val(char c) -> int { + ret (c as int) - ('0' as int); +} + +fn hex_digit_val(char c) -> int { + if (in_range(c, '0', '9')) { + ret (c as int) - ('0' as int); + } + + if (in_range(c, 'a', 'f')) { + ret ((c as int) - ('a' as int)) + 10; + } + + if (in_range(c, 'A', 'F')) { + ret ((c as int) - ('A' as int)) + 10; + } + + fail; +} + +fn bin_digit_value(char c) -> int { + if (c == '0') { ret 0; } + ret 1; +} + +fn is_whitespace(char c) -> bool { + ret c == ' ' || c == '\t' || c == '\r' || c == '\n'; +} + +state fn consume_any_whitespace(reader rdr) { + while (is_whitespace(rdr.curr())) { + rdr.bump(); + } + be consume_any_line_comment(rdr); +} + +state fn consume_any_line_comment(reader rdr) { + if (rdr.curr() == '/') { + alt (rdr.next()) { + case ('/') { + while (rdr.curr() != '\n') { + rdr.bump(); + } + // Restart whitespace munch. + be consume_any_whitespace(rdr); + } + case ('*') { + rdr.bump(); + rdr.bump(); + be consume_block_comment(rdr); + } + case (_) { + ret; + } + } + } +} + + +state fn consume_block_comment(reader rdr) { + let int level = 1; + while (level > 0) { + if (rdr.curr() == '/' && rdr.next() == '*') { + rdr.bump(); + rdr.bump(); + level += 1; + } else { + if (rdr.curr() == '*' && rdr.next() == '/') { + rdr.bump(); + rdr.bump(); + level -= 1; + } else { + rdr.bump(); + } + } + } + // restart whitespace munch. + be consume_any_whitespace(rdr); +} + +state fn next_token(reader rdr) -> token.token { + auto accum_str = ""; + auto accum_int = 0; + + consume_any_whitespace(rdr); + + if (rdr.is_eof()) { ret token.EOF; } + + auto c = rdr.curr(); + + if (is_alpha(c)) { + while (is_alpha(c) || c == '_') { + accum_str += (c as u8); + rdr.bump(); + c = rdr.curr(); + } + + auto kwds = rdr.get_keywords(); + if (kwds.contains_key(accum_str)) { + ret kwds.get(accum_str); + } + + ret token.IDENT(accum_str); + } + + if (is_dec_digit(c)) { + auto n = rdr.next(); + if (c == '0' && n == 'x') { + rdr.bump(); + rdr.bump(); + c = rdr.curr(); + while (is_hex_digit(c) || c == '_') { + accum_int *= 16; + accum_int += hex_digit_val(c); + rdr.bump(); + c = rdr.curr(); + } + } + + if (c == '0' && n == 'b') { + rdr.bump(); + rdr.bump(); + c = rdr.curr(); + while (is_bin_digit(c) || c == '_') { + accum_int *= 2; + accum_int += bin_digit_value(c); + rdr.bump(); + c = rdr.curr(); + } + } + + while (is_dec_digit(c) || c == '_') { + accum_int *= 10; + accum_int += dec_digit_val(c); + rdr.bump(); + c = rdr.curr(); + } + + ret token.LIT_INT(accum_int); + } + + state fn binop(reader rdr, token.binop op) -> token.token { + rdr.bump(); + if (rdr.next() == '=') { + rdr.bump(); + ret token.BINOPEQ(op); + } else { + ret token.BINOP(op); + } + } + + alt (c) { + // One-byte tokens. + case (':') { rdr.bump(); ret token.COLON; } + case ('?') { rdr.bump(); ret token.QUES; } + case (';') { rdr.bump(); ret token.SEMI; } + case (',') { rdr.bump(); ret token.COMMA; } + case ('.') { rdr.bump(); ret token.DOT; } + case ('(') { rdr.bump(); ret token.LPAREN; } + case (')') { rdr.bump(); ret token.RPAREN; } + case ('{') { rdr.bump(); ret token.LBRACE; } + case ('}') { rdr.bump(); ret token.RBRACE; } + case ('[') { rdr.bump(); ret token.LBRACKET; } + case (']') { rdr.bump(); ret token.RBRACKET; } + case ('@') { rdr.bump(); ret token.AT; } + case ('#') { rdr.bump(); ret token.POUND; } + case ('_') { rdr.bump(); ret token.UNDERSCORE; } + case ('~') { rdr.bump(); ret token.TILDE; } + + + // Multi-byte tokens. + case ('=') { + rdr.bump(); + if (rdr.curr() == '=') { + rdr.bump(); + ret token.EQEQ; + } else { + ret token.EQ; + } + } + + case ('!') { + rdr.bump(); + if (rdr.curr() == '=') { + rdr.bump(); + ret token.NE; + } else { + ret token.NOT; + } + } + + case ('<') { + rdr.bump(); + alt (rdr.curr()) { + case ('=') { + rdr.bump(); + ret token.LE; + } + case ('<') { + ret binop(rdr, token.LSL); + } + case ('-') { + rdr.bump(); + ret token.LARROW; + } + case ('|') { + rdr.bump(); + ret token.SEND; + } + case (_) { + ret token.LT; + } + } + } + + case ('>') { + rdr.bump(); + alt (rdr.curr()) { + case ('=') { + rdr.bump(); + ret token.GE; + } + + case ('>') { + if (rdr.next() == '>') { + rdr.bump(); + ret binop(rdr, token.ASR); + } else { + ret binop(rdr, token.LSR); + } + } + + case (_) { + ret token.GT; + } + } + } + + case ('\'') { + rdr.bump(); + auto c2 = rdr.curr(); + if (c2 == '\\') { + alt (rdr.next()) { + case ('n') { rdr.bump(); c2 = '\n'; } + case ('r') { rdr.bump(); c2 = '\r'; } + case ('t') { rdr.bump(); c2 = '\t'; } + case ('\\') { rdr.bump(); c2 = '\\'; } + case ('\'') { rdr.bump(); c2 = '\''; } + // FIXME: unicode numeric escapes. + case (?c2) { + log "unknown character escape"; + log c2; + fail; + } + } + } + + if (rdr.next() != '\'') { + log "unterminated character constant"; + fail; + } + rdr.bump(); + rdr.bump(); + ret token.LIT_CHAR(c2); + } + + case ('"') { + rdr.bump(); + // FIXME: general utf8-consumption support. + while (rdr.curr() != '"') { + alt (rdr.curr()) { + case ('\\') { + alt (rdr.next()) { + case ('n') { + rdr.bump(); + accum_str += '\n' as u8; + } + case ('r') { + rdr.bump(); + accum_str += '\r' as u8; + } + case ('t') { + rdr.bump(); + accum_str += '\t' as u8; + } + case ('\\') { + rdr.bump(); + accum_str += '\\' as u8; + } + case ('"') { + rdr.bump(); + accum_str += '"' as u8; + } + // FIXME: unicode numeric escapes. + case (?c2) { + log "unknown string escape"; + log c2; + fail; + } + } + } + case (_) { + accum_str += rdr.curr() as u8; + } + } + rdr.bump(); + } + rdr.bump(); + ret token.LIT_STR(accum_str); + } + + case ('-') { + if (rdr.next() == '>') { + rdr.bump(); + rdr.bump(); + ret token.RARROW; + } else { + ret binop(rdr, token.MINUS); + } + } + + case ('&') { + if (rdr.next() == '&') { + rdr.bump(); + rdr.bump(); + ret token.ANDAND; + } else { + ret binop(rdr, token.AND); + } + } + + case ('|') { + if (rdr.next() == '|') { + rdr.bump(); + rdr.bump(); + ret token.OROR; + } else { + ret binop(rdr, token.OR); + } + } + + case ('+') { + ret binop(rdr, token.PLUS); + } + + case ('*') { + ret binop(rdr, token.STAR); + } + + case ('/') { + ret binop(rdr, token.STAR); + } + + case ('^') { + ret binop(rdr, token.CARET); + } + + case ('%') { + ret binop(rdr, token.PERCENT); + } + + } + + log "lexer stopping at "; + log c; + ret token.EOF; +} + + +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: +// diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs new file mode 100644 index 00000000..ab2e15e3 --- /dev/null +++ b/src/comp/front/parser.rs @@ -0,0 +1,265 @@ +import std._io; +import driver.session; +import util.common; +import util.common.new_str_hash; + +// FIXME: import std.util.option and use it here. +// import std.util.option; + +tag option[T] { + none; + some(T); +} + + +state type parser = + state obj { + state fn peek() -> token.token; + state fn bump(); + io fn err(str s); + fn get_session() -> session.session; + fn get_span() -> common.span; + }; + +state fn new_parser(session.session sess, str path) -> parser { + state obj stdio_parser(session.session sess, + mutable token.token tok, + mutable common.pos lo, + mutable common.pos hi, + lexer.reader rdr) + { + state fn peek() -> token.token { + log token.to_str(tok); + ret tok; + } + + state fn bump() { + tok = lexer.next_token(rdr); + lo = rdr.get_mark_pos(); + hi = rdr.get_curr_pos(); + } + + io fn err(str m) { + auto span = rec(filename = rdr.get_filename(), + lo = lo, hi = hi); + sess.span_err(span, m); + } + + fn get_session() -> session.session { + ret sess; + } + + fn get_span() -> common.span { + ret rec(filename = rdr.get_filename(), + lo = lo, hi = hi); + } + } + auto srdr = _io.new_stdio_reader(path); + auto rdr = lexer.new_reader(srdr, path); + auto npos = rdr.get_curr_pos(); + ret stdio_parser(sess, lexer.next_token(rdr), npos, npos, rdr); +} + +state fn expect(parser p, token.token t) { + if (p.peek() == t) { + p.bump(); + } else { + let str s = "expecting "; + s += token.to_str(t); + s += ", found "; + s += token.to_str(p.peek()); + p.err(s); + } +} + +state fn parse_ident(parser p) -> ast.ident { + alt (p.peek()) { + case (token.IDENT(?i)) { p.bump(); ret i; } + case (_) { + p.err("expecting ident"); + fail; + } + } +} + +state fn parse_ty(parser p) -> ast.ty { + alt (p.peek()) { + case (token.INT) { p.bump(); ret ast.ty_int; } + case (token.UINT) { p.bump(); ret ast.ty_int; } + case (token.STR) { p.bump(); ret ast.ty_str; } + case (token.CHAR) { p.bump(); ret ast.ty_char; } + case (token.MACH(?tm)) { p.bump(); ret ast.ty_machine(tm); } + } + p.err("expecting type"); + fail; +} + +state fn parse_slot(parser p) -> ast.slot { + let ast.mode m = ast.val; + if (p.peek() == token.BINOP(token.AND)) { + m = ast.alias; + p.bump(); + } + let ast.ty t = parse_ty(p); + ret rec(ty=t, mode=m); +} + +state fn parse_seq[T](token.token bra, + token.token ket, + option[token.token] sep, + (state fn(parser) -> T) f, + parser p) -> vec[T] { + let bool first = true; + expect(p, bra); + let vec[T] v = vec(); + while (p.peek() != ket) { + alt(sep) { + case (some[token.token](?t)) { + if (first) { + first = false; + } else { + expect(p, t); + } + } + case (_) { + } + } + // FIXME: v += f(p) doesn't work at the moment. + let T t = f(p); + v += vec(t); + } + expect(p, ket); + ret v; +} + +state fn parse_lit(parser p) -> ast.lit { + alt (p.peek()) { + case (token.LIT_INT(?i)) { + p.bump(); + ret ast.lit_int(i); + } + case (token.LIT_UINT(?u)) { + p.bump(); + ret ast.lit_uint(u); + } + case (token.LIT_CHAR(?c)) { + p.bump(); + ret ast.lit_char(c); + } + case (token.LIT_BOOL(?b)) { + p.bump(); + ret ast.lit_bool(b); + } + } + p.err("expected literal"); + fail; +} + +state fn parse_atom(parser p) -> ast.atom { + ret ast.atom_lit(@parse_lit(p)); +} + +state fn parse_stmt(parser p) -> @ast.stmt { + alt (p.peek()) { + case (token.LOG) { + p.bump(); + auto a = @parse_atom(p); + expect(p, token.SEMI); + ret @ast.stmt_log(a); + } + } + p.err("expected statement"); + fail; +} + +state fn parse_block(parser p) -> ast.block { + auto f = parse_stmt; + // FIXME: passing parse_stmt as an lval doesn't work at the moment. + ret parse_seq[@ast.stmt](token.LBRACE, + token.RBRACE, + none[token.token], + f, p); +} + +state fn parse_slot_ident_pair(parser p) -> + rec(ast.slot slot, ast.ident ident) { + auto s = parse_slot(p); + auto i = parse_ident(p); + ret rec(slot=s, ident=i); +} + +state fn parse_fn(parser p) -> tup(ast.ident, ast.item) { + expect(p, token.FN); + auto id = parse_ident(p); + auto pf = parse_slot_ident_pair; + auto inputs = + // FIXME: passing parse_slot_ident_pair as an lval doesn't work at the + // moment. + parse_seq[rec(ast.slot slot, ast.ident ident)] + (token.LPAREN, + token.RPAREN, + some(token.COMMA), + pf, p); + + auto output; + if (p.peek() == token.RARROW) { + p.bump(); + output = rec(ty=parse_ty(p), mode=ast.val); + } else { + output = rec(ty=ast.ty_nil, mode=ast.val); + } + + auto body = parse_block(p); + + let ast._fn f = rec(inputs = inputs, + output = output, + body = body); + + ret tup(id, ast.item_fn(@f)); +} + +state fn parse_mod(parser p) -> tup(ast.ident, ast.item) { + expect(p, token.MOD); + auto id = parse_ident(p); + expect(p, token.LBRACE); + let ast._mod m = new_str_hash[ast.item](); + while (p.peek() != token.RBRACE) { + auto i = parse_item(p); + m.insert(i._0, i._1); + } + expect(p, token.RBRACE); + ret tup(id, ast.item_mod(@m)); +} + +state fn parse_item(parser p) -> tup(ast.ident, ast.item) { + alt (p.peek()) { + case (token.FN) { + ret parse_fn(p); + } + case (token.MOD) { + ret parse_mod(p); + } + } + p.err("expectied item"); + fail; +} + +state fn parse_crate(parser p) -> ast.crate { + let ast._mod m = new_str_hash[ast.item](); + while (p.peek() != token.EOF) { + auto i = parse_item(p); + m.insert(i._0, i._1); + } + ret rec(module=m); +} + +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: +// diff --git a/src/comp/front/token.rs b/src/comp/front/token.rs new file mode 100644 index 00000000..b9b2fa07 --- /dev/null +++ b/src/comp/front/token.rs @@ -0,0 +1,348 @@ +import util.common.ty_mach; +import util.common.ty_mach_to_str; +import util.common.new_str_hash; +import std._int; +import std._uint; + +tag binop { + PLUS; + MINUS; + STAR; + SLASH; + PERCENT; + CARET; + AND; + OR; + LSL; + LSR; + ASR; +} + +tag token { + /* Expression-operator symbols. */ + EQ; + LT; + LE; + EQEQ; + NE; + GE; + GT; + ANDAND; + OROR; + NOT; + TILDE; + + BINOP(binop); + BINOPEQ(binop); + + AS; + WITH; + + /* Structural symbols */ + AT; + DOT; + COMMA; + SEMI; + COLON; + QUES; + RARROW; + SEND; + LARROW; + LPAREN; + RPAREN; + LBRACKET; + RBRACKET; + LBRACE; + RBRACE; + + /* Module and crate keywords */ + MOD; + USE; + AUTH; + META; + + /* Metaprogramming keywords */ + SYNTAX; + POUND; + + /* Statement keywords */ + IF; + ELSE; + DO; + WHILE; + ALT; + CASE; + + FAIL; + DROP; + + IN; + FOR; + EACH; + PUT; + RET; + BE; + + /* Type and type-state keywords */ + TYPE; + CHECK; + CLAIM; + PROVE; + + /* Effect keywords */ + IO; + STATE; + UNSAFE; + + /* Type qualifiers */ + NATIVE; + AUTO; + MUTABLE; + + /* Name management */ + IMPORT; + EXPORT; + + /* Value / stmt declarators */ + LET; + CONST; + + /* Magic runtime services */ + LOG; + SPAWN; + BIND; + THREAD; + YIELD; + JOIN; + + /* Literals */ + LIT_INT(int); + LIT_UINT(uint); + LIT_MACH_INT(ty_mach, int); + LIT_STR(str); + LIT_CHAR(char); + LIT_BOOL(bool); + + /* Name components */ + IDENT(str); + IDX(int); + UNDERSCORE; + + /* Reserved type names */ + BOOL; + INT; + UINT; + FLOAT; + CHAR; + STR; + MACH(ty_mach); + + /* Algebraic type constructors */ + REC; + TUP; + TAG; + VEC; + ANY; + + /* Callable type constructors */ + FN; + ITER; + + /* Object type */ + OBJ; + + /* Comm and task types */ + CHAN; + PORT; + TASK; + + BRACEQUOTE(str); + EOF; +} + +fn binop_to_str(binop o) -> str { + alt (o) { + case (PLUS) { ret "+"; } + case (MINUS) { ret "-"; } + case (STAR) { ret "*"; } + case (SLASH) { ret "/"; } + case (PERCENT) { ret "%"; } + case (CARET) { ret "^"; } + case (AND) { ret "&"; } + case (OR) { ret "|"; } + case (LSL) { ret "<<"; } + case (LSR) { ret ">>"; } + case (ASR) { ret ">>>"; } + } +} + +fn to_str(token t) -> str { + alt (t) { + + case (EQ) { ret "="; } + case (LT) { ret "<"; } + case (LE) { ret "<="; } + case (EQEQ) { ret "=="; } + case (NE) { ret "!="; } + case (GE) { ret ">="; } + case (GT) { ret ">"; } + case (NOT) { ret "!"; } + case (TILDE) { ret "~"; } + case (OROR) { ret "||"; } + case (ANDAND) { ret "&&"; } + + case (BINOP(?op)) { ret binop_to_str(op); } + case (BINOPEQ(?op)) { ret binop_to_str(op) + "="; } + + case (AS) { ret "as"; } + case (WITH) { ret "with"; } + + + /* Structural symbols */ + case (AT) { ret "@"; } + case (DOT) { ret "."; } + case (COMMA) { ret ","; } + case (SEMI) { ret ";"; } + case (COLON) { ret ":"; } + case (QUES) { ret "?"; } + case (RARROW) { ret "->"; } + case (SEND) { ret "<|"; } + case (LARROW) { ret "<-"; } + case (LPAREN) { ret "("; } + case (RPAREN) { ret ")"; } + case (LBRACKET) { ret "["; } + case (RBRACKET) { ret "]"; } + case (LBRACE) { ret "{"; } + case (RBRACE) { ret "}"; } + + /* Module and crate keywords */ + case (MOD) { ret "mod"; } + case (USE) { ret "use"; } + case (AUTH) { ret "auth"; } + case (META) { ret "meta"; } + + /* Metaprogramming keywords */ + case (SYNTAX) { ret "syntax"; } + case (POUND) { ret "#"; } + + /* Statement keywords */ + case (IF) { ret "if"; } + case (ELSE) { ret "else"; } + case (DO) { ret "do"; } + case (WHILE) { ret "while"; } + case (ALT) { ret "alt"; } + case (CASE) { ret "case"; } + + case (FAIL) { ret "fail"; } + case (DROP) { ret "drop"; } + + case (IN) { ret "in"; } + case (FOR) { ret "for"; } + case (EACH) { ret "each"; } + case (PUT) { ret "put"; } + case (RET) { ret "ret"; } + case (BE) { ret "be"; } + + /* Type and type-state keywords */ + case (TYPE) { ret "type"; } + case (CHECK) { ret "check"; } + case (CLAIM) { ret "claim"; } + case (PROVE) { ret "prove"; } + + /* Effect keywords */ + case (IO) { ret "io"; } + case (STATE) { ret "state"; } + case (UNSAFE) { ret "unsafe"; } + + /* Type qualifiers */ + case (NATIVE) { ret "native"; } + case (AUTO) { ret "auto"; } + case (MUTABLE) { ret "mutable"; } + + /* Name management */ + case (IMPORT) { ret "import"; } + case (EXPORT) { ret "export"; } + + /* Value / stmt declarators */ + case (LET) { ret "let"; } + case (CONST) { ret "const"; } + + /* Magic runtime services */ + case (LOG) { ret "log"; } + case (SPAWN) { ret "spawn"; } + case (BIND) { ret "bind"; } + case (THREAD) { ret "thread"; } + case (YIELD) { ret "yield"; } + case (JOIN) { ret "join"; } + + /* Literals */ + case (LIT_INT(?i)) { ret _int.to_str(i, 10u); } + case (LIT_UINT(?u)) { ret _uint.to_str(u, 10u); } + case (LIT_MACH_INT(?tm, ?i)) { + ret _int.to_str(i, 10u) + + "_" + ty_mach_to_str(tm); + } + + case (LIT_STR(?s)) { + // FIXME: escape. + ret "\"" + s + "\""; + } + case (LIT_CHAR(?c)) { + // FIXME: escape and encode. + auto tmp = "'"; + tmp += c as u8; + tmp += '\'' as u8; + ret tmp; + } + + case (LIT_BOOL(?b)) { + if (b) { ret "true"; } else { ret "false"; } + } + + /* Name components */ + case (IDENT(?s)) { auto si = "ident:"; si += s; ret si; } + case (IDX(?i)) { ret "_" + _int.to_str(i, 10u); } + case (UNDERSCORE) { ret "_"; } + + /* Reserved type names */ + case (BOOL) { ret "bool"; } + case (INT) { ret "int"; } + case (UINT) { ret "uint"; } + case (FLOAT) { ret "float"; } + case (CHAR) { ret "char"; } + case (STR) { ret "str"; } + case (MACH(?tm)) { ret ty_mach_to_str(tm); } + + /* Algebraic type constructors */ + case (REC) { ret "rec"; } + case (TUP) { ret "tup"; } + case (TAG) { ret "tag"; } + case (VEC) { ret "vec"; } + case (ANY) { ret "any"; } + + /* Callable type constructors */ + case (FN) { ret "fn"; } + case (ITER) { ret "iter"; } + + /* Object type */ + case (OBJ) { ret "obj"; } + + /* Comm and task types */ + case (CHAN) { ret "chan"; } + case (PORT) { ret "port"; } + case (TASK) { ret "task"; } + + case (BRACEQUOTE(_)) { ret "<bracequote>"; } + case (EOF) { ret "<eof>"; } + } +} + + + +// Local Variables: +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: |