lang: Simplify compiler
bc8bdb048818c4f73bf2f24c1f4c815703ea7c0124c6a6655aee09f4ccfec096
The compiler fixes accumulated repeated parser context switching, integer bit-pattern conversion, and numeric inference branches. The behavior was correct but harder to audit. Centralize parser context and integer bit conversions, and use one operand-type selection path, reducing the implementation while preserving the fixed behavior. Assisted-by: Codex:gpt-5.6-sol
1 parent
55278d55
lib/std/lang/parser.rad
+17 -24
| 220 | 220 | /// Emit a unary operator node. |
|
| 221 | 221 | fn nodeUnary(p: *mut Parser, op: ast::UnaryOp, value: *ast::Node) -> *ast::Node { |
|
| 222 | 222 | return node(p, ast::NodeValue::UnOp({ op, value })); |
|
| 223 | 223 | } |
|
| 224 | 224 | ||
| 225 | + | /// Parse one expression without inheriting a surrounding condition or pattern context. |
|
| 226 | + | fn parseNormalExpr(p: *mut Parser) -> *ast::Node throws (ParseError) { |
|
| 227 | + | let saved = p.context; |
|
| 228 | + | set p.context = Context::Normal; |
|
| 229 | + | let expr = try parseExpr(p); |
|
| 230 | + | set p.context = saved; |
|
| 231 | + | return expr; |
|
| 232 | + | } |
|
| 233 | + | ||
| 225 | 234 | /// Parse a parenthesized expression without applying postfix operators. |
|
| 226 | 235 | fn parseParenthesized(p: *mut Parser) -> *ast::Node |
|
| 227 | 236 | throws (ParseError) |
|
| 228 | 237 | { |
|
| 229 | 238 | try expect(p, scanner::TokenKind::LParen, "expected `(`"); |
|
| 230 | 239 | ||
| 231 | - | let saved = p.context; |
|
| 232 | - | set p.context = Context::Normal; |
|
| 233 | - | let expr = try parseExpr(p); |
|
| 234 | - | set p.context = saved; |
|
| 240 | + | let expr = try parseNormalExpr(p); |
|
| 235 | 241 | ||
| 236 | 242 | try expect(p, scanner::TokenKind::RParen, "expected `)`"); |
|
| 237 | 243 | ||
| 238 | 244 | return expr; |
|
| 239 | 245 | } |
| 241 | 247 | /// Parse an array literal: `[a, b, c]` or `[item; count]`. |
|
| 242 | 248 | fn parseArrayLiteral(p: *mut Parser) -> *ast::Node |
|
| 243 | 249 | throws (ParseError) |
|
| 244 | 250 | { |
|
| 245 | 251 | try expect(p, scanner::TokenKind::LBracket, "expected `[`"); |
|
| 246 | - | let saved = p.context; |
|
| 247 | - | set p.context = Context::Normal; |
|
| 248 | 252 | if consume(p, scanner::TokenKind::RBracket) { // Empty array: `[]`. |
|
| 249 | 253 | let empty: *mut [*ast::Node] = &mut []; |
|
| 250 | - | set p.context = saved; |
|
| 251 | 254 | return node(p, ast::NodeValue::ArrayLit(empty)); |
|
| 252 | 255 | } |
|
| 253 | - | let firstExpr = try parseExpr(p); |
|
| 256 | + | let firstExpr = try parseNormalExpr(p); |
|
| 254 | 257 | ||
| 255 | 258 | if consume(p, scanner::TokenKind::Semicolon) { |
|
| 256 | 259 | // Array repeat literal: `[item; count]`. |
|
| 257 | - | let count = try parseExpr(p); |
|
| 260 | + | let count = try parseNormalExpr(p); |
|
| 258 | 261 | try expect(p, scanner::TokenKind::RBracket, "expected `]` after array repeat count"); |
|
| 259 | - | set p.context = saved; |
|
| 260 | 262 | ||
| 261 | 263 | return node(p, ast::NodeValue::ArrayRepeatLit( |
|
| 262 | 264 | ast::ArrayRepeatLit { item: firstExpr, count } |
|
| 263 | 265 | )); |
|
| 264 | 266 | } |
|
| 265 | 267 | // Regular array literal: `[a, b, ...]`. |
|
| 266 | 268 | let mut items = ast::nodeSlice(p.arena, 64).append(firstExpr, p.allocator); |
|
| 267 | 269 | ||
| 268 | 270 | while consume(p, scanner::TokenKind::Comma) and not check(p, scanner::TokenKind::RBracket) { |
|
| 269 | - | let elem = try parseExpr(p); |
|
| 271 | + | let elem = try parseNormalExpr(p); |
|
| 270 | 272 | items.append(elem, p.allocator); |
|
| 271 | 273 | } |
|
| 272 | 274 | try expect(p, scanner::TokenKind::RBracket, "expected `]` after array elements"); |
|
| 273 | - | set p.context = saved; |
|
| 274 | 275 | ||
| 275 | 276 | return node(p, ast::NodeValue::ArrayLit(items)); |
|
| 276 | 277 | } |
|
| 277 | 278 | ||
| 278 | 279 | /// Parse a function call expression. |
|
| 279 | 280 | fn parseCall(p: *mut Parser, callee: *ast::Node) -> *ast::Node |
|
| 280 | 281 | throws (ParseError) |
|
| 281 | 282 | { |
|
| 282 | - | // The argument list is delimited, so `{` starts a record literal rather |
|
| 283 | - | // than the body of an enclosing conditional statement. |
|
| 284 | - | let saved = p.context; |
|
| 285 | - | set p.context = Context::Normal; |
|
| 286 | 283 | let args = try parseList( |
|
| 287 | 284 | p, |
|
| 288 | 285 | scanner::TokenKind::LParen, |
|
| 289 | 286 | scanner::TokenKind::RParen, |
|
| 290 | - | parseExpr |
|
| 287 | + | parseNormalExpr |
|
| 291 | 288 | ); |
|
| 292 | - | set p.context = saved; |
|
| 293 | 289 | return node(p, ast::NodeValue::Call( |
|
| 294 | 290 | ast::Call { callee, args } |
|
| 295 | 291 | )); |
|
| 296 | 292 | } |
|
| 297 | 293 |
| 339 | 335 | /// Parse array subscript or slice expression after `[`. |
|
| 340 | 336 | fn parseSubscriptOrSlice(p: *mut Parser, container: *ast::Node) -> *ast::Node |
|
| 341 | 337 | throws (ParseError) |
|
| 342 | 338 | { |
|
| 343 | 339 | try expect(p, scanner::TokenKind::LBracket, "expected `[`"); |
|
| 344 | - | let saved = p.context; |
|
| 345 | - | set p.context = Context::Normal; |
|
| 346 | 340 | ||
| 347 | 341 | let mut index: *ast::Node = undefined; |
|
| 348 | 342 | ||
| 349 | 343 | if consume(p, scanner::TokenKind::DotDot) { |
|
| 350 | 344 | // Either `..` or `..end`. |
|
| 351 | 345 | let mut endExpr: ?*ast::Node = nil; |
|
| 352 | 346 | if not check(p, scanner::TokenKind::RBracket) { |
|
| 353 | - | set endExpr = try parseExpr(p); |
|
| 347 | + | set endExpr = try parseNormalExpr(p); |
|
| 354 | 348 | } |
|
| 355 | 349 | set index = node(p, ast::NodeValue::Range( |
|
| 356 | 350 | ast::Range { start: nil, end: endExpr } |
|
| 357 | 351 | )); |
|
| 358 | 352 | } else { |
|
| 359 | 353 | // Either `n`, `n..` or `n..end`. |
|
| 360 | - | let startExpr = try parseExpr(p); |
|
| 354 | + | let startExpr = try parseNormalExpr(p); |
|
| 361 | 355 | ||
| 362 | 356 | if consume(p, scanner::TokenKind::DotDot) { |
|
| 363 | 357 | // Either `n..` or `n..end`. |
|
| 364 | 358 | let mut endExpr: ?*ast::Node = nil; |
|
| 365 | 359 | if not check(p, scanner::TokenKind::RBracket) { |
|
| 366 | - | set endExpr = try parseExpr(p); |
|
| 360 | + | set endExpr = try parseNormalExpr(p); |
|
| 367 | 361 | } |
|
| 368 | 362 | set index = node(p, ast::NodeValue::Range( |
|
| 369 | 363 | ast::Range { start: startExpr, end: endExpr } |
|
| 370 | 364 | )); |
|
| 371 | 365 | } else { |
|
| 372 | 366 | // Just `n` - regular indexing. |
|
| 373 | 367 | set index = startExpr; |
|
| 374 | 368 | } |
|
| 375 | 369 | } |
|
| 376 | 370 | try expect(p, scanner::TokenKind::RBracket, "expected `]` after array index"); |
|
| 377 | - | set p.context = saved; |
|
| 378 | 371 | ||
| 379 | 372 | return node(p, ast::NodeValue::Subscript { container, index }); |
|
| 380 | 373 | } |
|
| 381 | 374 | ||
| 382 | 375 | /// Parse postfix operators (eg. field access, function call etc.) |
lib/std/lang/resolver.rad
+27 -44
| 2920 | 2920 | } |
|
| 2921 | 2921 | ||
| 2922 | 2922 | /// Apply an integer cast to a constant value, including target-width |
|
| 2923 | 2923 | /// truncation and signed interpretation. |
|
| 2924 | 2924 | fn castConstInt(value: ConstInt, target: Type) -> ConstValue { |
|
| 2925 | - | // Convert sign-magnitude metadata to its two's-complement bit pattern. |
|
| 2926 | - | let raw = (0 - value.magnitude) if value.negative else value.magnitude; |
|
| 2925 | + | let raw = constIntToBits(value); |
|
| 2927 | 2926 | let range = integerRange(target) |
|
| 2928 | 2927 | else panic "castConstInt: expected integer type"; |
|
| 2929 | 2928 | ||
| 2930 | 2929 | match range { |
|
| 2931 | - | case IntegerRange::Unsigned { bits, max } => |
|
| 2932 | - | return constInt(raw & max, bits, false, false), |
|
| 2933 | - | case IntegerRange::Signed { bits, max, lim, .. } => { |
|
| 2934 | - | let mask = (max as u64) | lim; |
|
| 2935 | - | let truncated = raw & mask; |
|
| 2936 | - | if (truncated & lim) <> 0 { |
|
| 2937 | - | return constInt((0 - truncated) & mask, bits, true, true); |
|
| 2938 | - | } |
|
| 2939 | - | return constInt(truncated, bits, true, false); |
|
| 2940 | - | } |
|
| 2930 | + | case IntegerRange::Unsigned { bits, .. } => |
|
| 2931 | + | return ConstValue::Int(constIntFromBits(raw, bits, false)), |
|
| 2932 | + | case IntegerRange::Signed { bits, .. } => |
|
| 2933 | + | return ConstValue::Int(constIntFromBits(raw, bits, true)), |
|
| 2941 | 2934 | } |
|
| 2942 | 2935 | } |
|
| 2943 | 2936 | ||
| 2944 | 2937 | /// Return the constant `u32` value for a slice bound when known. |
|
| 2945 | 2938 | fn constSliceIndex(self: *mut Resolver, node: *ast::Node) -> ?u32 { |
| 6274 | 6267 | setNodeCoercion(self, node, Coercion::ResultWrap); |
|
| 6275 | 6268 | } |
|
| 6276 | 6269 | return setNodeType(self, node, Type::Never); |
|
| 6277 | 6270 | } |
|
| 6278 | 6271 | ||
| 6279 | - | /// Convert a [`ConstInt`] to its signed two's-complement representation. |
|
| 6280 | - | fn constIntToSigned(c: ConstInt) -> i64 { |
|
| 6281 | - | if c.negative { |
|
| 6282 | - | return -(c.magnitude as i64); |
|
| 6283 | - | } |
|
| 6284 | - | return c.magnitude as i64; |
|
| 6285 | - | } |
|
| 6286 | - | ||
| 6287 | 6272 | /// Convert a [`ConstInt`] to its two's-complement bit pattern. |
|
| 6288 | 6273 | fn constIntToBits(c: ConstInt) -> u64 { |
|
| 6289 | 6274 | return (0 - c.magnitude) if c.negative else c.magnitude; |
|
| 6290 | 6275 | } |
|
| 6291 | 6276 | ||
| 6277 | + | /// Convert a [`ConstInt`] to its signed two's-complement representation. |
|
| 6278 | + | fn constIntToSigned(c: ConstInt) -> i64 { |
|
| 6279 | + | return constIntToBits(c) as i64; |
|
| 6280 | + | } |
|
| 6281 | + | ||
| 6292 | 6282 | /// Build a [`ConstInt`] from a signed result, preserving bit width and signedness. |
|
| 6293 | 6283 | fn constIntFromSigned(value: i64, bits: u8, signed: bool) -> ConstInt { |
|
| 6294 | 6284 | if value < 0 { |
|
| 6295 | 6285 | // Compute magnitude without signed overflow. |
|
| 6296 | 6286 | let uval = value as u64; |
| 6505 | 6495 | } |
|
| 6506 | 6496 | } |
|
| 6507 | 6497 | let leftTy = try checkNumeric(self, binop.left); |
|
| 6508 | 6498 | let rightTy = try checkNumeric(self, binop.right); |
|
| 6509 | 6499 | ||
| 6510 | - | // Ordering comparisons use the concrete operand type. Only an |
|
| 6511 | - | // unsuffixed integer expression may differ from that type. |
|
| 6500 | + | let mut operandTy = leftTy; |
|
| 6501 | + | if leftTy <> rightTy { |
|
| 6502 | + | if leftTy == Type::Int { |
|
| 6503 | + | set operandTy = rightTy; |
|
| 6504 | + | } else if rightTy <> Type::Int { |
|
| 6505 | + | throw emitTypeMismatch(self, binop.right, TypeMismatch { |
|
| 6506 | + | expected: leftTy, |
|
| 6507 | + | actual: rightTy, |
|
| 6508 | + | }); |
|
| 6509 | + | } |
|
| 6510 | + | } |
|
| 6511 | + | ||
| 6512 | + | // Ordering comparisons return `bool`, not the operand type. |
|
| 6512 | 6513 | match binop.op { |
|
| 6513 | 6514 | case ast::BinaryOp::Lt, ast::BinaryOp::Gt, |
|
| 6514 | - | ast::BinaryOp::Lte, ast::BinaryOp::Gte => { |
|
| 6515 | - | if leftTy <> rightTy and leftTy <> Type::Int and rightTy <> Type::Int { |
|
| 6516 | - | throw emitTypeMismatch(self, binop.right, TypeMismatch { |
|
| 6517 | - | expected: leftTy, |
|
| 6518 | - | actual: rightTy, |
|
| 6519 | - | }); |
|
| 6520 | - | } |
|
| 6521 | - | set resultTy = Type::Bool; |
|
| 6522 | - | } else => { |
|
| 6523 | - | if leftTy == rightTy { |
|
| 6524 | - | set resultTy = leftTy; |
|
| 6525 | - | } else if leftTy == Type::Int { |
|
| 6526 | - | set resultTy = rightTy; |
|
| 6527 | - | } else if rightTy == Type::Int { |
|
| 6528 | - | set resultTy = leftTy; |
|
| 6529 | - | } else { |
|
| 6530 | - | throw emitTypeMismatch(self, binop.right, TypeMismatch { |
|
| 6531 | - | expected: leftTy, |
|
| 6532 | - | actual: rightTy, |
|
| 6533 | - | }); |
|
| 6534 | - | } |
|
| 6535 | - | } |
|
| 6515 | + | ast::BinaryOp::Lte, ast::BinaryOp::Gte => |
|
| 6516 | + | set resultTy = Type::Bool, |
|
| 6517 | + | else => |
|
| 6518 | + | set resultTy = operandTy, |
|
| 6536 | 6519 | } |
|
| 6537 | 6520 | ||
| 6538 | 6521 | } |
|
| 6539 | 6522 | }; |
|
| 6540 | 6523 | // Try constant folding after both operands are resolved. |