-
Notifications
You must be signed in to change notification settings - Fork 9
Fix write() quoting of symbols in proper sexps #490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0b8ae6d
182bc86
05f500f
17addc8
c986740
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
toddjonker marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,34 +29,35 @@ | |
|
|
||
|
|
||
| (with_ion_from_string "0 1 2 3" | ||
| (lambda () | ||
| (check === 0 (read)) | ||
| (check === 1 (read)) | ||
| (with_ion_from_string " \"hello\" " | ||
| (lambda () | ||
| (check = "hello" (read)) | ||
| (check_true (is_eof (read))))) | ||
| (check === 2 (read)) | ||
| (check === 3 (read)) | ||
| (check_true (is_eof (read))))) | ||
| (lambda () | ||
| (check === 0 (read)) | ||
| (check === 1 (read)) | ||
| (with_ion_from_string " \"hello\" " | ||
| (lambda () | ||
| (check = "hello" (read)) | ||
| (check_true (is_eof (read))))) | ||
| (check === 2 (read)) | ||
| (check === 3 (read)) | ||
| (check_true (is_eof (read))))) | ||
|
|
||
|
|
||
| // This assumes that current_directory is at the project root. | ||
| (with_ion_from_file (test_data_file "ints.ion") | ||
| (lambda () | ||
| (check === 0 (read)) | ||
| (check === 1 (read)) | ||
| (with_ion_from_file (test_data_file "hello.ion") | ||
| (lambda () | ||
| (check = "hello" (read)) | ||
| (check_true (is_eof (read))))) | ||
| (check === 2 (read)) | ||
| (check === 3 (read)) | ||
| (check_true (is_eof (read))))) | ||
| (lambda () | ||
| (check === 0 (read)) | ||
| (check === 1 (read)) | ||
| (with_ion_from_file (test_data_file "hello.ion") | ||
| (lambda () | ||
| (check = "hello" (read)) | ||
| (check_true (is_eof (read))))) | ||
| (check === 2 (read)) | ||
| (check === 3 (read)) | ||
| (check_true (is_eof (read))))) | ||
|
|
||
|
|
||
| // A nice shortcut for reading a single value. | ||
| (check = "hello" | ||
| (with_ion_from_file (test_data_file "hello.ion") read)) | ||
| (with_ion_from_file (test_data_file "hello.ion") read)) | ||
|
|
||
| (check_true (is_eof eof)) | ||
|
|
||
|
|
@@ -65,22 +66,22 @@ | |
| // Lob I/O | ||
|
|
||
| (define_check (check_lob_io value) | ||
| (let [(lob (ionize_to_blob value))] | ||
| (check_pred is_blob lob) | ||
| (check_pred (negate is_null) lob) | ||
| (let [(v (with_ion_from_lob lob | ||
| (thunk | ||
| (let [(v (read))] | ||
| (check_pred (negate is_eof) v) | ||
| (check_pred is_eof (read)) | ||
| v))))] | ||
| (check === value v)))) | ||
| (let [(lob (ionize_to_blob value))] | ||
| (check_pred is_blob lob) | ||
| (check_pred (negate is_null) lob) | ||
| (let [(v (with_ion_from_lob lob | ||
| (thunk | ||
| (let [(v (read))] | ||
| (check_pred (negate is_eof) v) | ||
| (check_pred is_eof (read)) | ||
| v))))] | ||
| (check === value v)))) | ||
|
|
||
| (map (lambda (v) (check_lob_io v)) representative_ion_data) | ||
|
|
||
| // Make sure we can read Ion text | ||
| (check === (quote [only_me]) | ||
| (with_ion_from_lob {{"[only_me]"}} read)) | ||
| (with_ion_from_lob {{"[only_me]"}} read)) | ||
|
|
||
| (expect_arity_error (ionize_to_blob)) | ||
| (expect_arity_error (ionize_to_blob 1 2)) | ||
|
|
@@ -133,8 +134,8 @@ | |
| (check === "{f:\"a\"}" (display_to_string { f: "a" })) | ||
|
|
||
| (check_pred (|r| (or (=== "{f:a,g:b}" r) | ||
| (=== "{g:b,f:a}" r))) | ||
| (display_to_string (quote { f: a, g: b }))) | ||
| (=== "{g:b,f:a}" r))) | ||
| (display_to_string (quote { f: a, g: b }))) | ||
|
|
||
|
|
||
| //============================================================================= | ||
|
|
@@ -145,11 +146,104 @@ | |
| (check === "" (with_output_to_string)) | ||
|
|
||
| (check === "true12\n\"write\"display" | ||
| (with_output_to_string | ||
| (display "true") | ||
| (displayln 12) | ||
| (write "write") | ||
| (display "display"))) | ||
| (with_output_to_string | ||
| (display "true") | ||
| (displayln 12) | ||
| (write "write") | ||
| (display "display"))) | ||
|
|
||
|
|
||
| "SUCCESS (io.test)" | ||
| //============================================================================= | ||
| // write: symbols | ||
|
|
||
| // Plain identifier: written as-is, no quotes needed. | ||
| (check === "quoted_sym" | ||
| (with_output_to_string | ||
| (write (quote quoted_sym)))) | ||
|
|
||
|
Comment on lines
+159
to
+163
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And in this new code the indentation has all been lost. Oops! |
||
| // Symbol requiring quotes (contains spaces): always quoted regardless of context. | ||
| (check === "'with spaces'" | ||
| (with_output_to_string | ||
| (write (quote 'with spaces')))) | ||
|
|
||
| // Annotated symbol: annotation and value both written correctly. | ||
| (check === "tag::value" | ||
| (with_output_to_string | ||
| (write (quote tag::value)))) | ||
|
|
||
| // Operator symbol outside a sexp: must be quoted. | ||
| (check === "'+'" | ||
| (with_output_to_string | ||
| (write (quote '+')))) | ||
|
|
||
| (check === "'+='" | ||
| (with_output_to_string | ||
| (write (quote +=)))) | ||
|
|
||
| // null symbol | ||
| (check === "null.symbol" | ||
| (with_output_to_string | ||
| (write (quote null.symbol)))) | ||
|
|
||
|
|
||
|
|
||
| // write: sexps | ||
toddjonker marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // Context-switching: operator symbols in lists, structs, and sexps containing non-Ion values. | ||
|
|
||
| // List: operator symbols must be quoted (list is not a sexp context). | ||
| (check === "['+', ['+'], {'+':'+'}, (+ {{{void}}})]" | ||
| (with_output_to_string | ||
| (write (list (quote +) (list (quote +)) (struct "+" (quote +)) (sexp (quote +) (void)))))) | ||
|
|
||
| // Struct: operator symbols in field names and values must be quoted. | ||
| (check === "{f:'+'}" | ||
| (with_output_to_string | ||
| (write (quote {f: '+'})))) | ||
|
|
||
| // Sexp: operator symbols must NOT be quoted; void verified to stay in write mode. | ||
| (check === "(+ ['+', {{{void}}}] {'+':\"+\",f:{{{void}}}} (+ {{{void}}}) {{{void}}})" | ||
| (with_output_to_string | ||
| (write (sexp (quote +) (list (quote +) (void)) (struct "+" "+" "f" (void)) (sexp (quote +) (void)) (void))))) | ||
|
Comment on lines
+205
to
+207
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd expect this test to fail 50% of the time due to struct-ordering differences. Ion/Fusion doesn't guarantee that struct fields are output in any particular order, and the runtime intentionally shuffles structs to dissuade code from relying on that. There's no easy work-around when looking at serialized forms, and this is one of the rare cases where that's appropriate. I think the best solution today is to stick to single-field structs so the tests are robust. That said... I pulled the PR and after many runs it never failed. That's... surprising, and perhaps something broke in the shuffler. Regardless, we can leave this as-is for now, I guess! |
||
|
|
||
| // Empty and null sexps. | ||
| (check === "()" | ||
| (with_output_to_string | ||
| (write (sexp)))) | ||
|
|
||
| (check === "null.sexp" | ||
| (with_output_to_string | ||
| (write (quote null.sexp)))) | ||
|
|
||
| // Operator symbols inside a sexp: must NOT be quoted. | ||
| (check === "(+ 1 2)" | ||
| (with_output_to_string | ||
| (write (quote (+ 1 2))))) | ||
|
|
||
| (check === "(+ =)" | ||
| (with_output_to_string | ||
| (write (quote (+ =))))) | ||
|
|
||
| // Symbol requiring quotes inside a sexp: must still be quoted. | ||
| (check === "('with spaces')" | ||
| (with_output_to_string | ||
| (write (quote ('with spaces'))))) | ||
|
|
||
| // Annotated value inside a sexp: annotation written correctly. | ||
| (check === "(note::\"Hello\")" | ||
| (with_output_to_string | ||
| (write (quote (note::"Hello"))))) | ||
|
|
||
| // Improper sexp (pair): operator symbols in both head and tail unquoted. | ||
| (check === "(a {.} b)" | ||
| (with_output_to_string | ||
| (write (pair (quote a) (quote b))))) | ||
|
|
||
| (check === "(+ {.} =)" | ||
| (with_output_to_string | ||
| (write (pair (quote +) (quote =))))) | ||
|
|
||
| // Symbol requiring quotes in improper sexp tail: must still be quoted. | ||
| (check === "(a {.} 'with spaces')" | ||
| (with_output_to_string | ||
| (write (pair (quote a) (quote 'with spaces'))))) | ||
Uh oh!
There was an error while loading. Please reload this page.