Desktop entry module almost compiles

This commit is contained in:
Sasha Koshka 2024-10-12 23:34:57 -04:00
parent 3e72688127
commit e8af5d01d7
2 changed files with 68 additions and 44 deletions

View File

@ -31,22 +31,22 @@ export type comment = str;
// Specification: §3.3 // Specification: §3.3
export type entry = struct { export type entry = struct {
key: str, key: str,
value: value, value: str,
}; };
// A localized key/value pair. // A localized key/value pair.
// Specification: §5 // Specification: §5
export type localized_entry = struct { export type localized_entry = struct {
key: str, key: str,
value: value, value: str,
locale: locale::locale, locale: locale::locale,
}; };
// Gets a non-localized [[value]] from a [[file]]. If the group does not exist, // Gets a non-localized [[value]] from a [[file]]. If the group does not exist,
// or the group exists but the key isn't in it, it returns void. // or the group exists but the key isn't in it, it returns void.
export fn file_get(fil: *file, group_name: str, key: str) (value | void) = { export fn file_get(fil: *file, group_name: str, key: str) (str | void) = {
let grou = match (file_find_group(fil, group_name)) { let grou = match (file_find_group(fil, group_name)) {
case let index: size => yield &fil.groups[index]; case let index: size => yield fil.groups[index];
case void => return void; case void => return void;
}; };
let lin = match (group_find_entry(grou, key)) { let lin = match (group_find_entry(grou, key)) {
@ -70,9 +70,9 @@ export fn file_get_localized(
group_name: str, group_name: str,
key: str, key: str,
local: locale::locale, local: locale::locale,
) (value | void) = { ) (str | void) = {
let grou = match (file_find_group(fil, group_name)) { let grou = match (file_find_group(fil, group_name)) {
case let index: size => yield &fil.groups[index]; case let index: size => yield fil.groups[index];
case void => return void; case void => return void;
}; };
let lin = match (group_find_localized_entry(grou, key, local)) { let lin = match (group_find_localized_entry(grou, key, local)) {
@ -103,15 +103,37 @@ export fn file_get_localized(
//export fn file_encode //export fn file_encode
// Frees memory associated with a [[file]]. // Frees memory associated with a [[file]].
export fn file_finish(fil *file) void = { export fn file_finish(fil: *file) void = {
for (let lin .. file.lines) { for (let lin .. fil.preceeding_lines) {
line_finish(lin); line_finish(lin);
}; };
free(file.lines); free(fil.preceeding_lines);
for (let grou .. file.groups) { for (let grou .. fil.groups) {
group_finish(grou); group_finish(grou);
}; };
free(file.groups); free(fil.groups);
};
// Frees memory associated with a [[line]].
export fn line_finish(lin: line) void = match (lin) {
case let lin: comment =>
free(lin);
case let lin: entry =>
free(lin.key);
free(lin.value);
case let lin: localized_entry =>
free(lin.key);
free(lin.value);
locale::finish(lin.locale);
case => void;
};
// Frees memory associated with a [[group]].
export fn group_finish(grou: group) void = {
for (let lin .. grou.lines) {
line_finish(lin);
};
free(grou.lines);
}; };
fn file_find_group(fil: *file, group_name: str) (size | void) = { fn file_find_group(fil: *file, group_name: str) (size | void) = {
@ -124,7 +146,7 @@ fn file_find_group(fil: *file, group_name: str) (size | void) = {
}; };
}; };
fn group_find_entry(grou: *group, key: str) (size | void) = { fn group_find_entry(grou: group, key: str) (size | void) = {
let index = 0z; let index = 0z;
for (let lin .. grou.lines) { for (let lin .. grou.lines) {
match (lin) { match (lin) {
@ -138,7 +160,7 @@ fn group_find_entry(grou: *group, key: str) (size | void) = {
}; };
}; };
fn group_find_localized_entry(grou: *group, key: str, local: locale::locale) (size | void) = { fn group_find_localized_entry(grou: group, key: str, local: locale::locale) (size | void) = {
// The matching is done as follows. If LC_MESSAGES is of the form // The matching is done as follows. If LC_MESSAGES is of the form
// lang_COUNTRY.ENCODING@MODIFIER, then it will match a key of the form // lang_COUNTRY.ENCODING@MODIFIER, then it will match a key of the form
// lang_COUNTRY@MODIFIER. If such a key does not exist, it will attempt // lang_COUNTRY@MODIFIER. If such a key does not exist, it will attempt

View File

@ -1,14 +1,16 @@
use encoding;
use bufio; use bufio;
use encoding::utf8;
use io; use io;
use locale;
use memio; use memio;
use strings;
// Parses a [[file]]. The result must be freed using [[file_finish]]. // Parses a [[file]]. The result must be freed using [[file_finish]].
export fn file_parse(in: io::stream) (file | error | io::error | utf8::invalid) = { export fn file_parse(in: io::stream) !(file | error | io::error | utf8::invalid) = {
let scanner = bufio::newscanner(in); let scanner = bufio::newscanner(&in);
defer bufio::finish(scanner); defer bufio::finish(&scanner);
let fil: file = { ... }; let fil = file { ... };
for (true) { for (true) {
let text = match (bufio::scan_line(&scanner)) { let text = match (bufio::scan_line(&scanner)) {
@ -17,35 +19,35 @@ export fn file_parse(in: io::stream) (file | error | io::error | utf8::invalid)
case let err: io::EOF => case let err: io::EOF =>
break; break;
case let err: (io::error | utf8::invalid) => case let err: (io::error | utf8::invalid) =>
file_finish(fil); file_finish(&fil);
return err; return err;
}; };
if (text == "") { if (text == "") {
// blank line // blank line
file_append_line(fil, blank); file_append_line(&fil, blank);
} else if (strings::has_prefix(text, '#')) { } else if (strings::hasprefix(text, '#')) {
// comment // comment
let text = strings::dup(strings::ltrim(text, '#')); let text = strings::dup(strings::ltrim(text, '#'));
file_append_line(fil, text: comment); file_append_line(&fil, text: comment);
} else if (strings::has_prefix(text, '[')) { } else if (strings::hasprefix(text, '[')) {
// group header // group header
let name = strings::dup(parse_group_header(text)?); let name = strings::dup(parse_group_header(text)?);
file_append_group(fil, name); file_append_group(&fil, name);
} else { } else {
// key/value pair // key/value pair
let (key, valu, local) = match (parse_entry()) { let (key, valu, local) = match (parse_entry(text)) {
case let result: (str, value, (locale::locale | void)) => case let result: (str, str, (locale::locale | void)) =>
yield result; yield result;
case let err: error => case let err: error =>
file_finish(fil); file_finish(&fil);
return err; return err;
}; };
file_append_line(fil, match (local) { file_append_line(&fil, match (local) {
case let local: locale::locale => case let local: locale::locale =>
yield localized_entry { yield localized_entry {
key = key, key = key,
@ -63,9 +65,9 @@ export fn file_parse(in: io::stream) (file | error | io::error | utf8::invalid)
return fil; return fil;
}; };
fn file_append_line(fil: *file, lin: line) = { fn file_append_line(fil: *file, lin: line) void = {
if (len(fil.groups) > 0) { if (len(fil.groups) > 0) {
append(fil.groups[len(fil.groups - 1)].lines, lin); append(fil.groups[len(fil.groups) - 1].lines, lin);
} else { } else {
append(fil.preceeding_lines, lin); append(fil.preceeding_lines, lin);
}; };
@ -73,37 +75,37 @@ fn file_append_line(fil: *file, lin: line) = {
// memory is borrowed from the input // memory is borrowed from the input
fn parse_group_header(text: str) (str | error) = { fn parse_group_header(text: str) (str | error) = {
if !strings::has_prefix(text, '[') || !strings::has_suffix(text, ']') { if (!strings::hasprefix(text, '[') || !strings::hassuffix(text, ']')) {
return error::INVALID_GROUP_HEADER; return invalid_group_header;
}; };
text = strings::rtrim(strings::ltrim(text, '['), ']'); text = strings::rtrim(strings::ltrim(text, '['), ']');
if strings::contains(text, '[', ']') { if (strings::contains(text, '[', ']')) {
return error::INVALID_GROUP_HEADER; return invalid_group_header;
}; };
return text; return text;
}; };
// memory must be freed by the caller // memory must be freed by the caller
fn parse_entry(line: str) ((str, str, (locale::locale | void)) | error) = { fn parse_entry(line: str) ((str, str, (locale::locale | void)) | error) = {
if !strings::contains(line, '=') return error::INVALID_ENTRY; if (!strings::contains(line, '=')) return invalid_entry;
let key, valu_string = strings::cut(line, '='); let (key, valu) = strings::cut(line, "=");
key = strings::ltrim(strings::rtrim(key)); key = strings::ltrim(strings::rtrim(key));
if !validate_entry_key(key) return error::INVALID_ENTRY; if (!validate_entry_key(key)) return invalid_entry;
let local = (locale::locale | void) = void; let local: (locale::locale | void) = void;
let (key, local_string) = strings::cut(key, '['); let (key, local_string) = strings::cut(key, "[");
if (local_string != "") { if (local_string != "") {
local_string = locale(strings::rtrim(local, ']')); local_string = locale(strings::rtrim(local, "]"));
if (!validate_entry_locale(local_string)) return error::INVALID_ENTRY; if (!validate_entry_locale(local_string)) return invalid_entry;
local = match(local_string) { local = match(local_string) {
case let local = locale::locale => yield local; case let local: locale::locale => yield local;
case errors::invalid => return error::INVALID_ENTRY; case errors::invalid => return invalid_entry;
}; };
}; };
return strings::dup(key), strings::dup(valu), local; return (strings::dup(key), strings::dup(valu), local);
}; };
fn validate_entry_key(key: str) bool = { fn validate_entry_key(key: str) bool = {