// Simple TOML parser for cell modules // Supports basic TOML features needed for the module system function parse_toml(text) { if (typeof text != 'string') return null var lines = text.split('\n') var result = {} var current_section = result var current_section_name = '' for (var i = 0; i < lines.length; i++) { var line = lines[i].trim() // Skip empty lines and comments if (!line || line.startsWith('#')) continue // Section header if (line.startsWith('[') && line.endsWith(']')) { var section_path = parse_key_path(line.slice(1, -1)) current_section = result // Reconstruct name for debugging/legacy (not strictly needed for object construction) current_section_name = section_path.join('.') for (var j = 0; j < section_path.length; j++) { var key = section_path[j] if (!current_section[key]) { current_section[key] = {} } current_section = current_section[key] } continue } // Key-value pair var eq_index = line.indexOf('=') if (eq_index > 0) { var key_part = line.substring(0, eq_index).trim() var value = line.substring(eq_index + 1).trim() // Handle quoted keys in key-value pairs too if needed? // For now assuming simple keys or quoted keys var key = parse_key(key_part) // Parse value if (value.startsWith('"') && value.endsWith('"')) { // String - unescape quotes current_section[key] = value.slice(1, -1).replace(/\\"/g, '"') } else if (value.startsWith('[') && value.endsWith(']')) { // Array current_section[key] = parse_array(value) } else if (value == 'true' || value == 'false') { // Boolean current_section[key] = value == 'true' } else if (isa(value, number)) { // Number current_section[key] = Number(value) } else { // Unquoted string current_section[key] = value } } } return result } function parse_key(str) { if (str.startsWith('"') && str.endsWith('"')) { return str.slice(1, -1).replace(/\\"/g, '"') } return str } // Split a key path by dots, respecting quotes function parse_key_path(str) { var parts = [] var current = '' var in_quote = false for (var i = 0; i < str.length; i++) { var c = str[i] if (c == '"' && (i==0 || str[i-1] != '\\')) { in_quote = !in_quote // We don't verify if it's strictly correct TOML quote usage, just rudimentary } else if (c == '.' && !in_quote) { parts.push(parse_key(current.trim())) current = '' continue } current += c } if (current.trim().length > 0) parts.push(parse_key(current.trim())) return parts } function parse_array(str) { // Remove brackets str = str.slice(1, -1).trim() if (!str) return [] var items = [] var current = '' var in_quotes = false for (var i = 0; i < str.length; i++) { var char = str[i] if (char == '"' && (i == 0 || str[i-1] != '\\')) { in_quotes = !in_quotes current += char } else if (char == ',' && !in_quotes) { items.push(parse_value(current.trim())) current = '' } else { current += char } } if (current.trim()) { items.push(parse_value(current.trim())) } return items } function parse_value(str) { if (str.startsWith('"') && str.endsWith('"')) { return str.slice(1, -1).replace(/\\"/g, '"') } else if (str == 'true' || str == 'false') { return str == 'true' } else if (!isNaN(Number(str))) { return Number(str) } else { return str } } function encode_toml(obj) { var result = [] function encode_value(value) { if (typeof value == 'string') { return '"' + value.replace(/"/g, '\\"') + '"' } else if (typeof value == 'boolean') { return value ? 'true' : 'false' } else if (typeof value == 'number') { return text(value) } else if (isa(value, array)) { var items = [] for (var i = 0; i < value.length; i++) { items.push(encode_value(value[i])) } return '[' + items.join(', ') + ']' } return text(value) } function quote_key(k) { if (k.includes('.') || k.includes('"') || k.includes(' ')) { return '"' + k.replace(/"/g, '\\"') + '"' } return k } // First pass: encode top-level simple values var keys = array(obj) for (var i = 0; i < keys.length; i++) { var key = keys[i] var value = obj[key] if (!isa(value, object)) { result.push(quote_key(key) + ' = ' + encode_value(value)) } } // Second pass: encode nested objects function encode_section(obj, path) { var keys = array(obj) for (var i = 0; i < keys.length; i++) { var key = keys[i] var value = obj[key] if (isa(value, object)) { // Nested object - create section // We MUST quote the key segment if it has dots, otherwise it becomes a nested table path var quoted = quote_key(key) var section_path = path ? path + '.' + quoted : quoted result.push('[' + section_path + ']') // First encode direct properties of this section var section_keys = array(value) for (var j = 0; j < section_keys.length; j++) { var sk = section_keys[j] var sv = value[sk] if (!isa(sv, object)) { result.push(quote_key(sk) + ' = ' + encode_value(sv)) } } // Then encode nested sections encode_section(value, section_path) } } } encode_section(obj, '') return result.join('\n') } return { decode: parse_toml, encode: encode_toml }