compiler/
lib/
examples/
std/
arch/
char/
collections/
lang/
alloc/
ast/
gen/
il/
module/
parser/
resolver/
scanner/
alloc.rad
7.1 KiB
ast.rad
26.7 KiB
gen.rad
513 B
il.rad
20.3 KiB
lower.rad
315.0 KiB
module.rad
14.9 KiB
package.rad
1.3 KiB
parser.rad
91.2 KiB
resolver.rad
452.9 KiB
scanner.rad
17.9 KiB
sexpr.rad
6.7 KiB
strings.rad
2.2 KiB
types.rad
1.6 KiB
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
281 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
5.4 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
662 B
lib/std/lang/parser.rad
raw
| 1 | //! Recursive descent parser for the Radiance programming language. |
| 2 | @test export mod tests; |
| 3 | |
| 4 | use std::mem; |
| 5 | use std::io; |
| 6 | use std::fmt; |
| 7 | use std::lang::alloc; |
| 8 | use std::lang::ast; |
| 9 | use std::lang::strings; |
| 10 | use std::lang::scanner; |
| 11 | |
| 12 | /// Maximum `u32` value. |
| 13 | export constant U32_MAX: u32 = 0xFFFFFFFF; |
| 14 | /// Minimum `i64` value. |
| 15 | export constant I64_MIN: i64 = -0x8000000000000000; |
| 16 | /// Largest magnitude representable by a negative `i64`. |
| 17 | export constant I64_MIN_MAGNITUDE: u64 = 0x8000000000000000; |
| 18 | /// Maximum representable `i64` magnitude. |
| 19 | export constant I64_MAX_MAGNITUDE: u64 = 0x7FFFFFFFFFFFFFFF; |
| 20 | /// Maximum representable `u64` value. |
| 21 | export constant U64_MAX: u64 = 0xFFFFFFFFFFFFFFFF; |
| 22 | /// Maximum number of fields in a record. |
| 23 | export constant MAX_RECORD_FIELDS: u32 = 32; |
| 24 | |
| 25 | /// Maximum number of parser errors before aborting. |
| 26 | constant MAX_ERRORS: u32 = 8; |
| 27 | |
| 28 | /// Parser error type. |
| 29 | export union ParseError: Copy { |
| 30 | /// Encountered a token that was not expected in the current context. |
| 31 | UnexpectedToken, |
| 32 | } |
| 33 | |
| 34 | /// Represents a parsed name-type-value triple. |
| 35 | /// |
| 36 | /// Used for record field declarations, variable declarations, |
| 37 | /// and record field initializations. |
| 38 | record NameTypeValue: Copy { |
| 39 | /// The identifier name. |
| 40 | name: *ast::Node, |
| 41 | /// The optional type annotation. |
| 42 | type: ?*ast::Node, |
| 43 | /// The optional initialization value. |
| 44 | value: ?*ast::Node, |
| 45 | /// The optional alignment specifier. |
| 46 | alignment: ?*ast::Node, |
| 47 | } |
| 48 | |
| 49 | /// Behavioural differences when parsing record field lists. |
| 50 | union RecordFieldMode: Copy { |
| 51 | /// Labeled fields, allows for default values. |
| 52 | Labeled, |
| 53 | /// Unlabeled fields. |
| 54 | Unlabeled, |
| 55 | } |
| 56 | |
| 57 | /// Parser context differentiates between regular expressions and |
| 58 | /// conditional contexts where `{` begins a block. |
| 59 | union Context: Copy { |
| 60 | /// Normal expression context where `{` may start a record literal |
| 61 | /// and `if` may start a conditional expression. |
| 62 | Normal, |
| 63 | /// Pattern context where `{` may start a record literal |
| 64 | /// but `if` is reserved for guards. |
| 65 | Pattern, |
| 66 | /// Conditional context where `{` always begins a block |
| 67 | /// and `if` is reserved for guards. |
| 68 | Condition, |
| 69 | } |
| 70 | |
| 71 | /// A single parser error with location information. |
| 72 | export record Error: Copy { |
| 73 | /// Human-readable error message. |
| 74 | message: *[u8], |
| 75 | /// The token where the error occurred. |
| 76 | token: scanner::Token, |
| 77 | } |
| 78 | |
| 79 | /// List of parser errors encountered during parsing. |
| 80 | record ErrorList: Copy { |
| 81 | /// Fixed-size array of error records. |
| 82 | list: [Error; MAX_ERRORS], |
| 83 | /// Number of errors currently in the list. |
| 84 | count: u32, |
| 85 | } |
| 86 | |
| 87 | /// Snapshot of parser state for speculative parsing. |
| 88 | record SavedState: Copy { |
| 89 | /// Scanner position. |
| 90 | scanner: scanner::Scanner, |
| 91 | /// Token under examination. |
| 92 | current: scanner::Token, |
| 93 | /// Most recently consumed token. |
| 94 | previous: scanner::Token, |
| 95 | /// Diagnostics collected before speculative parsing. |
| 96 | errors: ErrorList, |
| 97 | /// Expression context before speculative parsing. |
| 98 | context: Context, |
| 99 | /// First byte available for tentative allocations. |
| 100 | arena: u32, |
| 101 | /// First node identifier available to the tentative parse. |
| 102 | nextId: u32, |
| 103 | } |
| 104 | |
| 105 | /// Operator metadata for precedence climbing. |
| 106 | record OpInfo: Copy { |
| 107 | op: ast::BinaryOp, |
| 108 | prec: i32, |
| 109 | } |
| 110 | |
| 111 | /// Get operator info for a token kind using match-based dispatch. |
| 112 | /// Returns nil if the token is not a binary operator. |
| 113 | fn getOpInfo(kind: scanner::TokenKind) -> ?OpInfo { |
| 114 | match kind { |
| 115 | case scanner::TokenKind::Star => |
| 116 | return { op: ast::BinaryOp::Mul, prec: 7 }, |
| 117 | case scanner::TokenKind::Slash => |
| 118 | return { op: ast::BinaryOp::Div, prec: 7 }, |
| 119 | case scanner::TokenKind::Percent => |
| 120 | return { op: ast::BinaryOp::Mod, prec: 7 }, |
| 121 | case scanner::TokenKind::Plus => |
| 122 | return { op: ast::BinaryOp::Add, prec: 6 }, |
| 123 | case scanner::TokenKind::Minus => |
| 124 | return { op: ast::BinaryOp::Sub, prec: 6 }, |
| 125 | case scanner::TokenKind::LtLt => |
| 126 | return { op: ast::BinaryOp::Shl, prec: 5 }, |
| 127 | case scanner::TokenKind::GtGt => |
| 128 | return { op: ast::BinaryOp::Shr, prec: 5 }, |
| 129 | case scanner::TokenKind::Amp => |
| 130 | return { op: ast::BinaryOp::BitAnd, prec: 4 }, |
| 131 | case scanner::TokenKind::Caret => |
| 132 | return { op: ast::BinaryOp::BitXor, prec: 3 }, |
| 133 | case scanner::TokenKind::Pipe => |
| 134 | return { op: ast::BinaryOp::BitOr, prec: 2 }, |
| 135 | case scanner::TokenKind::EqualEqual => |
| 136 | return { op: ast::BinaryOp::Eq, prec: 1 }, |
| 137 | case scanner::TokenKind::LtGt => |
| 138 | return { op: ast::BinaryOp::Ne, prec: 1 }, |
| 139 | case scanner::TokenKind::Lt => |
| 140 | return { op: ast::BinaryOp::Lt, prec: 1 }, |
| 141 | case scanner::TokenKind::Gt => |
| 142 | return { op: ast::BinaryOp::Gt, prec: 1 }, |
| 143 | case scanner::TokenKind::LtEqual => |
| 144 | return { op: ast::BinaryOp::Lte, prec: 1 }, |
| 145 | case scanner::TokenKind::GtEqual => |
| 146 | return { op: ast::BinaryOp::Gte, prec: 1 }, |
| 147 | case scanner::TokenKind::And => |
| 148 | return { op: ast::BinaryOp::And, prec: 0 }, |
| 149 | case scanner::TokenKind::Or => |
| 150 | return { op: ast::BinaryOp::Or, prec: 0 }, |
| 151 | else => |
| 152 | return nil, |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | /// Parser state. |
| 157 | export record Parser: 'pool { |
| 158 | /// The scanner that provides tokens. |
| 159 | scanner: scanner::Scanner, |
| 160 | /// Interned string pool borrowed for this parse. |
| 161 | pool: &'pool mut strings::Pool, |
| 162 | /// The current token being examined. |
| 163 | current: scanner::Token, |
| 164 | /// The most recently consumed token. |
| 165 | previous: scanner::Token, |
| 166 | /// Collection of errors encountered during parsing. |
| 167 | errors: ErrorList, |
| 168 | /// Arena for node allocations, borrowed for the parser's region. |
| 169 | arena: &'pool mut ast::NodeArena, |
| 170 | /// Allocator backed by the node arena. |
| 171 | allocator: alloc::Allocator, |
| 172 | /// Current parsing context (normal or conditional). |
| 173 | context: Context, |
| 174 | } |
| 175 | |
| 176 | /// Create a new parser initialized with the given source kind, source and node arena. |
| 177 | /// The node arena and string pool must outlive the parser. |
| 178 | export unsafe fn mkParser 'pool (sourceLoc: scanner::SourceLoc, source: *[u8], arena: &'pool mut ast::NodeArena, pool: &'pool mut strings::Pool) -> Parser 'pool { |
| 179 | let allocator = alloc::arenaAllocator(&mut arena.arena); |
| 180 | return Parser 'pool { |
| 181 | scanner: scanner::scanner(sourceLoc, source, pool), |
| 182 | pool, |
| 183 | current: scanner::invalid(0, ""), |
| 184 | previous: scanner::invalid(0, ""), |
| 185 | errors: ErrorList { list: [Error { message: "", token: scanner::invalid(0, "") }; MAX_ERRORS], count: 0 }, |
| 186 | arena, |
| 187 | allocator, |
| 188 | context: Context::Normal, |
| 189 | }; |
| 190 | } |
| 191 | |
| 192 | /// Emit a `true` or `false` literal node. |
| 193 | unsafe fn nodeBool 'pool (p: &mut Parser 'pool, value: bool) -> *ast::Node { |
| 194 | return node(p, ast::NodeValue::Bool(value)); |
| 195 | } |
| 196 | |
| 197 | /// Parse an integer literal while mapping shared errors into parser diagnostics. |
| 198 | fn parseIntLiteral 'pool (p: &mut Parser 'pool, text: *[u8]) -> fmt::IntLiteral |
| 199 | throws (ParseError) |
| 200 | { |
| 201 | let literal = try fmt::parseInt(text) catch err { |
| 202 | match err { |
| 203 | case fmt::ParseError::Invalid => |
| 204 | throw failParsing(p, "invalid integer literal"), |
| 205 | case fmt::ParseError::InvalidDigit => |
| 206 | throw failParsing(p, "invalid digit in integer literal"), |
| 207 | case fmt::ParseError::Overflow => |
| 208 | throw failParsing(p, "integer literal overflow"), |
| 209 | } |
| 210 | }; |
| 211 | return literal; |
| 212 | } |
| 213 | |
| 214 | /// Emit an integer type node. |
| 215 | unsafe fn nodeTypeInt 'pool (p: &mut Parser 'pool, width: u8, sign: ast::Signedness) -> *ast::Node { |
| 216 | return node(p, ast::NodeValue::TypeSig( |
| 217 | ast::TypeSig::Integer { width, sign } |
| 218 | )); |
| 219 | } |
| 220 | |
| 221 | /// Emit a number literal node with the provided literal metadata. |
| 222 | unsafe fn nodeNumber 'pool (p: &mut Parser 'pool, literal: fmt::IntLiteral) -> *ast::Node { |
| 223 | return node(p, ast::NodeValue::Number(literal)); |
| 224 | } |
| 225 | |
| 226 | /// Emit a `super` node. |
| 227 | unsafe fn nodeSuper 'pool (p: &mut Parser 'pool) -> *ast::Node { |
| 228 | return node(p, ast::NodeValue::Super); |
| 229 | } |
| 230 | |
| 231 | /// Emit a single attribute node. |
| 232 | unsafe fn nodeAttribute 'pool (p: &mut Parser 'pool, attr: ast::Attribute) -> *ast::Node { |
| 233 | return node(p, ast::NodeValue::Attribute(attr)); |
| 234 | } |
| 235 | |
| 236 | /// Emit a unary operator node. |
| 237 | unsafe fn nodeUnary 'pool (p: &mut Parser 'pool, op: ast::UnaryOp, value: *ast::Node) -> *ast::Node { |
| 238 | return node(p, ast::NodeValue::UnOp({ op, value })); |
| 239 | } |
| 240 | |
| 241 | /// Parse one expression without inheriting a surrounding condition or pattern context. |
| 242 | unsafe fn parseNormalExpr 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
| 243 | let saved = p.context; |
| 244 | set p.context = Context::Normal; |
| 245 | let expr = try parseExpr(p); |
| 246 | set p.context = saved; |
| 247 | return expr; |
| 248 | } |
| 249 | |
| 250 | /// Parse a parenthesized expression without applying postfix operators. |
| 251 | unsafe fn parseParenthesized 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 252 | throws (ParseError) |
| 253 | { |
| 254 | try expect(p, scanner::TokenKind::LParen, "expected `(`"); |
| 255 | |
| 256 | let expr = try parseNormalExpr(p); |
| 257 | |
| 258 | try expect(p, scanner::TokenKind::RParen, "expected `)`"); |
| 259 | |
| 260 | return expr; |
| 261 | } |
| 262 | |
| 263 | /// Parse an array literal: `[a, b, c]` or `[item; count]`. |
| 264 | unsafe fn parseArrayLiteral 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 265 | throws (ParseError) |
| 266 | { |
| 267 | try expect(p, scanner::TokenKind::LBracket, "expected `[`"); |
| 268 | if consume(p, scanner::TokenKind::RBracket) { // Empty array: `[]`. |
| 269 | let empty: *mut [*ast::Node] = &mut []; |
| 270 | return node(p, ast::NodeValue::ArrayLit(empty)); |
| 271 | } |
| 272 | let firstExpr = try parseNormalExpr(p); |
| 273 | |
| 274 | if consume(p, scanner::TokenKind::Semicolon) { |
| 275 | // Array repeat literal: `[item; count]`. |
| 276 | let count = try parseNormalExpr(p); |
| 277 | try expect(p, scanner::TokenKind::RBracket, "expected `]` after array repeat count"); |
| 278 | |
| 279 | return node(p, ast::NodeValue::ArrayRepeatLit( |
| 280 | ast::ArrayRepeatLit { item: firstExpr, count } |
| 281 | )); |
| 282 | } |
| 283 | // Regular array literal: `[a, b, ...]`. |
| 284 | let mut items = ast::nodeSlice(p.arena, 64).append(firstExpr, p.allocator); |
| 285 | |
| 286 | while consume(p, scanner::TokenKind::Comma) and not check(p, scanner::TokenKind::RBracket) { |
| 287 | let elem = try parseNormalExpr(p); |
| 288 | items.append(elem, p.allocator); |
| 289 | } |
| 290 | try expect(p, scanner::TokenKind::RBracket, "expected `]` after array elements"); |
| 291 | |
| 292 | return node(p, ast::NodeValue::ArrayLit(items)); |
| 293 | } |
| 294 | |
| 295 | /// Parse a function call expression. |
| 296 | unsafe fn parseCall 'pool (p: &mut Parser 'pool, callee: *ast::Node) -> *ast::Node |
| 297 | throws (ParseError) |
| 298 | { |
| 299 | let args = try parseList( |
| 300 | p, |
| 301 | scanner::TokenKind::LParen, |
| 302 | scanner::TokenKind::RParen, |
| 303 | parseNormalExpr 'pool |
| 304 | ); |
| 305 | return node(p, ast::NodeValue::Call( |
| 306 | ast::Call { callee, args } |
| 307 | )); |
| 308 | } |
| 309 | |
| 310 | /// Parse zero or more trailing `as` casts applied to `expr`. |
| 311 | unsafe fn parseAsCast 'pool (p: &mut Parser 'pool, expr: *ast::Node) -> *ast::Node |
| 312 | throws (ParseError) |
| 313 | { |
| 314 | let mut result = expr; |
| 315 | |
| 316 | while consume(p, scanner::TokenKind::As) { |
| 317 | let target = try parseType(p); |
| 318 | |
| 319 | set result = node(p, ast::NodeValue::As( |
| 320 | ast::As { value: result, type: target } |
| 321 | )); |
| 322 | } |
| 323 | return result; |
| 324 | } |
| 325 | |
| 326 | /// Parse an optional conditional expression suffix. |
| 327 | /// |
| 328 | /// `<thenExpr> if <condition> else <elseExpr>` |
| 329 | /// |
| 330 | /// If no `if` keyword follows, returns the input expression unchanged. |
| 331 | unsafe fn parseCondExpr 'pool (p: &mut Parser 'pool, thenExpr: *ast::Node) -> *ast::Node |
| 332 | throws (ParseError) |
| 333 | { |
| 334 | // Only parse conditional expressions in normal context. |
| 335 | // In conditional context, `if` is used for guards. |
| 336 | if p.context <> Context::Normal { |
| 337 | return thenExpr; |
| 338 | } |
| 339 | if not consume(p, scanner::TokenKind::If) { |
| 340 | return thenExpr; |
| 341 | } |
| 342 | let condition = try parseCond(p); |
| 343 | try expect(p, scanner::TokenKind::Else, "expected `else` in conditional expression"); |
| 344 | let elseExpr = try parseExpr(p); |
| 345 | |
| 346 | return node(p, ast::NodeValue::CondExpr( |
| 347 | ast::CondExpr { condition, thenExpr, elseExpr } |
| 348 | )); |
| 349 | } |
| 350 | |
| 351 | /// Parse array subscript or slice expression after `[`. |
| 352 | unsafe fn parseSubscriptOrSlice 'pool (p: &mut Parser 'pool, container: *ast::Node) -> *ast::Node |
| 353 | throws (ParseError) |
| 354 | { |
| 355 | try expect(p, scanner::TokenKind::LBracket, "expected `[`"); |
| 356 | |
| 357 | let mut index: *ast::Node = undefined; |
| 358 | |
| 359 | if consume(p, scanner::TokenKind::DotDot) { |
| 360 | // Either `..` or `..end`. |
| 361 | let mut endExpr: ?*ast::Node = nil; |
| 362 | if not check(p, scanner::TokenKind::RBracket) { |
| 363 | set endExpr = try parseNormalExpr(p); |
| 364 | } |
| 365 | set index = node(p, ast::NodeValue::Range( |
| 366 | ast::Range { start: nil, end: endExpr } |
| 367 | )); |
| 368 | } else { |
| 369 | // Either `n`, `n..` or `n..end`. |
| 370 | let startExpr = try parseNormalExpr(p); |
| 371 | |
| 372 | if consume(p, scanner::TokenKind::DotDot) { |
| 373 | // Either `n..` or `n..end`. |
| 374 | let mut endExpr: ?*ast::Node = nil; |
| 375 | if not check(p, scanner::TokenKind::RBracket) { |
| 376 | set endExpr = try parseNormalExpr(p); |
| 377 | } |
| 378 | set index = node(p, ast::NodeValue::Range( |
| 379 | ast::Range { start: startExpr, end: endExpr } |
| 380 | )); |
| 381 | } else { |
| 382 | // Just `n` - regular indexing. |
| 383 | set index = startExpr; |
| 384 | } |
| 385 | } |
| 386 | try expect(p, scanner::TokenKind::RBracket, "expected `]` after array index"); |
| 387 | |
| 388 | return node(p, ast::NodeValue::Subscript { container, index }); |
| 389 | } |
| 390 | |
| 391 | /// Parse postfix operators (eg. field access, function call etc.) |
| 392 | unsafe fn parsePostfix 'pool (p: &mut Parser 'pool, expr: *ast::Node) -> *ast::Node |
| 393 | throws (ParseError) |
| 394 | { |
| 395 | let mut result = expr; |
| 396 | |
| 397 | loop { |
| 398 | match p.current.kind { |
| 399 | case scanner::TokenKind::Dot => { |
| 400 | advance(p); |
| 401 | |
| 402 | let mut field: *ast::Node = undefined; |
| 403 | if consume(p, scanner::TokenKind::Set) { |
| 404 | set field = node(p, ast::NodeValue::Ident(p.previous.source)); |
| 405 | } else { |
| 406 | set field = try parseIdent(p, "expected field name after `.`"); |
| 407 | } |
| 408 | set result = node(p, ast::NodeValue::FieldAccess( |
| 409 | ast::Access { parent: result, child: field } |
| 410 | )); |
| 411 | } |
| 412 | case scanner::TokenKind::ColonColon => { |
| 413 | advance(p); |
| 414 | |
| 415 | let ident = try parseIdent(p, "expected identifier after `::`"); |
| 416 | set result = node(p, ast::NodeValue::ScopeAccess( |
| 417 | ast::Access { parent: result, child: ident } |
| 418 | )); |
| 419 | } |
| 420 | case scanner::TokenKind::Region => { |
| 421 | let regions = try parseRegions(p); |
| 422 | set result = node(p, ast::NodeValue::RegionApply { value: result, regions }); |
| 423 | } |
| 424 | case scanner::TokenKind::LBracket => { |
| 425 | set result = try parseSubscriptOrSlice(p, result); |
| 426 | } |
| 427 | case scanner::TokenKind::LParen => { |
| 428 | set result = try parseCall(p, result); |
| 429 | } |
| 430 | case scanner::TokenKind::LBrace if p.context <> Context::Condition => { |
| 431 | set result = try parseRecordLit(p, result); |
| 432 | } |
| 433 | else => { |
| 434 | break; |
| 435 | } |
| 436 | } |
| 437 | } |
| 438 | return result; |
| 439 | } |
| 440 | |
| 441 | /// Parse a conditional expression. |
| 442 | export unsafe fn parseCond 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
| 443 | let saved = p.context; |
| 444 | set p.context = Context::Condition; |
| 445 | let expr = try parseExpr(p); |
| 446 | set p.context = saved; |
| 447 | |
| 448 | return expr; |
| 449 | } |
| 450 | |
| 451 | /// Parse unary expression followed by optional `as` cast. |
| 452 | /// `as` has higher precedence than binary ops but lower than unary. |
| 453 | unsafe fn parseUnary 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
| 454 | let unary = try parseUnaryExpr(p); |
| 455 | return try parseAsCast(p, unary); |
| 456 | } |
| 457 | |
| 458 | /// Parse prefix unary expressions and defer to primary expressions otherwise. |
| 459 | unsafe fn parseUnaryExpr 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 460 | throws (ParseError) |
| 461 | { |
| 462 | match p.current.kind { |
| 463 | case scanner::TokenKind::Not => { |
| 464 | advance(p); |
| 465 | let value = try parseUnaryExpr(p); |
| 466 | return nodeUnary(p, ast::UnaryOp::Not, value); |
| 467 | } |
| 468 | case scanner::TokenKind::Minus => { |
| 469 | advance(p); |
| 470 | let value = try parseUnaryExpr(p); |
| 471 | return nodeUnary(p, ast::UnaryOp::Neg, value); |
| 472 | } |
| 473 | case scanner::TokenKind::Tilde => { |
| 474 | advance(p); |
| 475 | let value = try parseUnaryExpr(p); |
| 476 | return nodeUnary(p, ast::UnaryOp::BitNot, value); |
| 477 | } |
| 478 | case scanner::TokenKind::Star => { |
| 479 | advance(p); |
| 480 | let value = try parseUnaryExpr(p); |
| 481 | return node(p, ast::NodeValue::Deref(value)); |
| 482 | } |
| 483 | case scanner::TokenKind::Amp => { |
| 484 | advance(p); |
| 485 | let kind = parseAddressKind(p); |
| 486 | let target = try parseUnaryExpr(p); |
| 487 | return node(p, ast::NodeValue::AddressOf({ target, kind })); |
| 488 | } |
| 489 | else => { |
| 490 | return try parsePrimary(p); |
| 491 | } |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | /// Parse the access qualifier after an address operator. |
| 496 | fn parseAddressKind 'pool (p: &mut Parser 'pool) -> ast::AddressKind { |
| 497 | if consume(p, scanner::TokenKind::Mut) { |
| 498 | return ast::AddressKind::Mutable; |
| 499 | } |
| 500 | if check(p, scanner::TokenKind::Ident) and mem::eq(p.current.source, "cell") { |
| 501 | advance(p); |
| 502 | return ast::AddressKind::Cell; |
| 503 | } |
| 504 | return ast::AddressKind::Shared; |
| 505 | } |
| 506 | |
| 507 | /// Find the operator info for a token if it has precedence greater than the |
| 508 | /// given minimum. |
| 509 | fn findNextOp(kind: scanner::TokenKind, minPrec: i32) -> ?OpInfo { |
| 510 | if let opInfo = getOpInfo(kind) { |
| 511 | if opInfo.prec > minPrec { |
| 512 | return opInfo; |
| 513 | } |
| 514 | } |
| 515 | return nil; |
| 516 | } |
| 517 | |
| 518 | /// Determine whether the current token can terminate a range expression. |
| 519 | fn isRangeTerminator(kind: scanner::TokenKind) -> bool { |
| 520 | match kind { |
| 521 | case scanner::TokenKind::Comma, |
| 522 | scanner::TokenKind::Semicolon, |
| 523 | scanner::TokenKind::RParen, |
| 524 | scanner::TokenKind::RBrace, |
| 525 | scanner::TokenKind::RBracket, |
| 526 | scanner::TokenKind::Else, |
| 527 | scanner::TokenKind::In, |
| 528 | scanner::TokenKind::LBrace, |
| 529 | scanner::TokenKind::Eof => |
| 530 | return true, |
| 531 | else => |
| 532 | return false, |
| 533 | } |
| 534 | } |
| 535 | |
| 536 | /// Build a range expression node with an optional start and end expression. |
| 537 | unsafe fn parseRangeExpr 'pool (p: &mut Parser 'pool, start: ?*ast::Node) -> *ast::Node |
| 538 | throws (ParseError) |
| 539 | { |
| 540 | let mut endExpr: ?*ast::Node = nil; |
| 541 | |
| 542 | if not isRangeTerminator(p.current.kind) { |
| 543 | let right = try parseUnary(p); |
| 544 | set endExpr = try parseBinary(p, right, -1); |
| 545 | } |
| 546 | return node(p, ast::NodeValue::Range( |
| 547 | ast::Range { start, end: endExpr } |
| 548 | )); |
| 549 | } |
| 550 | |
| 551 | /// Parse binary expressions using precedence climbing. |
| 552 | unsafe fn parseBinary 'pool (p: &mut Parser 'pool, left: *ast::Node, minPrec: i32) -> *ast::Node |
| 553 | throws (ParseError) |
| 554 | { |
| 555 | let mut result = left; |
| 556 | |
| 557 | loop { |
| 558 | if p.current.kind == scanner::TokenKind::DotDot { |
| 559 | advance(p); |
| 560 | set result = try parseRangeExpr(p, result); |
| 561 | } else { |
| 562 | let opInfo = findNextOp(p.current.kind, minPrec) else break; |
| 563 | advance(p); |
| 564 | |
| 565 | let mut right = try parseUnary(p); |
| 566 | |
| 567 | while let _ = findNextOp(p.current.kind, opInfo.prec) { |
| 568 | set right = try parseBinary(p, right, opInfo.prec); |
| 569 | } |
| 570 | set result = node(p, ast::NodeValue::BinOp(ast::BinOp { |
| 571 | op: opInfo.op, left: result, right, |
| 572 | })); |
| 573 | } |
| 574 | } |
| 575 | return result; |
| 576 | } |
| 577 | |
| 578 | /// Check whether an expression may appear on the left side of an assignment. |
| 579 | fn isAssignableTarget(node: *ast::Node) -> bool { |
| 580 | match node.value { |
| 581 | case ast::NodeValue::Ident(_) => |
| 582 | return true, |
| 583 | case ast::NodeValue::FieldAccess(_) => |
| 584 | return true, |
| 585 | case ast::NodeValue::ScopeAccess(_) => |
| 586 | return true, |
| 587 | case ast::NodeValue::Subscript { .. } => |
| 588 | return true, |
| 589 | case ast::NodeValue::Deref(_) => |
| 590 | return true, |
| 591 | else => |
| 592 | return false, |
| 593 | } |
| 594 | } |
| 595 | /// Check if a statement requires a semicolon after it. |
| 596 | /// |
| 597 | /// Statements that end with blocks don't require semicolons. |
| 598 | /// All other statements do. |
| 599 | fn expectsSemicolon(stmt: *ast::Node) -> bool { |
| 600 | match stmt.value { |
| 601 | case ast::NodeValue::If(_), |
| 602 | ast::NodeValue::IfLet(_), |
| 603 | ast::NodeValue::While(_), |
| 604 | ast::NodeValue::WhileLet(_), |
| 605 | ast::NodeValue::For(_), |
| 606 | ast::NodeValue::Loop { .. }, |
| 607 | ast::NodeValue::Match(_), |
| 608 | ast::NodeValue::Block(_), |
| 609 | ast::NodeValue::RegionBlock { .. }, |
| 610 | ast::NodeValue::FnDecl(_), |
| 611 | ast::NodeValue::RecordDecl(_), |
| 612 | ast::NodeValue::UnionDecl(_), |
| 613 | ast::NodeValue::TraitDecl { .. }, |
| 614 | ast::NodeValue::InstanceDecl { .. }, |
| 615 | ast::NodeValue::MethodDecl { .. } => return false, |
| 616 | else => return true, |
| 617 | } |
| 618 | } |
| 619 | |
| 620 | /// Parse a primary leaf expression without postfix operators. |
| 621 | unsafe fn parseLeaf 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 622 | throws (ParseError) |
| 623 | { |
| 624 | match p.current.kind { |
| 625 | case scanner::TokenKind::True => { |
| 626 | advance(p); |
| 627 | return nodeBool(p, true); |
| 628 | } |
| 629 | case scanner::TokenKind::False => { |
| 630 | advance(p); |
| 631 | return nodeBool(p, false); |
| 632 | } |
| 633 | case scanner::TokenKind::Ident => { |
| 634 | advance(p); |
| 635 | return node(p, ast::NodeValue::Ident(p.previous.source)); |
| 636 | } |
| 637 | case scanner::TokenKind::Super => { |
| 638 | advance(p); |
| 639 | return nodeSuper(p); |
| 640 | } |
| 641 | case scanner::TokenKind::Number => { |
| 642 | advance(p); |
| 643 | let source = p.previous.source; |
| 644 | let literal = try parseIntLiteral(p, source); |
| 645 | return nodeNumber(p, literal); |
| 646 | } |
| 647 | case scanner::TokenKind::LParen => { |
| 648 | return try parseParenthesized(p); |
| 649 | } |
| 650 | case scanner::TokenKind::Try => { |
| 651 | return try parseTryExpr(p); |
| 652 | } |
| 653 | case scanner::TokenKind::Nil => { |
| 654 | advance(p); |
| 655 | return node(p, ast::NodeValue::Nil); |
| 656 | } |
| 657 | case scanner::TokenKind::Undefined => { |
| 658 | advance(p); |
| 659 | return node(p, ast::NodeValue::Undef); |
| 660 | } |
| 661 | case scanner::TokenKind::Char => { |
| 662 | advance(p); |
| 663 | let ch = try fmt::parseChar(p.previous.source) catch { |
| 664 | throw failParsing(p, "invalid char literal"); |
| 665 | }; |
| 666 | return node(p, ast::NodeValue::Char(ch)); |
| 667 | } |
| 668 | case scanner::TokenKind::String => { |
| 669 | advance(p); |
| 670 | let src = p.previous.source; |
| 671 | let raw = &src[1..src.len - 1]; // Strip quotes. |
| 672 | |
| 673 | // Process escape sequences into arena buffer. |
| 674 | let buf = alloc::remainingBuf(&mut p.arena.arena); |
| 675 | let len = fmt::unescapeString(raw, buf); |
| 676 | alloc::commit(&mut p.arena.arena, len); |
| 677 | |
| 678 | return node(p, ast::NodeValue::String(&buf[..len])); |
| 679 | } |
| 680 | case scanner::TokenKind::Underscore => { |
| 681 | advance(p); |
| 682 | return node(p, ast::NodeValue::Placeholder); |
| 683 | } |
| 684 | case scanner::TokenKind::LBracket => { |
| 685 | return try parseArrayLiteral(p); |
| 686 | } |
| 687 | case scanner::TokenKind::AtIdent => { |
| 688 | return try parseBuiltin(p); |
| 689 | } |
| 690 | case scanner::TokenKind::DotDot => { |
| 691 | advance(p); |
| 692 | return try parseRangeExpr(p, nil); |
| 693 | } |
| 694 | case scanner::TokenKind::LBrace => { |
| 695 | // Anonymous record literal: { x: 1, y: 2 }. |
| 696 | // Only allowed in normal context, not in conditions. |
| 697 | if p.context <> Context::Normal { |
| 698 | throw failParsing(p, "unexpected `{` in this context"); |
| 699 | } |
| 700 | return try parseRecordLit(p, nil); |
| 701 | } |
| 702 | else => { |
| 703 | throw failParsing(p, "expected expression"); |
| 704 | } |
| 705 | } |
| 706 | } |
| 707 | |
| 708 | /// Parse a primary expression (leaf nodes followed by postfix operators). |
| 709 | unsafe fn parsePrimary 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 710 | throws (ParseError) |
| 711 | { |
| 712 | let leaf = try parseLeaf(p); |
| 713 | return try parsePostfix(p, leaf); |
| 714 | } |
| 715 | |
| 716 | /// Parse a builtin function call like `@sizeOf(T)` or `@alignOf(T)`. |
| 717 | unsafe fn parseBuiltin 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 718 | throws (ParseError) |
| 719 | { |
| 720 | // Skip the '@' to get the name. |
| 721 | let ident = p.current.source; |
| 722 | advance(p); |
| 723 | |
| 724 | let mut kind: ast::Builtin = undefined; |
| 725 | // TODO: Use `match`. |
| 726 | if ident == "@sizeOf" { |
| 727 | set kind = ast::Builtin::SizeOf; |
| 728 | } else if ident == "@alignOf" { |
| 729 | set kind = ast::Builtin::AlignOf; |
| 730 | } else if ident == "@sliceOf" { |
| 731 | set kind = ast::Builtin::SliceOf; |
| 732 | } else { |
| 733 | throw failParsing(p, "unknown builtin"); |
| 734 | } |
| 735 | try expect(p, scanner::TokenKind::LParen, "expected `(` after builtin name"); |
| 736 | |
| 737 | // Parse arguments into a list. Use capacity 4 to handle any valid argument count |
| 738 | // plus some extra for error recovery. |
| 739 | let mut args = ast::nodeSlice(p.arena, 4); |
| 740 | |
| 741 | if kind == ast::Builtin::SliceOf { |
| 742 | // Parse comma-separated expressions until closing paren. |
| 743 | // Argument count validation is done in semantic analysis. |
| 744 | while not check(p, scanner::TokenKind::RParen) { |
| 745 | args.append(try parseExpr(p), p.allocator); |
| 746 | if not consume(p, scanner::TokenKind::Comma) { |
| 747 | break; |
| 748 | } |
| 749 | } |
| 750 | } else { |
| 751 | args.append(try parseType(p), p.allocator); |
| 752 | } |
| 753 | try expect(p, scanner::TokenKind::RParen, "expected `)` after builtin argument"); |
| 754 | |
| 755 | return node(p, ast::NodeValue::BuiltinCall { kind, args }); |
| 756 | } |
| 757 | |
| 758 | /// Parse a single expression. |
| 759 | /// |
| 760 | /// Parses unary and binary operators using precedence climbing. |
| 761 | /// Conditional expressions (`x if cond else y`) have lowest precedence. |
| 762 | export unsafe fn parseExpr 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 763 | throws (ParseError) |
| 764 | { |
| 765 | let left = try parseUnary(p); |
| 766 | let expr = try parseBinary(p, left, -1); |
| 767 | return try parseCondExpr(p, expr); |
| 768 | } |
| 769 | |
| 770 | /// Try to consume a compound assignment operator and return its binary op. |
| 771 | fn tryCompoundAssignOp 'pool (p: &mut Parser 'pool) -> ?ast::BinaryOp { |
| 772 | match p.current.kind { |
| 773 | case scanner::TokenKind::PlusEqual => { advance(p); return ast::BinaryOp::Add; } |
| 774 | case scanner::TokenKind::MinusEqual => { advance(p); return ast::BinaryOp::Sub; } |
| 775 | case scanner::TokenKind::StarEqual => { advance(p); return ast::BinaryOp::Mul; } |
| 776 | case scanner::TokenKind::SlashEqual => { advance(p); return ast::BinaryOp::Div; } |
| 777 | case scanner::TokenKind::PercentEqual => { advance(p); return ast::BinaryOp::Mod; } |
| 778 | case scanner::TokenKind::AmpEqual => { advance(p); return ast::BinaryOp::BitAnd; } |
| 779 | case scanner::TokenKind::PipeEqual => { advance(p); return ast::BinaryOp::BitOr; } |
| 780 | case scanner::TokenKind::CaretEqual => { advance(p); return ast::BinaryOp::BitXor; } |
| 781 | case scanner::TokenKind::LtLtEqual => { advance(p); return ast::BinaryOp::Shl; } |
| 782 | case scanner::TokenKind::GtGtEqual => { advance(p); return ast::BinaryOp::Shr; } |
| 783 | else => return nil, |
| 784 | } |
| 785 | } |
| 786 | |
| 787 | /// Parse an expression statement. |
| 788 | export unsafe fn parseExprStmt 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 789 | throws (ParseError) |
| 790 | { |
| 791 | let expr = try parseExpr(p); |
| 792 | return node(p, ast::NodeValue::ExprStmt(expr)); |
| 793 | } |
| 794 | |
| 795 | /// Parse a `set` statement assignment. |
| 796 | unsafe fn parseSetStmt 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 797 | throws (ParseError) |
| 798 | { |
| 799 | let target = try parseUnary(p); |
| 800 | if not ast::isPlaceExpr(target) { |
| 801 | throw failParsing(p, "invalid assignment target"); |
| 802 | } |
| 803 | if consume(p, scanner::TokenKind::Equal) { |
| 804 | let value = try parseExpr(p); |
| 805 | return node(p, ast::NodeValue::Assign( |
| 806 | ast::Assign { left: target, right: value } |
| 807 | )); |
| 808 | } |
| 809 | // Compound assignment: desugar `set x <op>= y` into `set x = x <op> y`. |
| 810 | // The target node is shared with the binary operand. |
| 811 | if let op = tryCompoundAssignOp(p) { |
| 812 | let rhs = try parseExpr(p); |
| 813 | let binop = node(p, ast::NodeValue::BinOp( |
| 814 | ast::BinOp { op, left: target, right: rhs } |
| 815 | )); |
| 816 | return node(p, ast::NodeValue::Assign( |
| 817 | ast::Assign { left: target, right: binop } |
| 818 | )); |
| 819 | } |
| 820 | throw failParsing(p, "expected assignment after `set`"); |
| 821 | } |
| 822 | |
| 823 | /// Parse leading attributes and declaration modifiers. |
| 824 | unsafe fn parseAttributes 'pool (p: &mut Parser 'pool) -> ?ast::Attributes { |
| 825 | let mut attrs = ast::nodeSlice(p.arena, 4); |
| 826 | |
| 827 | if let attr = tryParseAnnotation(p) { |
| 828 | attrs.append(attr, p.allocator); |
| 829 | } |
| 830 | if consume(p, scanner::TokenKind::Export) { |
| 831 | attrs.append(nodeAttribute(p, ast::Attribute::Export), p.allocator); |
| 832 | } |
| 833 | if consume(p, scanner::TokenKind::Unsafe) { |
| 834 | attrs.append(nodeAttribute(p, ast::Attribute::Unsafe), p.allocator); |
| 835 | } |
| 836 | if attrs.len > 0 { |
| 837 | return ast::Attributes { list: attrs }; |
| 838 | } |
| 839 | return nil; |
| 840 | } |
| 841 | |
| 842 | /// Try to parse an annotation like `@default`. |
| 843 | /// |
| 844 | /// Returns `nil` if not a known annotation (e.g. `@sizeOf` or `@alignOf` which are builtins). |
| 845 | /// Only consumes tokens if a valid annotation is found. |
| 846 | unsafe fn tryParseAnnotation 'pool (p: &mut Parser 'pool) -> ?*ast::Node { |
| 847 | if not check(p, scanner::TokenKind::AtIdent) { |
| 848 | return nil; |
| 849 | } |
| 850 | // Token is @identifier, skip the '@' to get the name. |
| 851 | let ident = p.current.source; |
| 852 | if ident == "@default" { |
| 853 | advance(p); // Consume `@default`. |
| 854 | return nodeAttribute(p, ast::Attribute::Default); |
| 855 | } |
| 856 | if ident == "@test" { |
| 857 | advance(p); // Consume `@test`. |
| 858 | return nodeAttribute(p, ast::Attribute::Test); |
| 859 | } |
| 860 | if ident == "@intrinsic" { |
| 861 | advance(p); // Consume `@intrinsic`. |
| 862 | return nodeAttribute(p, ast::Attribute::Intrinsic); |
| 863 | } |
| 864 | return nil; |
| 865 | } |
| 866 | |
| 867 | /// Parse a single statement. |
| 868 | /// |
| 869 | /// Dispatches to the appropriate statement parser based on the current token. |
| 870 | export unsafe fn parseStmt 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 871 | throws (ParseError) |
| 872 | { |
| 873 | // TODO: Why is `parseStmt` checking for attributes? |
| 874 | // We should have a `parseDecl` which is top-level, and `parseStmt` which |
| 875 | // is inside functions. |
| 876 | let attrs = parseAttributes(p); |
| 877 | if let list = attrs { |
| 878 | if ast::attributesContains(&list, ast::Attribute::Unsafe) |
| 879 | and p.current.kind == scanner::TokenKind::LBrace |
| 880 | { |
| 881 | if list.list.len <> 1 { |
| 882 | throw failParsing(p, "unsafe blocks cannot have declaration attributes"); |
| 883 | } |
| 884 | return try parseBlockBody(p, true); |
| 885 | } |
| 886 | if ast::attributesContains(&list, ast::Attribute::Unsafe) |
| 887 | and p.current.kind <> scanner::TokenKind::Fn |
| 888 | and p.current.kind <> scanner::TokenKind::Static |
| 889 | { |
| 890 | throw failParsing(p, "`unsafe` is only allowed on functions, blocks, and statics"); |
| 891 | } |
| 892 | let allowed: bool = |
| 893 | p.current.kind == scanner::TokenKind::Fn or |
| 894 | p.current.kind == scanner::TokenKind::Union or |
| 895 | p.current.kind == scanner::TokenKind::Record or |
| 896 | p.current.kind == scanner::TokenKind::Mod or |
| 897 | p.current.kind == scanner::TokenKind::Static or |
| 898 | p.current.kind == scanner::TokenKind::Constant or |
| 899 | p.current.kind == scanner::TokenKind::Use or |
| 900 | p.current.kind == scanner::TokenKind::Trait; |
| 901 | |
| 902 | if not allowed { |
| 903 | throw failParsing(p, "attributes are not allowed in this context"); |
| 904 | } |
| 905 | } |
| 906 | |
| 907 | match p.current.kind { |
| 908 | case scanner::TokenKind::If => { |
| 909 | return try parseIf(p); |
| 910 | } |
| 911 | case scanner::TokenKind::LBrace => { |
| 912 | return try parseBlock(p); |
| 913 | } |
| 914 | case scanner::TokenKind::While => { |
| 915 | return try parseWhile(p); |
| 916 | } |
| 917 | case scanner::TokenKind::Loop => { |
| 918 | return try parseLoop(p); |
| 919 | } |
| 920 | case scanner::TokenKind::For => { |
| 921 | return try parseFor(p); |
| 922 | } |
| 923 | case scanner::TokenKind::Return => { |
| 924 | return try parseReturn(p); |
| 925 | } |
| 926 | case scanner::TokenKind::Throw => { |
| 927 | return try parseThrow(p); |
| 928 | } |
| 929 | case scanner::TokenKind::Panic => { |
| 930 | return try parsePanic(p); |
| 931 | } |
| 932 | case scanner::TokenKind::Assert => { |
| 933 | return try parseAssert(p); |
| 934 | } |
| 935 | case scanner::TokenKind::Break => { |
| 936 | advance(p); |
| 937 | return node(p, ast::NodeValue::Break); |
| 938 | } |
| 939 | case scanner::TokenKind::Continue => { |
| 940 | advance(p); |
| 941 | return node(p, ast::NodeValue::Continue); |
| 942 | } |
| 943 | case scanner::TokenKind::Match => { |
| 944 | return try parseMatch(p); |
| 945 | } |
| 946 | case scanner::TokenKind::Let => { |
| 947 | if isRegionBlock(p) { |
| 948 | return try parseRegionBlock(p); |
| 949 | } |
| 950 | advance(p); |
| 951 | if consume(p, scanner::TokenKind::Case) { |
| 952 | return try parseLetCase(p); |
| 953 | } |
| 954 | if consume(p, scanner::TokenKind::Mut) { |
| 955 | return try parseLet(p, true); |
| 956 | } |
| 957 | return try parseLet(p, false); |
| 958 | } |
| 959 | case scanner::TokenKind::Set => { |
| 960 | advance(p); |
| 961 | return try parseSetStmt(p); |
| 962 | } |
| 963 | case scanner::TokenKind::Constant => { |
| 964 | return try parseConst(p, attrs); |
| 965 | } |
| 966 | case scanner::TokenKind::Static => { |
| 967 | return try parseStatic(p, attrs); |
| 968 | } |
| 969 | case scanner::TokenKind::Fn => { |
| 970 | return try parseFnDecl(p, attrs); |
| 971 | } |
| 972 | case scanner::TokenKind::Union => { |
| 973 | return try parseUnionDecl(p, attrs); |
| 974 | } |
| 975 | case scanner::TokenKind::Record => { |
| 976 | return try parseRecordDecl(p, attrs); |
| 977 | } |
| 978 | case scanner::TokenKind::Use => { |
| 979 | if isSessionBlock(p) { |
| 980 | return try parseSessionBlock(p); |
| 981 | } |
| 982 | return try parseUse(p, attrs); |
| 983 | } |
| 984 | case scanner::TokenKind::Mod => { |
| 985 | return try parseMod(p, attrs); |
| 986 | } |
| 987 | case scanner::TokenKind::Trait => { |
| 988 | return try parseTraitDecl(p, attrs); |
| 989 | } |
| 990 | case scanner::TokenKind::Instance => { |
| 991 | return try parseInstanceDecl(p); |
| 992 | } |
| 993 | else => { |
| 994 | return try parseExprStmt(p); |
| 995 | } |
| 996 | } |
| 997 | } |
| 998 | |
| 999 | /// Return whether the current `let` statement starts a regional block. |
| 1000 | fn isRegionBlock 'pool (p: &mut Parser 'pool) -> bool { |
| 1001 | let mut lookahead = p.scanner; |
| 1002 | return scanner::next(&mut lookahead, p.pool).kind == scanner::TokenKind::Ident |
| 1003 | and scanner::next(&mut lookahead, p.pool).kind == scanner::TokenKind::Colon |
| 1004 | and scanner::next(&mut lookahead, p.pool).kind == scanner::TokenKind::Region; |
| 1005 | } |
| 1006 | |
| 1007 | /// Return whether the current `use` statement has an allocation-session header. |
| 1008 | unsafe fn isSessionBlock 'pool (p: &mut Parser 'pool) -> bool { |
| 1009 | let saved = saveState(p); |
| 1010 | advance(p); |
| 1011 | let source: ?*ast::Node = try? parseUnaryExpr(p); |
| 1012 | let result = source <> nil |
| 1013 | and consume(p, scanner::TokenKind::As) |
| 1014 | and consume(p, scanner::TokenKind::Ident) |
| 1015 | and check(p, scanner::TokenKind::In); |
| 1016 | restoreState(p, &saved); |
| 1017 | return result; |
| 1018 | } |
| 1019 | |
| 1020 | /// Parse statements until the specified ending token is encountered. |
| 1021 | /// |
| 1022 | /// Returns the completed immutable statement list. |
| 1023 | export unsafe fn parseStmtsUntil 'pool (p: &mut Parser 'pool, end: scanner::TokenKind, capacity: u32) -> *[*ast::Node] |
| 1024 | throws (ParseError) |
| 1025 | { |
| 1026 | let mut statements = ast::nodeSlice(p.arena, capacity); |
| 1027 | while not check(p, end) { |
| 1028 | let stmt = try parseStmt(p); |
| 1029 | statements.append(stmt, p.allocator); |
| 1030 | |
| 1031 | if check(p, end) or check(p, scanner::TokenKind::Eof) { |
| 1032 | break; |
| 1033 | } |
| 1034 | if not consume(p, scanner::TokenKind::Semicolon) { |
| 1035 | // Only require semicolon if the statement needs one. |
| 1036 | if expectsSemicolon(stmt) { |
| 1037 | throw failParsing(p, "expected `;` after statement"); |
| 1038 | } |
| 1039 | } |
| 1040 | } |
| 1041 | return statements; |
| 1042 | } |
| 1043 | |
| 1044 | /// Parse a block of statements enclosed in curly braces. |
| 1045 | export unsafe fn parseBlock 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1046 | throws (ParseError) |
| 1047 | { |
| 1048 | return try parseBlockBody(p, false); |
| 1049 | } |
| 1050 | |
| 1051 | /// Parse a statement block with the specified unsafe permission. |
| 1052 | unsafe fn parseBlockBody 'pool (p: &mut Parser 'pool, isUnsafe: bool) -> *ast::Node |
| 1053 | throws (ParseError) |
| 1054 | { |
| 1055 | let start = p.current; |
| 1056 | |
| 1057 | if not consume(p, scanner::TokenKind::LBrace) { |
| 1058 | throw failParsing(p, "expected `{`"); |
| 1059 | } |
| 1060 | let statements = try parseStmtsUntil(p, scanner::TokenKind::RBrace, 64); |
| 1061 | let blk = ast::Block { statements, isUnsafe }; |
| 1062 | try expect(p, scanner::TokenKind::RBrace, "expected `}`"); |
| 1063 | |
| 1064 | return node(p, ast::NodeValue::Block(blk)); |
| 1065 | } |
| 1066 | |
| 1067 | /// Create a block containing a single statement node. |
| 1068 | unsafe fn mkBlockWith 'pool (p: &mut Parser 'pool, node: *ast::Node) -> ast::Block { |
| 1069 | let stmts = ast::nodeSlice(p.arena, 1).append(node, p.allocator); |
| 1070 | return ast::Block { statements: stmts, isUnsafe: false }; |
| 1071 | } |
| 1072 | |
| 1073 | /// Parse the branch that follows `else` in let-else style constructs. |
| 1074 | /// |
| 1075 | /// Allows either a block, a single statement like `return`, |
| 1076 | /// or a standalone expression which is returned directly. |
| 1077 | unsafe fn parseLetElseBranch 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1078 | throws (ParseError) |
| 1079 | { |
| 1080 | if check(p, scanner::TokenKind::LBrace) { |
| 1081 | return try parseBlock(p); |
| 1082 | } |
| 1083 | let branch = try parseStmt(p); |
| 1084 | |
| 1085 | if let case ast::NodeValue::ExprStmt(expr) = branch.value { |
| 1086 | return expr; |
| 1087 | } |
| 1088 | return branch; |
| 1089 | } |
| 1090 | |
| 1091 | /// Allocate a node with its span set from the most recently consumed token. |
| 1092 | unsafe fn node 'pool (p: &mut Parser 'pool, value: ast::NodeValue) -> *ast::Node { |
| 1093 | let start = p.previous.offset; |
| 1094 | let end = start + p.previous.source.len; |
| 1095 | let span = ast::Span { |
| 1096 | offset: start, |
| 1097 | length: end - start if end >= start else 0, |
| 1098 | }; |
| 1099 | return ast::allocNode(p.arena, span, value); |
| 1100 | } |
| 1101 | |
| 1102 | /// Save parser state for speculative parsing. |
| 1103 | fn saveState 'pool (p: &Parser 'pool) -> SavedState { |
| 1104 | return SavedState { |
| 1105 | scanner: p.scanner, |
| 1106 | current: p.current, |
| 1107 | previous: p.previous, |
| 1108 | errors: p.errors, |
| 1109 | context: p.context, |
| 1110 | arena: alloc::save(&p.arena.arena), |
| 1111 | nextId: p.arena.nextId, |
| 1112 | }; |
| 1113 | } |
| 1114 | |
| 1115 | /// Restore scanner state, diagnostics, arena storage, and node identifiers. |
| 1116 | /// Tentative nodes must be unreachable from all state retained by the caller. |
| 1117 | /// Interned tokens retain source storage, which must outlive the string pool. |
| 1118 | unsafe fn restoreState 'pool (p: &mut Parser 'pool, s: &SavedState) { |
| 1119 | set p.scanner = s.scanner; |
| 1120 | set p.current = s.current; |
| 1121 | set p.previous = s.previous; |
| 1122 | set p.errors = s.errors; |
| 1123 | set p.context = s.context; |
| 1124 | alloc::restore(&mut p.arena.arena, s.arena); |
| 1125 | set p.arena.nextId = s.nextId; |
| 1126 | } |
| 1127 | |
| 1128 | /// Report a parser error. |
| 1129 | fn reportError 'pool (p: &mut Parser 'pool, token: scanner::Token, message: *[u8]) { |
| 1130 | assert message.len > 0; |
| 1131 | |
| 1132 | // Ignore errors once the error list is full. |
| 1133 | if p.errors.count < p.errors.list.len { |
| 1134 | set p.errors.list[p.errors.count] = Error { message, token }; |
| 1135 | set p.errors.count += 1; |
| 1136 | } |
| 1137 | } |
| 1138 | |
| 1139 | /// Fail the parsing process with the given error. |
| 1140 | fn failParsing 'pool (p: &mut Parser 'pool, err: *[u8]) -> ParseError { |
| 1141 | let token = p.current; |
| 1142 | reportError(p, token, err); |
| 1143 | return ParseError::UnexpectedToken; |
| 1144 | } |
| 1145 | |
| 1146 | /// Print all errors that have been collected during parsing. |
| 1147 | export fn printErrors 'pool (p: &Parser 'pool) { |
| 1148 | for i in 0..p.errors.count { |
| 1149 | let e = p.errors.list[i]; |
| 1150 | if let loc = scanner::getLocation( |
| 1151 | p.scanner.sourceLoc, p.scanner.source, e.token.offset |
| 1152 | ) { |
| 1153 | if let case scanner::SourceLoc::File(path) = loc.source { |
| 1154 | io::print(path); |
| 1155 | io::print(":"); |
| 1156 | } |
| 1157 | io::printU32(loc.line as u32); |
| 1158 | io::print(":"); |
| 1159 | io::printU32(loc.col as u32); |
| 1160 | io::print(": error: "); |
| 1161 | } else { |
| 1162 | io::print("error: "); |
| 1163 | } |
| 1164 | io::print(e.message); |
| 1165 | if e.token.kind == scanner::TokenKind::Invalid { |
| 1166 | io::print(": "); |
| 1167 | io::print(e.token.source); |
| 1168 | } else { |
| 1169 | io::print(", got `"); |
| 1170 | io::print(e.token.source); |
| 1171 | io::print("`"); |
| 1172 | } |
| 1173 | io::print("\n"); |
| 1174 | } |
| 1175 | } |
| 1176 | |
| 1177 | /// Check whether the current token matches the expected kind. |
| 1178 | export fn check 'pool (p: &Parser 'pool, kind: scanner::TokenKind) -> bool { |
| 1179 | return p.current.kind == kind; |
| 1180 | } |
| 1181 | |
| 1182 | /// Advance the parser by one token. |
| 1183 | export fn advance 'pool (p: &mut Parser 'pool) { |
| 1184 | set p.previous = p.current; |
| 1185 | set p.current = scanner::next(&mut p.scanner, p.pool); |
| 1186 | } |
| 1187 | |
| 1188 | /// Parse an `if let` pattern matching statement. |
| 1189 | /// |
| 1190 | /// Syntax: `if let binding = scrutinee { ... }` |
| 1191 | /// Syntax: `if let mut binding = scrutinee { ... }` |
| 1192 | unsafe fn parseIfLet 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
| 1193 | try expect(p, scanner::TokenKind::Let, "expected `let`"); |
| 1194 | |
| 1195 | // Parse pattern: either `case <pattern>`, `mut <ident>`, or simple `<ident>`. |
| 1196 | let mut pattern: *ast::Node = undefined; |
| 1197 | let mut kind = ast::PatternKind::Binding; |
| 1198 | let mut mutable = false; |
| 1199 | |
| 1200 | if consume(p, scanner::TokenKind::Case) { |
| 1201 | set pattern = try parseMatchPattern(p); |
| 1202 | set kind = ast::PatternKind::Case; |
| 1203 | } else { |
| 1204 | set mutable = consume(p, scanner::TokenKind::Mut); |
| 1205 | set pattern = try parseIdentOrPlaceholder(p, "expected `case`, `mut`, or identifier after `let`"); |
| 1206 | } |
| 1207 | try expect(p, scanner::TokenKind::Equal, "expected `=` after pattern"); |
| 1208 | |
| 1209 | let scrutinee = try parseCond(p); |
| 1210 | let mut guard: ?*ast::Node = nil; |
| 1211 | |
| 1212 | if consume(p, scanner::TokenKind::Semicolon) { |
| 1213 | set guard = try parseCond(p); |
| 1214 | } |
| 1215 | let thenBranch = try parseBlock(p); |
| 1216 | let mut elseBranch: ?*ast::Node = nil; |
| 1217 | |
| 1218 | if consume(p, scanner::TokenKind::Else) { |
| 1219 | if check(p, scanner::TokenKind::If) { |
| 1220 | set elseBranch = node(p, ast::NodeValue::Block( |
| 1221 | mkBlockWith(p, try parseIf(p)) |
| 1222 | )); |
| 1223 | } else { |
| 1224 | set elseBranch = try parseBlock(p); |
| 1225 | } |
| 1226 | } |
| 1227 | |
| 1228 | return node(p, ast::NodeValue::IfLet(ast::IfLet { |
| 1229 | pattern: ast::PatternMatch { pattern, scrutinee, guard, kind, mutable }, |
| 1230 | thenBranch, |
| 1231 | elseBranch, |
| 1232 | })); |
| 1233 | } |
| 1234 | |
| 1235 | /// Parse a `while let` statement. |
| 1236 | unsafe fn parseWhileLet 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1237 | throws (ParseError) |
| 1238 | { |
| 1239 | try expect(p, scanner::TokenKind::Let, "expected `let`"); |
| 1240 | |
| 1241 | // Parse pattern: either `case <pattern>`, `mut <ident>`, or simple `<ident>`. |
| 1242 | let mut pattern: *ast::Node = undefined; |
| 1243 | let mut kind = ast::PatternKind::Binding; |
| 1244 | let mut mutable = false; |
| 1245 | if consume(p, scanner::TokenKind::Case) { |
| 1246 | set pattern = try parseMatchPattern(p); |
| 1247 | set kind = ast::PatternKind::Case; |
| 1248 | } else { |
| 1249 | set mutable = consume(p, scanner::TokenKind::Mut); |
| 1250 | set pattern = try parseIdentOrPlaceholder(p, "expected `case`, `mut`, or identifier after `let`"); |
| 1251 | } |
| 1252 | try expect(p, scanner::TokenKind::Equal, "expected `=` after pattern"); |
| 1253 | |
| 1254 | let scrutinee = try parseCond(p); |
| 1255 | let mut guard: ?*ast::Node = nil; |
| 1256 | |
| 1257 | if consume(p, scanner::TokenKind::Semicolon) { |
| 1258 | set guard = try parseCond(p); |
| 1259 | } |
| 1260 | let body = try parseBlock(p); |
| 1261 | let mut elseBranch: ?*ast::Node = nil; |
| 1262 | |
| 1263 | if consume(p, scanner::TokenKind::Else) { |
| 1264 | set elseBranch = try parseBlock(p); |
| 1265 | } |
| 1266 | return node(p, ast::NodeValue::WhileLet(ast::WhileLet { |
| 1267 | pattern: ast::PatternMatch { pattern, scrutinee, guard, kind, mutable }, |
| 1268 | body, |
| 1269 | elseBranch, |
| 1270 | })); |
| 1271 | } |
| 1272 | |
| 1273 | /// Parse a `while` statement. |
| 1274 | unsafe fn parseWhile 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1275 | throws (ParseError) |
| 1276 | { |
| 1277 | try expect(p, scanner::TokenKind::While, "expected `while`"); |
| 1278 | |
| 1279 | // Check for `while let` or `while let case` syntax. |
| 1280 | if check(p, scanner::TokenKind::Let) { |
| 1281 | return try parseWhileLet(p); |
| 1282 | } |
| 1283 | let condition = try parseCond(p); |
| 1284 | let body = try parseBlock(p); |
| 1285 | let mut elseBranch: ?*ast::Node = nil; |
| 1286 | |
| 1287 | if consume(p, scanner::TokenKind::Else) { |
| 1288 | set elseBranch = try parseBlock(p); |
| 1289 | } |
| 1290 | return node(p, ast::NodeValue::While(ast::While { |
| 1291 | condition, body, elseBranch, |
| 1292 | })); |
| 1293 | } |
| 1294 | |
| 1295 | /// Parse a `loop` statement. |
| 1296 | unsafe fn parseLoop 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1297 | throws (ParseError) |
| 1298 | { |
| 1299 | try expect(p, scanner::TokenKind::Loop, "expected `loop`"); |
| 1300 | let body = try parseBlock(p); |
| 1301 | |
| 1302 | return node(p, ast::NodeValue::Loop { body }); |
| 1303 | } |
| 1304 | |
| 1305 | /// Parse a `for` statement. |
| 1306 | unsafe fn parseFor 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1307 | throws (ParseError) |
| 1308 | { |
| 1309 | try expect(p, scanner::TokenKind::For, "expected `for`"); |
| 1310 | |
| 1311 | let binding = try parseIdentOrPlaceholder(p, "expected identifier or `_`"); |
| 1312 | let mut index: ?*ast::Node = nil; |
| 1313 | |
| 1314 | if consume(p, scanner::TokenKind::Comma) { |
| 1315 | set index = try parseIdentOrPlaceholder(p, "expected index identifier or `_` after `,`"); |
| 1316 | } |
| 1317 | try expect(p, scanner::TokenKind::In, "expected `in`"); |
| 1318 | |
| 1319 | let iterable = try parseCond(p); |
| 1320 | let body = try parseBlock(p); |
| 1321 | let mut elseBranch: ?*ast::Node = nil; |
| 1322 | |
| 1323 | if consume(p, scanner::TokenKind::Else) { |
| 1324 | set elseBranch = try parseBlock(p); |
| 1325 | } |
| 1326 | return node(p, ast::NodeValue::For(ast::For { |
| 1327 | binding, index, iterable, body, elseBranch, |
| 1328 | })); |
| 1329 | } |
| 1330 | |
| 1331 | /// Parse a `return` statement. |
| 1332 | unsafe fn parseReturn 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1333 | throws (ParseError) |
| 1334 | { |
| 1335 | try expect(p, scanner::TokenKind::Return, "expected `return`"); |
| 1336 | |
| 1337 | // Speculatively try to parse a return value expression. |
| 1338 | let saved = saveState(p); |
| 1339 | let value: ?*ast::Node = try? parseExpr(p); |
| 1340 | if value == nil { |
| 1341 | restoreState(p, &saved); |
| 1342 | } |
| 1343 | return node(p, ast::NodeValue::Return { value }); |
| 1344 | } |
| 1345 | |
| 1346 | /// Parse a `throw` statement. |
| 1347 | unsafe fn parseThrow 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1348 | throws (ParseError) |
| 1349 | { |
| 1350 | try expect(p, scanner::TokenKind::Throw, "expected `throw`"); |
| 1351 | let expr = try parseExpr(p); |
| 1352 | |
| 1353 | return node(p, ast::NodeValue::Throw { expr }); |
| 1354 | } |
| 1355 | |
| 1356 | /// Parse a `panic` statement. |
| 1357 | unsafe fn parsePanic 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1358 | throws (ParseError) |
| 1359 | { |
| 1360 | try expect(p, scanner::TokenKind::Panic, "expected `panic`"); |
| 1361 | |
| 1362 | // `panic { expr }`. |
| 1363 | if consume(p, scanner::TokenKind::LBrace) { |
| 1364 | let message: ?*ast::Node = try parseExpr(p); |
| 1365 | try expect(p, scanner::TokenKind::RBrace, "expected closing `}` after expression"); |
| 1366 | return node(p, ast::NodeValue::Panic { message }); |
| 1367 | } |
| 1368 | // `panic` or `panic "message"`. |
| 1369 | let saved = saveState(p); |
| 1370 | let message: ?*ast::Node = try? parseExpr(p); |
| 1371 | if message == nil { |
| 1372 | restoreState(p, &saved); |
| 1373 | } |
| 1374 | return node(p, ast::NodeValue::Panic { message }); |
| 1375 | } |
| 1376 | |
| 1377 | /// Parse an `assert` statement. |
| 1378 | /// |
| 1379 | /// Forms: |
| 1380 | /// `assert <expr>` |
| 1381 | /// `assert <expr>, "message"` |
| 1382 | /// `assert { <expr> }, "message"` |
| 1383 | unsafe fn parseAssert 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1384 | throws (ParseError) |
| 1385 | { |
| 1386 | try expect(p, scanner::TokenKind::Assert, "expected `assert`"); |
| 1387 | |
| 1388 | // `assert { expr }` block form or `assert <expr>`. |
| 1389 | let mut condition: *ast::Node = undefined; |
| 1390 | if consume(p, scanner::TokenKind::LBrace) { |
| 1391 | set condition = try parseExpr(p); |
| 1392 | try expect(p, scanner::TokenKind::RBrace, "expected closing `}` after expression"); |
| 1393 | } else { |
| 1394 | set condition = try parseExpr(p); |
| 1395 | } |
| 1396 | let mut message: ?*ast::Node = nil; |
| 1397 | if consume(p, scanner::TokenKind::Comma) { |
| 1398 | set message = try parseExpr(p); |
| 1399 | } |
| 1400 | return node(p, ast::NodeValue::Assert { condition, message }); |
| 1401 | } |
| 1402 | |
| 1403 | /// Parse a `try` expression with optional `catch` clause(s). |
| 1404 | unsafe fn parseTryExpr 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1405 | throws (ParseError) |
| 1406 | { |
| 1407 | try expect(p, scanner::TokenKind::Try, "expected `try`"); |
| 1408 | |
| 1409 | let shouldPanic = consume(p, scanner::TokenKind::Bang); |
| 1410 | let returnsOptional = consume(p, scanner::TokenKind::Question); |
| 1411 | let expr = try parseUnaryExpr(p); |
| 1412 | let mut catches = ast::nodeSlice(p.arena, 4); |
| 1413 | |
| 1414 | while consume(p, scanner::TokenKind::Catch) { |
| 1415 | let mut binding: ?*ast::Node = nil; |
| 1416 | let mut typeNode: ?*ast::Node = nil; |
| 1417 | |
| 1418 | // Check for optional error binding: `catch ident { ... }` or |
| 1419 | // `catch ident as Type { ... }`. |
| 1420 | if check(p, scanner::TokenKind::Ident) { |
| 1421 | set binding = try parseIdent(p, "expected identifier after `catch`"); |
| 1422 | if consume(p, scanner::TokenKind::As) { |
| 1423 | set typeNode = try parseType(p); |
| 1424 | } |
| 1425 | } |
| 1426 | if not check(p, scanner::TokenKind::LBrace) { |
| 1427 | throw failParsing(p, "expected `{` after `catch`"); |
| 1428 | } |
| 1429 | let body = try parseBlock(p); |
| 1430 | let clause = node(p, ast::NodeValue::CatchClause( |
| 1431 | ast::CatchClause { binding, typeNode, body } |
| 1432 | )); |
| 1433 | catches.append(clause, p.allocator); |
| 1434 | } |
| 1435 | return node(p, ast::NodeValue::Try( |
| 1436 | ast::Try { expr, catches, shouldPanic, returnsOptional } |
| 1437 | )); |
| 1438 | } |
| 1439 | |
| 1440 | /// Parse an `if` expression, with optional `else` or `else if` clauses. |
| 1441 | /// |
| 1442 | /// The `else if` construct is handled by creating a recursive structure: |
| 1443 | /// 1. When an `else` is followed by an `if`, we create a new block node. |
| 1444 | /// 2. We parse the nested `if` statement recursively using `parseIf`. |
| 1445 | /// 3. We put this nested `if` statement inside the block node. |
| 1446 | /// 4. This block node becomes the `elseBranch` of the parent `if`. |
| 1447 | /// |
| 1448 | /// This approach naturally handles multiple `else if` chains through recursion. |
| 1449 | /// |
| 1450 | /// For example: |
| 1451 | /// if x { |
| 1452 | /// a |
| 1453 | /// } else if y { |
| 1454 | /// b |
| 1455 | /// } else if z { |
| 1456 | /// c |
| 1457 | /// } else { |
| 1458 | /// d |
| 1459 | /// } |
| 1460 | /// |
| 1461 | /// Is represented as a nested structure like: |
| 1462 | /// |
| 1463 | /// if x { |
| 1464 | /// a |
| 1465 | /// } else { |
| 1466 | /// if y { |
| 1467 | /// b |
| 1468 | /// } else { |
| 1469 | /// if z { |
| 1470 | /// c |
| 1471 | /// } else { |
| 1472 | /// d |
| 1473 | /// } |
| 1474 | /// } |
| 1475 | /// } |
| 1476 | /// |
| 1477 | unsafe fn parseIf 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
| 1478 | try expect(p, scanner::TokenKind::If, "expected `if`"); |
| 1479 | |
| 1480 | // Check for `if let` or `if let case` syntax. |
| 1481 | if check(p, scanner::TokenKind::Let) { |
| 1482 | return try parseIfLet(p); |
| 1483 | } |
| 1484 | // Regular if statement. |
| 1485 | let cond = try parseCond(p); |
| 1486 | let thenBranch = try parseBlock(p); |
| 1487 | let mut elseBranch: ?*ast::Node = nil; |
| 1488 | |
| 1489 | if consume(p, scanner::TokenKind::Else) { |
| 1490 | // Check for `else if` construct. |
| 1491 | if check(p, scanner::TokenKind::If) { |
| 1492 | // Set the else branch to a block containing the nested if. |
| 1493 | set elseBranch = node(p, ast::NodeValue::Block( |
| 1494 | mkBlockWith(p, try parseIf(p)) |
| 1495 | )); |
| 1496 | } else { |
| 1497 | // Regular else clause. |
| 1498 | set elseBranch = try parseBlock(p); |
| 1499 | } |
| 1500 | } |
| 1501 | return node(p, ast::NodeValue::If(ast::If { |
| 1502 | condition: cond, thenBranch, elseBranch, |
| 1503 | })); |
| 1504 | } |
| 1505 | |
| 1506 | /// Parse a `match` statement. |
| 1507 | unsafe fn parseMatch 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1508 | throws (ParseError) |
| 1509 | { |
| 1510 | try expect(p, scanner::TokenKind::Match, "expected `match`"); |
| 1511 | |
| 1512 | let subject = try parseCond(p); |
| 1513 | try expect(p, scanner::TokenKind::LBrace, "expected `{` before match prongs"); |
| 1514 | |
| 1515 | let mut prongs = ast::nodeSlice(p.arena, 128); |
| 1516 | while not check(p, scanner::TokenKind::RBrace) and |
| 1517 | not check(p, scanner::TokenKind::Eof) // TODO: We shouldn't have to manually check for EOF. |
| 1518 | { |
| 1519 | let prongNode = try parseMatchProng(p); |
| 1520 | prongs.append(prongNode, p.allocator); |
| 1521 | consume(p, scanner::TokenKind::Comma); |
| 1522 | } |
| 1523 | try expect(p, scanner::TokenKind::RBrace, "expected `}` after match prongs"); |
| 1524 | |
| 1525 | return node(p, ast::NodeValue::Match( |
| 1526 | ast::Match { subject, prongs } |
| 1527 | )); |
| 1528 | } |
| 1529 | |
| 1530 | /// Parse a single `match` prong. |
| 1531 | unsafe fn parseMatchProng 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1532 | throws (ParseError) |
| 1533 | { |
| 1534 | let mut guard: ?*ast::Node = nil; |
| 1535 | |
| 1536 | // Case prong: `case <pattern>, ... if <guard> => <body>`. |
| 1537 | if consume(p, scanner::TokenKind::Case) { |
| 1538 | let mut patterns = ast::nodeSlice(p.arena, 16); |
| 1539 | loop { |
| 1540 | let pattern = try parseMatchPattern(p); |
| 1541 | patterns.append(pattern, p.allocator); |
| 1542 | |
| 1543 | if not consume(p, scanner::TokenKind::Comma) { |
| 1544 | break; |
| 1545 | } |
| 1546 | // After a comma, check for tokens that start a new prong. |
| 1547 | // This catches mistakes like `case A, case B`. |
| 1548 | if check(p, scanner::TokenKind::Case) or check(p, scanner::TokenKind::Else) { |
| 1549 | throw failParsing(p, "unexpected keyword after `,` in case pattern list"); |
| 1550 | } |
| 1551 | } |
| 1552 | if consume(p, scanner::TokenKind::If) { |
| 1553 | set guard = try parseCond(p); |
| 1554 | } |
| 1555 | try expect(p, scanner::TokenKind::FatArrow, "expected `=>` after case pattern"); |
| 1556 | let body = try parseStmt(p); |
| 1557 | |
| 1558 | return node(p, ast::NodeValue::MatchProng( |
| 1559 | ast::MatchProng { arm: ast::ProngArm::Case(patterns), guard, body } |
| 1560 | )); |
| 1561 | } |
| 1562 | // Else prong: `else if <guard> => <body>`. |
| 1563 | if consume(p, scanner::TokenKind::Else) { |
| 1564 | if consume(p, scanner::TokenKind::If) { |
| 1565 | set guard = try parseCond(p); |
| 1566 | } |
| 1567 | try expect(p, scanner::TokenKind::FatArrow, "expected `=>` after else"); |
| 1568 | let body = try parseStmt(p); |
| 1569 | |
| 1570 | return node(p, ast::NodeValue::MatchProng( |
| 1571 | ast::MatchProng { arm: ast::ProngArm::Else, guard, body } |
| 1572 | )); |
| 1573 | } |
| 1574 | // Binding prong: `<ident> if <guard> => <body>` or `_ if <guard> => <body>`. |
| 1575 | let binding = try parseIdentOrPlaceholder(p, "expected `case`, `else`, or identifier"); |
| 1576 | |
| 1577 | if consume(p, scanner::TokenKind::If) { |
| 1578 | set guard = try parseCond(p); |
| 1579 | } |
| 1580 | try expect(p, scanner::TokenKind::FatArrow, "expected `=>` after binding"); |
| 1581 | let body = try parseStmt(p); |
| 1582 | |
| 1583 | return node(p, ast::NodeValue::MatchProng( |
| 1584 | ast::MatchProng { arm: ast::ProngArm::Binding(binding), guard, body } |
| 1585 | )); |
| 1586 | } |
| 1587 | |
| 1588 | /// Parse a pattern expression used by `case` constructs. |
| 1589 | /// Uses `Pattern` context to allow record literals but not conditional expressions. |
| 1590 | unsafe fn parseMatchPattern 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1591 | throws (ParseError) |
| 1592 | { |
| 1593 | let saved = p.context; |
| 1594 | set p.context = Context::Pattern; |
| 1595 | let pattern = try parseExpr(p); |
| 1596 | set p.context = saved; |
| 1597 | |
| 1598 | return pattern; |
| 1599 | } |
| 1600 | |
| 1601 | /// Parse a region name. |
| 1602 | unsafe fn parseRegion 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
| 1603 | let name = try expect(p, scanner::TokenKind::Region, "expected region name"); |
| 1604 | return node(p, ast::NodeValue::Region { name, parent: nil }); |
| 1605 | } |
| 1606 | |
| 1607 | /// Parse consecutive region names. |
| 1608 | unsafe fn parseRegions 'pool (p: &mut Parser 'pool) -> *mut [*ast::Node] throws (ParseError) { |
| 1609 | let mut regions = ast::nodeSlice(p.arena, 4); |
| 1610 | while check(p, scanner::TokenKind::Region) { |
| 1611 | regions.append(try parseRegion(p), p.allocator); |
| 1612 | } |
| 1613 | return regions; |
| 1614 | } |
| 1615 | |
| 1616 | /// Parse region bounds for a declaration. |
| 1617 | unsafe fn parseRegionBounds 'pool (p: &mut Parser 'pool, regions: &mut [*ast::Node]) |
| 1618 | throws (ParseError) |
| 1619 | { |
| 1620 | if not consume(p, scanner::TokenKind::Where) { |
| 1621 | return; |
| 1622 | } |
| 1623 | loop { |
| 1624 | let parent = try parseRegion(p); |
| 1625 | try expect(p, scanner::TokenKind::Colon, "expected `:` in region bound"); |
| 1626 | let childName = try expect(p, scanner::TokenKind::Region, "expected region name"); |
| 1627 | let mut matched = false; |
| 1628 | for i in 0..regions.len { |
| 1629 | let region = regions[i]; |
| 1630 | if let case ast::NodeValue::Region { name, parent: declaredParent } = region.value; |
| 1631 | mem::eq(name, childName) |
| 1632 | { |
| 1633 | if declaredParent <> nil { |
| 1634 | throw failParsing(p, "region parameter already has a bound"); |
| 1635 | } |
| 1636 | set regions[i] = node(p, ast::NodeValue::Region { name, parent }); |
| 1637 | set matched = true; |
| 1638 | break; |
| 1639 | } |
| 1640 | } |
| 1641 | if not matched { |
| 1642 | throw failParsing(p, "expected declared region parameter in bound"); |
| 1643 | } |
| 1644 | if not consume(p, scanner::TokenKind::Comma) { |
| 1645 | break; |
| 1646 | } |
| 1647 | } |
| 1648 | } |
| 1649 | |
| 1650 | /// Parse scoped borrow bindings. |
| 1651 | unsafe fn parseRegionBlock 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
| 1652 | advance(p); |
| 1653 | let mut binding = try parseIdent(p, "expected region binding name"); |
| 1654 | try expect(p, scanner::TokenKind::Colon, "expected `:` after region binding"); |
| 1655 | let regionName = try expect(p, scanner::TokenKind::Region, "expected region name after `:`"); |
| 1656 | let mut region = node(p, ast::NodeValue::Region { name: regionName, parent: nil }); |
| 1657 | let mut bindings = ast::nodeSlice(p.arena, 4); |
| 1658 | loop { |
| 1659 | try expect(p, scanner::TokenKind::Equal, "expected `=` after region binding"); |
| 1660 | try expect(p, scanner::TokenKind::Amp, "expected `&` before borrowed place"); |
| 1661 | let kind = parseAddressKind(p); |
| 1662 | let target = try parseUnaryExpr(p); |
| 1663 | let value = node(p, ast::NodeValue::AddressOf({ target, kind })); |
| 1664 | bindings.append(node(p, ast::NodeValue::RegionBinding({ label: binding, value })), p.allocator); |
| 1665 | if not consume(p, scanner::TokenKind::Comma) { |
| 1666 | break; |
| 1667 | } |
| 1668 | set binding = try parseIdent(p, "expected region binding name"); |
| 1669 | } |
| 1670 | if consume(p, scanner::TokenKind::Where) { |
| 1671 | let parent = try parseRegion(p); |
| 1672 | try expect(p, scanner::TokenKind::Colon, "expected `:` in region bound"); |
| 1673 | let childName = try expect(p, scanner::TokenKind::Region, "expected child region in bound"); |
| 1674 | if not mem::eq(regionName, childName) { |
| 1675 | throw failParsing(p, "region bound must name the declared region"); |
| 1676 | } |
| 1677 | set region = node(p, ast::NodeValue::Region { name: regionName, parent }); |
| 1678 | } |
| 1679 | try expect(p, scanner::TokenKind::In, "expected `in` after region bindings"); |
| 1680 | let body = try parseBlock(p); |
| 1681 | return node(p, ast::NodeValue::RegionBlock { region, bindings, body, isSession: false }); |
| 1682 | } |
| 1683 | |
| 1684 | /// Create a region name from an allocation-session binding name. |
| 1685 | unsafe fn sessionRegion 'pool (p: &mut Parser 'pool, binding: *ast::Node) -> *ast::Node { |
| 1686 | let case ast::NodeValue::Ident(name) = binding.value |
| 1687 | else panic "sessionRegion: invalid binding"; |
| 1688 | let len = name.len + 1; |
| 1689 | let buf = alloc::remainingBuf(&mut p.arena.arena); |
| 1690 | assert buf.len >= len, "sessionRegion: node arena is full"; |
| 1691 | set buf[0] = 39; |
| 1692 | try! mem::copy(&mut buf[1..len], name); |
| 1693 | alloc::commit(&mut p.arena.arena, len); |
| 1694 | return node(p, ast::NodeValue::Region { name: &buf[..len], parent: nil }); |
| 1695 | } |
| 1696 | |
| 1697 | /// Parse an allocation session with an implicit exclusive source borrow. |
| 1698 | unsafe fn parseSessionBlock 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
| 1699 | try expect(p, scanner::TokenKind::Use, "expected `use`"); |
| 1700 | let target = try parseUnaryExpr(p); |
| 1701 | let value = node(p, ast::NodeValue::AddressOf({ target, kind: ast::AddressKind::Mutable })); |
| 1702 | try expect(p, scanner::TokenKind::As, "expected `as` after allocation source"); |
| 1703 | let binding = try parseIdent(p, "expected allocation binding after `as`"); |
| 1704 | let region = sessionRegion(p, binding); |
| 1705 | try expect(p, scanner::TokenKind::In, "expected `in` after allocation binding"); |
| 1706 | let bindings = ast::nodeSlice(p.arena, 1).append( |
| 1707 | node(p, ast::NodeValue::RegionBinding({ label: binding, value })), |
| 1708 | p.allocator, |
| 1709 | ); |
| 1710 | let body = try parseBlock(p); |
| 1711 | return node(p, ast::NodeValue::RegionBlock { region, bindings, body, isSession: true }); |
| 1712 | } |
| 1713 | |
| 1714 | /// Parse an identifier. |
| 1715 | unsafe fn parseIdent 'pool (p: &mut Parser 'pool, err: *[u8]) -> *ast::Node |
| 1716 | throws (ParseError) |
| 1717 | { |
| 1718 | let source = try expect(p, scanner::TokenKind::Ident, err); |
| 1719 | return node(p, ast::NodeValue::Ident(source)); |
| 1720 | } |
| 1721 | |
| 1722 | /// Parse either an identifier or a placeholder (`_`). |
| 1723 | unsafe fn parseIdentOrPlaceholder 'pool (p: &mut Parser 'pool, err: *[u8]) -> *ast::Node |
| 1724 | throws (ParseError) |
| 1725 | { |
| 1726 | if consume(p, scanner::TokenKind::Underscore) { |
| 1727 | return node(p, ast::NodeValue::Placeholder); |
| 1728 | } |
| 1729 | return try parseIdent(p, err); |
| 1730 | } |
| 1731 | |
| 1732 | /// Parse an alignment specifier. |
| 1733 | /// |
| 1734 | /// Syntax: `align(N)` where N is a power of 2. |
| 1735 | unsafe fn parseAlign 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1736 | throws (ParseError) |
| 1737 | { |
| 1738 | try expect(p, scanner::TokenKind::Align, "expected `align`"); |
| 1739 | let value = try parseParenthesized(p); |
| 1740 | return node(p, ast::NodeValue::Align { value }); |
| 1741 | } |
| 1742 | |
| 1743 | /// Parse a comma-separated list of record fields. |
| 1744 | /// The opening delimiter should already be consumed. |
| 1745 | /// For labeled fields: `{ name: T, ... }`. |
| 1746 | /// For unlabeled fields: `(T, T, ...)`. |
| 1747 | unsafe fn parseRecordFields 'pool ( |
| 1748 | p: &mut Parser 'pool, |
| 1749 | mode: RecordFieldMode |
| 1750 | ) -> *mut [*ast::Node] |
| 1751 | throws (ParseError) |
| 1752 | { |
| 1753 | let terminator = scanner::TokenKind::RBrace if mode == RecordFieldMode::Labeled |
| 1754 | else scanner::TokenKind::RParen; |
| 1755 | let mut fields = ast::nodeSlice(p.arena, MAX_RECORD_FIELDS); |
| 1756 | while not check(p, terminator) { |
| 1757 | let mut recordField: ast::NodeValue = undefined; |
| 1758 | match mode { |
| 1759 | case RecordFieldMode::Labeled => { |
| 1760 | // Allow optional `let` keyword before field name. |
| 1761 | consume(p, scanner::TokenKind::Let); |
| 1762 | |
| 1763 | let field = try parseNameTypeValue(p); |
| 1764 | let type = field.type else { |
| 1765 | throw failParsing(p, "expected type annotation in record field"); |
| 1766 | }; |
| 1767 | if field.alignment <> nil { |
| 1768 | throw failParsing(p, "record fields cannot specify alignment"); |
| 1769 | } |
| 1770 | if field.value <> nil and mode <> RecordFieldMode::Labeled { |
| 1771 | throw failParsing(p, "record fields cannot have initializers"); |
| 1772 | } |
| 1773 | set recordField = ast::NodeValue::RecordField { |
| 1774 | field: field.name, type, value: field.value, |
| 1775 | }; |
| 1776 | } |
| 1777 | case RecordFieldMode::Unlabeled => { |
| 1778 | let type = try parseType(p); |
| 1779 | set recordField = ast::NodeValue::RecordField { |
| 1780 | field: nil, type, value: nil, |
| 1781 | }; |
| 1782 | } |
| 1783 | } |
| 1784 | fields.append(node(p, recordField), p.allocator); |
| 1785 | |
| 1786 | if not consume(p, scanner::TokenKind::Comma) { |
| 1787 | break; |
| 1788 | } |
| 1789 | } |
| 1790 | try expect(p, terminator, "expected closing delimiter after record fields"); |
| 1791 | |
| 1792 | return fields; |
| 1793 | } |
| 1794 | |
| 1795 | /// Parse an optional declaration list and separate regions from derives. |
| 1796 | unsafe fn parseNominalClauses 'pool ( |
| 1797 | p: &mut Parser 'pool, |
| 1798 | regions: &mut *mut [*ast::Node], |
| 1799 | derives: &mut *mut [*ast::Node], |
| 1800 | ) throws (ParseError) { |
| 1801 | if not consume(p, scanner::TokenKind::Colon) { |
| 1802 | return; |
| 1803 | } |
| 1804 | set *regions = ast::nodeSlice(p.arena, 4); |
| 1805 | set *derives = ast::nodeSlice(p.arena, 4); |
| 1806 | loop { |
| 1807 | if check(p, scanner::TokenKind::Region) { |
| 1808 | regions.append(try parseRegion(p), p.allocator); |
| 1809 | } else { |
| 1810 | derives.append( |
| 1811 | try parseIdent(p, "expected region or trait name in declaration list"), |
| 1812 | p.allocator, |
| 1813 | ); |
| 1814 | } |
| 1815 | |
| 1816 | if not consume(p, scanner::TokenKind::Plus) { |
| 1817 | break; |
| 1818 | } |
| 1819 | } |
| 1820 | } |
| 1821 | |
| 1822 | /// Parse an optional list of trait names. |
| 1823 | unsafe fn parseDerives 'pool (p: &mut Parser 'pool) -> *mut [*ast::Node] throws (ParseError) { |
| 1824 | if not consume(p, scanner::TokenKind::Colon) { |
| 1825 | return &mut []; |
| 1826 | } |
| 1827 | let mut derives = ast::nodeSlice(p.arena, 4); |
| 1828 | loop { |
| 1829 | derives.append(try parseIdent(p, "expected trait name"), p.allocator); |
| 1830 | if not consume(p, scanner::TokenKind::Plus) { |
| 1831 | break; |
| 1832 | } |
| 1833 | } |
| 1834 | return derives; |
| 1835 | } |
| 1836 | |
| 1837 | /// Parse a single record literal field. |
| 1838 | /// Can be either labeled, or shorthand. |
| 1839 | unsafe fn parseRecordLitField 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1840 | throws (ParseError) |
| 1841 | { |
| 1842 | let name = try parseIdent(p, "expected field name"); |
| 1843 | if consume(p, scanner::TokenKind::Colon) { |
| 1844 | // Labeled field: `name: value`. |
| 1845 | let value = try parseExpr(p); |
| 1846 | return node(p, ast::NodeValue::RecordLitField( |
| 1847 | ast::Arg { label: name, value } |
| 1848 | )); |
| 1849 | } |
| 1850 | // Shorthand syntax: `{ x }` is equivalent to `{ x: x }`. |
| 1851 | return node(p, ast::NodeValue::RecordLitField( |
| 1852 | ast::Arg { label: name, value: name } |
| 1853 | )); |
| 1854 | } |
| 1855 | |
| 1856 | /// Parse a record literal body. |
| 1857 | /// Eg. `{ x: 1, y: 2 }` |
| 1858 | /// Eg. `{ x: 1, .. }` |
| 1859 | unsafe fn parseRecordLit 'pool (p: &mut Parser 'pool, typeName: ?*ast::Node) -> *ast::Node |
| 1860 | throws (ParseError) |
| 1861 | { |
| 1862 | let mut fields = ast::nodeSlice(p.arena, MAX_RECORD_FIELDS); |
| 1863 | let mut ignoreRest = false; |
| 1864 | try expect(p, scanner::TokenKind::LBrace, "expected `{` to begin record literal"); |
| 1865 | |
| 1866 | while not check(p, scanner::TokenKind::RBrace) { |
| 1867 | // Check for `..` to ignore remaining fields. |
| 1868 | if consume(p, scanner::TokenKind::DotDot) { |
| 1869 | set ignoreRest = true; |
| 1870 | break; |
| 1871 | } |
| 1872 | let field = try parseRecordLitField(p); |
| 1873 | fields.append(field, p.allocator); |
| 1874 | |
| 1875 | if not consume(p, scanner::TokenKind::Comma) { |
| 1876 | break; |
| 1877 | } |
| 1878 | } |
| 1879 | try expect(p, scanner::TokenKind::RBrace, "expected `}` to end record literal"); |
| 1880 | |
| 1881 | return node(p, ast::NodeValue::RecordLit( |
| 1882 | ast::RecordLit { typeName, fields, ignoreRest } |
| 1883 | )); |
| 1884 | } |
| 1885 | |
| 1886 | /// Parse a named record declaration. |
| 1887 | /// `record Point { x: i32, y: i32 }`, or `record Pair(i32, i32);` |
| 1888 | unsafe fn parseRecordDecl 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
| 1889 | throws (ParseError) |
| 1890 | { |
| 1891 | try expect(p, scanner::TokenKind::Record, "expected `record`"); |
| 1892 | |
| 1893 | let name = try parseIdent(p, "expected record name"); |
| 1894 | let mut regions: *mut [*ast::Node] = &mut []; |
| 1895 | let mut derives: *mut [*ast::Node] = &mut []; |
| 1896 | try parseNominalClauses(p, &mut regions, &mut derives); |
| 1897 | try parseRegionBounds(p, &mut regions[..]); |
| 1898 | |
| 1899 | if consume(p, scanner::TokenKind::LParen) { |
| 1900 | let fields = try parseRecordFields(p, RecordFieldMode::Unlabeled); |
| 1901 | try expect(p, scanner::TokenKind::Semicolon, "expected `;` after record"); |
| 1902 | return node(p, ast::NodeValue::RecordDecl( |
| 1903 | ast::RecordDecl { |
| 1904 | name, fields, attrs, regions, derives, labeled: false, |
| 1905 | } |
| 1906 | )); |
| 1907 | } else { |
| 1908 | try expect(p, scanner::TokenKind::LBrace, "expected `{` before record body"); |
| 1909 | let fields = try parseRecordFields(p, RecordFieldMode::Labeled); |
| 1910 | return node(p, ast::NodeValue::RecordDecl( |
| 1911 | ast::RecordDecl { |
| 1912 | name, fields, attrs, regions, derives, labeled: true, |
| 1913 | } |
| 1914 | )); |
| 1915 | } |
| 1916 | } |
| 1917 | |
| 1918 | /// Parse a union declaration. |
| 1919 | /// Example: `union Color { Red, Green, Blue = 5 }` |
| 1920 | unsafe fn parseUnionDecl 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
| 1921 | throws (ParseError) |
| 1922 | { |
| 1923 | try expect(p, scanner::TokenKind::Union, "expected `union`"); |
| 1924 | |
| 1925 | let name = try parseIdent(p, "expected union name"); |
| 1926 | let mut regions: *mut [*ast::Node] = &mut []; |
| 1927 | let mut derives: *mut [*ast::Node] = &mut []; |
| 1928 | try parseNominalClauses(p, &mut regions, &mut derives); |
| 1929 | try parseRegionBounds(p, &mut regions[..]); |
| 1930 | |
| 1931 | try expect(p, scanner::TokenKind::LBrace, "expected `{` before union body"); |
| 1932 | |
| 1933 | let mut variants = ast::nodeSlice(p.arena, 128); |
| 1934 | while not check(p, scanner::TokenKind::RBrace) { |
| 1935 | // Allow optional `case` keyword before variant name. |
| 1936 | consume(p, scanner::TokenKind::Case); |
| 1937 | |
| 1938 | let variantName = try parseIdent(p, "expected variant name"); |
| 1939 | let mut payloadType: ?*ast::Node = nil; |
| 1940 | let mut explicitValue: ?*ast::Node = nil; |
| 1941 | |
| 1942 | if consume(p, scanner::TokenKind::LParen) { // `Variant(T, U)`. |
| 1943 | let fields = try parseRecordFields(p, RecordFieldMode::Unlabeled); |
| 1944 | set payloadType = node(p, ast::NodeValue::TypeSig( |
| 1945 | ast::TypeSig::Record { fields, labeled: false } |
| 1946 | )); |
| 1947 | } else if consume(p, scanner::TokenKind::LBrace) { // `Variant { x: T, y: T }`. |
| 1948 | let fields = try parseRecordFields(p, RecordFieldMode::Labeled); |
| 1949 | set payloadType = node(p, ast::NodeValue::TypeSig( |
| 1950 | ast::TypeSig::Record { fields, labeled: true } |
| 1951 | )); |
| 1952 | } else if consume(p, scanner::TokenKind::Equal) { |
| 1953 | // TODO: Support constant expressions. |
| 1954 | try expect(p, scanner::TokenKind::Number, "expected integer literal after `=`"); |
| 1955 | let source = p.previous.source; |
| 1956 | let literal = try parseIntLiteral(p, source); |
| 1957 | set explicitValue = nodeNumber(p, literal); |
| 1958 | } |
| 1959 | |
| 1960 | let variant = node(p, ast::NodeValue::UnionDeclVariant( |
| 1961 | ast::UnionDeclVariant { |
| 1962 | name: variantName, index: variants.len as u32, value: explicitValue, type: payloadType, |
| 1963 | } |
| 1964 | )); |
| 1965 | variants.append(variant, p.allocator); |
| 1966 | |
| 1967 | if not consume(p, scanner::TokenKind::Comma) { |
| 1968 | break; |
| 1969 | } |
| 1970 | } |
| 1971 | try expect(p, scanner::TokenKind::RBrace, "expected `}`"); |
| 1972 | |
| 1973 | return node(p, ast::NodeValue::UnionDecl( |
| 1974 | ast::UnionDecl { |
| 1975 | name, variants, attrs, regions, derives, |
| 1976 | } |
| 1977 | )); |
| 1978 | } |
| 1979 | |
| 1980 | /// Parse a function parameter. |
| 1981 | unsafe fn parseFnParam 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 1982 | throws (ParseError) |
| 1983 | { |
| 1984 | let ntv = try parseNameTypeValue(p); |
| 1985 | let type = ntv.type |
| 1986 | else throw failParsing(p, "missing type in function parameter"); |
| 1987 | |
| 1988 | return node(p, ast::NodeValue::FnParam( |
| 1989 | ast::FnParam { name: ntv.name, type } |
| 1990 | )); |
| 1991 | } |
| 1992 | |
| 1993 | /// Parse an optional `throws` clause and return the collected type list. |
| 1994 | unsafe fn parseThrowList 'pool (p: &mut Parser 'pool) -> *mut [*ast::Node] |
| 1995 | throws (ParseError) |
| 1996 | { |
| 1997 | if not consume(p, scanner::TokenKind::Throws) { |
| 1998 | return ast::nodeSlice(p.arena, 0); |
| 1999 | } |
| 2000 | return try parseList( |
| 2001 | p, |
| 2002 | scanner::TokenKind::LParen, |
| 2003 | scanner::TokenKind::RParen, |
| 2004 | parseType 'pool |
| 2005 | ); |
| 2006 | } |
| 2007 | |
| 2008 | /// Parse a function type signature. |
| 2009 | unsafe fn parseFnType 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 2010 | throws (ParseError) |
| 2011 | { |
| 2012 | let isUnsafe = consume(p, scanner::TokenKind::Unsafe); |
| 2013 | try expect(p, scanner::TokenKind::Fn, "expected `fn`"); |
| 2014 | let params = try parseList( |
| 2015 | p, |
| 2016 | scanner::TokenKind::LParen, |
| 2017 | scanner::TokenKind::RParen, |
| 2018 | parseType 'pool |
| 2019 | ); |
| 2020 | let mut returnType: ?*ast::Node = nil; |
| 2021 | |
| 2022 | if consume(p, scanner::TokenKind::Arrow) { |
| 2023 | set returnType = try parseReturnType(p); |
| 2024 | } |
| 2025 | let throwList = try parseThrowList(p); |
| 2026 | let sig = ast::FnSig { params, returnType, throwList }; |
| 2027 | return node(p, ast::NodeValue::TypeSig( |
| 2028 | ast::TypeSig::Fn { sig, isUnsafe } |
| 2029 | )); |
| 2030 | } |
| 2031 | |
| 2032 | /// Parse a function signature following the function name. |
| 2033 | unsafe fn parseFnTypeSig 'pool (p: &mut Parser 'pool) -> ast::FnSig |
| 2034 | throws (ParseError) |
| 2035 | { |
| 2036 | try expect(p, scanner::TokenKind::LParen, "expected `(` after function name"); |
| 2037 | let mut params = ast::nodeSlice(p.arena, 8); |
| 2038 | |
| 2039 | while not check(p, scanner::TokenKind::RParen) { |
| 2040 | let param = try parseFnParam(p); |
| 2041 | params.append(param, p.allocator); |
| 2042 | |
| 2043 | if not consume(p, scanner::TokenKind::Comma) { |
| 2044 | break; |
| 2045 | } |
| 2046 | } |
| 2047 | try expect(p, scanner::TokenKind::RParen, "expected `)` after function parameters"); |
| 2048 | |
| 2049 | let mut returnType: ?*ast::Node = nil; |
| 2050 | if consume(p, scanner::TokenKind::Arrow) { |
| 2051 | set returnType = try parseReturnType(p); |
| 2052 | } |
| 2053 | let throwList = try parseThrowList(p); |
| 2054 | |
| 2055 | return ast::FnSig { params, returnType, throwList }; |
| 2056 | } |
| 2057 | |
| 2058 | /// Parse a function return type, including the uninhabited type. |
| 2059 | unsafe fn parseReturnType 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
| 2060 | if consume(p, scanner::TokenKind::Bang) { |
| 2061 | return node(p, ast::NodeValue::TypeSig(ast::TypeSig::Never)); |
| 2062 | } |
| 2063 | return try parseType(p); |
| 2064 | } |
| 2065 | |
| 2066 | /// Parse a function declaration. |
| 2067 | unsafe fn parseFnDecl 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
| 2068 | throws (ParseError) |
| 2069 | { |
| 2070 | try expect(p, scanner::TokenKind::Fn, "expected `fn`"); |
| 2071 | |
| 2072 | // Method syntax: `fn (recv: *Type) name(params) { body }`. |
| 2073 | if check(p, scanner::TokenKind::LParen) { |
| 2074 | return try parseMethodDecl(p, attrs); |
| 2075 | } |
| 2076 | let name = try parseIdent(p, "expected function name"); |
| 2077 | let regions = try parseRegions(p); |
| 2078 | let sig = try parseFnTypeSig(p); |
| 2079 | try parseRegionBounds(p, &mut regions[..]); |
| 2080 | let mut body: ?*ast::Node = nil; |
| 2081 | let mut fnAttrs = attrs; |
| 2082 | |
| 2083 | if consume(p, scanner::TokenKind::Semicolon) { |
| 2084 | if let a = attrs; ast::attributesContains(&a, ast::Attribute::Extern) { |
| 2085 | // Keep existing attributes unchanged. |
| 2086 | } else { |
| 2087 | let mut list = ast::nodeSlice(p.arena, 4); |
| 2088 | if let a = attrs { |
| 2089 | for i in 0..a.list.len { |
| 2090 | list.append(a.list[i], p.allocator); |
| 2091 | } |
| 2092 | } |
| 2093 | let attrNode = nodeAttribute(p, ast::Attribute::Extern); |
| 2094 | list.append(attrNode, p.allocator); |
| 2095 | set fnAttrs = ast::Attributes { list }; |
| 2096 | } |
| 2097 | } else { |
| 2098 | set body = try parseBlock(p); |
| 2099 | } |
| 2100 | return node(p, ast::NodeValue::FnDecl( |
| 2101 | ast::FnDecl { name, regions, sig, body, attrs: fnAttrs } |
| 2102 | )); |
| 2103 | } |
| 2104 | |
| 2105 | /// Parse a pointer-like type after its ownership prefix. |
| 2106 | unsafe fn parsePointerLikeType 'pool ( |
| 2107 | p: &mut Parser 'pool, |
| 2108 | class: ast::PointerClass, |
| 2109 | ) -> *ast::Node throws (ParseError) { |
| 2110 | if check(p, scanner::TokenKind::Ident) and mem::eq(p.current.source, "cell") { |
| 2111 | advance(p); |
| 2112 | let payload = try parseType(p); |
| 2113 | return node(p, ast::NodeValue::TypeSig(ast::TypeSig::Cell { class, payload })); |
| 2114 | } |
| 2115 | let mutable = consume(p, scanner::TokenKind::Mut); |
| 2116 | |
| 2117 | if consume(p, scanner::TokenKind::LBracket) { |
| 2118 | let itemType = try parseType(p); |
| 2119 | try expect(p, scanner::TokenKind::RBracket, "expected `]` after slice element type"); |
| 2120 | |
| 2121 | return node(p, ast::NodeValue::TypeSig( |
| 2122 | ast::TypeSig::Slice { class, itemType, mutable } |
| 2123 | )); |
| 2124 | } |
| 2125 | // Check for an opaque trait object. |
| 2126 | if consume(p, scanner::TokenKind::Opaque) { |
| 2127 | if check(p, scanner::TokenKind::Ident) or check(p, scanner::TokenKind::Super) { |
| 2128 | let traitName = try parseTypePath(p); |
| 2129 | return node(p, ast::NodeValue::TypeSig( |
| 2130 | ast::TypeSig::TraitObject { class, traitName, mutable } |
| 2131 | )); |
| 2132 | } |
| 2133 | // Plain opaque target. |
| 2134 | let valueType = node(p, ast::NodeValue::TypeSig(ast::TypeSig::Opaque)); |
| 2135 | return node(p, ast::NodeValue::TypeSig( |
| 2136 | ast::TypeSig::Pointer { class, valueType, mutable } |
| 2137 | )); |
| 2138 | } |
| 2139 | let valueType = try parseType(p); |
| 2140 | |
| 2141 | return node(p, ast::NodeValue::TypeSig( |
| 2142 | ast::TypeSig::Pointer { class, valueType, mutable } |
| 2143 | )); |
| 2144 | } |
| 2145 | |
| 2146 | /// Parse an array type. |
| 2147 | unsafe fn parseArrayType 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 2148 | throws (ParseError) |
| 2149 | { |
| 2150 | try expect(p, scanner::TokenKind::LBracket, "expected `[`"); |
| 2151 | let itemType = try parseType(p); |
| 2152 | |
| 2153 | try expect(p, scanner::TokenKind::Semicolon, "expected `;` in array type"); |
| 2154 | let length = try parseExpr(p); |
| 2155 | |
| 2156 | try expect(p, scanner::TokenKind::RBracket, "expected `]` after array length"); |
| 2157 | return node(p, ast::NodeValue::TypeSig( |
| 2158 | ast::TypeSig::Array { itemType, length } |
| 2159 | )); |
| 2160 | } |
| 2161 | |
| 2162 | /// Parse a type path: an identifier optionally followed by `::` scope access. |
| 2163 | /// Returns an identifier node or a scope access chain. |
| 2164 | unsafe fn parseTypePath 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 2165 | throws (ParseError) |
| 2166 | { |
| 2167 | let mut path: *ast::Node = undefined; |
| 2168 | if p.current.kind == scanner::TokenKind::Super { |
| 2169 | advance(p); |
| 2170 | set path = nodeSuper(p); |
| 2171 | } else { |
| 2172 | set path = try parseIdent(p, "expected type identifier"); |
| 2173 | } |
| 2174 | while consume(p, scanner::TokenKind::ColonColon) { |
| 2175 | let part = try parseIdent(p, "expected identifier after `::`"); |
| 2176 | set path = node(p, ast::NodeValue::ScopeAccess( |
| 2177 | ast::Access { parent: path, child: part } |
| 2178 | )); |
| 2179 | } |
| 2180 | return path; |
| 2181 | } |
| 2182 | |
| 2183 | /// Parse a type annotation. |
| 2184 | export unsafe fn parseType 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 2185 | throws (ParseError) |
| 2186 | { |
| 2187 | match p.current.kind { |
| 2188 | case scanner::TokenKind::Question => { |
| 2189 | advance(p); |
| 2190 | let valueType = try parseType(p); |
| 2191 | |
| 2192 | return node(p, ast::NodeValue::TypeSig( |
| 2193 | ast::TypeSig::Optional { valueType } |
| 2194 | )); |
| 2195 | } |
| 2196 | case scanner::TokenKind::Star => { |
| 2197 | advance(p); |
| 2198 | let class = ast::PointerClass::Unsafe |
| 2199 | if consume(p, scanner::TokenKind::Unsafe) |
| 2200 | else ast::PointerClass::Owned; |
| 2201 | return try parsePointerLikeType(p, class); |
| 2202 | } |
| 2203 | case scanner::TokenKind::Amp => { |
| 2204 | advance(p); |
| 2205 | let mut region: ?*ast::Node = nil; |
| 2206 | if check(p, scanner::TokenKind::Region) { |
| 2207 | set region = try parseRegion(p); |
| 2208 | } |
| 2209 | let type = try parsePointerLikeType(p, ast::PointerClass::Ref); |
| 2210 | if let r = region { |
| 2211 | return node(p, ast::NodeValue::TypeSig(ast::TypeSig::RegionRef { region: r, type })); |
| 2212 | } |
| 2213 | return type; |
| 2214 | } |
| 2215 | case scanner::TokenKind::LBracket => { |
| 2216 | return try parseArrayType(p); |
| 2217 | } |
| 2218 | case scanner::TokenKind::Super, scanner::TokenKind::Ident => { |
| 2219 | let path = try parseTypePath(p); |
| 2220 | if check(p, scanner::TokenKind::Region) { |
| 2221 | let regions = try parseRegions(p); |
| 2222 | return node(p, ast::NodeValue::TypeSig(ast::TypeSig::Applied { name: path, regions })); |
| 2223 | } |
| 2224 | return node(p, ast::NodeValue::TypeSig( |
| 2225 | ast::TypeSig::Nominal(path) |
| 2226 | )); |
| 2227 | } |
| 2228 | case scanner::TokenKind::U8 => { |
| 2229 | advance(p); |
| 2230 | return nodeTypeInt(p, 1, ast::Signedness::Unsigned); |
| 2231 | } |
| 2232 | case scanner::TokenKind::U16 => { |
| 2233 | advance(p); |
| 2234 | return nodeTypeInt(p, 2, ast::Signedness::Unsigned); |
| 2235 | } |
| 2236 | case scanner::TokenKind::U32 => { |
| 2237 | advance(p); |
| 2238 | return nodeTypeInt(p, 4, ast::Signedness::Unsigned); |
| 2239 | } |
| 2240 | case scanner::TokenKind::U64 => { |
| 2241 | advance(p); |
| 2242 | return nodeTypeInt(p, 8, ast::Signedness::Unsigned); |
| 2243 | } |
| 2244 | case scanner::TokenKind::I8 => { |
| 2245 | advance(p); |
| 2246 | return nodeTypeInt(p, 1, ast::Signedness::Signed); |
| 2247 | } |
| 2248 | case scanner::TokenKind::I16 => { |
| 2249 | advance(p); |
| 2250 | return nodeTypeInt(p, 2, ast::Signedness::Signed); |
| 2251 | } |
| 2252 | case scanner::TokenKind::I32 => { |
| 2253 | advance(p); |
| 2254 | return nodeTypeInt(p, 4, ast::Signedness::Signed); |
| 2255 | } |
| 2256 | case scanner::TokenKind::I64 => { |
| 2257 | advance(p); |
| 2258 | return nodeTypeInt(p, 8, ast::Signedness::Signed); |
| 2259 | } |
| 2260 | case scanner::TokenKind::Bool => { |
| 2261 | advance(p); |
| 2262 | return node(p, ast::NodeValue::TypeSig(ast::TypeSig::Bool)); |
| 2263 | } |
| 2264 | case scanner::TokenKind::Opaque => { |
| 2265 | advance(p); |
| 2266 | return node(p, ast::NodeValue::TypeSig(ast::TypeSig::Opaque)); |
| 2267 | } |
| 2268 | case scanner::TokenKind::Fn, scanner::TokenKind::Unsafe => { |
| 2269 | return try parseFnType(p); |
| 2270 | } |
| 2271 | else => { |
| 2272 | throw failParsing(p, "expected type"); |
| 2273 | } |
| 2274 | } |
| 2275 | } |
| 2276 | |
| 2277 | /// Parse a name, optional type, and optional value. |
| 2278 | /// |
| 2279 | /// Used for record field declarations, variable declarations, |
| 2280 | /// and record field initializations. |
| 2281 | unsafe fn parseNameTypeValue 'pool (p: &mut Parser 'pool) -> NameTypeValue |
| 2282 | throws (ParseError) |
| 2283 | { |
| 2284 | let name = try parseIdentOrPlaceholder(p, "expected identifier or `_`"); |
| 2285 | let mut type: ?*ast::Node = nil; |
| 2286 | let mut alignment: ?*ast::Node = nil; |
| 2287 | let mut value: ?*ast::Node = nil; |
| 2288 | |
| 2289 | if consume(p, scanner::TokenKind::Colon) { |
| 2290 | set type = try parseType(p); |
| 2291 | |
| 2292 | if check(p, scanner::TokenKind::Align) { |
| 2293 | set alignment = try parseAlign(p); |
| 2294 | } |
| 2295 | } |
| 2296 | if consume(p, scanner::TokenKind::Equal) { |
| 2297 | set value = try parseExpr(p); |
| 2298 | } |
| 2299 | return NameTypeValue { name, type, value, alignment }; |
| 2300 | } |
| 2301 | |
| 2302 | /// Parse a constant declaration. |
| 2303 | unsafe fn parseConst 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
| 2304 | throws (ParseError) |
| 2305 | { |
| 2306 | try expect(p, scanner::TokenKind::Constant, "expected `constant`"); |
| 2307 | |
| 2308 | let ident = try parseIdent(p, "expected identifier in constant declaration"); |
| 2309 | try expect(p, scanner::TokenKind::Colon, "expected `:` after identifier"); |
| 2310 | |
| 2311 | let type = try parseType(p); |
| 2312 | try expect(p, scanner::TokenKind::Equal, "expected `=` in constant declaration"); |
| 2313 | |
| 2314 | let value = try parseExpr(p); |
| 2315 | |
| 2316 | return node(p, ast::NodeValue::ConstDecl( |
| 2317 | ast::ConstDecl { ident, type, value, attrs } |
| 2318 | )); |
| 2319 | } |
| 2320 | |
| 2321 | /// Parse a static declaration. |
| 2322 | unsafe fn parseStatic 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
| 2323 | throws (ParseError) |
| 2324 | { |
| 2325 | try expect(p, scanner::TokenKind::Static, "expected `static`"); |
| 2326 | |
| 2327 | let ident = try parseIdent(p, "expected identifier in static declaration"); |
| 2328 | try expect(p, scanner::TokenKind::Colon, "expected `:` after identifier"); |
| 2329 | |
| 2330 | let type = try parseType(p); |
| 2331 | try expect(p, scanner::TokenKind::Equal, "expected `=` in static declaration"); |
| 2332 | |
| 2333 | let value = try parseExpr(p); |
| 2334 | |
| 2335 | return node(p, ast::NodeValue::StaticDecl( |
| 2336 | ast::StaticDecl { ident, type, value, attrs } |
| 2337 | )); |
| 2338 | } |
| 2339 | |
| 2340 | /// Parse a `use` declaration. |
| 2341 | unsafe fn parseUse 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
| 2342 | throws (ParseError) |
| 2343 | { |
| 2344 | try expect(p, scanner::TokenKind::Use, "expected `use`"); |
| 2345 | |
| 2346 | // Allow `super` or identifier as the first part of the path. |
| 2347 | let mut path: *ast::Node = undefined; |
| 2348 | if consume(p, scanner::TokenKind::Super) { |
| 2349 | set path = nodeSuper(p); |
| 2350 | } else { |
| 2351 | set path = try parseIdent(p, "expected module name or `super` after `use`"); |
| 2352 | } |
| 2353 | while consume(p, scanner::TokenKind::ColonColon) { |
| 2354 | // Check for wildcard import (e.g., `use parser::*`) |
| 2355 | if consume(p, scanner::TokenKind::Star) { |
| 2356 | return node(p, ast::NodeValue::Use( |
| 2357 | ast::Use { path, wildcard: true, attrs } |
| 2358 | )); |
| 2359 | } |
| 2360 | let part = try parseIdent(p, "expected identifier or `*` after `::`"); |
| 2361 | set path = node(p, ast::NodeValue::ScopeAccess( |
| 2362 | ast::Access { parent: path, child: part } |
| 2363 | )); |
| 2364 | } |
| 2365 | return node(p, ast::NodeValue::Use( |
| 2366 | ast::Use { path, wildcard: false, attrs } |
| 2367 | )); |
| 2368 | } |
| 2369 | |
| 2370 | /// Parse a `mod` declaration. |
| 2371 | unsafe fn parseMod 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
| 2372 | throws (ParseError) |
| 2373 | { |
| 2374 | try expect(p, scanner::TokenKind::Mod, "expected `mod`"); |
| 2375 | let name = try parseIdent(p, "expected module name after `mod`"); |
| 2376 | |
| 2377 | return node(p, ast::NodeValue::Mod( |
| 2378 | ast::Mod { name, attrs } |
| 2379 | )); |
| 2380 | } |
| 2381 | |
| 2382 | /// Parse a `let case` guard statement. |
| 2383 | /// |
| 2384 | /// Eg. `let case <pattern> = <expr> else { ... };` |
| 2385 | /// Eg. `let case <pattern> = <expr> if <guard> else { ... };` |
| 2386 | /// |
| 2387 | /// Expects `let case` tokens to have already been consumed. |
| 2388 | unsafe fn parseLetCase 'pool (p: &mut Parser 'pool) -> *ast::Node throws (ParseError) { |
| 2389 | let pattern = try parseMatchPattern(p); |
| 2390 | |
| 2391 | try expect(p, scanner::TokenKind::Equal, "expected `=` after pattern"); |
| 2392 | let expr = try parseCond(p); |
| 2393 | |
| 2394 | let mut guard: ?*ast::Node = nil; |
| 2395 | if consume(p, scanner::TokenKind::If) { |
| 2396 | set guard = try parseCond(p); |
| 2397 | } |
| 2398 | |
| 2399 | try expect(p, scanner::TokenKind::Else, "expected `else` after pattern"); |
| 2400 | let elseBranch = try parseLetElseBranch(p); |
| 2401 | |
| 2402 | return node(p, ast::NodeValue::LetElse(ast::LetElse { |
| 2403 | pattern: ast::PatternMatch { pattern, scrutinee: expr, guard, kind: ast::PatternKind::Case, mutable: false }, |
| 2404 | elseBranch, |
| 2405 | })); |
| 2406 | } |
| 2407 | |
| 2408 | /// Parse a `let` binding statement. |
| 2409 | /// |
| 2410 | /// Eg. `let <ident> = <expr>;` |
| 2411 | /// Eg. `let <ident> = <expr> else { ... };` |
| 2412 | /// Eg. `let mut <ident> = <expr> else { ... };` |
| 2413 | /// Eg. `let <ident> = <expr> if <guard> else { ... };` |
| 2414 | /// Eg. `mut <ident> = <expr>;` |
| 2415 | /// |
| 2416 | /// Expects `let` or `mut` token to have already been consumed. |
| 2417 | unsafe fn parseLet 'pool (p: &mut Parser 'pool, mutable: bool) -> *ast::Node throws (ParseError) { |
| 2418 | let binding = try parseNameTypeValue(p); |
| 2419 | let value = binding.value |
| 2420 | else throw failParsing(p, "expected value initializer"); |
| 2421 | |
| 2422 | // Check for optional `else` clause (let-else). |
| 2423 | if consume(p, scanner::TokenKind::Else) { |
| 2424 | let elseBranch = try parseLetElseBranch(p); |
| 2425 | |
| 2426 | return node(p, ast::NodeValue::LetElse(ast::LetElse { |
| 2427 | pattern: ast::PatternMatch { pattern: binding.name, scrutinee: value, guard: nil, kind: ast::PatternKind::Binding, mutable }, |
| 2428 | elseBranch, |
| 2429 | })); |
| 2430 | } |
| 2431 | return node(p, ast::NodeValue::Let(ast::Let { |
| 2432 | ident: binding.name, type: binding.type, value, alignment: binding.alignment, mutable, |
| 2433 | })); |
| 2434 | } |
| 2435 | |
| 2436 | /// Parse a module from source text using the provided arena for node storage. |
| 2437 | export unsafe fn parse(sourceLoc: scanner::SourceLoc, input: *[u8], arena: &mut ast::NodeArena, pool: &mut strings::Pool) -> *ast::Node |
| 2438 | throws (ParseError) |
| 2439 | { |
| 2440 | let poolRef: 'pool = &mut *pool, arenaRef = &mut *arena in { |
| 2441 | let mut p = mkParser(sourceLoc, input, arenaRef, poolRef); |
| 2442 | return try parseModule(&mut p) catch { |
| 2443 | printErrors(&p); |
| 2444 | throw ParseError::UnexpectedToken; |
| 2445 | }; |
| 2446 | } |
| 2447 | } |
| 2448 | |
| 2449 | /// Parse a complete module into a block of top-level statements. |
| 2450 | /// |
| 2451 | /// This is the main entry point for parsing an entire Radiance source file. |
| 2452 | /// The parser must already be initialized with source code. |
| 2453 | export unsafe fn parseModule 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 2454 | throws (ParseError) |
| 2455 | { |
| 2456 | advance(p); // Set the parser up with a first token. |
| 2457 | |
| 2458 | let statements = try parseStmtsUntil(p, scanner::TokenKind::Eof, 512); |
| 2459 | let blk = ast::Block { statements, isUnsafe: false }; |
| 2460 | consume(p, scanner::TokenKind::Eof); |
| 2461 | |
| 2462 | return node(p, ast::NodeValue::Block(blk)); |
| 2463 | } |
| 2464 | |
| 2465 | /// Consume a token of the given kind if present. |
| 2466 | export fn consume 'pool (p: &mut Parser 'pool, kind: scanner::TokenKind) -> bool { |
| 2467 | if check(p, kind) { |
| 2468 | advance(p); |
| 2469 | return true; |
| 2470 | } |
| 2471 | return false; |
| 2472 | } |
| 2473 | |
| 2474 | /// Expect a token of the given kind or report an error. |
| 2475 | export fn expect 'pool (p: &mut Parser 'pool, kind: scanner::TokenKind, message: *[u8]) -> *[u8] |
| 2476 | throws (ParseError) |
| 2477 | { |
| 2478 | if not consume(p, kind) { |
| 2479 | let token = p.current; |
| 2480 | reportError(p, token, message); |
| 2481 | throw ParseError::UnexpectedToken; |
| 2482 | } |
| 2483 | return p.previous.source; |
| 2484 | } |
| 2485 | |
| 2486 | /// Return a generic expectation message for a delimiter token. |
| 2487 | fn listExpectMessage(kind: scanner::TokenKind) -> *[u8] { |
| 2488 | match kind { |
| 2489 | case scanner::TokenKind::LParen => return "expected `(`", |
| 2490 | case scanner::TokenKind::RParen => return "expected `)`", |
| 2491 | case scanner::TokenKind::LBracket => return "expected `[`", |
| 2492 | case scanner::TokenKind::RBracket => return "expected `]`", |
| 2493 | case scanner::TokenKind::LBrace => return "expected `{`", |
| 2494 | case scanner::TokenKind::RBrace => return "expected `}`", |
| 2495 | else => return "expected delimiter", |
| 2496 | } |
| 2497 | } |
| 2498 | |
| 2499 | /// Parse a trait declaration. |
| 2500 | /// Syntax: `trait Name { fn (*Trait) method(...) -> T; ... }` |
| 2501 | unsafe fn parseTraitDecl 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
| 2502 | throws (ParseError) |
| 2503 | { |
| 2504 | try expect(p, scanner::TokenKind::Trait, "expected `trait`"); |
| 2505 | let name = try parseIdent(p, "expected trait name"); |
| 2506 | let supertraits = try parseDerives(p); |
| 2507 | try expect(p, scanner::TokenKind::LBrace, "expected `{` after trait name"); |
| 2508 | |
| 2509 | let mut methods = ast::nodeSlice(p.arena, ast::MAX_TRAIT_METHODS); |
| 2510 | while not check(p, scanner::TokenKind::RBrace) and |
| 2511 | not check(p, scanner::TokenKind::Eof) |
| 2512 | { |
| 2513 | let method = try parseTraitMethodSig(p); |
| 2514 | methods.append(method, p.allocator); |
| 2515 | } |
| 2516 | try expect(p, scanner::TokenKind::RBrace, "expected `}` after trait methods"); |
| 2517 | |
| 2518 | return node(p, ast::NodeValue::TraitDecl { name, supertraits, methods, attrs }); |
| 2519 | } |
| 2520 | |
| 2521 | /// Parse a trait method signature. |
| 2522 | /// Syntax: `fn (*Trait) fnord(<params>) -> ReturnType;` |
| 2523 | unsafe fn parseTraitMethodSig 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 2524 | throws (ParseError) |
| 2525 | { |
| 2526 | let attrs = parseAttributes(p); |
| 2527 | try expect(p, scanner::TokenKind::Fn, "expected `fn`"); |
| 2528 | try expect(p, scanner::TokenKind::LParen, "expected `(` before receiver"); |
| 2529 | |
| 2530 | let receiver = try parseType(p); |
| 2531 | |
| 2532 | try expect(p, scanner::TokenKind::RParen, "expected `)` after receiver"); |
| 2533 | |
| 2534 | let name = try parseIdent(p, "expected method name"); |
| 2535 | let mut regions = try parseRegions(p); |
| 2536 | let sig = try parseFnTypeSig(p); |
| 2537 | try parseRegionBounds(p, &mut regions[..]); |
| 2538 | try expect(p, scanner::TokenKind::Semicolon, "expected `;` after method signature"); |
| 2539 | |
| 2540 | let modifiers = try! alloc::alloc( |
| 2541 | &mut p.arena.arena, @sizeOf(ast::MethodModifiers), @alignOf(ast::MethodModifiers) |
| 2542 | ) as *mut ast::MethodModifiers; |
| 2543 | set *modifiers = ast::MethodModifiers { regions, attrs }; |
| 2544 | return node(p, ast::NodeValue::TraitMethodSig { name, modifiers, receiver, sig }); |
| 2545 | } |
| 2546 | |
| 2547 | /// Parse an instance block. |
| 2548 | /// Syntax: `instance Trait for Type { fn (t: *mut Type) fnord(..) {..} }` |
| 2549 | /// |
| 2550 | /// Instance declarations do not accept attributes (e.g. `export`). |
| 2551 | /// Visibility is determined by the trait declaration itself. |
| 2552 | unsafe fn parseInstanceDecl 'pool (p: &mut Parser 'pool) -> *ast::Node |
| 2553 | throws (ParseError) |
| 2554 | { |
| 2555 | try expect(p, scanner::TokenKind::Instance, "expected `instance`"); |
| 2556 | let traitName = try parseTypePath(p); |
| 2557 | try expect(p, scanner::TokenKind::For, "expected `for` after trait name"); |
| 2558 | let targetType = try parseTypePath(p); |
| 2559 | let mut regions = try parseRegions(p); |
| 2560 | try parseRegionBounds(p, &mut regions[..]); |
| 2561 | try expect(p, scanner::TokenKind::LBrace, "expected `{` after target type"); |
| 2562 | |
| 2563 | let mut methods = ast::nodeSlice(p.arena, ast::MAX_TRAIT_METHODS); |
| 2564 | |
| 2565 | while not check(p, scanner::TokenKind::RBrace) and |
| 2566 | not check(p, scanner::TokenKind::Eof) |
| 2567 | { |
| 2568 | let attrs = parseAttributes(p); |
| 2569 | try expect(p, scanner::TokenKind::Fn, "expected `fn`"); |
| 2570 | let method = try parseMethodDecl(p, attrs); |
| 2571 | |
| 2572 | methods.append(method, p.allocator); |
| 2573 | } |
| 2574 | try expect(p, scanner::TokenKind::RBrace, "expected `}` after instance methods"); |
| 2575 | |
| 2576 | return node(p, ast::NodeValue::InstanceDecl { traitName, targetType, regions, methods }); |
| 2577 | } |
| 2578 | |
| 2579 | /// Parse a method declaration with a receiver. |
| 2580 | /// Syntax: `fn (t: *mut Type) fnord(<params>) -> ReturnType { body }` |
| 2581 | /// |
| 2582 | /// Used both inside `instance` blocks and as standalone methods at the top level. |
| 2583 | /// Expects the `fn` token to have already been consumed. |
| 2584 | unsafe fn parseMethodDecl 'pool (p: &mut Parser 'pool, attrs: ?ast::Attributes) -> *ast::Node |
| 2585 | throws (ParseError) |
| 2586 | { |
| 2587 | try expect(p, scanner::TokenKind::LParen, "expected `(` before receiver"); |
| 2588 | |
| 2589 | let receiverName = try parseIdent(p, "expected receiver name"); |
| 2590 | try expect(p, scanner::TokenKind::Colon, "expected `:` after receiver name"); |
| 2591 | let receiverType = try parseType(p); |
| 2592 | |
| 2593 | try expect(p, scanner::TokenKind::RParen, "expected `)` after receiver type"); |
| 2594 | |
| 2595 | let name = try parseIdent(p, "expected method name"); |
| 2596 | let mut regions = try parseRegions(p); |
| 2597 | let sig = try parseFnTypeSig(p); |
| 2598 | try parseRegionBounds(p, &mut regions[..]); |
| 2599 | let body = try parseBlock(p); |
| 2600 | |
| 2601 | let modifiers = try! alloc::alloc( |
| 2602 | &mut p.arena.arena, @sizeOf(ast::MethodModifiers), @alignOf(ast::MethodModifiers) |
| 2603 | ) as *mut ast::MethodModifiers; |
| 2604 | set *modifiers = ast::MethodModifiers { regions, attrs }; |
| 2605 | return node(p, ast::NodeValue::MethodDecl { |
| 2606 | name, modifiers, receiverName, receiverType, sig, body, |
| 2607 | }); |
| 2608 | } |
| 2609 | |
| 2610 | /// Parse a comma-separated list enclosed by the given delimiters. |
| 2611 | unsafe fn parseList 'pool ( |
| 2612 | p: &mut Parser 'pool, |
| 2613 | open: scanner::TokenKind, |
| 2614 | close: scanner::TokenKind, |
| 2615 | parseItem: unsafe fn (&mut Parser 'pool) -> *ast::Node throws (ParseError) |
| 2616 | ) -> *mut [*ast::Node] throws (ParseError) { |
| 2617 | try expect(p, open, listExpectMessage(open)); |
| 2618 | let mut items = ast::nodeSlice(p.arena, 8); |
| 2619 | |
| 2620 | while not check(p, close) { |
| 2621 | let item = try parseItem(p); |
| 2622 | items.append(item, p.allocator); |
| 2623 | |
| 2624 | if not consume(p, scanner::TokenKind::Comma) { |
| 2625 | break; |
| 2626 | } |
| 2627 | } |
| 2628 | try expect(p, close, listExpectMessage(close)); |
| 2629 | |
| 2630 | return items; |
| 2631 | } |