⬆️ rust-analyzer

This commit is contained in:
Laurențiu Nicola 2023-02-20 10:14:12 +02:00
parent bc45c7659a
commit 7e711da2f0
98 changed files with 1801 additions and 943 deletions

View file

@ -20,4 +20,5 @@ limit.workspace = true
[dev-dependencies]
expect-test = "1.4.0"
stdx.workspace = true
sourcegen.workspace = true

View file

@ -200,6 +200,8 @@ impl BlockLike {
}
}
const VISIBILITY_FIRST: TokenSet = TokenSet::new(&[T![pub], T![crate]]);
fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool {
match p.current() {
T![pub] => {
@ -340,3 +342,31 @@ fn error_block(p: &mut Parser<'_>, message: &str) {
p.eat(T!['}']);
m.complete(p, ERROR);
}
/// The `parser` passed this is required to at least consume one token if it returns `true`.
/// If the `parser` returns false, parsing will stop.
fn delimited(
p: &mut Parser<'_>,
bra: SyntaxKind,
ket: SyntaxKind,
delim: SyntaxKind,
first_set: TokenSet,
mut parser: impl FnMut(&mut Parser<'_>) -> bool,
) {
p.bump(bra);
while !p.at(ket) && !p.at(EOF) {
if !parser(p) {
break;
}
if !p.at(delim) {
if p.at_ts(first_set) {
p.error(format!("expected {:?}", delim));
} else {
break;
}
} else {
p.bump(delim);
}
}
p.expect(ket);
}

View file

@ -1,5 +1,7 @@
use super::*;
pub(super) const ATTRIBUTE_FIRST: TokenSet = TokenSet::new(&[T![#]]);
pub(super) fn inner_attrs(p: &mut Parser<'_>) {
while p.at(T![#]) && p.nth(1) == T![!] {
attr(p, true);

View file

@ -1,5 +1,7 @@
mod atom;
use crate::grammar::attributes::ATTRIBUTE_FIRST;
use super::*;
pub(crate) use self::atom::{block_expr, match_arm_list};
@ -68,6 +70,12 @@ pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) {
Err(m) => m,
};
if !p.at_ts(EXPR_FIRST) {
p.err_and_bump("expected expression, item or let statement");
m.abandon(p);
return;
}
if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) {
if !(p.at(T!['}']) || (semicolon != Semicolon::Required && p.at(EOF))) {
// test no_semi_after_block
@ -227,6 +235,12 @@ fn expr_bp(
attributes::outer_attrs(p);
m
});
if !p.at_ts(EXPR_FIRST) {
p.err_recover("expected expression", atom::EXPR_RECOVERY_SET);
m.abandon(p);
return None;
}
let mut lhs = match lhs(p, r) {
Some((lhs, blocklike)) => {
let lhs = lhs.extend_to(p, m);
@ -551,23 +565,20 @@ fn cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
m.complete(p, CAST_EXPR)
}
// test_err arg_list_recovery
// fn main() {
// foo(bar::);
// foo(bar:);
// foo(bar+);
// }
fn arg_list(p: &mut Parser<'_>) {
assert!(p.at(T!['(']));
let m = p.start();
p.bump(T!['(']);
while !p.at(T![')']) && !p.at(EOF) {
// test arg_with_attr
// fn main() {
// foo(#[attr] 92)
// }
if !expr(p) {
break;
}
if !p.at(T![')']) && !p.expect(T![,]) {
break;
}
}
p.eat(T![')']);
// test arg_with_attr
// fn main() {
// foo(#[attr] 92)
// }
delimited(p, T!['('], T![')'], T![,], EXPR_FIRST.union(ATTRIBUTE_FIRST), expr);
m.complete(p, ARG_LIST);
}

View file

@ -40,26 +40,28 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
T!['{'],
T!['['],
T![|],
T![move],
T![box],
T![if],
T![while],
T![match],
T![unsafe],
T![return],
T![yield],
T![do],
T![break],
T![continue],
T![async],
T![try],
T![box],
T![break],
T![const],
T![loop],
T![continue],
T![do],
T![for],
T![if],
T![let],
T![loop],
T![match],
T![move],
T![return],
T![static],
T![try],
T![unsafe],
T![while],
T![yield],
LIFETIME_IDENT,
]));
const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![let]]);
pub(super) const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![')'], T![']']]);
pub(super) fn atom_expr(
p: &mut Parser<'_>,
@ -116,7 +118,7 @@ pub(super) fn atom_expr(
// fn main() {
// 'loop: impl
// }
p.error("expected a loop");
p.error("expected a loop or block");
m.complete(p, ERROR);
return None;
}
@ -157,7 +159,7 @@ pub(super) fn atom_expr(
T![for] => for_expr(p, None),
_ => {
p.err_recover("expected expression", EXPR_RECOVERY_SET);
p.err_and_bump("expected expression");
return None;
}
};

View file

@ -5,27 +5,35 @@ pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: boo
if p.at(T![::]) && p.nth(2) == T![<] {
m = p.start();
p.bump(T![::]);
p.bump(T![<]);
} else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
m = p.start();
p.bump(T![<]);
} else {
return;
}
while !p.at(EOF) && !p.at(T![>]) {
generic_arg(p);
if !p.at(T![>]) && !p.expect(T![,]) {
break;
}
}
p.expect(T![>]);
delimited(p, T![<], T![>], T![,], GENERIC_ARG_FIRST, generic_arg);
m.complete(p, GENERIC_ARG_LIST);
}
const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[
LIFETIME_IDENT,
IDENT,
T!['{'],
T![true],
T![false],
T![-],
INT_NUMBER,
FLOAT_NUMBER,
CHAR,
BYTE,
STRING,
BYTE_STRING,
])
.union(types::TYPE_FIRST);
// test generic_arg
// type T = S<i32>;
fn generic_arg(p: &mut Parser<'_>) {
fn generic_arg(p: &mut Parser<'_>) -> bool {
match p.current() {
LIFETIME_IDENT => lifetime_arg(p),
T!['{'] | T![true] | T![false] | T![-] => const_arg(p),
@ -68,8 +76,10 @@ fn generic_arg(p: &mut Parser<'_>) {
}
}
}
_ => type_arg(p),
_ if p.at_ts(types::TYPE_FIRST) => type_arg(p),
_ => return false,
}
true
}
// test lifetime_arg

View file

@ -1,3 +1,5 @@
use crate::grammar::attributes::ATTRIBUTE_FIRST;
use super::*;
pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {
@ -11,32 +13,31 @@ pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {
fn generic_param_list(p: &mut Parser<'_>) {
assert!(p.at(T![<]));
let m = p.start();
p.bump(T![<]);
delimited(p, T![<], T![>], T![,], GENERIC_PARAM_FIRST.union(ATTRIBUTE_FIRST), |p| {
// test generic_param_attribute
// fn foo<#[lt_attr] 'a, #[t_attr] T>() {}
let m = p.start();
attributes::outer_attrs(p);
generic_param(p, m)
});
while !p.at(EOF) && !p.at(T![>]) {
generic_param(p);
if !p.at(T![>]) && !p.expect(T![,]) {
break;
}
}
p.expect(T![>]);
m.complete(p, GENERIC_PARAM_LIST);
}
fn generic_param(p: &mut Parser<'_>) {
let m = p.start();
// test generic_param_attribute
// fn foo<#[lt_attr] 'a, #[t_attr] T>() {}
attributes::outer_attrs(p);
const GENERIC_PARAM_FIRST: TokenSet = TokenSet::new(&[IDENT, LIFETIME_IDENT, T![const]]);
fn generic_param(p: &mut Parser<'_>, m: Marker) -> bool {
match p.current() {
LIFETIME_IDENT => lifetime_param(p, m),
IDENT => type_param(p, m),
T![const] => const_param(p, m),
_ => {
m.abandon(p);
p.err_and_bump("expected type parameter");
p.err_and_bump("expected generic parameter");
return false;
}
}
true
}
// test lifetime_param

View file

@ -1,3 +1,5 @@
use crate::grammar::attributes::ATTRIBUTE_FIRST;
use super::*;
// test struct_item
@ -141,28 +143,31 @@ pub(crate) fn record_field_list(p: &mut Parser<'_>) {
}
}
const TUPLE_FIELD_FIRST: TokenSet =
types::TYPE_FIRST.union(ATTRIBUTE_FIRST).union(VISIBILITY_FIRST);
fn tuple_field_list(p: &mut Parser<'_>) {
assert!(p.at(T!['(']));
let m = p.start();
p.bump(T!['(']);
while !p.at(T![')']) && !p.at(EOF) {
delimited(p, T!['('], T![')'], T![,], TUPLE_FIELD_FIRST, |p| {
let m = p.start();
// test tuple_field_attrs
// struct S (#[attr] f32);
attributes::outer_attrs(p);
opt_visibility(p, true);
let has_vis = opt_visibility(p, true);
if !p.at_ts(types::TYPE_FIRST) {
p.error("expected a type");
m.complete(p, ERROR);
break;
if has_vis {
m.complete(p, ERROR);
} else {
m.abandon(p);
}
return false;
}
types::type_(p);
m.complete(p, TUPLE_FIELD);
true
});
if !p.at(T![')']) {
p.expect(T![,]);
}
}
p.expect(T![')']);
m.complete(p, TUPLE_FIELD_LIST);
}

View file

@ -1,3 +1,5 @@
use crate::grammar::attributes::ATTRIBUTE_FIRST;
use super::*;
// test param_list
@ -66,14 +68,20 @@ fn list_(p: &mut Parser<'_>, flavor: Flavor) {
}
};
if !p.at_ts(PARAM_FIRST) {
if !p.at_ts(PARAM_FIRST.union(ATTRIBUTE_FIRST)) {
p.error("expected value parameter");
m.abandon(p);
break;
}
param(p, m, flavor);
if !p.at(ket) {
p.expect(T![,]);
if !p.at(T![,]) {
if p.at_ts(PARAM_FIRST.union(ATTRIBUTE_FIRST)) {
p.error("expected `,`");
} else {
break;
}
} else {
p.bump(T![,]);
}
}

View file

@ -67,6 +67,10 @@ fn path_for_qualifier(
}
}
const EXPR_PATH_SEGMENT_RECOVERY_SET: TokenSet =
items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')'], T![,], T![let]]));
const TYPE_PATH_SEGMENT_RECOVERY_SET: TokenSet = types::TYPE_RECOVERY_SET;
fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) {
let m = p.start();
// test qual_paths
@ -102,7 +106,12 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) {
m.complete(p, NAME_REF);
}
_ => {
p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
let recover_set = match mode {
Mode::Use => items::ITEM_RECOVERY_SET,
Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET,
Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET,
};
p.err_recover("expected identifier", recover_set);
if empty {
// test_err empty_segment
// use crate::;

View file

@ -17,8 +17,9 @@ pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[
T![Self],
]));
const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[
pub(super) const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[
T![')'],
T![>],
T![,],
// test_err struct_field_recover
// struct S { f pub g: () }

View file

@ -15,6 +15,7 @@ use crate::{LexedStr, TopEntryPoint};
#[test]
fn lex_ok() {
for case in TestCase::list("lexer/ok") {
let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let actual = lex(&case.text);
expect_file![case.rast].assert_eq(&actual)
}
@ -23,6 +24,7 @@ fn lex_ok() {
#[test]
fn lex_err() {
for case in TestCase::list("lexer/err") {
let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let actual = lex(&case.text);
expect_file![case.rast].assert_eq(&actual)
}
@ -46,6 +48,7 @@ fn lex(text: &str) -> String {
#[test]
fn parse_ok() {
for case in TestCase::list("parser/ok") {
let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(!errors, "errors in an OK file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual);
@ -55,6 +58,7 @@ fn parse_ok() {
#[test]
fn parse_inline_ok() {
for case in TestCase::list("parser/inline/ok") {
let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(!errors, "errors in an OK file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual);
@ -64,6 +68,7 @@ fn parse_inline_ok() {
#[test]
fn parse_err() {
for case in TestCase::list("parser/err") {
let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(errors, "no errors in an ERR file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual)
@ -73,6 +78,7 @@ fn parse_err() {
#[test]
fn parse_inline_err() {
for case in TestCase::list("parser/inline/err") {
let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(errors, "no errors in an ERR file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual)

View file

@ -65,7 +65,7 @@ fn macro_stmt() {
MACRO_STMTS
ERROR
SHEBANG "#!/usr/bin/rust"
error 0: expected expression
error 0: expected expression, item or let statement
"##]],
);
check(

View file

@ -44,8 +44,7 @@ SOURCE_FILE
IDENT "T"
SEMICOLON ";"
WHITESPACE "\n"
error 9: expected type parameter
error 11: expected COMMA
error 9: expected generic parameter
error 11: expected R_ANGLE
error 11: expected `;`, `{`, or `(`
error 12: expected an item

View file

@ -43,17 +43,14 @@ SOURCE_FILE
IDENT "Box"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
ERROR
AT "@"
WHITESPACE " "
TUPLE_FIELD
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Any"
ERROR
ERROR
AT "@"
WHITESPACE " "
MACRO_CALL
PATH
PATH_SEGMENT
NAME_REF
IDENT "Any"
ERROR
R_ANGLE ">"
ERROR
@ -69,17 +66,14 @@ SOURCE_FILE
ERROR
SEMICOLON ";"
WHITESPACE "\n\n"
error 67: expected type
error 68: expected COMMA
error 68: expected R_ANGLE
error 68: expected COMMA
error 68: expected R_ANGLE
error 68: expected COMMA
error 68: expected R_ANGLE
error 68: expected COMMA
error 72: expected COMMA
error 72: expected a type
error 72: expected R_PAREN
error 67: expected R_ANGLE
error 67: expected R_ANGLE
error 67: expected R_ANGLE
error 67: expected R_PAREN
error 67: expected SEMICOLON
error 67: expected an item
error 72: expected BANG
error 72: expected `{`, `[`, `(`
error 72: expected SEMICOLON
error 72: expected an item
error 73: expected an item

View file

@ -145,27 +145,29 @@ SOURCE_FILE
error 16: expected expression
error 17: expected R_BRACK
error 17: expected SEMICOLON
error 17: expected expression
error 17: expected expression, item or let statement
error 25: expected a name
error 26: expected `;`, `{`, or `(`
error 30: expected pattern
error 31: expected SEMICOLON
error 53: expected expression
error 54: expected R_PAREN
error 54: expected SEMICOLON
error 54: expected expression
error 54: expected expression, item or let statement
error 60: expected type
error 60: expected `{`
error 60: expected expression
error 60: expected expression, item or let statement
error 65: expected pattern
error 65: expected SEMICOLON
error 65: expected expression
error 65: expected expression, item or let statement
error 92: expected expression
error 93: expected R_PAREN
error 93: expected SEMICOLON
error 93: expected expression
error 95: expected expression
error 96: expected expression
error 93: expected expression, item or let statement
error 95: expected expression, item or let statement
error 96: expected expression, item or let statement
error 103: expected a name
error 104: expected `{`
error 108: expected pattern
error 108: expected SEMICOLON
error 108: expected expression
error 108: expected expression, item or let statement

View file

@ -168,44 +168,44 @@ SOURCE_FILE
L_PAREN "("
ERROR
QUESTION "?"
EXPR_STMT
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "Sized"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Sized"
ERROR
R_PAREN ")"
WHITESPACE " "
ERROR
PLUS "+"
WHITESPACE " "
TUPLE_EXPR
L_PAREN "("
CLOSURE_EXPR
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
LIFETIME_PARAM
LIFETIME
LIFETIME_IDENT "'a"
R_ANGLE ">"
WHITESPACE " "
EXPR_STMT
BIN_EXPR
BIN_EXPR
BIN_EXPR
TUPLE_EXPR
L_PAREN "("
CLOSURE_EXPR
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
LIFETIME_PARAM
LIFETIME
LIFETIME_IDENT "'a"
R_ANGLE ">"
WHITESPACE " "
BIN_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "Trait"
L_ANGLE "<"
ERROR
LIFETIME_IDENT "'a"
R_ANGLE ">"
ERROR
R_PAREN ")"
BIN_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "Trait"
L_ANGLE "<"
ERROR
LIFETIME_IDENT "'a"
R_ANGLE ">"
R_PAREN ")"
WHITESPACE " "
PLUS "+"
WHITESPACE " "
@ -220,108 +220,93 @@ SOURCE_FILE
R_ANGLE ">"
ERROR
SEMICOLON ";"
WHITESPACE "\n "
LET_EXPR
LET_KW "let"
WHITESPACE " "
WILDCARD_PAT
UNDERSCORE "_"
ERROR
COLON ":"
WHITESPACE "\n "
LET_STMT
LET_KW "let"
WHITESPACE " "
BIN_EXPR
BIN_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "Box"
L_ANGLE "<"
TUPLE_EXPR
L_PAREN "("
CLOSURE_EXPR
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
LIFETIME_PARAM
LIFETIME
LIFETIME_IDENT "'a"
R_ANGLE ">"
WHITESPACE " "
BIN_EXPR
BIN_EXPR
BIN_EXPR
BIN_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "Trait"
WILDCARD_PAT
UNDERSCORE "_"
COLON ":"
WHITESPACE " "
DYN_TRAIT_TYPE
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Box"
GENERIC_ARG_LIST
L_ANGLE "<"
ERROR
LIFETIME_IDENT "'a"
R_ANGLE ">"
ERROR
R_PAREN ")"
WHITESPACE " "
PLUS "+"
WHITESPACE " "
PAREN_EXPR
L_PAREN "("
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "Copy"
R_PAREN ")"
WHITESPACE " "
PLUS "+"
WHITESPACE " "
PAREN_EXPR
L_PAREN "("
ERROR
QUESTION "?"
PATH_EXPR
TYPE_ARG
PAREN_TYPE
L_PAREN "("
FOR_TYPE
FOR_KW "for"
GENERIC_PARAM_LIST
L_ANGLE "<"
LIFETIME_PARAM
LIFETIME
LIFETIME_IDENT "'a"
R_ANGLE ">"
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Trait"
GENERIC_ARG_LIST
L_ANGLE "<"
LIFETIME_ARG
LIFETIME
LIFETIME_IDENT "'a"
R_ANGLE ">"
R_PAREN ")"
WHITESPACE " "
PLUS "+"
WHITESPACE " "
TYPE_BOUND
L_PAREN "("
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Copy"
R_PAREN ")"
WHITESPACE " "
PLUS "+"
WHITESPACE " "
TYPE_BOUND
L_PAREN "("
QUESTION "?"
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Sized"
R_PAREN ")"
R_ANGLE ">"
ERROR
SEMICOLON ";"
ERROR
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
R_CURLY "}"
WHITESPACE "\n"
error 88: expected COMMA
error 88: expected R_ANGLE
error 121: expected SEMICOLON
error 121: expected expression
error 121: expected expression, item or let statement
error 140: expected type
error 141: expected R_PAREN
error 141: expected COMMA
error 141: expected R_ANGLE
error 141: expected SEMICOLON
error 146: expected R_ANGLE
error 146: expected SEMICOLON
error 146: expected expression
error 148: expected expression
error 146: expected expression, item or let statement
error 148: expected expression, item or let statement
error 158: expected `|`
error 158: expected COMMA
error 165: expected expression
error 168: expected expression
error 179: expected expression
error 180: expected COMMA
error 190: expected EQ
error 190: expected expression
error 191: expected COMMA
error 204: expected `|`
error 204: expected COMMA
error 211: expected expression
error 214: expected expression
error 228: expected expression
error 229: expected R_PAREN
error 229: expected COMMA
error 236: expected expression
error 237: expected COMMA
error 237: expected expression
error 237: expected R_PAREN
error 180: expected SEMICOLON
error 215: expected R_ANGLE
error 235: expected SEMICOLON
error 235: expected expression, item or let statement

View file

@ -156,8 +156,7 @@ SOURCE_FILE
PATH_SEGMENT
NAME_REF
IDENT "i32"
WHITESPACE " "
ERROR
WHITESPACE " "
ERROR
L_CURLY "{"
R_CURLY "}"
@ -199,10 +198,8 @@ error 95: expected type
error 95: expected COMMA
error 96: expected field
error 98: expected field declaration
error 371: expected R_PAREN
error 371: expected COMMA
error 372: expected a type
error 372: expected R_PAREN
error 372: expected COMMA
error 372: expected enum variant
error 374: expected enum variant
error 494: expected pattern

View file

@ -72,4 +72,4 @@ SOURCE_FILE
error 24: expected existential, fn, trait or impl
error 41: expected existential, fn, trait or impl
error 56: expected a block
error 75: expected a loop
error 75: expected a loop or block

View file

@ -12,7 +12,7 @@ SOURCE_FILE
STMT_LIST
L_CURLY "{"
WHITESPACE "\n "
EXPR_STMT
BIN_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
@ -41,13 +41,14 @@ SOURCE_FILE
COLON2 "::"
ERROR
L_ANGLE "<"
BIN_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "nope"
SHR ">>"
TYPE_ARG
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "nope"
R_ANGLE ">"
R_ANGLE ">"
ERROR
SEMICOLON ";"
WHITESPACE "\n"
@ -114,8 +115,6 @@ SOURCE_FILE
WHITESPACE "\n"
error 30: expected identifier
error 31: expected COMMA
error 31: expected R_ANGLE
error 31: expected SEMICOLON
error 37: expected expression
error 75: expected identifier
error 76: expected SEMICOLON

View file

@ -23,6 +23,6 @@ SOURCE_FILE
WHITESPACE "\n"
R_CURLY "}"
WHITESPACE "\n"
error 22: expected a loop
error 22: expected a loop or block
error 27: expected type
error 27: expected `{`

View file

@ -0,0 +1,77 @@
SOURCE_FILE
FN
FN_KW "fn"
WHITESPACE " "
NAME
IDENT "main"
PARAM_LIST
L_PAREN "("
R_PAREN ")"
WHITESPACE " "
BLOCK_EXPR
STMT_LIST
L_CURLY "{"
WHITESPACE "\n "
EXPR_STMT
CALL_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "foo"
ARG_LIST
L_PAREN "("
PATH_EXPR
PATH
PATH
PATH_SEGMENT
NAME_REF
IDENT "bar"
COLON2 "::"
R_PAREN ")"
SEMICOLON ";"
WHITESPACE "\n "
EXPR_STMT
CALL_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "foo"
ARG_LIST
L_PAREN "("
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "bar"
ERROR
COLON ":"
R_PAREN ")"
SEMICOLON ";"
WHITESPACE "\n "
EXPR_STMT
CALL_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "foo"
ARG_LIST
L_PAREN "("
BIN_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "bar"
PLUS "+"
R_PAREN ")"
SEMICOLON ";"
WHITESPACE "\n"
R_CURLY "}"
WHITESPACE "\n"
error 25: expected identifier
error 39: expected COMMA
error 39: expected expression
error 55: expected expression

View file

@ -0,0 +1,5 @@
fn main() {
foo(bar::);
foo(bar:);
foo(bar+);
}

View file

@ -49,5 +49,5 @@ SOURCE_FILE
R_CURLY "}"
WHITESPACE "\n"
error 6: missing type for function parameter
error 6: expected COMMA
error 6: expected `,`
error 16: missing type for function parameter