Add locale module
This commit is contained in:
		
							parent
							
								
									d1e521ba97
								
							
						
					
					
						commit
						218e6253e7
					
				
							
								
								
									
										61
									
								
								locale/locale.ha
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								locale/locale.ha
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
use errors;
 | 
			
		||||
use fmt;
 | 
			
		||||
use strings;
 | 
			
		||||
 | 
			
		||||
// A parsed locale name.
 | 
			
		||||
export type locale = struct {
 | 
			
		||||
	language: str,
 | 
			
		||||
	country:  str,
 | 
			
		||||
	encoding: str,
 | 
			
		||||
	modifier: str,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Parses a [[locale]] name of the form:
 | 
			
		||||
// 
 | 
			
		||||
//   lang_COUNTRY.ENCODING@MODIFIER
 | 
			
		||||
// 
 | 
			
		||||
// Where _COUNTRY, .ENCODING, and @MODIFIER may be omitted. The function
 | 
			
		||||
// returns a [[locale]], or [[errors::invalid]] if the input cannot be parsed.
 | 
			
		||||
// All memory is borrowed from the input.
 | 
			
		||||
export fn parse_locale(in: str) (locale | errors::invalid) = {
 | 
			
		||||
	let (in, modifier) = strings::rcut(in, "@");
 | 
			
		||||
	if (strings::compare(in, "") == 0) return void: errors::invalid;
 | 
			
		||||
	let (in, encoding) = strings::rcut(in, ".");
 | 
			
		||||
	if (strings::compare(in, "") == 0) return void: errors::invalid;
 | 
			
		||||
	let (in, country) = strings::rcut(in, "_");
 | 
			
		||||
	if (strings::compare(in, "") == 0) return void: errors::invalid;
 | 
			
		||||
	return locale {
 | 
			
		||||
		language = in,
 | 
			
		||||
		country  = country,
 | 
			
		||||
		encoding = encoding,
 | 
			
		||||
		modifier = modifier,
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Formats a [[locale]]. The caller must free the return value.
 | 
			
		||||
export fn format_locale(local: locale) str = {
 | 
			
		||||
	let output = strings::dup(local.language);
 | 
			
		||||
	if (strings::compare(local.country, "") != 0) {
 | 
			
		||||
		let new_output = strings::join("_", output, local.country);
 | 
			
		||||
		free(output);
 | 
			
		||||
		output = new_output;
 | 
			
		||||
	};
 | 
			
		||||
	if (strings::compare(local.encoding, "") != 0) {
 | 
			
		||||
		let new_output = strings::join(".", output, local.encoding);
 | 
			
		||||
		free(output);
 | 
			
		||||
		output = new_output;
 | 
			
		||||
	};
 | 
			
		||||
	if (strings::compare(local.modifier, "") != 0) {
 | 
			
		||||
		let new_output = strings::join("@", output, local.modifier);
 | 
			
		||||
		free(output);
 | 
			
		||||
		output = new_output;
 | 
			
		||||
	};
 | 
			
		||||
	return output;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Checks if two [[locale]]s are equal.
 | 
			
		||||
export fn locale_equal(a: locale, b: locale) bool =
 | 
			
		||||
	strings::compare(a.language, b.language) == 0 &&
 | 
			
		||||
	strings::compare(a.country,  b.country ) == 0 &&
 | 
			
		||||
	strings::compare(a.encoding, b.encoding) == 0 &&
 | 
			
		||||
	strings::compare(a.modifier, b.modifier) == 0;
 | 
			
		||||
							
								
								
									
										143
									
								
								locale/locale_test.ha
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								locale/locale_test.ha
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,143 @@
 | 
			
		||||
use fmt;
 | 
			
		||||
use errors;
 | 
			
		||||
use strings;
 | 
			
		||||
 | 
			
		||||
@test fn parse_locale_full() void = {
 | 
			
		||||
	let local = match(parse_locale("lang_COUNTRY.ENCODING@MODIFIER")) {
 | 
			
		||||
	case let local: locale => yield local;
 | 
			
		||||
	case                   => abort("error");
 | 
			
		||||
	};
 | 
			
		||||
	fmt::printf("[{}]\n", local.language)!;
 | 
			
		||||
	assert(strings::compare(local.language, "lang") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.country)!;
 | 
			
		||||
	assert(strings::compare(local.country, "COUNTRY") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.encoding)!;
 | 
			
		||||
	assert(strings::compare(local.encoding, "ENCODING") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.modifier)!;
 | 
			
		||||
	assert(strings::compare(local.modifier, "MODIFIER") == 0);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@test fn parse_locale_sparse_a() void = {
 | 
			
		||||
	let local = match(parse_locale("lang.ENCODING@MODIFIER")) {
 | 
			
		||||
	case let local: locale => yield local;
 | 
			
		||||
	case                   => abort("error");
 | 
			
		||||
	};
 | 
			
		||||
	fmt::printf("[{}]\n", local.language)!;
 | 
			
		||||
	assert(strings::compare(local.language, "lang") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.country)!;
 | 
			
		||||
	assert(strings::compare(local.country, "") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.encoding)!;
 | 
			
		||||
	assert(strings::compare(local.encoding, "ENCODING") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.modifier)!;
 | 
			
		||||
	assert(strings::compare(local.modifier, "MODIFIER") == 0);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@test fn parse_locale_sparse_b() void = {
 | 
			
		||||
	let local = match(parse_locale("lang.ENCODING")) {
 | 
			
		||||
	case let local: locale => yield local;
 | 
			
		||||
	case                   => abort("error");
 | 
			
		||||
	};
 | 
			
		||||
	fmt::printf("[{}]\n", local.language)!;
 | 
			
		||||
	assert(strings::compare(local.language, "lang") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.country)!;
 | 
			
		||||
	assert(strings::compare(local.country, "") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.encoding)!;
 | 
			
		||||
	assert(strings::compare(local.encoding, "ENCODING") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.modifier)!;
 | 
			
		||||
	assert(strings::compare(local.modifier, "") == 0);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@test fn parse_locale_sparse_c() void = {
 | 
			
		||||
	let local = match(parse_locale("lang")) {
 | 
			
		||||
	case let local: locale => yield local;
 | 
			
		||||
	case                   => abort("error");
 | 
			
		||||
	};
 | 
			
		||||
	fmt::printf("[{}]\n", local.language)!;
 | 
			
		||||
	assert(strings::compare(local.language, "lang") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.country)!;
 | 
			
		||||
	assert(strings::compare(local.country, "") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.encoding)!;
 | 
			
		||||
	assert(strings::compare(local.encoding, "") == 0);
 | 
			
		||||
	fmt::printf("[{}]\n", local.modifier)!;
 | 
			
		||||
	assert(strings::compare(local.modifier, "") == 0);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@test fn parse_locale_error() void = {
 | 
			
		||||
	let local = match(parse_locale("_COUNTRY.ENCODING@MODIFIER")) {
 | 
			
		||||
	case errors::invalid => void;
 | 
			
		||||
	case                 => abort("error");
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@test fn format_locale_a() void = {
 | 
			
		||||
	let string = format_locale(locale {
 | 
			
		||||
		language = "lang",
 | 
			
		||||
		country  = "COUNTRY",
 | 
			
		||||
		encoding = "ENCODING",
 | 
			
		||||
		modifier = "MODIFIER",
 | 
			
		||||
	});
 | 
			
		||||
	defer free(string);
 | 
			
		||||
	fmt::printf("[{}]\n", string)!;
 | 
			
		||||
	assert(strings::compare(string, "lang_COUNTRY.ENCODING@MODIFIER") == 0);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@test fn format_locale_b() void = {
 | 
			
		||||
	let string = format_locale(locale {
 | 
			
		||||
		language = "lang",
 | 
			
		||||
		country  = "COUNTRY",
 | 
			
		||||
		modifier = "MODIFIER",
 | 
			
		||||
		...
 | 
			
		||||
	});
 | 
			
		||||
	defer free(string);
 | 
			
		||||
	fmt::printf("[{}]\n", string)!;
 | 
			
		||||
	assert(strings::compare(string, "lang_COUNTRY@MODIFIER") == 0);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@test fn format_locale_c() void = {
 | 
			
		||||
	let string = format_locale(locale {
 | 
			
		||||
		language = "lang",
 | 
			
		||||
		...
 | 
			
		||||
	});
 | 
			
		||||
	defer free(string);
 | 
			
		||||
	fmt::printf("[{}]\n", string)!;
 | 
			
		||||
	assert(strings::compare(string, "lang") == 0);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@test fn locale_equal() void = {
 | 
			
		||||
	assert(locale_equal(locale {
 | 
			
		||||
		language = "lang",
 | 
			
		||||
		country  = "COUNTRY",
 | 
			
		||||
		encoding = "ENCODING",
 | 
			
		||||
		modifier = "MODIFIER",
 | 
			
		||||
	},
 | 
			
		||||
	locale {
 | 
			
		||||
		language = "lang",
 | 
			
		||||
		country  = "COUNTRY",
 | 
			
		||||
		encoding = "ENCODING",
 | 
			
		||||
		modifier = "MODIFIER",
 | 
			
		||||
	}));
 | 
			
		||||
	assert(!locale_equal(locale {
 | 
			
		||||
		language = "lang",
 | 
			
		||||
		country  = "COUNTRY",
 | 
			
		||||
		encoding = "ENCODING",
 | 
			
		||||
		modifier = "MODIFIER",
 | 
			
		||||
	},
 | 
			
		||||
	locale {
 | 
			
		||||
		language = "foo",
 | 
			
		||||
		country  = "COUNTRY",
 | 
			
		||||
		encoding = "ENCODING",
 | 
			
		||||
		modifier = "MODIFIER",
 | 
			
		||||
	}));
 | 
			
		||||
	assert(!locale_equal(locale {
 | 
			
		||||
		language = "lang",
 | 
			
		||||
		encoding = "ENCODING",
 | 
			
		||||
		modifier = "MODIFIER",
 | 
			
		||||
		...
 | 
			
		||||
	},
 | 
			
		||||
	locale {
 | 
			
		||||
		language = "lang",
 | 
			
		||||
		country  = "COUNTRY",
 | 
			
		||||
		encoding = "ENCODING",
 | 
			
		||||
		...
 | 
			
		||||
	}));
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user