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
Alexis Sellier committed ago 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.