aboutsummaryrefslogtreecommitdiff
path: root/kscurses/lambdas.jai
blob: fd5ffa45edf64c6a0d9ff67cbf94eec026768580 (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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
decl_lambda :: ($code_src : Code) -> Code #expand {
	node_src := compiler_get_nodes(code_src);
	proc_node, data_node, names, names_field, node_header, node_block := split_src(false, node_src);
	pair_names, pair_srcs := get_lambda_pairs(proc_node, data_node, names, names_field, node_header, node_block);
	return compiler_get_code(*Code_Compound_Declaration.{
		kind = .COMPOUND_DECLARATION,
		comma_separated_assignment = xx pair_names,
		declaration_properties = *Code_Declaration.{
			kind = .DECLARATION,
			expression = pair_srcs
		}
	});
}
assign_lambda :: ($code_src : Code, parent_scope := #caller_code) #expand {
	#insert,scope(parent_scope) #run _assign_lambda(code_src);	
}
struct_lambda :: ($code_src : Code, parent_scope := #caller_code) #expand {
	#insert,scope(parent_scope) #run _struct_lambda(code_src);
}
#scope_file
#import "Compiler";
#import "Basic";
#import "Program_Print";
debug_print_code :: (root : *Code_Node) {
	builder := String_Builder.{allocator = temp};
	print_expression(*builder, root);
	print("%\n", builder_to_string(*builder, allocator = temp));
}
_assign_lambda :: ($code_src : Code) -> Code {
	node_src := compiler_get_nodes(code_src);
	proc_node, data_node, names, names_field, node_header, node_block := split_src(false, node_src);
	pair_names, pair_srcs := get_lambda_pairs(proc_node, data_node, names, names_field, node_header, node_block);
	node_assign := Code_Binary_Operator.{
		kind = .BINARY_OPERATOR,
		operator_type = #char"=",
		left = pair_names,
		right = pair_srcs
	};
	return compiler_get_code(*node_assign);
}
_struct_lambda :: ($code_src : Code) -> Code {
	node_src := compiler_get_nodes(code_src);
	proc_node, data_node, names, names_field, node_header, node_block := split_src(true, node_src);
	pair_names, pair_srcs := get_lambda_pairs(proc_node, data_node, names, names_field, node_header, node_block);
	node_assign := Code_Binary_Operator.{
		kind = .BINARY_OPERATOR,
		operator_type = #char"=",
		left = pair_names,
		right = pair_srcs
	};
	debug_print_code(*node_assign);
	return compiler_get_code(*node_assign);
}
//TODO add support for non-"proc/data" names
split_src :: (gen_pair : bool, node_src : *Code_Node) -> proc_node:*Code_Node, data_node:*Code_Node, names:[]string, names_field:[]string, node_header:*Code_Procedure_Header, node_block:*Code_Block #expand {
	offset := ifx gen_pair then 1 else 2;
	assert(node_src.kind == .BLOCK);
	node_src_block := cast(*Code_Block) node_src;
	node_src_statements := node_src_block.statements;
	captured_count := node_src_statements.count - 2 - offset;
	assert(captured_count >= 0);
	names := NewArray(captured_count, string);
	names_field := NewArray(captured_count, string);
	for i : offset..captured_count-1+offset {
		assert(node_src_statements[i].kind == .IDENT);
	}
	for i : 0..captured_count-1 {
		name := (cast(*Code_Ident)node_src_statements[i + offset]).name;
		names[i], names_field[i] = name, sprint("_%", name);
	}
	assert(node_src_statements[captured_count + offset].kind == .PROCEDURE_HEADER);
	node_header := cast(*Code_Procedure_Header) node_src_statements[captured_count + offset];
	assert(node_src_statements[captured_count + offset + 1].kind == .BLOCK);
	node_block := cast(*Code_Block) node_src_statements[captured_count + offset + 1];
	assert(node_block.block_type == .IMPERATIVE);
	proc_node, data_node : *Code_Node;
	if gen_pair {
		proc_node = *Code_Binary_Operator.{
			kind = .BINARY_OPERATOR,
			operator_type = #char".",
			left = node_src_statements[0],
			right = *Code_Ident.{
				kind = .IDENT,
				name = "proc"
			}
		};
		data_node = *Code_Binary_Operator.{
			kind = .BINARY_OPERATOR,
			operator_type = #char".",
			left = node_src_statements[0],
			right = *Code_Ident.{
				kind = .IDENT,
				name = "data"
			}
		};
	} else {
		proc_node, data_node = node_src_statements[0], node_src_statements[1];
	}
	return proc_node, data_node, names, names_field, node_header, node_block;
}
gen_struct_type_node :: (names : []string, names_field : []string) -> *Code_Node #expand {
	captured_count := names.count;
	nodes_ident := NewArray(captured_count, Code_Ident);
	nodes_ptr := NewArray(captured_count, Code_Unary_Operator);
	nodes_typeof := NewArray(captured_count, Code_Size_Or_Type_Info);
	nodes_type := NewArray(captured_count, Code_Type_Instantiation);
	nodes_declaration := NewArray(captured_count, Code_Declaration);
	nodes_declaration_ptr := NewArray(captured_count, *Code_Node);
	for i : 0..captured_count-1 {
		nodes_ident[i] = .{
			kind = .IDENT,
			name = names[i]
		};
		nodes_ptr[i] = .{
			kind = .UNARY_OPERATOR,
			operator_type = #char"*",
			subexpression = *(nodes_ident[i])			
		};
		nodes_typeof[i] = .{
			kind = .SIZE_OR_TYPE_INFO,
			query_kind = .TYPE_OF,
			type_of_expression = *(nodes_ptr[i])
		};
		nodes_type[i] = .{
			kind = .TYPE_INSTANTIATION,
			type_valued_expression = *(nodes_typeof[i])
		};
		nodes_declaration[i] = .{
			kind = .DECLARATION,
			name = names_field[i],
			type_inst = *(nodes_type[i])
		};
		nodes_declaration_ptr[i] = *(nodes_declaration[i]);
	}
	node_struct := Code_Struct.{
		kind = .STRUCT,
		block = *Code_Block.{
			kind = .BLOCK,
			block_type = .DATA_DECLARATIONS,
			statements = nodes_declaration_ptr
		}
	};
	return *node_struct;
}
//TODO better assertions
get_lambda_pairs :: (proc_node:*Code_Node, data_node:*Code_Node, names:[]string, names_field:[]string, node_header:*Code_Procedure_Header, node_block:*Code_Block) -> pair_names:*Code_Node, pair_srcs:*Code_Node #expand {
	node_0 := gen_struct_type_node(names, names_field);
	stat_count := node_block.statements.count;
	nodes_new_statements := NewArray(stat_count + 1, *Code_Node);
	for i : 0..stat_count-1 {
		nodes_new_statements[i + 1] = node_block.statements[i];
	}
	nodes_new_statements[0] = *Code_Using.{
		kind = .USING,
		expression = *Code_Cast.{
			kind = .CAST,
			target_type = *Code_Type_Instantiation.{
				kind = .TYPE_INSTANTIATION,
				type_valued_expression = *Code_Unary_Operator.{
					kind = .UNARY_OPERATOR,
					subexpression = node_0,
					operator_type = #char"*"
				}
			},
			expression = *Code_Ident.{
				kind = .IDENT,
				name = "__data"
			}
		}
	};
	arg_count := node_header.arguments.count;
	node_new_args := NewArray(arg_count + 1, *Code_Declaration);
	for i : 0..arg_count-1 {
		node_new_args[i] = node_header.arguments[i];
	}
	node_new_args[arg_count] = *Code_Declaration.{
		kind = .DECLARATION,
		name = "__data",
		type_inst = *Code_Type_Instantiation.{
			kind = .TYPE_INSTANTIATION,
			type_valued_expression = *Code_Unary_Operator.{
				kind = .UNARY_OPERATOR,
				operator_type = #char"*",
				subexpression = *Code_Ident.{
					kind = .IDENT,
					name = "void"
				}
			}
		}
	};
	nodes_13 := NewArray(names.count, Code_Ident);
	nodes_14 := NewArray(names.count, Code_Unary_Operator);
	nodes_14_ptr := NewArray(names.count, *Code_Node);
	for i : 0..names.count-1 {
		nodes_13[i] = Code_Ident.{
			kind = .IDENT,
			name = names[i]
		};
		nodes_14[i] = Code_Unary_Operator.{
			kind = .UNARY_OPERATOR,
			subexpression = *(nodes_13[i]),
			operator_type = #char"*"
		};
		nodes_14_ptr[i] = *(nodes_14[i]);
	}
	exprs : [2]*Code_Node;
	exprs[0] = *Code_Procedure_Header.{
		kind = .PROCEDURE_HEADER,
		arguments = node_new_args,
		returns = node_header.returns,
		body_or_null = *Code_Procedure_Body.{
			kind = .PROCEDURE_BODY,
			block = *Code_Block.{
				kind = .BLOCK,
				statements = nodes_new_statements
			}
		}
	};
	exprs[1] = *Code_Unary_Operator.{
		kind = .UNARY_OPERATOR,
		operator_type = #char"*",
		subexpression = *Code_Literal.{
			kind = .LITERAL,
			value_type = .STRUCT,
			struct_literal_info = *Code_Struct_Literal_Info.{
				type_expression = *Code_Type_Instantiation.{
					kind = .TYPE_INSTANTIATION,
					type_valued_expression = node_0
				},
				arguments = nodes_14_ptr
			}
		}
	};
	_exprs : [2]Code_Comma_Separated_Argument = .[
		.{exprs[0], .NONE},
		.{exprs[1], .NONE},
	];
	node_19 := Code_Comma_Separated_Arguments.{
		kind = .COMMA_SEPARATED_ARGUMENTS,
		arguments = _exprs
	};
	exprs2 : [2]*Code_Node;
	exprs2[0] = proc_node;
	exprs2[1] = data_node;
	_exprs2 : [2]Code_Comma_Separated_Argument = .[
		.{exprs2[0], .NONE},
		.{exprs2[1], .NONE},
	];

	node_22 := Code_Comma_Separated_Arguments.{
		kind = .COMMA_SEPARATED_ARGUMENTS,
		arg = _exprs2
	};
	return *node_22, *node_19;
}