Implement parsing for *traits* feature
7c675193733c63905e6b426393a971e02397bf82be956f5aa664e047c51d66d6
1 parent
66464ff6
lib/std/lang/ast.rad
+47 -0
| 277 | 277 | /// Whether this record has labeled fields. |
|
| 278 | 278 | labeled: bool, |
|
| 279 | 279 | }, |
|
| 280 | 280 | /// Anonymous function type. |
|
| 281 | 281 | Fn(FnSig), |
|
| 282 | + | /// Trait object type, eg. `*opaque Allocator`. |
|
| 283 | + | TraitObject { |
|
| 284 | + | /// Trait name identifier. |
|
| 285 | + | traitName: *Node, |
|
| 286 | + | /// Whether the pointer is mutable. |
|
| 287 | + | mutable: bool, |
|
| 288 | + | }, |
|
| 282 | 289 | } |
|
| 283 | 290 | ||
| 284 | 291 | /// Function signature. |
|
| 285 | 292 | pub record FnSig { |
|
| 286 | 293 | /// Parameter type nodes in declaration order. |
| 801 | 808 | /// Alignment value. |
|
| 802 | 809 | value: *Node, |
|
| 803 | 810 | }, |
|
| 804 | 811 | /// Catch clause within a try expression. |
|
| 805 | 812 | CatchClause(CatchClause), |
|
| 813 | + | /// Trait declaration. |
|
| 814 | + | TraitDecl { |
|
| 815 | + | /// Trait name identifier. |
|
| 816 | + | name: *Node, |
|
| 817 | + | /// Method signature nodes ([`TraitMethodSig`]). |
|
| 818 | + | methods: NodeList, |
|
| 819 | + | /// Optional attributes. |
|
| 820 | + | attrs: ?Attributes, |
|
| 821 | + | }, |
|
| 822 | + | /// Method signature inside a trait declaration. |
|
| 823 | + | TraitMethodSig { |
|
| 824 | + | /// Method name identifier. |
|
| 825 | + | name: *Node, |
|
| 826 | + | /// Receiver type node (eg. `*mut Allocator`). |
|
| 827 | + | receiver: *Node, |
|
| 828 | + | /// Function signature. |
|
| 829 | + | sig: FnSig, |
|
| 830 | + | }, |
|
| 831 | + | /// Instance block. |
|
| 832 | + | InstanceDecl { |
|
| 833 | + | /// Trait name identifier. |
|
| 834 | + | traitName: *Node, |
|
| 835 | + | /// Target type identifier. |
|
| 836 | + | targetType: *Node, |
|
| 837 | + | /// Method definition nodes ([`InstanceMethodDecl`]). |
|
| 838 | + | methods: NodeList, |
|
| 839 | + | }, |
|
| 840 | + | /// Method definition inside an instance block. |
|
| 841 | + | InstanceMethodDecl { |
|
| 842 | + | /// Method name identifier. |
|
| 843 | + | name: *Node, |
|
| 844 | + | /// Receiver binding name ([`Ident`] node). |
|
| 845 | + | receiverName: *Node, |
|
| 846 | + | /// Receiver type node (eg. `*mut Arena`). |
|
| 847 | + | receiverType: *Node, |
|
| 848 | + | /// Function signature. |
|
| 849 | + | sig: FnSig, |
|
| 850 | + | /// Method body. |
|
| 851 | + | body: *Node, |
|
| 852 | + | }, |
|
| 806 | 853 | } |
|
| 807 | 854 | ||
| 808 | 855 | /// Full AST node with shared metadata and variant-specific payload. |
|
| 809 | 856 | pub record Node { |
|
| 810 | 857 | /// Unique identifier for this node. |
lib/std/lang/ast/printer.rad
+21 -0
| 93 | 93 | if let rt = sig.returnType { |
|
| 94 | 94 | ret = toExpr(a, rt); |
|
| 95 | 95 | } |
|
| 96 | 96 | return sexpr::list(a, "fn", &[sexpr::list(a, "params", nodeListToExprs(a, &sig.params)), ret]); |
|
| 97 | 97 | } |
|
| 98 | + | case super::TypeSig::TraitObject { traitName, mutable } => |
|
| 99 | + | return sexpr::list(a, "obj", &[sexpr::sym("mut"), toExpr(a, traitName)]) if mutable |
|
| 100 | + | else sexpr::list(a, "obj", &[toExpr(a, traitName)]), |
|
| 98 | 101 | } |
|
| 99 | 102 | } |
|
| 100 | 103 | ||
| 101 | 104 | /// Convert a node list to a slice of expressions. |
|
| 102 | 105 | fn nodeListToExprs(a: *mut alloc::Arena, nodes: *super::NodeList) -> *[sexpr::Expr] { |
| 433 | 436 | } |
|
| 434 | 437 | case super::NodeValue::UnionDeclVariant(v) => { |
|
| 435 | 438 | return variantToExpr(a, v.name, v.type); |
|
| 436 | 439 | } |
|
| 437 | 440 | case super::NodeValue::ExprStmt(e) => return toExpr(a, e), |
|
| 441 | + | case super::NodeValue::TraitDecl { name, methods, .. } => { |
|
| 442 | + | let children = nodeListToExprs(a, &methods); |
|
| 443 | + | return sexpr::block(a, "trait", &[toExpr(a, name)], children); |
|
| 444 | + | } |
|
| 445 | + | case super::NodeValue::TraitMethodSig { name, receiver, sig } => { |
|
| 446 | + | let params = sexpr::list(a, "params", nodeListToExprs(a, &sig.params)); |
|
| 447 | + | let ret = toExprOrNull(a, sig.returnType); |
|
| 448 | + | return sexpr::list(a, "methodSig", &[toExpr(a, receiver), toExpr(a, name), params, ret]); |
|
| 449 | + | } |
|
| 450 | + | case super::NodeValue::InstanceDecl { traitName, targetType, methods } => { |
|
| 451 | + | let children = nodeListToExprs(a, &methods); |
|
| 452 | + | return sexpr::block(a, "instance", &[toExpr(a, traitName), toExpr(a, targetType)], children); |
|
| 453 | + | } |
|
| 454 | + | case super::NodeValue::InstanceMethodDecl { name, receiverName, receiverType, sig, body } => { |
|
| 455 | + | let params = sexpr::list(a, "params", nodeListToExprs(a, &sig.params)); |
|
| 456 | + | let ret = toExprOrNull(a, sig.returnType); |
|
| 457 | + | return sexpr::block(a, "method", &[toExpr(a, receiverType), toExpr(a, receiverName), toExpr(a, name), params, ret], &[toExpr(a, body)]); |
|
| 458 | + | } |
|
| 438 | 459 | else => return sexpr::sym("?"), |
|
| 439 | 460 | } |
|
| 440 | 461 | } |
|
| 441 | 462 | ||
| 442 | 463 | /// Dump the tree rooted at `root`, using the provided arena for allocation. |
lib/std/lang/parser.rad
+140 -18
| 13 | 13 | pub const U32_MAX: u32 = 0xFFFFFFFF; |
|
| 14 | 14 | /// Maximum representable `u64` value. |
|
| 15 | 15 | pub const U64_MAX: u64 = 0xFFFFFFFFFFFFFFFF; |
|
| 16 | 16 | /// Maximum number of fields in a record. |
|
| 17 | 17 | pub const MAX_RECORD_FIELDS: u32 = 32; |
|
| 18 | + | /// Maximum number of trait methods. |
|
| 19 | + | pub const MAX_TRAIT_METHODS: u32 = 8; |
|
| 18 | 20 | ||
| 19 | 21 | /// Maximum number of parser errors before aborting. |
|
| 20 | 22 | const MAX_ERRORS: u32 = 8; |
|
| 21 | 23 | ||
| 22 | 24 | /// Parser error type. |
| 672 | 674 | case ast::NodeValue::Match(_) => return false, |
|
| 673 | 675 | case ast::NodeValue::Block(_) => return false, |
|
| 674 | 676 | case ast::NodeValue::FnDecl(_) => return false, |
|
| 675 | 677 | case ast::NodeValue::RecordDecl(_) => return false, |
|
| 676 | 678 | case ast::NodeValue::UnionDecl(_) => return false, |
|
| 679 | + | case ast::NodeValue::TraitDecl { .. } => return false, |
|
| 680 | + | case ast::NodeValue::InstanceDecl { .. } => return false, |
|
| 677 | 681 | else => return true, |
|
| 678 | 682 | } |
|
| 679 | 683 | } |
|
| 680 | 684 | ||
| 681 | 685 | /// Parse a primary leaf expression without postfix operators. |
| 955 | 959 | p.current.kind == scanner::TokenKind::Union or |
|
| 956 | 960 | p.current.kind == scanner::TokenKind::Record or |
|
| 957 | 961 | p.current.kind == scanner::TokenKind::Mod or |
|
| 958 | 962 | p.current.kind == scanner::TokenKind::Static or |
|
| 959 | 963 | p.current.kind == scanner::TokenKind::Const or |
|
| 960 | - | p.current.kind == scanner::TokenKind::Use; |
|
| 964 | + | p.current.kind == scanner::TokenKind::Use or |
|
| 965 | + | p.current.kind == scanner::TokenKind::Trait; |
|
| 961 | 966 | ||
| 962 | 967 | if not allowed { |
|
| 963 | 968 | throw failParsing(p, "attributes are not allowed in this context"); |
|
| 964 | 969 | } |
|
| 965 | 970 | } |
| 1032 | 1037 | return try parseUse(p, attrs); |
|
| 1033 | 1038 | } |
|
| 1034 | 1039 | case scanner::TokenKind::Mod => { |
|
| 1035 | 1040 | return try parseMod(p, attrs); |
|
| 1036 | 1041 | } |
|
| 1042 | + | case scanner::TokenKind::Trait => { |
|
| 1043 | + | return try parseTraitDecl(p, attrs); |
|
| 1044 | + | } |
|
| 1045 | + | case scanner::TokenKind::Instance => { |
|
| 1046 | + | return try parseInstanceDecl(p); |
|
| 1047 | + | } |
|
| 1037 | 1048 | else => { |
|
| 1038 | 1049 | return try parseExprStmt(p); |
|
| 1039 | 1050 | } |
|
| 1040 | 1051 | } |
|
| 1041 | 1052 | } |
| 1933 | 1944 | ||
| 1934 | 1945 | return node(p, ast::NodeValue::TypeSig( |
|
| 1935 | 1946 | ast::TypeSig::Slice { itemType, mutable } |
|
| 1936 | 1947 | )); |
|
| 1937 | 1948 | } |
|
| 1949 | + | // Check for `*opaque Trait` or `*mut opaque Trait`. |
|
| 1950 | + | if consume(p, scanner::TokenKind::Opaque) { |
|
| 1951 | + | if check(p, scanner::TokenKind::Ident) or check(p, scanner::TokenKind::Super) { |
|
| 1952 | + | let traitName = try parseTypePath(p); |
|
| 1953 | + | return node(p, ast::NodeValue::TypeSig( |
|
| 1954 | + | ast::TypeSig::TraitObject { traitName, mutable } |
|
| 1955 | + | )); |
|
| 1956 | + | } |
|
| 1957 | + | // Plain `*opaque`. |
|
| 1958 | + | return node(p, ast::NodeValue::TypeSig( |
|
| 1959 | + | ast::TypeSig::Pointer { |
|
| 1960 | + | valueType: node(p, ast::NodeValue::TypeSig(ast::TypeSig::Opaque)), |
|
| 1961 | + | mutable, |
|
| 1962 | + | } |
|
| 1963 | + | )); |
|
| 1964 | + | } |
|
| 1938 | 1965 | let valueType = try parseType(p); |
|
| 1939 | 1966 | ||
| 1940 | 1967 | return node(p, ast::NodeValue::TypeSig( |
|
| 1941 | 1968 | ast::TypeSig::Pointer { valueType, mutable } |
|
| 1942 | 1969 | )); |
| 1956 | 1983 | return node(p, ast::NodeValue::TypeSig( |
|
| 1957 | 1984 | ast::TypeSig::Array { itemType, length } |
|
| 1958 | 1985 | )); |
|
| 1959 | 1986 | } |
|
| 1960 | 1987 | ||
| 1988 | + | /// Parse a type path: an identifier optionally followed by `::` scope access. |
|
| 1989 | + | /// Returns an identifier node or a scope access chain. |
|
| 1990 | + | fn parseTypePath(p: *mut Parser) -> *ast::Node |
|
| 1991 | + | throws (ParseError) |
|
| 1992 | + | { |
|
| 1993 | + | let mut path: *ast::Node = undefined; |
|
| 1994 | + | if p.current.kind == scanner::TokenKind::Super { |
|
| 1995 | + | advance(p); |
|
| 1996 | + | path = nodeSuper(p); |
|
| 1997 | + | } else { |
|
| 1998 | + | path = try parseIdent(p, "expected type identifier"); |
|
| 1999 | + | } |
|
| 2000 | + | while consume(p, scanner::TokenKind::ColonColon) { |
|
| 2001 | + | let part = try parseIdent(p, "expected identifier after `::`"); |
|
| 2002 | + | path = node(p, ast::NodeValue::ScopeAccess( |
|
| 2003 | + | ast::Access { parent: path, child: part } |
|
| 2004 | + | )); |
|
| 2005 | + | } |
|
| 2006 | + | return path; |
|
| 2007 | + | } |
|
| 2008 | + | ||
| 1961 | 2009 | /// Parse a type annotation. |
|
| 1962 | - | /// |
|
| 1963 | - | /// Handles primitive types (u8, u16, u32, i8, i16, i32, bool, void), |
|
| 1964 | - | /// optional types (?T), pointer types (*T), array types ([T; N]), |
|
| 1965 | - | /// slice types (*[T]), record types, and function types. |
|
| 1966 | 2010 | pub fn parseType(p: *mut Parser) -> *ast::Node |
|
| 1967 | 2011 | throws (ParseError) |
|
| 1968 | 2012 | { |
|
| 1969 | 2013 | match p.current.kind { |
|
| 1970 | 2014 | case scanner::TokenKind::Question => { |
| 1980 | 2024 | } |
|
| 1981 | 2025 | case scanner::TokenKind::LBracket => { |
|
| 1982 | 2026 | return try parseArrayType(p); |
|
| 1983 | 2027 | } |
|
| 1984 | 2028 | case scanner::TokenKind::Super, scanner::TokenKind::Ident => { |
|
| 1985 | - | let mut path: *ast::Node = undefined; |
|
| 1986 | - | if p.current.kind == scanner::TokenKind::Super { |
|
| 1987 | - | advance(p); |
|
| 1988 | - | path = nodeSuper(p); |
|
| 1989 | - | } else { |
|
| 1990 | - | path = try parseIdent(p, "expected type identifier"); |
|
| 1991 | - | } |
|
| 1992 | - | while consume(p, scanner::TokenKind::ColonColon) { |
|
| 1993 | - | let part = try parseIdent(p, "expected identifier after `::`"); |
|
| 1994 | - | path = node(p, ast::NodeValue::ScopeAccess( |
|
| 1995 | - | ast::Access { parent: path, child: part } |
|
| 1996 | - | )); |
|
| 1997 | - | } |
|
| 2029 | + | let path = try parseTypePath(p); |
|
| 2030 | + | ||
| 1998 | 2031 | return node(p, ast::NodeValue::TypeSig( |
|
| 1999 | 2032 | ast::TypeSig::Nominal(path) |
|
| 2000 | 2033 | )); |
|
| 2001 | 2034 | } |
|
| 2002 | 2035 | case scanner::TokenKind::U8 => { |
| 2270 | 2303 | case scanner::TokenKind::RBrace => return "expected `}`", |
|
| 2271 | 2304 | else => return "expected delimiter", |
|
| 2272 | 2305 | } |
|
| 2273 | 2306 | } |
|
| 2274 | 2307 | ||
| 2308 | + | /// Parse a trait declaration. |
|
| 2309 | + | /// Syntax: `trait Name { fn (*Trait) method(...) -> T; ... }` |
|
| 2310 | + | fn parseTraitDecl(p: *mut Parser, attrs: ?ast::Attributes) -> *ast::Node |
|
| 2311 | + | throws (ParseError) |
|
| 2312 | + | { |
|
| 2313 | + | try expect(p, scanner::TokenKind::Trait, "expected `trait`"); |
|
| 2314 | + | let name = try parseIdent(p, "expected trait name"); |
|
| 2315 | + | try expect(p, scanner::TokenKind::LBrace, "expected `{` after trait name"); |
|
| 2316 | + | ||
| 2317 | + | let mut methods = ast::nodeList(p.arena, MAX_TRAIT_METHODS); |
|
| 2318 | + | while not check(p, scanner::TokenKind::RBrace) and |
|
| 2319 | + | not check(p, scanner::TokenKind::Eof) |
|
| 2320 | + | { |
|
| 2321 | + | let method = try parseTraitMethodSig(p); |
|
| 2322 | + | ast::nodeListPush(&mut methods, method); |
|
| 2323 | + | } |
|
| 2324 | + | try expect(p, scanner::TokenKind::RBrace, "expected `}` after trait methods"); |
|
| 2325 | + | ||
| 2326 | + | return node(p, ast::NodeValue::TraitDecl { name, methods, attrs }); |
|
| 2327 | + | } |
|
| 2328 | + | ||
| 2329 | + | /// Parse a trait method signature. |
|
| 2330 | + | /// Syntax: `fn (*Trait) fnord(<params>) -> ReturnType;` |
|
| 2331 | + | fn parseTraitMethodSig(p: *mut Parser) -> *ast::Node |
|
| 2332 | + | throws (ParseError) |
|
| 2333 | + | { |
|
| 2334 | + | try expect(p, scanner::TokenKind::Fn, "expected `fn`"); |
|
| 2335 | + | try expect(p, scanner::TokenKind::LParen, "expected `(` before receiver"); |
|
| 2336 | + | ||
| 2337 | + | let receiver = try parseType(p); |
|
| 2338 | + | ||
| 2339 | + | try expect(p, scanner::TokenKind::RParen, "expected `)` after receiver"); |
|
| 2340 | + | ||
| 2341 | + | let name = try parseIdent(p, "expected method name"); |
|
| 2342 | + | let sig = try parseFnTypeSig(p); |
|
| 2343 | + | try expect(p, scanner::TokenKind::Semicolon, "expected `;` after method signature"); |
|
| 2344 | + | ||
| 2345 | + | return node(p, ast::NodeValue::TraitMethodSig { name, receiver, sig }); |
|
| 2346 | + | } |
|
| 2347 | + | ||
| 2348 | + | /// Parse an instance block. |
|
| 2349 | + | /// Syntax: `instance Trait for Type { fn (t: *mut Type) fnord(..) {..} }` |
|
| 2350 | + | /// |
|
| 2351 | + | /// Instance declarations do not accept attributes (e.g. `pub`). |
|
| 2352 | + | /// Visibility is determined by the trait declaration itself. |
|
| 2353 | + | fn parseInstanceDecl(p: *mut Parser) -> *ast::Node |
|
| 2354 | + | throws (ParseError) |
|
| 2355 | + | { |
|
| 2356 | + | try expect(p, scanner::TokenKind::Instance, "expected `instance`"); |
|
| 2357 | + | let traitName = try parseTypePath(p); |
|
| 2358 | + | try expect(p, scanner::TokenKind::For, "expected `for` after trait name"); |
|
| 2359 | + | let targetType = try parseTypePath(p); |
|
| 2360 | + | try expect(p, scanner::TokenKind::LBrace, "expected `{` after target type"); |
|
| 2361 | + | ||
| 2362 | + | let mut methods = ast::nodeList(p.arena, MAX_TRAIT_METHODS); |
|
| 2363 | + | while not check(p, scanner::TokenKind::RBrace) and |
|
| 2364 | + | not check(p, scanner::TokenKind::Eof) |
|
| 2365 | + | { |
|
| 2366 | + | let method = try parseInstanceMethodDecl(p); |
|
| 2367 | + | ast::nodeListPush(&mut methods, method); |
|
| 2368 | + | } |
|
| 2369 | + | try expect(p, scanner::TokenKind::RBrace, "expected `}` after instance methods"); |
|
| 2370 | + | ||
| 2371 | + | return node(p, ast::NodeValue::InstanceDecl { traitName, targetType, methods }); |
|
| 2372 | + | } |
|
| 2373 | + | ||
| 2374 | + | /// Parse an instance method declaration. |
|
| 2375 | + | /// Syntax: `fn (t: *mut Type) fnord(<params>) -> ReturnType { body }` |
|
| 2376 | + | fn parseInstanceMethodDecl(p: *mut Parser) -> *ast::Node |
|
| 2377 | + | throws (ParseError) |
|
| 2378 | + | { |
|
| 2379 | + | try expect(p, scanner::TokenKind::Fn, "expected `fn`"); |
|
| 2380 | + | try expect(p, scanner::TokenKind::LParen, "expected `(` before receiver"); |
|
| 2381 | + | ||
| 2382 | + | let receiverName = try parseIdent(p, "expected receiver name"); |
|
| 2383 | + | try expect(p, scanner::TokenKind::Colon, "expected `:` after receiver name"); |
|
| 2384 | + | let receiverType = try parseType(p); |
|
| 2385 | + | ||
| 2386 | + | try expect(p, scanner::TokenKind::RParen, "expected `)` after receiver type"); |
|
| 2387 | + | ||
| 2388 | + | let name = try parseIdent(p, "expected method name"); |
|
| 2389 | + | let sig = try parseFnTypeSig(p); |
|
| 2390 | + | let body = try parseBlock(p); |
|
| 2391 | + | ||
| 2392 | + | return node(p, ast::NodeValue::InstanceMethodDecl { |
|
| 2393 | + | name, receiverName, receiverType, sig, body, |
|
| 2394 | + | }); |
|
| 2395 | + | } |
|
| 2396 | + | ||
| 2275 | 2397 | /// Parse a comma-separated list enclosed by the given delimiters. |
|
| 2276 | 2398 | fn parseList( |
|
| 2277 | 2399 | p: *mut Parser, |
|
| 2278 | 2400 | open: scanner::TokenKind, |
|
| 2279 | 2401 | close: scanner::TokenKind, |
lib/std/lang/resolver.rad
+4 -0
| 5398 | 5398 | } else { |
|
| 5399 | 5399 | fnType.returnType = allocType(self, Type::Void); |
|
| 5400 | 5400 | } |
|
| 5401 | 5401 | return Type::Fn(allocFnType(self, fnType)); |
|
| 5402 | 5402 | } |
|
| 5403 | + | case ast::TypeSig::TraitObject { .. } => { |
|
| 5404 | + | // TODO. |
|
| 5405 | + | throw emitError(self, node, ErrorKind::Internal); |
|
| 5406 | + | } |
|
| 5403 | 5407 | } |
|
| 5404 | 5408 | } |
|
| 5405 | 5409 | ||
| 5406 | 5410 | /// Check if a type can be used for inferrence. |
|
| 5407 | 5411 | fn isTypeInferrable(type: Type) -> bool { |
lib/std/lang/scanner.rad
+8 -1
| 100 | 100 | Mod, Use, Super, |
|
| 101 | 101 | ||
| 102 | 102 | // Type or function attributes. |
|
| 103 | 103 | Pub, Extern, Static, |
|
| 104 | 104 | ||
| 105 | + | // Trait-related tokens. |
|
| 106 | + | Trait, Instance, |
|
| 107 | + | ||
| 105 | 108 | // Type-related tokens. |
|
| 106 | 109 | I8, I16, I32, I64, U8, U16, U32, U64, |
|
| 107 | 110 | Void, Opaque, Fn, Bool, Union, Record, As |
|
| 108 | 111 | } |
|
| 109 | 112 |
| 196 | 199 | case TokenKind::Use => return "Use", |
|
| 197 | 200 | case TokenKind::Super => return "Super", |
|
| 198 | 201 | case TokenKind::Pub => return "Pub", |
|
| 199 | 202 | case TokenKind::Extern => return "Extern", |
|
| 200 | 203 | case TokenKind::Static => return "Static", |
|
| 204 | + | case TokenKind::Trait => return "Trait", |
|
| 205 | + | case TokenKind::Instance => return "Instance", |
|
| 201 | 206 | case TokenKind::I8 => return "I8", |
|
| 202 | 207 | case TokenKind::I16 => return "I16", |
|
| 203 | 208 | case TokenKind::I32 => return "I32", |
|
| 204 | 209 | case TokenKind::I64 => return "I64", |
|
| 205 | 210 | case TokenKind::U8 => return "U8", |
| 223 | 228 | /// Corresponding token. |
|
| 224 | 229 | tok: TokenKind, |
|
| 225 | 230 | } |
|
| 226 | 231 | ||
| 227 | 232 | /// Sorted keyword table for binary search. |
|
| 228 | - | const KEYWORDS: [Keyword; 50] = [ |
|
| 233 | + | const KEYWORDS: [Keyword; 52] = [ |
|
| 229 | 234 | { name: "align", tok: TokenKind::Align }, |
|
| 230 | 235 | { name: "and", tok: TokenKind::And }, |
|
| 231 | 236 | { name: "as", tok: TokenKind::As }, |
|
| 232 | 237 | { name: "assert", tok: TokenKind::Assert }, |
|
| 233 | 238 | { name: "bool", tok: TokenKind::Bool }, |
| 245 | 250 | { name: "i32", tok: TokenKind::I32 }, |
|
| 246 | 251 | { name: "i64", tok: TokenKind::I64 }, |
|
| 247 | 252 | { name: "i8", tok: TokenKind::I8 }, |
|
| 248 | 253 | { name: "if", tok: TokenKind::If }, |
|
| 249 | 254 | { name: "in", tok: TokenKind::In }, |
|
| 255 | + | { name: "instance", tok: TokenKind::Instance }, |
|
| 250 | 256 | { name: "let", tok: TokenKind::Let }, |
|
| 251 | 257 | { name: "log", tok: TokenKind::Log }, |
|
| 252 | 258 | { name: "loop", tok: TokenKind::Loop }, |
|
| 253 | 259 | { name: "match", tok: TokenKind::Match }, |
|
| 254 | 260 | { name: "mod", tok: TokenKind::Mod }, |
| 263 | 269 | { name: "return", tok: TokenKind::Return }, |
|
| 264 | 270 | { name: "static", tok: TokenKind::Static }, |
|
| 265 | 271 | { name: "super", tok: TokenKind::Super }, |
|
| 266 | 272 | { name: "throw", tok: TokenKind::Throw }, |
|
| 267 | 273 | { name: "throws", tok: TokenKind::Throws }, |
|
| 274 | + | { name: "trait", tok: TokenKind::Trait }, |
|
| 268 | 275 | { name: "true", tok: TokenKind::True }, |
|
| 269 | 276 | { name: "try", tok: TokenKind::Try }, |
|
| 270 | 277 | { name: "u16", tok: TokenKind::U16 }, |
|
| 271 | 278 | { name: "u32", tok: TokenKind::U32 }, |
|
| 272 | 279 | { name: "u64", tok: TokenKind::U64 }, |