summaryrefslogtreecommitdiff
path: root/starts/meaning-vm/level-2-wip-stmtexprs/statementref.cpp
blob: 2f23dc85fa13aa622af8f01f155bc8edec6a0756 (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
#include "statementref.hpp"

#include "concepts.hpp"
#include "ref.hpp"

using namespace intellect;
using namespace level2;
using namespace concepts;

// so, anonymous-assignment is both a statement and an expression.
// multiple-member-assignment is only an expression: it is an error to evaluate it
// the submember operator will be both a statement and an expression, but doesn't need to be held as a ref
// single-member-assignment is mostly a statement: using it as an expression should be an error.

static statementref makebinary(
	ref lhs, ref kind, ref rhs,
	std::function<ref(ref)> expraction,
	std::function<void(ref)> stmtaction
)
{
	a(statement-expresion, kind-expression);
	ref r = a(kind-expression);
	r.set(left-operand, lhs);
	r.set(right-operand, rhs);
	r.vset(expression-action, expraction);
	r.vset(statement-action, stmtaction);
	return r;
}

statementref::statementref(ref r)
: r(r.ptr())
{
	if (!r.isa(statement-expression)) {
		throw std::logic_error("that is not a statement expression");
	}
}

static void de(ref & r)
{
	ref lhs, rhs, expraction, stmtaction;

	try { lhs = r.get(left-operand); } catch(level0::no_such_link_type&) {}
	try { rhs = r.get(right-operand); } catch(level0::no_such_link_type&) {}

	expraction = r.get(expression-action);
	stmtaction = r.get(statement-action);
	dealloc(r);
	if (lhs != nothing) { dealloc(lhs); }
	if (rhs != nothing) { dealloc(rhs); }
	dealloc(expraction);
	dealloc(stmtaction);
	r = 0;
}

statementref::~statementref()
{
	if (r == 0) { return; }
	r.vget<std::function<void(ref)>>(statement-action)(r);
	de(r);
}

statementref::operator ref()
{
	if (r == 0) { throw std::logic_error("doubly evaluated expression"); }
	auto ret = r.vget<std::function<void(ref)>>(expression-action)(r);
	de(r);
	return ret;
}