summaryrefslogtreecommitdiff
path: root/evaluate.h
blob: 9571626005eb6a8c2bfa52eb5a419e1ab8e963cc (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
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#pragma once

#include <iostream>
#include <string>
#include <unordered_map>
#include "ast.h"

using namespace std;


class CompilationError : public runtime_error{
public:
	explicit CompilationError(const string &what_arg);
	explicit CompilationError(const char *what_arg);
	CompilationError(Site site,const string &what_arg);
};

class ExecutionError : public runtime_error{
public:
	explicit ExecutionError(const string &what_arg);
	explicit ExecutionError(const char *what_arg);
};


class ScopeVal;
class Assembly;

class Value{
public:
	enum class Type{
		nil,
		number,  // numval
		string,  // strval
		scope,  // scopeval
		lazy,  // asmval
		function,  // asmval
	};

	Type type;
	double numval;
	string strval;
	ScopeVal *scopeval=nullptr;
	Assembly *asmval=nullptr;

	Value();
	Value(double numval);
	Value(const string &strval);
	Value(ScopeVal *scopeval);
	Value(Type type,Assembly *asmval);  // lazy, function
	Value(const Value &other);
	Value(Value &&other);
	~Value();

	Value& operator=(const Value &other) = delete;
	Value& operator=(Value &&other) = delete;
};

class ScopeVal{
public:
	ScopeDef scopeDef;
	unordered_map<string,Value> values;

	ScopeVal(const ScopeDef &scopeDef);
};


namespace A {

	template <typename T>
	T* ref(T *value);

	template <typename T>
	void unref(T *value);

	void unref_all();

}


class Assembly{
	class Instruction{
	public:
		enum class Type{
			pushnil,    // [ -> nil]
			pushnum,    // [ -> this.num]
			pushstr,    // [ -> this.str]
			pushscope,  // [ -> this.scope]
			pushfunc,   // [ -> Value(function,this.asmval)]
			newscope,   // [ -> {}]
			pop,        // [x -> ]
			swap,       // [x,y -> y,x]
			add,        // [x,y -> x+y]
			sub,        // [x,y -> x-y]
			mul,        // [x,y -> x*y]
			div,        // [x,y -> x/y]
			mod,        // [x,y -> x%y]
			create,     // [value -> ] Creates binding this.name in the top scope
			store,      // [value -> ] Stores in the first scope to contain a this.name binding
			load,       // [ -> value] Retrieves from the first scope to contain a this.name binding
			enter,      // [scope -> scope] Copies the given scope to the scope stack
			leave,      // [ -> ] Pops from the scope stack
			call,       // [scope,arg,...,arg -> scope] Pops this.nargs arguments and replaces for names from scope.scopeDef.args
		};

		Type type;
		double num;
		string str;
		ScopeDef *scope=nullptr;
		string name;
		int nargs;
		Assembly *asmval=nullptr;

		Instruction(Type type);
		Instruction(Type type,double num);  // pushnum
		Instruction(Type type,const string &str);  // pushstr, create, store, load
		Instruction(Type type,ScopeDef *scope);  // pushscope
		Instruction(Type type,int nargs);  // call
		Instruction(Type type,Assembly *asmval);  // pushfunc
		Instruction(const Instruction &other);
		Instruction(Instruction &&other);
		~Instruction();

		Instruction& operator=(const Instruction &other) = delete;
		Instruction& operator=(Instruction &&other) = delete;
	};

	vector<Instruction> listing;

	void codegen(const StatementList &stl);
	void codegen(const Statement &stmt);
	void codegen(const Expression &expr);

	Assembly(const ScopeDef &scopeDef);

public:
	Assembly(const StatementList &stl);

	friend ostream& operator<<(ostream &os,const Assembly &as);
};

ostream& operator<<(ostream &os,const Assembly &as);


class Context{
	vector<ScopeVal> sstack;

public:
	void evaluate(const Assembly &as);
};