summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes/simple/parser/Conversions.java
blob: d50e203138c8e73765c7e69555f13dcd5f6cf850 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.seaofnodes.simple.parser;

import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;

/** Shared declaration, assignment, and return conversions. */
final class Conversions {
    private final Parser P;

    Conversions(Parser P) { this.P = P; }

    // Widen ints to floats; narrow wide int types.
    // Early error if types do not match variable.
    Node convertExpr( Node expr, Type t ) {
        if( !expr._type.accessISA(t) )
            throw P.error("Type "+expr._type.str()+" is not of declared type "+t.str());
        if( t instanceof TypeMemPtr tmp && tmp.isFinal() )
            expr = P.peep(new ReadOnlyNode(expr));
        // A FunPtr carries the semantic edge to its function's Return.  Do not
        // hide that edge behind a Convert which can fold to a plain constant.
        if( expr instanceof FunPtrNode && t instanceof TypeFunPtr )
            return expr;
        // Auto-widen array to i64 (cast ptr to raw int bits)
        if( t == TypeInteger.BOT && expr._type instanceof TypeMemPtr tmp && tmp._obj.isAry() )
            return P.peep(new AddNode(P.peep(new PtrToIntNode(expr)),Parser.off(tmp._obj,"[]")));
        // Widen ints to floats, narrow wide types
        return P.peep(new ConvertNode(t,expr));
    }

    // Inferred `var` declarations describe writable slots, not the exact
    // value used to initialize them.  Explicitly typed locals retain the
    // user's nullability and numeric-width guarantees; `val` retains the
    // initializer's precise type.
    static Type mutableInferredType(Type t) {
        return switch( t ) {
        case TypeInteger ti -> TypeInteger.BOT;
        case TypeFloat   tf -> TypeFloat.F64;
        case TypeMemPtr tmp -> tmp.makeVar();
        case TypeFunPtr tfp -> tfp;
        case TypeConAry<?> a -> a;
        case TypePtr     ptr -> TypePtr.PTR;
        case TypeScalar  ts -> TypeScalar.BOT;
        default             -> t;
        };
    }

    Type constructorFieldType(Type t) {
        if( t instanceof TypeMemPtr ptr && ptr._obj.isConAry() ) {
            TypeStruct declared = (TypeStruct)Parser.TYPES.get(ptr._obj._name);
            TypeStruct shape = P.types.typeAry(declared._fields[1]._t,ptr._obj._fields[1]._final);
            return TypeMemPtr.make((byte)2,shape,false).withAccess(ptr._ro);
        }
        return mutableInferredType(t);
    }

    // Seed an inferred return merge with the declared numeric family instead
    // of a transient constant/range.  Pointer nullability remains part of the
    // inferred function result and is combined by the later Phi.
    static Type inferredReturnType(Type t) {
        return switch( t ) {
        case TypeInteger ti -> TypeInteger.BOT;
        case TypeFloat   tf -> TypeFloat.F64;
        default             -> t;
        };
    }

    Node widenInt( Node expr, Type t ) {
        return (expr._type instanceof TypeInteger || expr._type==Type.NIL) && t instanceof TypeFloat
            ? P.peep(new ToFloatNode(expr)) : expr;
    }

}