File: cast.bs

package info (click to toggle)
storm-lang 0.7.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 51,836 kB
  • sloc: ansic: 261,420; cpp: 138,870; sh: 14,877; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (115 lines) | stat: -rw-r--r-- 2,696 bytes parent folder | download | duplicates (4)
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use core:lang;
use core:asm;
use lang:bs:macro;

on Compiler:

// De-reference a reference, if applicable.
Expr deref(Expr refExpr) {
	if (refExpr.result.type.isCppRef) {
		Deref:ref(refExpr);
	} else {
		refExpr;
	}
}

// Assume we can cast whatever expression is available to the specified type. Throws an exception otherwise.
Expr expectCast(Expr of, Type to) {
	ExprResult r = of.result;
	if (r.nothing)
		return of;

	if (r.type.type is to)
		return of;

	if (of.suggestResult(to))
		return of;

	of = deref(of);
	Value type = of.result.type;
	if (type.type is to)
		return of;

	if (from = type.type) {
		// Pointers are binary compatible, so this will work unless some of the expr:s are overly pedantic.
		if (castablePtr(from, to))
			return of;
	}

	if (inside = to.isCppRRef()) {
		// Possible to make it an r-value reference?
		if (of.temporary & Value(inside).mayReferTo(type.asRef(false)))
			return MakeRRef(of);
	} else if (inside = to.isCppRef()) {
		// Regular reference?
		if (!to.isCppConst() & of.temporary) {
		} else if (Value(inside).mayReferTo(type.asRef(false))) {
			return MakeRef(of);
		}
	}

	throw SyntaxError(of.pos, "Expected type ${to.identifier()}, but got ${r.type}");
}

// Compute the cast penalty for a value.
Int castPenalty(Expr e, Type to) {
	ExprResult r = e.result;
	if (r.nothing)
		return 0;

	// No work to be done here!
	Value type = r.type;
	if (type.type is to)
		return 0;

	// Is 'e' able to produce the type directly?
	if (e.suggestResult(to))
		return 1;

	// If 'e' is a reference, "dereference" that.
	type = unwrapRef(type);
	if (type.type is to)
		return 0;

	// Check if both 'type' and 'to' are pointers, but they differ in "const" or have compatible types.
	if (from = type.type) {
		if (castablePtr(from, to))
			return 1;
	}

	if (inside = to.isCppRRef()) {
		// If we're a temporary, we can be bound to an rvalue reference.
		if (e.temporary & Value(inside).mayReferTo(type.asRef(false)))
			return 0;
	} else if (inside = to.isCppRef()) {
		// Is it possible that "to" is a reference? Make this a bit more expensive, to make the
		// rvalue ref take precedence if we have multiple options.
		if (!to.isCppConst() & (e.temporary | e.constant))
			return -1;
		if (Value(inside).mayReferTo(type.asRef(false)))
			return 1;
	}

	return -1;
}

// Check if 'from' and 'to' are compatible pointer types.
Bool castablePtr(Type from, Type to) {
	unless (to as PtrType)
		return false;
	unless (from as PtrType)
		return false;

	if (!from.isPtr | !to.isPtr)
		return false;

	if (!to.params[0].mayReferTo(from.params[0]))
		return false;

	// Matching const, or can we add const?
	if (from.isConst & !to.isConst)
		return false;

	true;
}