kym-tables-overhaul #30
| @ -270,63 +270,168 @@ pub fn parse_expression(self: *Self) ParseError!Expression { | ||||
| fn parse_factor(self: *Self) ParseError!Expression { | ||||
| 	const allocator = self.arena.as_allocator(); | ||||
| 
 | ||||
| 	switch (self.tokenizer.token) { | ||||
| 		.symbol_paren_left => { | ||||
| 			self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 			if (self.tokenizer.token == .end) { | ||||
| 				return self.report("expected an expression after `(`"); | ||||
| 			} | ||||
| 
 | ||||
| 			const expression = try self.parse_expression(); | ||||
| 
 | ||||
| 			if (self.tokenizer.token != .symbol_paren_right) { | ||||
| 				return self.report("expected a closing `)` after expression"); | ||||
| 			} | ||||
| 
 | ||||
| 			self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 			return Expression{.grouped_expression = try coral.io.allocate_one(allocator, expression)}; | ||||
| 		}, | ||||
| 
 | ||||
| 		.keyword_nil => { | ||||
| 			self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 			return .nil_literal; | ||||
| 		}, | ||||
| 
 | ||||
| 		.keyword_true => { | ||||
| 			self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 			return .true_literal; | ||||
| 		}, | ||||
| 
 | ||||
| 		.keyword_false => { | ||||
| 			self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 			return .false_literal; | ||||
| 		}, | ||||
| 
 | ||||
| 		.number => |value| { | ||||
| 			self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 			return .{.number_literal = value}; | ||||
| 		}, | ||||
| 
 | ||||
| 		.string => |value| { | ||||
| 			self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 			return .{.string_literal = value}; | ||||
| 		}, | ||||
| 
 | ||||
| 		.identifier => |local_identifier| { | ||||
| 			var expression = Expression{.get_local = local_identifier}; | ||||
| 
 | ||||
| 			self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 			while (self.tokenizer.token == .symbol_period) { | ||||
| 	var expression = @as(Expression, parse: { | ||||
| 		switch (self.tokenizer.token) { | ||||
| 			.symbol_paren_left => { | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				if (self.tokenizer.token == .end) { | ||||
| 					return self.report("expected an expression after `(`"); | ||||
| 				} | ||||
| 
 | ||||
| 				const expression = try self.parse_expression(); | ||||
| 
 | ||||
| 				if (self.tokenizer.token != .symbol_paren_right) { | ||||
| 					return self.report("expected a closing `)` after expression"); | ||||
| 				} | ||||
| 
 | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				break: parse .{.grouped_expression = try coral.io.allocate_one(allocator, expression)}; | ||||
| 			}, | ||||
| 
 | ||||
| 			.keyword_nil => { | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				break: parse .nil_literal; | ||||
| 			}, | ||||
| 
 | ||||
| 			.keyword_true => { | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				break: parse .true_literal; | ||||
| 			}, | ||||
| 
 | ||||
| 			.keyword_false => { | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				break: parse .false_literal; | ||||
| 			}, | ||||
| 
 | ||||
| 			.number => |value| { | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				break: parse .{.number_literal = value}; | ||||
| 			}, | ||||
| 
 | ||||
| 			.string => |value| { | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				break: parse .{.string_literal = value}; | ||||
| 			}, | ||||
| 
 | ||||
| 			.identifier => |local_identifier| { | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				break: parse .{.get_local = local_identifier}; | ||||
| 			}, | ||||
| 
 | ||||
| 			.symbol_brace_left => { | ||||
| 				var table_literal = Expression.TableLiteral.make(allocator); | ||||
| 
 | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				while (true) { | ||||
| 					switch (self.tokenizer.token) { | ||||
| 						.symbol_brace_right => { | ||||
| 							self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 							break: parse .{.table_literal = table_literal}; | ||||
| 						}, | ||||
| 
 | ||||
| 						.symbol_bracket_left => { | ||||
| 							self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 							if (self.tokenizer.token != .symbol_equals) { | ||||
| 								return self.report("expected expression after identifier"); | ||||
| 							} | ||||
| 						}, | ||||
| 
 | ||||
| 						.symbol_period => { | ||||
| 							self.tokenizer.step(); | ||||
| 
 | ||||
| 							const identifier = switch (self.tokenizer.token) { | ||||
| 								.identifier => |identifier| identifier, | ||||
| 								else => return self.report("expected identifier after `.`"), | ||||
| 							}; | ||||
| 
 | ||||
| 							self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 							if (self.tokenizer.token != .symbol_equals) { | ||||
| 								return self.report("expected `=` after key"); | ||||
| 							} | ||||
| 
 | ||||
| 							self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 							if (self.tokenizer.token == .end) { | ||||
| 								return self.report("unexpected end after `=`"); | ||||
| 							} | ||||
| 
 | ||||
| 							try table_literal.push_one(.{ | ||||
| 								.value_expression = try self.parse_expression(), | ||||
| 								.key_expression = .{.symbol_literal = identifier}, | ||||
| 							}); | ||||
| 
 | ||||
| 							switch (self.tokenizer.token) { | ||||
| 								.symbol_comma => self.tokenizer.skip_newlines(), | ||||
| 
 | ||||
| 								.symbol_brace_right => { | ||||
| 									self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 									break: parse .{.table_literal = table_literal}; | ||||
| 								}, | ||||
| 
 | ||||
| 								else => return self.report("expected `,` or `}` after expression"), | ||||
| 							} | ||||
| 						}, | ||||
| 
 | ||||
| 						else => return self.report("expected `}` or fields in table literal"), | ||||
| 					} | ||||
| 				} | ||||
| 			}, | ||||
| 
 | ||||
| 			.symbol_minus => { | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				if (self.tokenizer.token == .end) { | ||||
| 					return self.report("expected expression after numeric negation (`-`)"); | ||||
| 				} | ||||
| 
 | ||||
| 				break: parse .{ | ||||
| 					.unary_operation = .{ | ||||
| 						.expression = try coral.io.allocate_one(allocator, try self.parse_factor()), | ||||
| 						.operator = .numeric_negation, | ||||
| 					}, | ||||
| 				}; | ||||
| 			}, | ||||
| 
 | ||||
| 			.symbol_bang => { | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				if (self.tokenizer.token == .end) { | ||||
| 					return self.report("expected expression after boolean negation (`!`)"); | ||||
| 				} | ||||
| 
 | ||||
| 				break: parse .{ | ||||
| 					.unary_operation = .{ | ||||
| 						.expression = try coral.io.allocate_one(allocator, try self.parse_factor()), | ||||
| 						.operator = .boolean_negation, | ||||
| 					}, | ||||
| 				}; | ||||
| 			}, | ||||
| 
 | ||||
| 			else => return self.report("unexpected token in expression"), | ||||
| 		} | ||||
| 	}); | ||||
| 
 | ||||
| 	while (true) { | ||||
| 		switch (self.tokenizer.token) { | ||||
| 			.symbol_period => { | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 				// TODO: Remove when Zig fixes miscompilation with in-place struct re-assignment. | ||||
| 				const unnecessary_temp = try coral.io.allocate_one(allocator, expression); | ||||
| 
 | ||||
| 				expression = .{ | ||||
| 					.get_field = .{ | ||||
| 						.identifier = switch (self.tokenizer.token) { | ||||
| @ -334,112 +439,18 @@ fn parse_factor(self: *Self) ParseError!Expression { | ||||
| 							else => return self.report("expected identifier after `.`"), | ||||
| 						}, | ||||
| 
 | ||||
| 						.object_expression = try coral.io.allocate_one(allocator, expression), | ||||
| 						.object_expression = unnecessary_temp, | ||||
| 					}, | ||||
| 				}; | ||||
| 
 | ||||
| 				self.tokenizer.skip_newlines(); | ||||
| 			} | ||||
| 			}, | ||||
| 
 | ||||
| 			return expression; | ||||
| 		}, | ||||
| 
 | ||||
| 		.symbol_brace_left => { | ||||
| 			var table_literal = Expression.TableLiteral.make(allocator); | ||||
| 
 | ||||
| 			self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 			while (true) { | ||||
| 				switch (self.tokenizer.token) { | ||||
| 					.symbol_brace_right => { | ||||
| 						self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 						return .{.table_literal = table_literal}; | ||||
| 					}, | ||||
| 
 | ||||
| 					.symbol_bracket_left => { | ||||
| 						self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 						if (self.tokenizer.token != .symbol_equals) { | ||||
| 							return self.report("expected expression after identifier"); | ||||
| 						} | ||||
| 					}, | ||||
| 
 | ||||
| 					.symbol_period => { | ||||
| 						self.tokenizer.step(); | ||||
| 
 | ||||
| 						const identifier = switch (self.tokenizer.token) { | ||||
| 							.identifier => |identifier| identifier, | ||||
| 							else => return self.report("expected identifier after `.`"), | ||||
| 						}; | ||||
| 
 | ||||
| 						self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 						if (self.tokenizer.token != .symbol_equals) { | ||||
| 							return self.report("expected `=` after key"); | ||||
| 						} | ||||
| 
 | ||||
| 						self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 						if (self.tokenizer.token == .end) { | ||||
| 							return self.report("unexpected end after `=`"); | ||||
| 						} | ||||
| 
 | ||||
| 						try table_literal.push_one(.{ | ||||
| 							.value_expression = try self.parse_expression(), | ||||
| 							.key_expression = .{.symbol_literal = identifier}, | ||||
| 						}); | ||||
| 
 | ||||
| 						switch (self.tokenizer.token) { | ||||
| 							.symbol_comma => self.tokenizer.skip_newlines(), | ||||
| 
 | ||||
| 							.symbol_brace_right => { | ||||
| 								self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 								return .{.table_literal = table_literal}; | ||||
| 							}, | ||||
| 
 | ||||
| 							else => return self.report("expected `,` or `}` after expression"), | ||||
| 						} | ||||
| 					}, | ||||
| 
 | ||||
| 					else => return self.report("expected `}` or fields in table literal"), | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| 
 | ||||
| 		.symbol_minus => { | ||||
| 			self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 			if (self.tokenizer.token == .end) { | ||||
| 				return self.report("expected expression after numeric negation (`-`)"); | ||||
| 			} | ||||
| 
 | ||||
| 			return .{ | ||||
| 				.unary_operation = .{ | ||||
| 					.expression = try coral.io.allocate_one(allocator, try self.parse_factor()), | ||||
| 					.operator = .numeric_negation, | ||||
| 				}, | ||||
| 			}; | ||||
| 		}, | ||||
| 
 | ||||
| 		.symbol_bang => { | ||||
| 			self.tokenizer.skip_newlines(); | ||||
| 
 | ||||
| 			if (self.tokenizer.token == .end) { | ||||
| 				return self.report("expected expression after boolean negation (`!`)"); | ||||
| 			} | ||||
| 
 | ||||
| 			return .{ | ||||
| 				.unary_operation = .{ | ||||
| 					.expression = try coral.io.allocate_one(allocator, try self.parse_factor()), | ||||
| 					.operator = .boolean_negation, | ||||
| 				}, | ||||
| 			}; | ||||
| 		}, | ||||
| 
 | ||||
| 		else => return self.report("unexpected token in expression"), | ||||
| 			else => break, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return expression; | ||||
| } | ||||
| 
 | ||||
| const parse_term = binary_operation_parser(parse_factor, &.{ | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user