diff --git a/src/bytecode.rs b/src/bytecode.rs index 06ace56..d7af510 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -143,7 +143,7 @@ impl Op { pub enum ObjectType { Plist, Hashtable, - // TODO: Alist, + Alist, } pub struct BytecodeOptions { @@ -216,16 +216,22 @@ impl BytecodeCompiler { } } - fn compile_value_map_plist(&mut self, map: &json::Map) { - let list_len = map.len() * 2; + fn compile_value_map_plist_or_alist(&mut self, map: &json::Map, alist: bool) { + let list_len = if alist { map.len() } else { map.len() * 2 }; // see below if list_len < (1 << 16) && list_len >= (1 << 8) { self.compile_constant_op(LispObject::Symbol("list".into())); } for (key, value) in map { - self.compile_constant_op(LispObject::Keyword(key.clone())); - self.compile_value(value); + if alist { + self.compile_constant_op(LispObject::Symbol(key.clone())); + self.compile_value(value); + self.ops.push(Op::Cons); + } else { + self.compile_constant_op(LispObject::Keyword(key.clone())); + self.compile_value(value); + } } // four modes: 0. (empty) just nil 1. list op; 2. list call; 3. recursive cons @@ -287,7 +293,8 @@ impl BytecodeCompiler { }, &json::Value::Object(ref map) => { match self.options.object_type { - ObjectType::Plist => self.compile_value_map_plist(&map), + ObjectType::Plist => self.compile_value_map_plist_or_alist(&map, false), + ObjectType::Alist => self.compile_value_map_plist_or_alist(&map, true), ObjectType::Hashtable => self.compile_value_map_hashtable(&map), }; }, diff --git a/tests/benchmark_and_compare.template.el b/tests/benchmark_and_compare.template.el index 9905b3b..909d39c 100644 --- a/tests/benchmark_and_compare.template.el +++ b/tests/benchmark_and_compare.template.el @@ -19,6 +19,13 @@ (setq p (cddr p))) (sort res (lambda (a b) (string< (symbol-name (car a)) (symbol-name (car b))))))) +(defun -alistp (x) + (and (listp x) + (-all (lambda (e) (and (consp e) (symbolp (car e)))) x))) + +(defun -sort-alist (x) + (sort x (lambda (a b) (string< (symbol-name (car a)) (symbol-name (car b)))))) + (defun -hashtable-to-sorted-alist (h) (let (res) (maphash (lambda (k v) (push (cons k v) res)) h) @@ -48,6 +55,11 @@ (equal (length a) (length b)) (-all (lambda (idx) (json-equal (aref a idx) (aref b idx))) (number-sequence 0 (1- (length a)))))) + ((pred -alistp) + (and (-alistp b) + (equal (length a) (length b)) + (-check-equal-sorted-alist (-sort-alist a) + (-sort-alist b)))) ((pred plistp) (and (plistp b) (equal (length a) (length b)) @@ -66,7 +78,7 @@ (bytecode-str (with-temp-buffer (insert-file-contents "{}") (buffer-string))) - (object-type (if (equal "{}" "plist") 'plist 'hash-table)) + (object-type (intern "{}")) json-val bytecode-val) (message "Object-type: %s" object-type) (unless (json-equal (setq json-val diff --git a/tests/bytecode_test.rs b/tests/bytecode_test.rs index 0f81c75..18b92bd 100644 --- a/tests/bytecode_test.rs +++ b/tests/bytecode_test.rs @@ -30,7 +30,8 @@ fn run_one_test(json_str: &str, object_type: bytecode::ObjectType) -> Result<()> bytecode_file.display(), match object_type { bytecode::ObjectType::Plist => "plist", - bytecode::ObjectType::Hashtable => "hashtable", + bytecode::ObjectType::Hashtable => "hash-table", + bytecode::ObjectType::Alist => "alist", }); std::fs::write(&elisp_file, elisp_code.as_bytes())?; @@ -68,25 +69,34 @@ fn test_huge_object() { #[test] fn test_completion_100k() { run_one_test(include_str!("./data/completion.json"), bytecode::ObjectType::Plist).unwrap(); + run_one_test(include_str!("./data/completion.json"), bytecode::ObjectType::Alist).unwrap(); run_one_test(include_str!("./data/completion.json"), bytecode::ObjectType::Hashtable).unwrap(); } #[test] fn test_completion_100k_2() { run_one_test(include_str!("./data/completion2.json"), bytecode::ObjectType::Plist).unwrap(); + run_one_test(include_str!("./data/completion2.json"), bytecode::ObjectType::Alist).unwrap(); + run_one_test(include_str!("./data/completion2.json"), bytecode::ObjectType::Hashtable).unwrap(); } #[test] fn test_completion_4k() { run_one_test(include_str!("./data/completion3.json"), bytecode::ObjectType::Plist).unwrap(); + run_one_test(include_str!("./data/completion3.json"), bytecode::ObjectType::Alist).unwrap(); + run_one_test(include_str!("./data/completion3.json"), bytecode::ObjectType::Hashtable).unwrap(); } #[test] fn test_diagnostics_12k() { run_one_test(include_str!("./data/publishDiagnostics.json"), bytecode::ObjectType::Plist).unwrap(); + run_one_test(include_str!("./data/publishDiagnostics.json"), bytecode::ObjectType::Alist).unwrap(); + run_one_test(include_str!("./data/publishDiagnostics.json"), bytecode::ObjectType::Hashtable).unwrap(); } #[test] fn test_diagnostics_12k_2() { run_one_test(include_str!("./data/publishDiagnostics2.json"), bytecode::ObjectType::Plist).unwrap(); + run_one_test(include_str!("./data/publishDiagnostics2.json"), bytecode::ObjectType::Alist).unwrap(); + run_one_test(include_str!("./data/publishDiagnostics2.json"), bytecode::ObjectType::Hashtable).unwrap(); }