aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/conformance/1-source/backtick_get_c_eof.zc4
-rw-r--r--tests/conformance/1-source/backtick_in_literals_and_comments.zc9
-rw-r--r--tests/conformance/1-source/backtick_stdin.zc4
-rw-r--r--tests/conformance/1-source/comment_block.zc8
-rw-r--r--tests/conformance/1-source/comment_block_in_middle_of_expr.zc5
-rw-r--r--tests/conformance/1-source/comment_block_no_nest.zc7
-rw-r--r--tests/conformance/1-source/comment_block_spans_lines_with_quote.zc10
-rw-r--r--tests/conformance/1-source/comment_block_unclosed.zc4
-rw-r--r--tests/conformance/1-source/comment_doc_does_not_change_code.zc6
-rw-r--r--tests/conformance/1-source/comment_line.zc8
-rw-r--r--tests/conformance/1-source/comment_line_ends_at_newline.zc9
-rw-r--r--tests/conformance/1-source/comment_line_in_string.zc4
-rw-r--r--tests/conformance/1-source/comment_slash_star_in_string.zc5
-rw-r--r--tests/conformance/1-source/ident_case_sensitive.zc6
-rw-r--r--tests/conformance/1-source/ident_digits_underscore_long.zc5
-rw-r--r--tests/conformance/1-source/ident_forms.zc8
-rw-r--r--tests/conformance/1-source/ident_keyword_as_local_if.zc4
-rw-r--r--tests/conformance/1-source/ident_keyword_as_local_len.zc4
-rw-r--r--tests/conformance/1-source/ident_keyword_as_param.zc5
-rw-r--r--tests/conformance/1-source/ident_non_letter_start.zc5
-rw-r--r--tests/conformance/1-source/ident_positional_words_as_names.zc8
-rw-r--r--tests/conformance/1-source/ident_positional_words_as_names_2.zc8
-rw-r--r--tests/conformance/1-source/ident_tags_as_variables.zc9
-rw-r--r--tests/conformance/1-source/ident_tags_as_variables_glued_star.zc8
-rw-r--r--tests/conformance/1-source/ident_type_name_shadow.zc4
-rw-r--r--tests/conformance/1-source/keyword_expr_keywords_ok.zc6
-rw-r--r--tests/conformance/1-source/keyword_in_expr_break.zc5
-rw-r--r--tests/conformance/1-source/keyword_in_expr_do.zc5
-rw-r--r--tests/conformance/1-source/keyword_in_expr_else.zc5
-rw-r--r--tests/conformance/1-source/keyword_in_expr_for.zc5
-rw-r--r--tests/conformance/1-source/keyword_in_expr_if.zc5
-rw-r--r--tests/conformance/1-source/keyword_in_expr_let.zc5
-rw-r--r--tests/conformance/1-source/keyword_in_expr_return.zc5
-rw-r--r--tests/conformance/1-source/keyword_in_expr_switch.zc5
-rw-r--r--tests/conformance/1-source/keyword_s_only_in_expression.zc2
-rw-r--r--tests/conformance/1-source/lit_bstr_basic.zc9
-rw-r--r--tests/conformance/1-source/lit_bstr_cast_to_int_pointer.zc10
-rw-r--r--tests/conformance/1-source/lit_bstr_empty.zc5
-rw-r--r--tests/conformance/1-source/lit_bstr_escape_and_len.zc5
-rw-r--r--tests/conformance/1-source/lit_bstr_layout.zc11
-rw-r--r--tests/conformance/1-source/lit_bstr_name_b_still_usable.zc4
-rw-r--r--tests/conformance/1-source/lit_bstr_nul_truncates.zc4
-rw-r--r--tests/conformance/1-source/lit_bstr_space_is_name.zc7
-rw-r--r--tests/conformance/1-source/lit_char_non_ascii.zc4
-rw-r--r--tests/conformance/1-source/lit_char_non_ascii_global.zc5
-rw-r--r--tests/conformance/1-source/lit_char_non_ascii_later.zc5
-rw-r--r--tests/conformance/1-source/lit_char_range_0_255.zc4
-rw-r--r--tests/conformance/1-source/lit_char_two_bytes.zc4
-rw-r--r--tests/conformance/1-source/lit_char_two_bytes_global.zc5
-rw-r--r--tests/conformance/1-source/lit_char_two_bytes_later.zc5
-rw-r--r--tests/conformance/1-source/lit_char_two_bytes_local_init.zc5
-rw-r--r--tests/conformance/1-source/lit_char_values.zc8
-rw-r--r--tests/conformance/1-source/lit_float_bad_exponent.zc4
-rw-r--r--tests/conformance/1-source/lit_float_bad_exponent_capital.zc5
-rw-r--r--tests/conformance/1-source/lit_float_bad_exponent_first_stmt_local.zc5
-rw-r--r--tests/conformance/1-source/lit_float_bad_exponent_first_stmt_paren.zc5
-rw-r--r--tests/conformance/1-source/lit_float_bad_exponent_global.zc5
-rw-r--r--tests/conformance/1-source/lit_float_bad_exponent_in_helper.zc5
-rw-r--r--tests/conformance/1-source/lit_float_bad_exponent_later.zc5
-rw-r--r--tests/conformance/1-source/lit_float_bad_exponent_sign.zc4
-rw-r--r--tests/conformance/1-source/lit_float_bad_exponent_sign_later.zc5
-rw-r--r--tests/conformance/1-source/lit_float_dot_forms.zc14
-rw-r--r--tests/conformance/1-source/lit_float_dot_letter_is_field.zc6
-rw-r--r--tests/conformance/1-source/lit_float_exponent_negative_digit.zc4
-rw-r--r--tests/conformance/1-source/lit_float_forms.zc7
-rw-r--r--tests/conformance/1-source/lit_float_is_float_type.zc10
-rw-r--r--tests/conformance/1-source/lit_hex.zc4
-rw-r--r--tests/conformance/1-source/lit_hex_letter_after_0x_new_token.zc5
-rw-r--r--tests/conformance/1-source/lit_hex_no_digits_is_zero.zc4
-rw-r--r--tests/conformance/1-source/lit_hex_wide.zc5
-rw-r--r--tests/conformance/1-source/lit_hex_wraps.zc4
-rw-r--r--tests/conformance/1-source/lit_int_max.zc5
-rw-r--r--tests/conformance/1-source/lit_int_octal_is_decimal.zc4
-rw-r--r--tests/conformance/1-source/lit_int_type_is_int_never_negative.zc5
-rw-r--r--tests/conformance/1-source/lit_int_wraps.zc4
-rw-r--r--tests/conformance/1-source/lit_int_zero_and_leading_zeros.zc5
-rw-r--r--tests/conformance/1-source/lit_minus_folded.zc4
-rw-r--r--tests/conformance/1-source/lit_no_binary.zc7
-rw-r--r--tests/conformance/1-source/lit_no_digit_separator.zc7
-rw-r--r--tests/conformance/1-source/lit_no_suffix.zc7
-rw-r--r--tests/conformance/1-source/lit_str_adjacent_not_joined.zc7
-rw-r--r--tests/conformance/1-source/lit_str_empty.zc5
-rw-r--r--tests/conformance/1-source/lit_str_escapes.zc8
-rw-r--r--tests/conformance/1-source/lit_str_hex_escape_is_plain_char.zc5
-rw-r--r--tests/conformance/1-source/lit_str_high_byte_one_word_each.zc5
-rw-r--r--tests/conformance/1-source/lit_str_nul_truncates.zc4
-rw-r--r--tests/conformance/1-source/lit_str_raw_newline.zc9
-rw-r--r--tests/conformance/1-source/lit_str_unterminated.zc4
-rw-r--r--tests/conformance/1-source/lit_str_utf8_bytes.zc4
-rw-r--r--tests/conformance/1-source/lit_str_word_per_cell.zc9
-rw-r--r--tests/conformance/1-source/lit_str_zero_terminated.zc5
-rw-r--r--tests/conformance/1-source/module_join_hidden_by_local.zc10
-rw-r--r--tests/conformance/1-source/module_join_known_name_not_module.zc7
-rw-r--r--tests/conformance/1-source/module_join_needs_include.zc2
-rw-r--r--tests/conformance/1-source/module_join_one_dot_only.zc5
-rw-r--r--tests/conformance/1-source/module_join_prints_A.zc3
-rw-r--r--tests/conformance/1-source/module_unqualified_rt_name.zc2
-rw-r--r--tests/conformance/1-source/op_compound_all.zc15
-rw-r--r--tests/conformance/1-source/op_compound_or.zc4
-rw-r--r--tests/conformance/1-source/op_greedy_compound_shift.zc4
-rw-r--r--tests/conformance/1-source/op_incr_decr_split.zc4
-rw-r--r--tests/conformance/1-source/op_lexing_a_minus_minus_b.zc5
-rw-r--r--tests/conformance/1-source/op_no_space_needed_lt_neg.zc4
-rw-r--r--tests/conformance/1-source/op_non_ascii_byte_error.zc7
-rw-r--r--tests/conformance/1-source/op_not_not.zc4
-rw-r--r--tests/conformance/1-source/op_star_neg_and_assign_neg.zc4
-rw-r--r--tests/conformance/1-source/op_ternary_colon_tokens.zc6
-rw-r--r--tests/conformance/1-source/op_unknown_char.zc5
-rw-r--r--tests/conformance/1-source/unit_ends_at_backtick.zc4
-rw-r--r--tests/conformance/1-source/unit_ends_at_backtick_first_line.zc6
-rw-r--r--tests/conformance/1-source/unit_eof_ends_unit.zc6
-rw-r--r--tests/conformance/1-source/ws_basic.zc11
-rw-r--r--tests/conformance/1-source/ws_carriage_return_tab_ff.zc5
-rw-r--r--tests/conformance/1-source/ws_no_space_needed_between_tokens.zc5
-rw-r--r--tests/conformance/2-types/alias_pointer_to_array.zc15
-rw-r--r--tests/conformance/2-types/alias_simple.zc6
-rw-r--r--tests/conformance/2-types/array_assign_whole.zc7
-rw-r--r--tests/conformance/2-types/array_assign_whole_field.zc8
-rw-r--r--tests/conformance/2-types/array_const_index_negative.zc8
-rw-r--r--tests/conformance/2-types/array_const_index_out_of_range.zc7
-rw-r--r--tests/conformance/2-types/array_init_bytes_string.zc8
-rw-r--r--tests/conformance/2-types/array_init_compound_literal.zc9
-rw-r--r--tests/conformance/2-types/array_init_designator.zc9
-rw-r--r--tests/conformance/2-types/array_init_negative_designator.zc6
-rw-r--r--tests/conformance/2-types/array_init_nested.zc9
-rw-r--r--tests/conformance/2-types/array_init_short.zc9
-rw-r--r--tests/conformance/2-types/array_init_string.zc8
-rw-r--r--tests/conformance/2-types/array_init_too_many.zc6
-rw-r--r--tests/conformance/2-types/array_of_arrays.zc15
-rw-r--r--tests/conformance/2-types/array_param_decays.zc10
-rw-r--r--tests/conformance/2-types/array_unsized_from_init.zc9
-rw-r--r--tests/conformance/2-types/array_unsized_needs_init.zc6
-rw-r--r--tests/conformance/2-types/array_value_is_address.zc11
-rw-r--r--tests/conformance/2-types/cast_to_sized.zc8
-rw-r--r--tests/conformance/2-types/closure_result_type_coerces.zc9
-rw-r--r--tests/conformance/2-types/const_array_read_and_copy.zc10
-rw-r--r--tests/conformance/2-types/const_array_write.zc3
-rw-r--r--tests/conformance/2-types/const_compound_assign.zc3
-rw-r--r--tests/conformance/2-types/const_fixed_order.zc3
-rw-r--r--tests/conformance/2-types/const_fixed_order_2.zc3
-rw-r--r--tests/conformance/2-types/const_increment.zc3
-rw-r--r--tests/conformance/2-types/const_local_assign.zc3
-rw-r--r--tests/conformance/2-types/const_local_constant.zc5
-rw-r--r--tests/conformance/2-types/const_local_needs_init.zc3
-rw-r--r--tests/conformance/2-types/const_local_typed.zc5
-rw-r--r--tests/conformance/2-types/const_pointer_element_write.zc3
-rw-r--r--tests/conformance/2-types/const_pointer_write.zc3
-rw-r--r--tests/conformance/2-types/const_to_mutable_no_typecheck.zc3
-rw-r--r--tests/conformance/2-types/conv_argument_and_return.zc8
-rw-r--r--tests/conformance/2-types/conv_assignment_to_float.zc4
-rw-r--r--tests/conformance/2-types/conv_f32_rounds.zc4
-rw-r--r--tests/conformance/2-types/conv_float_to_int_truncates.zc4
-rw-r--r--tests/conformance/2-types/conv_int_to_float_initializer.zc4
-rw-r--r--tests/conformance/2-types/conv_word_keeps_bits.zc4
-rw-r--r--tests/conformance/2-types/dynarray_handle_layout.zc14
-rw-r--r--tests/conformance/2-types/dynarray_new_n_zero_filled.zc9
-rw-r--r--tests/conformance/2-types/dynarray_packed_elem_size_negated.zc16
-rw-r--r--tests/conformance/2-types/enum_in_case_labels.zc14
-rw-r--r--tests/conformance/2-types/enum_local.zc9
-rw-r--r--tests/conformance/2-types/enum_names_earlier_enum.zc7
-rw-r--r--tests/conformance/2-types/enum_names_own_member.zc4
-rw-r--r--tests/conformance/2-types/enum_plain_values.zc10
-rw-r--r--tests/conformance/2-types/enum_tagged_basic.zc15
-rw-r--r--tests/conformance/2-types/enum_tagged_constructor_fields.zc12
-rw-r--r--tests/conformance/2-types/enum_tagged_float_payload.zc11
-rw-r--r--tests/conformance/2-types/enum_tagged_wrong_arg_count.zc8
-rw-r--r--tests/conformance/2-types/enum_typecheck_enum_to_enum.zc10
-rw-r--r--tests/conformance/2-types/enum_typecheck_enum_to_int.zc12
-rw-r--r--tests/conformance/2-types/enum_typecheck_int_to_enum.zc8
-rw-r--r--tests/conformance/2-types/enum_unnamed.zc6
-rw-r--r--tests/conformance/2-types/enum_value_const_expr.zc7
-rw-r--r--tests/conformance/2-types/f32_rounds_on_store.zc12
-rw-r--r--tests/conformance/2-types/fixed_array_n_is_array_n.zc9
-rw-r--r--tests/conformance/2-types/fixed_cannot_grow.zc7
-rw-r--r--tests/conformance/2-types/fixed_cannot_pop.zc7
-rw-r--r--tests/conformance/2-types/fixed_cannot_resize.zc7
-rw-r--r--tests/conformance/2-types/fixed_len_and_index.zc10
-rw-r--r--tests/conformance/2-types/fixed_new_needs_length.zc6
-rw-r--r--tests/conformance/2-types/fixed_to_plain_dyn_param.zc9
-rw-r--r--tests/conformance/2-types/float_f64_same.zc4
-rw-r--r--tests/conformance/2-types/float_truthy.zc17
-rw-r--r--tests/conformance/2-types/float_truthy_operators.zc19
-rw-r--r--tests/conformance/2-types/function_type_fn_word.zc6
-rw-r--r--tests/conformance/2-types/function_type_param.zc6
-rw-r--r--tests/conformance/2-types/function_type_var.zc12
-rw-r--r--tests/conformance/2-types/function_value_and_let.zc10
-rw-r--r--tests/conformance/2-types/function_value_closure_call.zc10
-rw-r--r--tests/conformance/2-types/function_value_closure_typed.zc9
-rw-r--r--tests/conformance/2-types/generic_fn_explicit.zc11
-rw-r--r--tests/conformance/2-types/generic_fn_inferred.zc12
-rw-r--r--tests/conformance/2-types/generic_fn_own_copy.zc8
-rw-r--r--tests/conformance/2-types/generic_fn_return_unconfirmed.zc4
-rw-r--r--tests/conformance/2-types/generic_fn_value_explicit.zc10
-rw-r--r--tests/conformance/2-types/generic_struct_basic.zc15
-rw-r--r--tests/conformance/2-types/generic_struct_nested_close.zc13
-rw-r--r--tests/conformance/2-types/generic_struct_static_fn.zc4
-rw-r--r--tests/conformance/2-types/generic_struct_unpacked_fields.zc7
-rw-r--r--tests/conformance/2-types/int_sized_cut_more.zc10
-rw-r--r--tests/conformance/2-types/int_sized_cut_store.zc9
-rw-r--r--tests/conformance/2-types/int_sized_field.zc12
-rw-r--r--tests/conformance/2-types/int_sized_param_return.zc6
-rw-r--r--tests/conformance/2-types/no_long.zc6
-rw-r--r--tests/conformance/2-types/no_u64.zc6
-rw-r--r--tests/conformance/2-types/null_pointer.zc11
-rw-r--r--tests/conformance/2-types/packed_bytes_in_word.zc14
-rw-r--r--tests/conformance/2-types/packed_element_has_no_address.zc7
-rw-r--r--tests/conformance/2-types/packed_read_back.zc11
-rw-r--r--tests/conformance/2-types/packed_sizeof.zc10
-rw-r--r--tests/conformance/2-types/plain_dyn_to_fixed_param.zc11
-rw-r--r--tests/conformance/2-types/prefix_array_is_error.zc6
-rw-r--r--tests/conformance/2-types/prefix_pointer_is_error.zc6
-rw-r--r--tests/conformance/2-types/sizeof_bstr.zc5
-rw-r--r--tests/conformance/2-types/sizeof_builtin.zc10
-rw-r--r--tests/conformance/2-types/struct_arrow_same_as_dot.zc11
-rw-r--r--tests/conformance/2-types/struct_contains_itself.zc4
-rw-r--r--tests/conformance/2-types/struct_field_on_int_unique.zc6
-rw-r--r--tests/conformance/2-types/struct_field_on_word_ambiguous.zc9
-rw-r--r--tests/conformance/2-types/struct_field_on_word_unique.zc12
-rw-r--r--tests/conformance/2-types/struct_layout_offsets.zc13
-rw-r--r--tests/conformance/2-types/struct_layout_pack_rules.zc9
-rw-r--r--tests/conformance/2-types/struct_layout_pix.zc6
-rw-r--r--tests/conformance/2-types/struct_layout_words.zc6
-rw-r--r--tests/conformance/2-types/struct_param_by_value.zc5
-rw-r--r--tests/conformance/2-types/struct_value_is_address.zc12
-rw-r--r--tests/conformance/2-types/tag_names_unreserved.zc4
-rw-r--r--tests/conformance/2-types/tag_on_field.zc4
-rw-r--r--tests/conformance/2-types/tag_on_global.zc4
-rw-r--r--tests/conformance/2-types/type_hash_consed.zc10
-rw-r--r--tests/conformance/2-types/typecheck_array_to_pointer_decay.zc6
-rw-r--r--tests/conformance/2-types/typecheck_bstr_to_bstr.zc5
-rw-r--r--tests/conformance/2-types/typecheck_bstr_to_int.zc4
-rw-r--r--tests/conformance/2-types/typecheck_call_non_function.zc4
-rw-r--r--tests/conformance/2-types/typecheck_compare_incompatible.zc4
-rw-r--r--tests/conformance/2-types/typecheck_const_to_mutable.zc4
-rw-r--r--tests/conformance/2-types/typecheck_default_off.zc4
-rw-r--r--tests/conformance/2-types/typecheck_deref_non_pointer.zc4
-rw-r--r--tests/conformance/2-types/typecheck_float_to_int_number.zc5
-rw-r--r--tests/conformance/2-types/typecheck_generic_unify.zc5
-rw-r--r--tests/conformance/2-types/typecheck_index_with_pointer.zc4
-rw-r--r--tests/conformance/2-types/typecheck_number_kinds_convert.zc5
-rw-r--r--tests/conformance/2-types/typecheck_off_argument_count.zc4
-rw-r--r--tests/conformance/2-types/typecheck_off_field_on_int.zc4
-rw-r--r--tests/conformance/2-types/typecheck_off_missing_field.zc4
-rw-r--r--tests/conformance/2-types/typecheck_off_void_return_value_ok.zc5
-rw-r--r--tests/conformance/2-types/typecheck_pointer_arithmetic_ok.zc13
-rw-r--r--tests/conformance/2-types/typecheck_pointer_element_mismatch.zc4
-rw-r--r--tests/conformance/2-types/typecheck_pointer_from_int.zc4
-rw-r--r--tests/conformance/2-types/typecheck_pointer_plus_float.zc4
-rw-r--r--tests/conformance/2-types/typecheck_pointer_times_number.zc4
-rw-r--r--tests/conformance/2-types/typecheck_return_void_value.zc5
-rw-r--r--tests/conformance/2-types/typecheck_string_to_word.zc4
-rw-r--r--tests/conformance/2-types/typecheck_toggle_off.zc7
-rw-r--r--tests/conformance/2-types/typecheck_word_compatible.zc5
-rw-r--r--tests/conformance/2-types/typecheck_zero_to_pointer_function_dyn.zc9
-rw-r--r--tests/conformance/2-types/void_pointer_compatible.zc12
-rw-r--r--tests/conformance/2-types/void_variable.zc6
-rw-r--r--tests/conformance/3-expressions/assign_target_address_first.zc11
-rw-r--r--tests/conformance/3-expressions/assign_to_deref_and_field.zc15
-rw-r--r--tests/conformance/3-expressions/assign_to_literal.zc6
-rw-r--r--tests/conformance/3-expressions/assign_to_non_lvalue.zc7
-rw-r--r--tests/conformance/3-expressions/assign_yields_value.zc11
-rw-r--r--tests/conformance/3-expressions/block_expr_array_literal_vs_block.zc13
-rw-r--r--tests/conformance/3-expressions/block_expr_break_rejected.zc6
-rw-r--r--tests/conformance/3-expressions/block_expr_continue_rejected.zc6
-rw-r--r--tests/conformance/3-expressions/block_expr_m_tail_rejected.zc6
-rw-r--r--tests/conformance/3-expressions/block_expr_return_rejected.zc6
-rw-r--r--tests/conformance/3-expressions/block_expr_scope.zc10
-rw-r--r--tests/conformance/3-expressions/block_expr_u_tail.zc9
-rw-r--r--tests/conformance/3-expressions/block_expr_value.zc11
-rw-r--r--tests/conformance/3-expressions/bstr_compare.zc13
-rw-r--r--tests/conformance/3-expressions/bstr_compare_unsigned.zc8
-rw-r--r--tests/conformance/3-expressions/bstr_concat_and_len.zc9
-rw-r--r--tests/conformance/3-expressions/bstr_index_and_range.zc11
-rw-r--r--tests/conformance/3-expressions/bstr_index_not_lvalue.zc7
-rw-r--r--tests/conformance/3-expressions/bstr_mix_compare_error.zc6
-rw-r--r--tests/conformance/3-expressions/bstr_mix_error.zc6
-rw-r--r--tests/conformance/3-expressions/bstr_put_s_writes_bytes.zc7
-rw-r--r--tests/conformance/3-expressions/bstr_results_shared_not_freed.zc9
-rw-r--r--tests/conformance/3-expressions/bstr_slice.zc14
-rw-r--r--tests/conformance/3-expressions/call_23_parameters.zc8
-rw-r--r--tests/conformance/3-expressions/call_24_parameters.zc7
-rw-r--r--tests/conformance/3-expressions/call_24_parameters_prototype.zc6
-rw-r--r--tests/conformance/3-expressions/call_25_parameters_rejected.zc8
-rw-r--r--tests/conformance/3-expressions/call_before_definition.zc5
-rw-r--r--tests/conformance/3-expressions/call_new_without_rt.zc10
-rw-r--r--tests/conformance/3-expressions/call_params_converted_to_float.zc5
-rw-r--r--tests/conformance/3-expressions/call_params_sized_cut.zc6
-rw-r--r--tests/conformance/3-expressions/call_static_and_const.zc6
-rw-r--r--tests/conformance/3-expressions/call_tag_limit.zc4
-rw-r--r--tests/conformance/3-expressions/call_through_value.zc5
-rw-r--r--tests/conformance/3-expressions/call_type_name_as_value.zc4
-rw-r--r--tests/conformance/3-expressions/call_void_bare_return_value_zero.zc5
-rw-r--r--tests/conformance/3-expressions/call_void_value_zero.zc6
-rw-r--r--tests/conformance/3-expressions/call_wrong_arg_count.zc4
-rw-r--r--tests/conformance/3-expressions/cast_as_char_unchanged.zc9
-rw-r--r--tests/conformance/3-expressions/cast_forms.zc14
-rw-r--r--tests/conformance/3-expressions/cast_name_is_paren_expression.zc8
-rw-r--r--tests/conformance/3-expressions/closure_capture_by_reference.zc11
-rw-r--r--tests/conformance/3-expressions/closure_in_o3_rejected.zc9
-rw-r--r--tests/conformance/3-expressions/closure_outlives_creator.zc15
-rw-r--r--tests/conformance/3-expressions/closure_writes_visible_outside.zc11
-rw-r--r--tests/conformance/3-expressions/compound_assign_evaluates_once.zc11
-rw-r--r--tests/conformance/3-expressions/compound_assign_owner_rejected.zc7
-rw-r--r--tests/conformance/3-expressions/compound_assign_yields_value.zc9
-rw-r--r--tests/conformance/3-expressions/const_expr_array_length.zc9
-rw-r--r--tests/conformance/3-expressions/const_expr_case_label.zc12
-rw-r--r--tests/conformance/3-expressions/const_expr_compare_rejected.zc4
-rw-r--r--tests/conformance/3-expressions/const_expr_division_rejected.zc4
-rw-r--r--tests/conformance/3-expressions/const_expr_function_address.zc7
-rw-r--r--tests/conformance/3-expressions/const_expr_global_const_array_length.zc7
-rw-r--r--tests/conformance/3-expressions/const_expr_left_to_right.zc8
-rw-r--r--tests/conformance/3-expressions/const_expr_local_const_rejected.zc7
-rw-r--r--tests/conformance/3-expressions/const_expr_modulo_rejected.zc4
-rw-r--r--tests/conformance/3-expressions/const_expr_names.zc8
-rw-r--r--tests/conformance/3-expressions/const_expr_neg_not_parens.zc8
-rw-r--r--tests/conformance/3-expressions/const_expr_shift.zc6
-rw-r--r--tests/conformance/3-expressions/const_expr_ternary_rejected.zc4
-rw-r--r--tests/conformance/3-expressions/const_expr_xor_rejected.zc4
-rw-r--r--tests/conformance/3-expressions/decr_prefix_postfix.zc11
-rw-r--r--tests/conformance/3-expressions/dyn_array_array_len_cap_const.zc9
-rw-r--r--tests/conformance/3-expressions/dyn_array_cap_at_least_doubles.zc17
-rw-r--r--tests/conformance/3-expressions/dyn_array_const_index_warning.zc8
-rw-r--r--tests/conformance/3-expressions/dyn_array_index_negative.zc11
-rw-r--r--tests/conformance/3-expressions/dyn_array_index_out_of_range.zc12
-rw-r--r--tests/conformance/3-expressions/dyn_array_intrinsics.zc11
-rw-r--r--tests/conformance/3-expressions/dyn_array_len_of_pointer_typecheck.zc7
-rw-r--r--tests/conformance/3-expressions/dyn_array_new_len_cap.zc13
-rw-r--r--tests/conformance/3-expressions/dyn_array_pop_empty.zc10
-rw-r--r--tests/conformance/3-expressions/dyn_array_pop_returns_last.zc10
-rw-r--r--tests/conformance/3-expressions/dyn_array_push_aggregate.zc9
-rw-r--r--tests/conformance/3-expressions/dyn_array_receiver_calls.zc11
-rw-r--r--tests/conformance/3-expressions/dyn_array_resize.zc16
-rw-r--r--tests/conformance/3-expressions/eval_order_arguments.zc9
-rw-r--r--tests/conformance/3-expressions/eval_order_binary_calls.zc10
-rw-r--r--tests/conformance/3-expressions/eval_order_calls_left_to_right.zc11
-rw-r--r--tests/conformance/3-expressions/eval_order_operands.zc10
-rw-r--r--tests/conformance/3-expressions/float_as_keeps_bits.zc10
-rw-r--r--tests/conformance/3-expressions/float_basic_arith.zc12
-rw-r--r--tests/conformance/3-expressions/float_cast_value_and_bits.zc15
-rw-r--r--tests/conformance/3-expressions/float_division_int_stored.zc10
-rw-r--r--tests/conformance/3-expressions/float_int_ops_on_bits.zc12
-rw-r--r--tests/conformance/3-expressions/float_lit_exponent_arith.zc8
-rw-r--r--tests/conformance/3-expressions/float_mixed_comparisons.zc8
-rw-r--r--tests/conformance/3-expressions/float_negate_is_zero_minus.zc14
-rw-r--r--tests/conformance/3-expressions/float_operand_conversion.zc12
-rw-r--r--tests/conformance/3-expressions/float_tracked_through_locals_fields_params.zc20
-rw-r--r--tests/conformance/3-expressions/incr_needs_lvalue.zc7
-rw-r--r--tests/conformance/3-expressions/incr_needs_lvalue_prefix.zc6
-rw-r--r--tests/conformance/3-expressions/incr_on_float_changes_bits.zc10
-rw-r--r--tests/conformance/3-expressions/int_add_wrap.zc15
-rw-r--r--tests/conformance/3-expressions/int_bitwise_and.zc15
-rw-r--r--tests/conformance/3-expressions/int_bitwise_or.zc13
-rw-r--r--tests/conformance/3-expressions/int_bitwise_xor.zc15
-rw-r--r--tests/conformance/3-expressions/int_compare_ge.zc17
-rw-r--r--tests/conformance/3-expressions/int_compare_signed.zc19
-rw-r--r--tests/conformance/3-expressions/int_div_signs.zc19
-rw-r--r--tests/conformance/3-expressions/int_div_zero.zc13
-rw-r--r--tests/conformance/3-expressions/int_logical_or_values.zc17
-rw-r--r--tests/conformance/3-expressions/int_logical_values.zc17
-rw-r--r--tests/conformance/3-expressions/int_min_div_minus1.zc9
-rw-r--r--tests/conformance/3-expressions/int_min_mod_minus1.zc9
-rw-r--r--tests/conformance/3-expressions/int_mod_signs.zc19
-rw-r--r--tests/conformance/3-expressions/int_mod_zero.zc13
-rw-r--r--tests/conformance/3-expressions/int_mul_wrap.zc15
-rw-r--r--tests/conformance/3-expressions/int_shl_count_mod64.zc23
-rw-r--r--tests/conformance/3-expressions/int_shr_arith.zc23
-rw-r--r--tests/conformance/3-expressions/int_sub_wrap.zc13
-rw-r--r--tests/conformance/3-expressions/member_dot_arrow_same.zc14
-rw-r--r--tests/conformance/3-expressions/member_field_wins_over_method.zc12
-rw-r--r--tests/conformance/3-expressions/member_method_call.zc12
-rw-r--r--tests/conformance/3-expressions/member_missing_field_suggestion.zc8
-rw-r--r--tests/conformance/3-expressions/member_two_pointer_levels.zc9
-rw-r--r--tests/conformance/3-expressions/prec_as_binds_tight.zc10
-rw-r--r--tests/conformance/3-expressions/prec_as_then_star.zc7
-rw-r--r--tests/conformance/3-expressions/prec_assign_lower_than_ternary.zc12
-rw-r--r--tests/conformance/3-expressions/prec_assign_right_assoc.zc9
-rw-r--r--tests/conformance/3-expressions/prec_chains.zc55
-rw-r--r--tests/conformance/3-expressions/prec_compound_assign_right.zc9
-rw-r--r--tests/conformance/3-expressions/prec_deref_postfix.zc12
-rw-r--r--tests/conformance/3-expressions/prec_left_add.zc39
-rw-r--r--tests/conformance/3-expressions/prec_left_and.zc41
-rw-r--r--tests/conformance/3-expressions/prec_left_andand.zc41
-rw-r--r--tests/conformance/3-expressions/prec_left_div.zc43
-rw-r--r--tests/conformance/3-expressions/prec_left_eq.zc43
-rw-r--r--tests/conformance/3-expressions/prec_left_ge.zc43
-rw-r--r--tests/conformance/3-expressions/prec_left_gt.zc43
-rw-r--r--tests/conformance/3-expressions/prec_left_le.zc43
-rw-r--r--tests/conformance/3-expressions/prec_left_lt.zc43
-rw-r--r--tests/conformance/3-expressions/prec_left_mod.zc43
-rw-r--r--tests/conformance/3-expressions/prec_left_mul.zc39
-rw-r--r--tests/conformance/3-expressions/prec_left_ne.zc43
-rw-r--r--tests/conformance/3-expressions/prec_left_or.zc41
-rw-r--r--tests/conformance/3-expressions/prec_left_oror.zc41
-rw-r--r--tests/conformance/3-expressions/prec_left_shl.zc43
-rw-r--r--tests/conformance/3-expressions/prec_left_shr.zc43
-rw-r--r--tests/conformance/3-expressions/prec_left_sub.zc43
-rw-r--r--tests/conformance/3-expressions/prec_left_xor.zc41
-rw-r--r--tests/conformance/3-expressions/prec_postfix_incr_value.zc11
-rw-r--r--tests/conformance/3-expressions/prec_postfix_tighter_than_prefix.zc12
-rw-r--r--tests/conformance/3-expressions/prec_table_examples.zc24
-rw-r--r--tests/conformance/3-expressions/prec_ternary_cond_is_binary.zc12
-rw-r--r--tests/conformance/3-expressions/prec_ternary_else_assign.zc13
-rw-r--r--tests/conformance/3-expressions/prec_ternary_middle_full_expr.zc10
-rw-r--r--tests/conformance/3-expressions/prec_unary_vs_binary.zc12
-rw-r--r--tests/conformance/3-expressions/ptr_add_words.zc14
-rw-r--r--tests/conformance/3-expressions/ptr_addr_of_forms.zc24
-rw-r--r--tests/conformance/3-expressions/ptr_deref_struct_is_address.zc11
-rw-r--r--tests/conformance/3-expressions/ptr_difference.zc12
-rw-r--r--tests/conformance/3-expressions/ptr_field_of_new_object.zc7
-rw-r--r--tests/conformance/3-expressions/ptr_index_must_be_number.zc8
-rw-r--r--tests/conformance/3-expressions/ptr_index_new_object.zc6
-rw-r--r--tests/conformance/3-expressions/ptr_index_scaled.zc13
-rw-r--r--tests/conformance/3-expressions/short_circuit.zc15
-rw-r--r--tests/conformance/3-expressions/short_circuit_and_evaluates_right.zc10
-rw-r--r--tests/conformance/3-expressions/short_circuit_or_evaluates_right_when_zero.zc10
-rw-r--r--tests/conformance/3-expressions/short_circuit_or_skips_right.zc10
-rw-r--r--tests/conformance/3-expressions/sizeof_expr_not_run.zc10
-rw-r--r--tests/conformance/3-expressions/sizeof_packed.zc6
-rw-r--r--tests/conformance/3-expressions/ternary_nests_right.zc10
-rw-r--r--tests/conformance/3-expressions/ternary_one_branch_only.zc14
-rw-r--r--tests/conformance/3-expressions/typeof_print.zc9
-rw-r--r--tests/conformance/3-expressions/unary_minus_wraps.zc9
-rw-r--r--tests/conformance/3-expressions/unary_ops_values.zc8
-rw-r--r--tests/conformance/4-statements/asm_arith_mnemonics.zc11
-rw-r--r--tests/conformance/4-statements/asm_constant_name.zc6
-rw-r--r--tests/conformance/4-statements/asm_expression_value.zc5
-rw-r--r--tests/conformance/4-statements/asm_float_literal.zc7
-rw-r--r--tests/conformance/4-statements/asm_function_name.zc6
-rw-r--r--tests/conformance/4-statements/asm_negative_literal.zc5
-rw-r--r--tests/conformance/4-statements/asm_statement_local.zc5
-rw-r--r--tests/conformance/4-statements/asm_string_pushes_address.zc5
-rw-r--r--tests/conformance/4-statements/asm_unknown_name.zc5
-rw-r--r--tests/conformance/4-statements/break_inner_loop_only.zc12
-rw-r--r--tests/conformance/4-statements/break_outside.zc5
-rw-r--r--tests/conformance/4-statements/checked_owned_never_used.zc9
-rw-r--r--tests/conformance/4-statements/continue_in_switch_outside_loop.zc5
-rw-r--r--tests/conformance/4-statements/continue_outside.zc5
-rw-r--r--tests/conformance/4-statements/decl_const_assign.zc5
-rw-r--r--tests/conformance/4-statements/decl_const_increment.zc5
-rw-r--r--tests/conformance/4-statements/decl_const_local_typed_float.zc6
-rw-r--r--tests/conformance/4-statements/decl_const_takes_initializer_type.zc6
-rw-r--r--tests/conformance/4-statements/decl_for_init_scope.zc5
-rw-r--r--tests/conformance/4-statements/decl_for_let_init_scope.zc5
-rw-r--r--tests/conformance/4-statements/decl_let_array.zc10
-rw-r--r--tests/conformance/4-statements/decl_let_bstr.zc9
-rw-r--r--tests/conformance/4-statements/decl_let_char_ptr.zc9
-rw-r--r--tests/conformance/4-statements/decl_let_float_local.zc10
-rw-r--r--tests/conformance/4-statements/decl_let_function_type.zc6
-rw-r--r--tests/conformance/4-statements/decl_let_integer_is_word.zc5
-rw-r--r--tests/conformance/4-statements/decl_let_multiple.zc10
-rw-r--r--tests/conformance/4-statements/decl_redeclare_same_block.zc5
-rw-r--r--tests/conformance/4-statements/decl_scope_ends_with_block.zc5
-rw-r--r--tests/conformance/4-statements/decl_shadow_function_name.zc6
-rw-r--r--tests/conformance/4-statements/decl_shadow_global.zc6
-rw-r--r--tests/conformance/4-statements/decl_shadow_outer_block.zc10
-rw-r--r--tests/conformance/4-statements/decl_shadow_param.zc6
-rw-r--r--tests/conformance/4-statements/decl_tag_only.zc10
-rw-r--r--tests/conformance/4-statements/decl_typed_array_declarator.zc10
-rw-r--r--tests/conformance/4-statements/decl_typed_multi.zc11
-rw-r--r--tests/conformance/4-statements/decl_typed_tag_u_hand_up.zc14
-rw-r--r--tests/conformance/4-statements/decl_uninit_global_is_zero.zc8
-rw-r--r--tests/conformance/4-statements/decl_void_variable.zc5
-rw-r--r--tests/conformance/4-statements/do_basic.zc11
-rw-r--r--tests/conformance/4-statements/do_break.zc6
-rw-r--r--tests/conformance/4-statements/do_continue_jumps_to_test.zc6
-rw-r--r--tests/conformance/4-statements/do_runs_once.zc6
-rw-r--r--tests/conformance/4-statements/for_basic.zc5
-rw-r--r--tests/conformance/4-statements/for_cond_tests_first.zc5
-rw-r--r--tests/conformance/4-statements/for_continue_runs_step.zc10
-rw-r--r--tests/conformance/4-statements/for_empty_parts.zc10
-rw-r--r--tests/conformance/4-statements/for_expression_init.zc5
-rw-r--r--tests/conformance/4-statements/for_let_init.zc5
-rw-r--r--tests/conformance/4-statements/for_variable_is_scoped.zc11
-rw-r--r--tests/conformance/4-statements/hints_forms_accepted.zc9
-rw-r--r--tests/conformance/4-statements/if_basic.zc10
-rw-r--r--tests/conformance/4-statements/if_branch_is_own_scope.zc5
-rw-r--r--tests/conformance/4-statements/if_else_binds_nearest.zc8
-rw-r--r--tests/conformance/4-statements/if_else_binds_nearest_outer_not_taken.zc8
-rw-r--r--tests/conformance/4-statements/if_else_chain.zc9
-rw-r--r--tests/conformance/4-statements/if_float_condition.zc11
-rw-r--r--tests/conformance/4-statements/memdebug_double_free.zc10
-rw-r--r--tests/conformance/4-statements/memdebug_off.zc8
-rw-r--r--tests/conformance/4-statements/memdebug_report.zc15
-rw-r--r--tests/conformance/4-statements/memdebug_report_line.zc15
-rw-r--r--tests/conformance/4-statements/memdebug_scrub_accepted.zc7
-rw-r--r--tests/conformance/4-statements/memdebug_scrub_fills.zc10
-rw-r--r--tests/conformance/4-statements/memdebug_statement_form.zc6
-rw-r--r--tests/conformance/4-statements/memdebug_use_after_free.zc10
-rw-r--r--tests/conformance/4-statements/nested_return_in_loop.zc9
-rw-r--r--tests/conformance/4-statements/o3_asm_cannot_reach.zc6
-rw-r--r--tests/conformance/4-statements/o3_block.zc11
-rw-r--r--tests/conformance/4-statements/o3_fn_form.zc7
-rw-r--r--tests/conformance/4-statements/o3_function_sum.zc13
-rw-r--r--tests/conformance/4-statements/o3_nested_is_ordinary_block.zc6
-rw-r--r--tests/conformance/4-statements/o3_no_address_of.zc6
-rw-r--r--tests/conformance/4-statements/o3_outside_function_ordinary_block.zc7
-rw-r--r--tests/conformance/4-statements/o3_parameter_needs_type.zc7
-rw-r--r--tests/conformance/4-statements/o3_single_variable.zc6
-rw-r--r--tests/conformance/4-statements/o3_variable_needs_type.zc6
-rw-r--r--tests/conformance/4-statements/return_bare_is_zero.zc6
-rw-r--r--tests/conformance/4-statements/return_fall_off_is_zero.zc6
-rw-r--r--tests/conformance/4-statements/return_frees_owned_locals.zc11
-rw-r--r--tests/conformance/4-statements/return_outside_function.zc6
-rw-r--r--tests/conformance/4-statements/return_value_converted_float.zc7
-rw-r--r--tests/conformance/4-statements/return_value_converted_int.zc6
-rw-r--r--tests/conformance/4-statements/return_void_value_typecheck_on.zc7
-rw-r--r--tests/conformance/4-statements/stmt_block_scope.zc5
-rw-r--r--tests/conformance/4-statements/stmt_empty_statement.zc5
-rw-r--r--tests/conformance/4-statements/stmt_expression_value_dropped.zc5
-rw-r--r--tests/conformance/4-statements/stmt_fresh_value_thrown_away.zc5
-rw-r--r--tests/conformance/4-statements/stmt_u_result_thrown_away.zc6
-rw-r--r--tests/conformance/4-statements/switch_break_in_loop_leaves_switch_only.zc13
-rw-r--r--tests/conformance/4-statements/switch_break_leaves_early.zc10
-rw-r--r--tests/conformance/4-statements/switch_case_own_block.zc11
-rw-r--r--tests/conformance/4-statements/switch_case_three.zc10
-rw-r--r--tests/conformance/4-statements/switch_case_underscore.zc7
-rw-r--r--tests/conformance/4-statements/switch_continue_continues_loop.zc10
-rw-r--r--tests/conformance/4-statements/switch_default_and_underscore.zc5
-rw-r--r--tests/conformance/4-statements/switch_default_first_position_not_matched.zc10
-rw-r--r--tests/conformance/4-statements/switch_default_first_position_taken.zc10
-rw-r--r--tests/conformance/4-statements/switch_default_middle.zc7
-rw-r--r--tests/conformance/4-statements/switch_default_runs.zc10
-rw-r--r--tests/conformance/4-statements/switch_duplicate_labels_first_wins.zc10
-rw-r--r--tests/conformance/4-statements/switch_expression_evaluated_once.zc10
-rw-r--r--tests/conformance/4-statements/switch_label_forms.zc16
-rw-r--r--tests/conformance/4-statements/switch_nested.zc14
-rw-r--r--tests/conformance/4-statements/switch_no_fallthrough_k2.zc10
-rw-r--r--tests/conformance/4-statements/switch_no_match_no_default.zc11
-rw-r--r--tests/conformance/4-statements/switch_non_constant_label.zc5
-rw-r--r--tests/conformance/4-statements/switch_return_inside_case.zc6
-rw-r--r--tests/conformance/4-statements/switch_tagged_all_covered_no_warning.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_binding_count.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_binding_scoped_to_case.zc12
-rw-r--r--tests/conformance/4-statements/switch_tagged_circle.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_default_no_warning.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_example.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_match_by_tag.zc19
-rw-r--r--tests/conformance/4-statements/switch_tagged_uncovered_warning.zc11
-rw-r--r--tests/conformance/4-statements/switch_tagged_uncovered_warning_not_error.zc11
-rw-r--r--tests/conformance/4-statements/switch_two_defaults.zc5
-rw-r--r--tests/conformance/4-statements/switch_two_underscores.zc5
-rw-r--r--tests/conformance/4-statements/unchecked_fn.zc6
-rw-r--r--tests/conformance/4-statements/unchecked_fn_does_not_extend.zc6
-rw-r--r--tests/conformance/4-statements/unchecked_stmt_block.zc9
-rw-r--r--tests/conformance/4-statements/unchecked_stmt_single.zc10
-rw-r--r--tests/conformance/4-statements/unchecked_toplevel_rest_of_unit.zc10
-rw-r--r--tests/conformance/4-statements/unchecked_tracked_local_rejected.zc9
-rw-r--r--tests/conformance/4-statements/while_basic.zc5
-rw-r--r--tests/conformance/4-statements/while_continue.zc10
-rw-r--r--tests/conformance/4-statements/while_one_exit_by_return.zc6
-rw-r--r--tests/conformance/4-statements/while_one_exits_by_break.zc5
-rw-r--r--tests/conformance/4-statements/while_tests_before.zc5
-rwxr-xr-xtests/conformance/run.sh180
553 files changed, 5294 insertions, 0 deletions
diff --git a/tests/conformance/1-source/backtick_get_c_eof.zc b/tests/conformance/1-source/backtick_get_c_eof.zc
new file mode 100644
index 0000000..71084b2
--- /dev/null
+++ b/tests/conformance/1-source/backtick_get_c_eof.zc
@@ -0,0 +1,4 @@
+// expect: 120/-1/
+include rt;
+fn main() { rt.put_n(rt.get_c()); rt.put_c(10); rt.get_c(); rt.put_n(rt.get_c()); rt.put_c(10); return 0; }
+`x
diff --git a/tests/conformance/1-source/backtick_in_literals_and_comments.zc b/tests/conformance/1-source/backtick_in_literals_and_comments.zc
new file mode 100644
index 0000000..bc21425
--- /dev/null
+++ b/tests/conformance/1-source/backtick_in_literals_and_comments.zc
@@ -0,0 +1,9 @@
+// expect: 96/96/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+// a backtick in a line comment ` is ordinary
+/* and in a block comment ` too */
+fn main() {
+ pn('`'); pn("`"[0]); pn(1);
+ return 0;
+}
diff --git a/tests/conformance/1-source/backtick_stdin.zc b/tests/conformance/1-source/backtick_stdin.zc
new file mode 100644
index 0000000..21dff76
--- /dev/null
+++ b/tests/conformance/1-source/backtick_stdin.zc
@@ -0,0 +1,4 @@
+// expect: 120/121/10/
+include rt;
+fn main() { while (!rt.eof()) { rt.put_n(rt.get_c()); rt.put_c(10); } return 0; }
+`xy
diff --git a/tests/conformance/1-source/comment_block.zc b/tests/conformance/1-source/comment_block.zc
new file mode 100644
index 0000000..6115037
--- /dev/null
+++ b/tests/conformance/1-source/comment_block.zc
@@ -0,0 +1,8 @@
+// expect: 2/
+include rt;
+fn main() {
+ /* rt.put_n(9);
+ // still inside */ rt.put_n(2);
+ rt.put_c(10);
+ return 0;
+}
diff --git a/tests/conformance/1-source/comment_block_in_middle_of_expr.zc b/tests/conformance/1-source/comment_block_in_middle_of_expr.zc
new file mode 100644
index 0000000..7c1c465
--- /dev/null
+++ b/tests/conformance/1-source/comment_block_in_middle_of_expr.zc
@@ -0,0 +1,5 @@
+// expect: 9/
+// spec 1.2.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(4 /* five */ + /* nine */ 5); return 0; }
diff --git a/tests/conformance/1-source/comment_block_no_nest.zc b/tests/conformance/1-source/comment_block_no_nest.zc
new file mode 100644
index 0000000..026167a
--- /dev/null
+++ b/tests/conformance/1-source/comment_block_no_nest.zc
@@ -0,0 +1,7 @@
+// expect: 7/
+include rt;
+fn main() {
+ /* outer /* inner */ rt.put_n(7); /* tail */
+ rt.put_c(10);
+ return 0;
+}
diff --git a/tests/conformance/1-source/comment_block_spans_lines_with_quote.zc b/tests/conformance/1-source/comment_block_spans_lines_with_quote.zc
new file mode 100644
index 0000000..9ffb42d
--- /dev/null
+++ b/tests/conformance/1-source/comment_block_spans_lines_with_quote.zc
@@ -0,0 +1,10 @@
+// expect: 1/
+// spec 1.2.2: a quote inside a comment is not a literal
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ /* "unterminated
+ ' also */
+ pn(1);
+ return 0;
+}
diff --git a/tests/conformance/1-source/comment_block_unclosed.zc b/tests/conformance/1-source/comment_block_unclosed.zc
new file mode 100644
index 0000000..4ae34e7
--- /dev/null
+++ b/tests/conformance/1-source/comment_block_unclosed.zc
@@ -0,0 +1,4 @@
+// expect: 4/
+include rt;
+fn main() { rt.put_n(4); rt.put_c(10); return 0; }
+/* never closed: rt.put_n(9);
diff --git a/tests/conformance/1-source/comment_doc_does_not_change_code.zc b/tests/conformance/1-source/comment_doc_does_not_change_code.zc
new file mode 100644
index 0000000..2784c2b
--- /dev/null
+++ b/tests/conformance/1-source/comment_doc_does_not_change_code.zc
@@ -0,0 +1,6 @@
+// expect: 3/
+include rt;
+//: implementation note
+// documents f
+int f() { return 3; }
+fn main() { rt.put_n(/* intentional */ f()); rt.put_c(10); return 0; }
diff --git a/tests/conformance/1-source/comment_line.zc b/tests/conformance/1-source/comment_line.zc
new file mode 100644
index 0000000..7fd68f0
--- /dev/null
+++ b/tests/conformance/1-source/comment_line.zc
@@ -0,0 +1,8 @@
+// expect: 1/
+include rt;
+fn main() {
+ // rt.put_n(9); /* not a block start
+ rt.put_n(1); // trailing comment
+ rt.put_c(10);
+ return 0;
+}
diff --git a/tests/conformance/1-source/comment_line_ends_at_newline.zc b/tests/conformance/1-source/comment_line_ends_at_newline.zc
new file mode 100644
index 0000000..e3f5053
--- /dev/null
+++ b/tests/conformance/1-source/comment_line_ends_at_newline.zc
@@ -0,0 +1,9 @@
+// expect: 6/
+// spec 1.2.1: a // comment runs to the end of the line only
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 1; // pn(100);
+ int b = 5; pn(a + b);
+ return 0;
+}
diff --git a/tests/conformance/1-source/comment_line_in_string.zc b/tests/conformance/1-source/comment_line_in_string.zc
new file mode 100644
index 0000000..d8a16f5
--- /dev/null
+++ b/tests/conformance/1-source/comment_line_in_string.zc
@@ -0,0 +1,4 @@
+// expect: 4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(rt.len_w("a//b")); return 0; }
diff --git a/tests/conformance/1-source/comment_slash_star_in_string.zc b/tests/conformance/1-source/comment_slash_star_in_string.zc
new file mode 100644
index 0000000..f552cc4
--- /dev/null
+++ b/tests/conformance/1-source/comment_slash_star_in_string.zc
@@ -0,0 +1,5 @@
+// expect: 2/
+// spec 1.2: comment starts inside a string literal are ordinary characters
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(rt.len_w("/*")); /* real comment */ return 0; }
diff --git a/tests/conformance/1-source/ident_case_sensitive.zc b/tests/conformance/1-source/ident_case_sensitive.zc
new file mode 100644
index 0000000..eb53ddb
--- /dev/null
+++ b/tests/conformance/1-source/ident_case_sensitive.zc
@@ -0,0 +1,6 @@
+// expect: 10/20/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int Foo() { return 10; }
+int foo() { return 20; }
+fn main() { pn(Foo()); pn(foo()); return 0; }
diff --git a/tests/conformance/1-source/ident_digits_underscore_long.zc b/tests/conformance/1-source/ident_digits_underscore_long.zc
new file mode 100644
index 0000000..92a068f
--- /dev/null
+++ b/tests/conformance/1-source/ident_digits_underscore_long.zc
@@ -0,0 +1,5 @@
+// expect: 3/
+// spec 1.3.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int __x_9 = 1, _q = 2; pn(__x_9 + _q); return 0; }
diff --git a/tests/conformance/1-source/ident_forms.zc b/tests/conformance/1-source/ident_forms.zc
new file mode 100644
index 0000000..6735dec
--- /dev/null
+++ b/tests/conformance/1-source/ident_forms.zc
@@ -0,0 +1,8 @@
+// expect: 1/2/3/4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int _a = 1, a1_b2 = 2, A = 3, a = 4;
+ pn(_a); pn(a1_b2); pn(A); pn(a);
+ return 0;
+}
diff --git a/tests/conformance/1-source/ident_keyword_as_local_if.zc b/tests/conformance/1-source/ident_keyword_as_local_if.zc
new file mode 100644
index 0000000..3d03b43
--- /dev/null
+++ b/tests/conformance/1-source/ident_keyword_as_local_if.zc
@@ -0,0 +1,4 @@
+// expect: 5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int if = 4; pn(if + 1); return 0; }
diff --git a/tests/conformance/1-source/ident_keyword_as_local_len.zc b/tests/conformance/1-source/ident_keyword_as_local_len.zc
new file mode 100644
index 0000000..f324f5c
--- /dev/null
+++ b/tests/conformance/1-source/ident_keyword_as_local_len.zc
@@ -0,0 +1,4 @@
+// expect: 5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int len = 5; pn(len); return 0; }
diff --git a/tests/conformance/1-source/ident_keyword_as_param.zc b/tests/conformance/1-source/ident_keyword_as_param.zc
new file mode 100644
index 0000000..1a66c5c
--- /dev/null
+++ b/tests/conformance/1-source/ident_keyword_as_param.zc
@@ -0,0 +1,5 @@
+// expect: 9/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f(int push, int sizeof) { return push + sizeof; }
+fn main() { pn(f(4, 5)); return 0; }
diff --git a/tests/conformance/1-source/ident_non_letter_start.zc b/tests/conformance/1-source/ident_non_letter_start.zc
new file mode 100644
index 0000000..4de3ca2
--- /dev/null
+++ b/tests/conformance/1-source/ident_non_letter_start.zc
@@ -0,0 +1,5 @@
+// expect error: zc: line
+// spec 1.3.1: an identifier starts with a letter or underscore
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int 9a = 1; return 0; }
diff --git a/tests/conformance/1-source/ident_positional_words_as_names.zc b/tests/conformance/1-source/ident_positional_words_as_names.zc
new file mode 100644
index 0000000..c4ee296
--- /dev/null
+++ b/tests/conformance/1-source/ident_positional_words_as_names.zc
@@ -0,0 +1,8 @@
+// expect: 21/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int fn = 1, const = 2, fixed = 3, static = 4, case = 5, default = 6;
+ pn(fn + const + fixed + static + case + default);
+ return 0;
+}
diff --git a/tests/conformance/1-source/ident_positional_words_as_names_2.zc b/tests/conformance/1-source/ident_positional_words_as_names_2.zc
new file mode 100644
index 0000000..12e5883
--- /dev/null
+++ b/tests/conformance/1-source/ident_positional_words_as_names_2.zc
@@ -0,0 +1,8 @@
+// expect: 15/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int on = 1, off = 2, small = 3, micro = 4, vm = 5;
+ pn(on + off + small + micro + vm);
+ return 0;
+}
diff --git a/tests/conformance/1-source/ident_tags_as_variables.zc b/tests/conformance/1-source/ident_tags_as_variables.zc
new file mode 100644
index 0000000..f453d3b
--- /dev/null
+++ b/tests/conformance/1-source/ident_tags_as_variables.zc
@@ -0,0 +1,9 @@
+// expect: 12/7/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int u = 3, d = 4, m = 0;
+ pn(u * d);
+ pn(u+d+m);
+ return 0;
+}
diff --git a/tests/conformance/1-source/ident_tags_as_variables_glued_star.zc b/tests/conformance/1-source/ident_tags_as_variables_glued_star.zc
new file mode 100644
index 0000000..a8dc700
--- /dev/null
+++ b/tests/conformance/1-source/ident_tags_as_variables_glued_star.zc
@@ -0,0 +1,8 @@
+// expect: 12/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int u = 3, d = 4;
+ pn(u*d);
+ return 0;
+}
diff --git a/tests/conformance/1-source/ident_type_name_shadow.zc b/tests/conformance/1-source/ident_type_name_shadow.zc
new file mode 100644
index 0000000..6ed2018
--- /dev/null
+++ b/tests/conformance/1-source/ident_type_name_shadow.zc
@@ -0,0 +1,4 @@
+// expect: 8/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int float = 7; pn(float + 1); return 0; }
diff --git a/tests/conformance/1-source/keyword_expr_keywords_ok.zc b/tests/conformance/1-source/keyword_expr_keywords_ok.zc
new file mode 100644
index 0000000..6300e16
--- /dev/null
+++ b/tests/conformance/1-source/keyword_expr_keywords_ok.zc
@@ -0,0 +1,6 @@
+// expect: 1/1/1/
+// spec 1.3.4: sizeof, typeof, len are expression keywords
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int[4] a; pn(sizeof(int)); pn(typeof(int) != 0); pn(len(a) == 4); return 0; }
+// zc0: skip
diff --git a/tests/conformance/1-source/keyword_in_expr_break.zc b/tests/conformance/1-source/keyword_in_expr_break.zc
new file mode 100644
index 0000000..2b8f3b9
--- /dev/null
+++ b/tests/conformance/1-source/keyword_in_expr_break.zc
@@ -0,0 +1,5 @@
+// expect error: break: can't be used inside an expression
+// spec 1.3.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { while (1) { int x = break; } return 0; }
diff --git a/tests/conformance/1-source/keyword_in_expr_do.zc b/tests/conformance/1-source/keyword_in_expr_do.zc
new file mode 100644
index 0000000..2307d12
--- /dev/null
+++ b/tests/conformance/1-source/keyword_in_expr_do.zc
@@ -0,0 +1,5 @@
+// expect error: do: can't be used inside an expression
+// spec 1.3.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = do; return 0; }
diff --git a/tests/conformance/1-source/keyword_in_expr_else.zc b/tests/conformance/1-source/keyword_in_expr_else.zc
new file mode 100644
index 0000000..234d71e
--- /dev/null
+++ b/tests/conformance/1-source/keyword_in_expr_else.zc
@@ -0,0 +1,5 @@
+// expect error: zc: line
+// spec 1.3.4: else is consumed by if, so it can't stand alone
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { else { } return 0; }
diff --git a/tests/conformance/1-source/keyword_in_expr_for.zc b/tests/conformance/1-source/keyword_in_expr_for.zc
new file mode 100644
index 0000000..a697992
--- /dev/null
+++ b/tests/conformance/1-source/keyword_in_expr_for.zc
@@ -0,0 +1,5 @@
+// expect error: for: can't be used inside an expression
+// spec 1.3.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = for; return 0; }
diff --git a/tests/conformance/1-source/keyword_in_expr_if.zc b/tests/conformance/1-source/keyword_in_expr_if.zc
new file mode 100644
index 0000000..eab2e45
--- /dev/null
+++ b/tests/conformance/1-source/keyword_in_expr_if.zc
@@ -0,0 +1,5 @@
+// expect error: if: can't be used inside an expression
+// spec 1.3.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = if + 1; return 0; }
diff --git a/tests/conformance/1-source/keyword_in_expr_let.zc b/tests/conformance/1-source/keyword_in_expr_let.zc
new file mode 100644
index 0000000..f16b0f6
--- /dev/null
+++ b/tests/conformance/1-source/keyword_in_expr_let.zc
@@ -0,0 +1,5 @@
+// expect error: let: can't be used inside an expression
+// spec 1.3.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = let; return 0; }
diff --git a/tests/conformance/1-source/keyword_in_expr_return.zc b/tests/conformance/1-source/keyword_in_expr_return.zc
new file mode 100644
index 0000000..c1bee83
--- /dev/null
+++ b/tests/conformance/1-source/keyword_in_expr_return.zc
@@ -0,0 +1,5 @@
+// expect error: return: can't be used inside an expression
+// spec 1.3.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = return; return 0; }
diff --git a/tests/conformance/1-source/keyword_in_expr_switch.zc b/tests/conformance/1-source/keyword_in_expr_switch.zc
new file mode 100644
index 0000000..626d897
--- /dev/null
+++ b/tests/conformance/1-source/keyword_in_expr_switch.zc
@@ -0,0 +1,5 @@
+// expect error: switch: can't be used inside an expression
+// spec 1.3.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = switch; return 0; }
diff --git a/tests/conformance/1-source/keyword_s_only_in_expression.zc b/tests/conformance/1-source/keyword_s_only_in_expression.zc
new file mode 100644
index 0000000..7e6c6cc
--- /dev/null
+++ b/tests/conformance/1-source/keyword_s_only_in_expression.zc
@@ -0,0 +1,2 @@
+// expect error: can't be used inside an expression
+fn main() { int x = while + 1; return 0; }
diff --git a/tests/conformance/1-source/lit_bstr_basic.zc b/tests/conformance/1-source/lit_bstr_basic.zc
new file mode 100644
index 0000000..3157bd1
--- /dev/null
+++ b/tests/conformance/1-source/lit_bstr_basic.zc
@@ -0,0 +1,9 @@
+// expect: 5/el/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let t = b"hello";
+ pn(len(t));
+ rt.put_s(t[1:3]); rt.put_c(10);
+ return 0;
+}
diff --git a/tests/conformance/1-source/lit_bstr_cast_to_int_pointer.zc b/tests/conformance/1-source/lit_bstr_cast_to_int_pointer.zc
new file mode 100644
index 0000000..8959ca3
--- /dev/null
+++ b/tests/conformance/1-source/lit_bstr_cast_to_int_pointer.zc
@@ -0,0 +1,10 @@
+// expect: 2/16961/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ bstr t = b"AB";
+ int* w = (int*)t;
+ pn(w[0]); pn(w[1]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/1-source/lit_bstr_empty.zc b/tests/conformance/1-source/lit_bstr_empty.zc
new file mode 100644
index 0000000..9b2374b
--- /dev/null
+++ b/tests/conformance/1-source/lit_bstr_empty.zc
@@ -0,0 +1,5 @@
+// expect: 0/
+// spec 1.4.5
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { bstr t = b""; pn(len(t)); return 0; }
diff --git a/tests/conformance/1-source/lit_bstr_escape_and_len.zc b/tests/conformance/1-source/lit_bstr_escape_and_len.zc
new file mode 100644
index 0000000..33b3c11
--- /dev/null
+++ b/tests/conformance/1-source/lit_bstr_escape_and_len.zc
@@ -0,0 +1,5 @@
+// expect: 4/10/9/
+// spec 1.4.5
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { bstr t = b"a\n\tb"; pn(len(t)); pn(t[1]); pn(t[2]); return 0; }
diff --git a/tests/conformance/1-source/lit_bstr_layout.zc b/tests/conformance/1-source/lit_bstr_layout.zc
new file mode 100644
index 0000000..0104237
--- /dev/null
+++ b/tests/conformance/1-source/lit_bstr_layout.zc
@@ -0,0 +1,11 @@
+// expect: 2/16961/9/5208208757389214273/73/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn rd(a, i) { return asm { a @ i @ + @ }; }
+fn main() {
+ bstr t = b"AB";
+ pn(rd(t, 0)); pn(rd(t, 1));
+ bstr u = b"ABCDEFGHI";
+ pn(rd(u, 0)); pn(rd(u, 1)); pn(rd(u, 2));
+ return 0;
+}
diff --git a/tests/conformance/1-source/lit_bstr_name_b_still_usable.zc b/tests/conformance/1-source/lit_bstr_name_b_still_usable.zc
new file mode 100644
index 0000000..06534a0
--- /dev/null
+++ b/tests/conformance/1-source/lit_bstr_name_b_still_usable.zc
@@ -0,0 +1,4 @@
+// expect: 7/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { let b = 7; let t = b"hi"; pn(b); pn(len(t)); return 0; }
diff --git a/tests/conformance/1-source/lit_bstr_nul_truncates.zc b/tests/conformance/1-source/lit_bstr_nul_truncates.zc
new file mode 100644
index 0000000..fbf1522
--- /dev/null
+++ b/tests/conformance/1-source/lit_bstr_nul_truncates.zc
@@ -0,0 +1,4 @@
+// expect: 3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { bstr t = b"hi\n\0x"; pn(len(t)); return 0; }
diff --git a/tests/conformance/1-source/lit_bstr_space_is_name.zc b/tests/conformance/1-source/lit_bstr_space_is_name.zc
new file mode 100644
index 0000000..7f4e27a
--- /dev/null
+++ b/tests/conformance/1-source/lit_bstr_space_is_name.zc
@@ -0,0 +1,7 @@
+// expect error: zc: line 4:
+include rt;
+fn main() {
+ let b = 1; let t = b "hi";
+ return 0;
+}
+// zc0: error
diff --git a/tests/conformance/1-source/lit_char_non_ascii.zc b/tests/conformance/1-source/lit_char_non_ascii.zc
new file mode 100644
index 0000000..4eebaac
--- /dev/null
+++ b/tests/conformance/1-source/lit_char_non_ascii.zc
@@ -0,0 +1,4 @@
+// expect error: bad character literal
+include rt;
+fn main() { rt.put_n('é'); return 0; }
+// zc0: error
diff --git a/tests/conformance/1-source/lit_char_non_ascii_global.zc b/tests/conformance/1-source/lit_char_non_ascii_global.zc
new file mode 100644
index 0000000..d63db4f
--- /dev/null
+++ b/tests/conformance/1-source/lit_char_non_ascii_global.zc
@@ -0,0 +1,5 @@
+// expect error: bad character literal
+include rt;
+int g = 'é';
+fn main() { rt.put_n(g); return 0; }
+// zc0: error
diff --git a/tests/conformance/1-source/lit_char_non_ascii_later.zc b/tests/conformance/1-source/lit_char_non_ascii_later.zc
new file mode 100644
index 0000000..e447b2a
--- /dev/null
+++ b/tests/conformance/1-source/lit_char_non_ascii_later.zc
@@ -0,0 +1,5 @@
+// expect error: bad character literal
+// spec 1.4.2 (the literal is not in the first statement of the function)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(1); rt.put_n('é'); return 0; }
diff --git a/tests/conformance/1-source/lit_char_range_0_255.zc b/tests/conformance/1-source/lit_char_range_0_255.zc
new file mode 100644
index 0000000..684a838
--- /dev/null
+++ b/tests/conformance/1-source/lit_char_range_0_255.zc
@@ -0,0 +1,4 @@
+// expect: 97/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int c = 'a'; pn(c); return 0; }
diff --git a/tests/conformance/1-source/lit_char_two_bytes.zc b/tests/conformance/1-source/lit_char_two_bytes.zc
new file mode 100644
index 0000000..ad57dde
--- /dev/null
+++ b/tests/conformance/1-source/lit_char_two_bytes.zc
@@ -0,0 +1,4 @@
+// expect error: bad character literal
+include rt;
+fn main() { rt.put_n('ab'); return 0; }
+// zc0: error
diff --git a/tests/conformance/1-source/lit_char_two_bytes_global.zc b/tests/conformance/1-source/lit_char_two_bytes_global.zc
new file mode 100644
index 0000000..97ad88c
--- /dev/null
+++ b/tests/conformance/1-source/lit_char_two_bytes_global.zc
@@ -0,0 +1,5 @@
+// expect error: bad character literal
+include rt;
+int g = 'ab';
+fn main() { rt.put_n(g); return 0; }
+// zc0: error
diff --git a/tests/conformance/1-source/lit_char_two_bytes_later.zc b/tests/conformance/1-source/lit_char_two_bytes_later.zc
new file mode 100644
index 0000000..741d193
--- /dev/null
+++ b/tests/conformance/1-source/lit_char_two_bytes_later.zc
@@ -0,0 +1,5 @@
+// expect error: bad character literal
+// spec 1.4.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(1); rt.put_n('ab'); return 0; }
diff --git a/tests/conformance/1-source/lit_char_two_bytes_local_init.zc b/tests/conformance/1-source/lit_char_two_bytes_local_init.zc
new file mode 100644
index 0000000..e9df924
--- /dev/null
+++ b/tests/conformance/1-source/lit_char_two_bytes_local_init.zc
@@ -0,0 +1,5 @@
+// expect error: bad character literal
+// spec 1.4.2 (a local initializer as the first statement)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 'ab'; pn(5); return 0; }
diff --git a/tests/conformance/1-source/lit_char_values.zc b/tests/conformance/1-source/lit_char_values.zc
new file mode 100644
index 0000000..34b7f81
--- /dev/null
+++ b/tests/conformance/1-source/lit_char_values.zc
@@ -0,0 +1,8 @@
+// expect: 65/10/9/13/0/27/92/39/120/34/34/96/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn('A'); pn('\n'); pn('\t'); pn('\r'); pn('\0'); pn('\e');
+ pn('\\'); pn('\''); pn('\x'); pn('"'); pn('\"'); pn('`');
+ return 0;
+}
diff --git a/tests/conformance/1-source/lit_float_bad_exponent.zc b/tests/conformance/1-source/lit_float_bad_exponent.zc
new file mode 100644
index 0000000..581985d
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_bad_exponent.zc
@@ -0,0 +1,4 @@
+// expect error: bad float
+include rt;
+fn main() { rt.put_n(1e); return 0; }
+// zc0: error
diff --git a/tests/conformance/1-source/lit_float_bad_exponent_capital.zc b/tests/conformance/1-source/lit_float_bad_exponent_capital.zc
new file mode 100644
index 0000000..4e4c903
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_bad_exponent_capital.zc
@@ -0,0 +1,5 @@
+// expect error: bad float
+// spec 1.4.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(1); float f = 2E; return 0; }
diff --git a/tests/conformance/1-source/lit_float_bad_exponent_first_stmt_local.zc b/tests/conformance/1-source/lit_float_bad_exponent_first_stmt_local.zc
new file mode 100644
index 0000000..b1cd771
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_bad_exponent_first_stmt_local.zc
@@ -0,0 +1,5 @@
+// expect error: bad float
+// spec 1.4.3 (first statement of the function body)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = 1e; return 0; }
diff --git a/tests/conformance/1-source/lit_float_bad_exponent_first_stmt_paren.zc b/tests/conformance/1-source/lit_float_bad_exponent_first_stmt_paren.zc
new file mode 100644
index 0000000..99fbdb9
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_bad_exponent_first_stmt_paren.zc
@@ -0,0 +1,5 @@
+// expect error: bad float
+// spec 1.4.3 (first statement, inside parentheses)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = (1e); pn(5); return 0; }
diff --git a/tests/conformance/1-source/lit_float_bad_exponent_global.zc b/tests/conformance/1-source/lit_float_bad_exponent_global.zc
new file mode 100644
index 0000000..e7870bd
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_bad_exponent_global.zc
@@ -0,0 +1,5 @@
+// expect error: bad float
+include rt;
+int g = 1e;
+fn main() { rt.put_n(g); return 0; }
+// zc0: error
diff --git a/tests/conformance/1-source/lit_float_bad_exponent_in_helper.zc b/tests/conformance/1-source/lit_float_bad_exponent_in_helper.zc
new file mode 100644
index 0000000..e9e9d07
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_bad_exponent_in_helper.zc
@@ -0,0 +1,5 @@
+// expect error: bad float
+include rt;
+int f() { int x = 1e; return x; }
+fn main() { rt.put_n(8); return 0; }
+// zc0: error
diff --git a/tests/conformance/1-source/lit_float_bad_exponent_later.zc b/tests/conformance/1-source/lit_float_bad_exponent_later.zc
new file mode 100644
index 0000000..9e4293c
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_bad_exponent_later.zc
@@ -0,0 +1,5 @@
+// expect error: bad float
+// spec 1.4.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(1); rt.put_n(1e); return 0; }
diff --git a/tests/conformance/1-source/lit_float_bad_exponent_sign.zc b/tests/conformance/1-source/lit_float_bad_exponent_sign.zc
new file mode 100644
index 0000000..17d0f11
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_bad_exponent_sign.zc
@@ -0,0 +1,4 @@
+// expect error: bad float
+include rt;
+fn main() { rt.put_n(1.5e+); return 0; }
+// zc0: error
diff --git a/tests/conformance/1-source/lit_float_bad_exponent_sign_later.zc b/tests/conformance/1-source/lit_float_bad_exponent_sign_later.zc
new file mode 100644
index 0000000..5e36728
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_bad_exponent_sign_later.zc
@@ -0,0 +1,5 @@
+// expect error: bad float
+// spec 1.4.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(1); rt.put_n(1.5e+); return 0; }
diff --git a/tests/conformance/1-source/lit_float_dot_forms.zc b/tests/conformance/1-source/lit_float_dot_forms.zc
new file mode 100644
index 0000000..c5e3328
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_dot_forms.zc
@@ -0,0 +1,14 @@
+// expect: 1/1/1/
+// spec 1.4.3: 1. ends the literal when no digit, e or E follows; 1.e3 and 1.5e-3 are fractions
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ float a = 1.;
+ pn(a == 1.0);
+ float b = 1.e0;
+ pn(b == 1.0);
+ float c = 5e-1;
+ pn(c == 0.5);
+ return 0;
+}
diff --git a/tests/conformance/1-source/lit_float_dot_letter_is_field.zc b/tests/conformance/1-source/lit_float_dot_letter_is_field.zc
new file mode 100644
index 0000000..469ce80
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_dot_letter_is_field.zc
@@ -0,0 +1,6 @@
+// expect: 0/
+include rt;
+struct zbox { int zfld; }
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(2.zfld * 0); return 0; }
+// zc0: skip
diff --git a/tests/conformance/1-source/lit_float_exponent_negative_digit.zc b/tests/conformance/1-source/lit_float_exponent_negative_digit.zc
new file mode 100644
index 0000000..0ae3b64
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_exponent_negative_digit.zc
@@ -0,0 +1,4 @@
+// expect: 0.250000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() { pf(25e-2); return 0; }
diff --git a/tests/conformance/1-source/lit_float_forms.zc b/tests/conformance/1-source/lit_float_forms.zc
new file mode 100644
index 0000000..80af566
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_forms.zc
@@ -0,0 +1,7 @@
+// expect: 1.500000/1.000000/0.500000/1000.000000/0.001500/1000.000000/1000.000000/1000.000000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ pf(1.5); pf(1.); pf(.5); pf(1e3); pf(1.5e-3); pf(1E+3); pf(1.e3); pf(1e+3);
+ return 0;
+}
diff --git a/tests/conformance/1-source/lit_float_is_float_type.zc b/tests/conformance/1-source/lit_float_is_float_type.zc
new file mode 100644
index 0000000..0474747
--- /dev/null
+++ b/tests/conformance/1-source/lit_float_is_float_type.zc
@@ -0,0 +1,10 @@
+// expect: 2.500000/7.000000/
+// spec 1.4.3: the type of a float literal is float; spec 3.5.1 an int operand converts by value
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ pf(1.25 * 2);
+ pf(3 + 4.0);
+ return 0;
+}
diff --git a/tests/conformance/1-source/lit_hex.zc b/tests/conformance/1-source/lit_hex.zc
new file mode 100644
index 0000000..e326b9a
--- /dev/null
+++ b/tests/conformance/1-source/lit_hex.zc
@@ -0,0 +1,4 @@
+// expect: 171/171/255/9223372036854775807/-1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(0xAB); pn(0Xab); pn(0xfF); pn(0x7fffffffffffffff); pn(0xFFFFFFFFFFFFFFFF); return 0; }
diff --git a/tests/conformance/1-source/lit_hex_letter_after_0x_new_token.zc b/tests/conformance/1-source/lit_hex_letter_after_0x_new_token.zc
new file mode 100644
index 0000000..684195e
--- /dev/null
+++ b/tests/conformance/1-source/lit_hex_letter_after_0x_new_token.zc
@@ -0,0 +1,5 @@
+// expect error: zc: line
+// spec 1.4.1: 0x with no digits is 0 and a letter after it starts a new token (0xg is 0 then the name g)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(0xg); return 0; }
diff --git a/tests/conformance/1-source/lit_hex_no_digits_is_zero.zc b/tests/conformance/1-source/lit_hex_no_digits_is_zero.zc
new file mode 100644
index 0000000..6cae9b4
--- /dev/null
+++ b/tests/conformance/1-source/lit_hex_no_digits_is_zero.zc
@@ -0,0 +1,4 @@
+// expect: 0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(0x); return 0; }
diff --git a/tests/conformance/1-source/lit_hex_wide.zc b/tests/conformance/1-source/lit_hex_wide.zc
new file mode 100644
index 0000000..7b841da
--- /dev/null
+++ b/tests/conformance/1-source/lit_hex_wide.zc
@@ -0,0 +1,5 @@
+// expect: 4096/48879/-1/
+// spec 1.4.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(0x1000); pn(0XBeEf); pn(0xffffffffffffffff); return 0; }
diff --git a/tests/conformance/1-source/lit_hex_wraps.zc b/tests/conformance/1-source/lit_hex_wraps.zc
new file mode 100644
index 0000000..cb71526
--- /dev/null
+++ b/tests/conformance/1-source/lit_hex_wraps.zc
@@ -0,0 +1,4 @@
+// expect: 1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(0x10000000000000001); return 0; }
diff --git a/tests/conformance/1-source/lit_int_max.zc b/tests/conformance/1-source/lit_int_max.zc
new file mode 100644
index 0000000..439d6aa
--- /dev/null
+++ b/tests/conformance/1-source/lit_int_max.zc
@@ -0,0 +1,5 @@
+// expect: 9223372036854775807/-9223372036854775808/-1/
+// spec 1.4.1: wraps modulo 2^64
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(9223372036854775807); pn(9223372036854775808); pn(18446744073709551615); return 0; }
diff --git a/tests/conformance/1-source/lit_int_octal_is_decimal.zc b/tests/conformance/1-source/lit_int_octal_is_decimal.zc
new file mode 100644
index 0000000..1099694
--- /dev/null
+++ b/tests/conformance/1-source/lit_int_octal_is_decimal.zc
@@ -0,0 +1,4 @@
+// expect: 10/18/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(010); pn(018); return 0; }
diff --git a/tests/conformance/1-source/lit_int_type_is_int_never_negative.zc b/tests/conformance/1-source/lit_int_type_is_int_never_negative.zc
new file mode 100644
index 0000000..57b483e
--- /dev/null
+++ b/tests/conformance/1-source/lit_int_type_is_int_never_negative.zc
@@ -0,0 +1,5 @@
+// expect: 1/-5/
+// spec 1.4.1: a literal is never negative, -5 is unary minus on 5
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(-5 < 0 && 5 > 0); pn(-5); return 0; }
diff --git a/tests/conformance/1-source/lit_int_wraps.zc b/tests/conformance/1-source/lit_int_wraps.zc
new file mode 100644
index 0000000..6520f26
--- /dev/null
+++ b/tests/conformance/1-source/lit_int_wraps.zc
@@ -0,0 +1,4 @@
+// expect: 7766279631452241919/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(99999999999999999999); return 0; }
diff --git a/tests/conformance/1-source/lit_int_zero_and_leading_zeros.zc b/tests/conformance/1-source/lit_int_zero_and_leading_zeros.zc
new file mode 100644
index 0000000..e47f989
--- /dev/null
+++ b/tests/conformance/1-source/lit_int_zero_and_leading_zeros.zc
@@ -0,0 +1,5 @@
+// expect: 0/7/100/
+// spec 1.4.1: decimal, no octal
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(0); pn(007); pn(0100); return 0; }
diff --git a/tests/conformance/1-source/lit_minus_folded.zc b/tests/conformance/1-source/lit_minus_folded.zc
new file mode 100644
index 0000000..82e5601
--- /dev/null
+++ b/tests/conformance/1-source/lit_minus_folded.zc
@@ -0,0 +1,4 @@
+// expect: -5/-9223372036854775808/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(-5); pn(-9223372036854775808); return 0; }
diff --git a/tests/conformance/1-source/lit_no_binary.zc b/tests/conformance/1-source/lit_no_binary.zc
new file mode 100644
index 0000000..33f5555
--- /dev/null
+++ b/tests/conformance/1-source/lit_no_binary.zc
@@ -0,0 +1,7 @@
+// expect error: zc: line 4:
+include rt;
+fn main() {
+ rt.put_n(0b101);
+ return 0;
+}
+// zc0: error
diff --git a/tests/conformance/1-source/lit_no_digit_separator.zc b/tests/conformance/1-source/lit_no_digit_separator.zc
new file mode 100644
index 0000000..eeab051
--- /dev/null
+++ b/tests/conformance/1-source/lit_no_digit_separator.zc
@@ -0,0 +1,7 @@
+// expect error: zc: line 4:
+include rt;
+fn main() {
+ rt.put_n(1_000);
+ return 0;
+}
+// zc0: error
diff --git a/tests/conformance/1-source/lit_no_suffix.zc b/tests/conformance/1-source/lit_no_suffix.zc
new file mode 100644
index 0000000..7c3d1dd
--- /dev/null
+++ b/tests/conformance/1-source/lit_no_suffix.zc
@@ -0,0 +1,7 @@
+// expect error: zc: line 4:
+include rt;
+fn main() {
+ rt.put_n(10u);
+ return 0;
+}
+// zc0: error
diff --git a/tests/conformance/1-source/lit_str_adjacent_not_joined.zc b/tests/conformance/1-source/lit_str_adjacent_not_joined.zc
new file mode 100644
index 0000000..1d1bfc5
--- /dev/null
+++ b/tests/conformance/1-source/lit_str_adjacent_not_joined.zc
@@ -0,0 +1,7 @@
+// expect error: zc: line 4:
+include rt;
+fn main() {
+ rt.put_s("a" "b");
+ return 0;
+}
+// zc0: error
diff --git a/tests/conformance/1-source/lit_str_empty.zc b/tests/conformance/1-source/lit_str_empty.zc
new file mode 100644
index 0000000..ef388be
--- /dev/null
+++ b/tests/conformance/1-source/lit_str_empty.zc
@@ -0,0 +1,5 @@
+// expect: 0/0/
+// spec 1.4.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { char* s = ""; pn(rt.len_w(s)); pn(s[0]); return 0; }
diff --git a/tests/conformance/1-source/lit_str_escapes.zc b/tests/conformance/1-source/lit_str_escapes.zc
new file mode 100644
index 0000000..c7077f6
--- /dev/null
+++ b/tests/conformance/1-source/lit_str_escapes.zc
@@ -0,0 +1,8 @@
+// expect: 9/10/34/92/101/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ char* s = "\t\n\"\\e";
+ pn(s[0]); pn(s[1]); pn(s[2]); pn(s[3]); pn(s[4]);
+ return 0;
+}
diff --git a/tests/conformance/1-source/lit_str_hex_escape_is_plain_char.zc b/tests/conformance/1-source/lit_str_hex_escape_is_plain_char.zc
new file mode 100644
index 0000000..2cf8e17
--- /dev/null
+++ b/tests/conformance/1-source/lit_str_hex_escape_is_plain_char.zc
@@ -0,0 +1,5 @@
+// expect: 120/
+// spec 1.4.2: a backslash before any other character is that character
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn("\x"[0]); return 0; }
diff --git a/tests/conformance/1-source/lit_str_high_byte_one_word_each.zc b/tests/conformance/1-source/lit_str_high_byte_one_word_each.zc
new file mode 100644
index 0000000..4827ada
--- /dev/null
+++ b/tests/conformance/1-source/lit_str_high_byte_one_word_each.zc
@@ -0,0 +1,5 @@
+// expect: 195/169/
+// spec 1.1.1: a byte of 128 or more in a string literal is one word of the string
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { char* s = "é"; pn(s[0]); pn(s[1]); return 0; }
diff --git a/tests/conformance/1-source/lit_str_nul_truncates.zc b/tests/conformance/1-source/lit_str_nul_truncates.zc
new file mode 100644
index 0000000..9144cc1
--- /dev/null
+++ b/tests/conformance/1-source/lit_str_nul_truncates.zc
@@ -0,0 +1,4 @@
+// expect: 2/ab/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(rt.len_w("ab\0cd")); rt.put_s("ab\0cd"); rt.put_c(10); return 0; }
diff --git a/tests/conformance/1-source/lit_str_raw_newline.zc b/tests/conformance/1-source/lit_str_raw_newline.zc
new file mode 100644
index 0000000..de02e45
--- /dev/null
+++ b/tests/conformance/1-source/lit_str_raw_newline.zc
@@ -0,0 +1,9 @@
+// expect: 3/10/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ char* s = "a
+b";
+ pn(rt.len_w(s)); pn(s[1]);
+ return 0;
+}
diff --git a/tests/conformance/1-source/lit_str_unterminated.zc b/tests/conformance/1-source/lit_str_unterminated.zc
new file mode 100644
index 0000000..6639741
--- /dev/null
+++ b/tests/conformance/1-source/lit_str_unterminated.zc
@@ -0,0 +1,4 @@
+// expect error: zc: line
+include rt;
+fn main() { rt.put_s("abc); return 0; }
+// zc0: error
diff --git a/tests/conformance/1-source/lit_str_utf8_bytes.zc b/tests/conformance/1-source/lit_str_utf8_bytes.zc
new file mode 100644
index 0000000..3c1d07a
--- /dev/null
+++ b/tests/conformance/1-source/lit_str_utf8_bytes.zc
@@ -0,0 +1,4 @@
+// expect: 6/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(rt.len_w("héllo")); return 0; }
diff --git a/tests/conformance/1-source/lit_str_word_per_cell.zc b/tests/conformance/1-source/lit_str_word_per_cell.zc
new file mode 100644
index 0000000..ab214c0
--- /dev/null
+++ b/tests/conformance/1-source/lit_str_word_per_cell.zc
@@ -0,0 +1,9 @@
+// expect: 65/66/0/3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ char* s = "AB";
+ pn(s[0]); pn(s[1]); pn(s[2]);
+ pn(rt.len_w("xyz"));
+ return 0;
+}
diff --git a/tests/conformance/1-source/lit_str_zero_terminated.zc b/tests/conformance/1-source/lit_str_zero_terminated.zc
new file mode 100644
index 0000000..846294a
--- /dev/null
+++ b/tests/conformance/1-source/lit_str_zero_terminated.zc
@@ -0,0 +1,5 @@
+// expect: 3/0/
+// spec 1.4.4: stored one per word, followed by a 0 word
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { char* s = "abc"; pn(rt.len_w(s)); pn(s[3]); return 0; }
diff --git a/tests/conformance/1-source/module_join_hidden_by_local.zc b/tests/conformance/1-source/module_join_hidden_by_local.zc
new file mode 100644
index 0000000..294f9ec
--- /dev/null
+++ b/tests/conformance/1-source/module_join_hidden_by_local.zc
@@ -0,0 +1,10 @@
+// expect: 4/
+include rt;
+struct pt { int x; int y; }
+fn main() {
+ pt* std = rt.new(pt);
+ std.x = 4;
+ rt.put_n(std.x); rt.put_c(10);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/1-source/module_join_known_name_not_module.zc b/tests/conformance/1-source/module_join_known_name_not_module.zc
new file mode 100644
index 0000000..3c98fb5
--- /dev/null
+++ b/tests/conformance/1-source/module_join_known_name_not_module.zc
@@ -0,0 +1,7 @@
+// expect: 7/
+// spec 1.3.3: x.y with x not a known module is field access
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct pt { int x; int y; }
+fn main() { pt* q = rt.new(pt); q.y = 7; pn(q.y); rt.free(q); return 0; }
+// zc0: skip
diff --git a/tests/conformance/1-source/module_join_needs_include.zc b/tests/conformance/1-source/module_join_needs_include.zc
new file mode 100644
index 0000000..671fd38
--- /dev/null
+++ b/tests/conformance/1-source/module_join_needs_include.zc
@@ -0,0 +1,2 @@
+// expect error: module access requires `include rt;`
+fn main() { rt.put_c(65); return 0; }
diff --git a/tests/conformance/1-source/module_join_one_dot_only.zc b/tests/conformance/1-source/module_join_one_dot_only.zc
new file mode 100644
index 0000000..c63db40
--- /dev/null
+++ b/tests/conformance/1-source/module_join_one_dot_only.zc
@@ -0,0 +1,5 @@
+// expect error: zc: line
+// spec 1.3.3: rt.x.y is the token rt.x then . then y
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { rt.put_c.zz(1); return 0; }
diff --git a/tests/conformance/1-source/module_join_prints_A.zc b/tests/conformance/1-source/module_join_prints_A.zc
new file mode 100644
index 0000000..f255fc4
--- /dev/null
+++ b/tests/conformance/1-source/module_join_prints_A.zc
@@ -0,0 +1,3 @@
+// expect: A/
+include rt;
+fn main() { rt.put_c(65); rt.put_c(10); return 0; }
diff --git a/tests/conformance/1-source/module_unqualified_rt_name.zc b/tests/conformance/1-source/module_unqualified_rt_name.zc
new file mode 100644
index 0000000..6acc581
--- /dev/null
+++ b/tests/conformance/1-source/module_unqualified_rt_name.zc
@@ -0,0 +1,2 @@
+// expect error: put_c is used but never defined
+fn main() { put_c(65); return 0; }
diff --git a/tests/conformance/1-source/op_compound_all.zc b/tests/conformance/1-source/op_compound_all.zc
new file mode 100644
index 0000000..ab7a1ef
--- /dev/null
+++ b/tests/conformance/1-source/op_compound_all.zc
@@ -0,0 +1,15 @@
+// expect: 14/7/21/5/1/12/4/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 7;
+ a += 7; pn(a);
+ a -= 7; pn(a);
+ a *= 3; pn(a);
+ a /= 4; pn(a);
+ a %= 2; pn(a);
+ a = 12; pn(a);
+ a &= 6; pn(a);
+ a ^= 6; pn(a);
+ return 0;
+}
diff --git a/tests/conformance/1-source/op_compound_or.zc b/tests/conformance/1-source/op_compound_or.zc
new file mode 100644
index 0000000..f76339a
--- /dev/null
+++ b/tests/conformance/1-source/op_compound_or.zc
@@ -0,0 +1,4 @@
+// expect: 7/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 5; a |= 2; pn(a); return 0; }
diff --git a/tests/conformance/1-source/op_greedy_compound_shift.zc b/tests/conformance/1-source/op_greedy_compound_shift.zc
new file mode 100644
index 0000000..697aad5
--- /dev/null
+++ b/tests/conformance/1-source/op_greedy_compound_shift.zc
@@ -0,0 +1,4 @@
+// expect: 12/3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 3; a<<=2; pn(a); a>>=2; pn(a); return 0; }
diff --git a/tests/conformance/1-source/op_incr_decr_split.zc b/tests/conformance/1-source/op_incr_decr_split.zc
new file mode 100644
index 0000000..48dba51
--- /dev/null
+++ b/tests/conformance/1-source/op_incr_decr_split.zc
@@ -0,0 +1,4 @@
+// expect: 1/4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 3, b = 2; int c = a---b; int e = a+++b; pn(c); pn(e); return 0; }
diff --git a/tests/conformance/1-source/op_lexing_a_minus_minus_b.zc b/tests/conformance/1-source/op_lexing_a_minus_minus_b.zc
new file mode 100644
index 0000000..360f132
--- /dev/null
+++ b/tests/conformance/1-source/op_lexing_a_minus_minus_b.zc
@@ -0,0 +1,5 @@
+// expect: 5/
+// spec 1.6.2: greedy: a---b is a-- - b
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 6, b = 1; pn(a---b); return 0; }
diff --git a/tests/conformance/1-source/op_no_space_needed_lt_neg.zc b/tests/conformance/1-source/op_no_space_needed_lt_neg.zc
new file mode 100644
index 0000000..57d7ad4
--- /dev/null
+++ b/tests/conformance/1-source/op_no_space_needed_lt_neg.zc
@@ -0,0 +1,4 @@
+// expect: 0/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 1, b = 2; pn(a<-b); pn(a>-b); return 0; }
diff --git a/tests/conformance/1-source/op_non_ascii_byte_error.zc b/tests/conformance/1-source/op_non_ascii_byte_error.zc
new file mode 100644
index 0000000..94e293c
--- /dev/null
+++ b/tests/conformance/1-source/op_non_ascii_byte_error.zc
@@ -0,0 +1,7 @@
+// expect error: zc: line 4:
+include rt;
+fn main() {
+ int x = ¢;
+ return 0;
+}
+// zc0: error
diff --git a/tests/conformance/1-source/op_not_not.zc b/tests/conformance/1-source/op_not_not.zc
new file mode 100644
index 0000000..657a106
--- /dev/null
+++ b/tests/conformance/1-source/op_not_not.zc
@@ -0,0 +1,4 @@
+// expect: 1/0/1/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(!!7); pn(!!0); pn(!0); pn(!!!7); return 0; }
diff --git a/tests/conformance/1-source/op_star_neg_and_assign_neg.zc b/tests/conformance/1-source/op_star_neg_and_assign_neg.zc
new file mode 100644
index 0000000..14993a4
--- /dev/null
+++ b/tests/conformance/1-source/op_star_neg_and_assign_neg.zc
@@ -0,0 +1,4 @@
+// expect: -2/-2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 1, b = 2; int c = a*-b; int d; d=-b; pn(c); pn(d); return 0; }
diff --git a/tests/conformance/1-source/op_ternary_colon_tokens.zc b/tests/conformance/1-source/op_ternary_colon_tokens.zc
new file mode 100644
index 0000000..8d154f9
--- /dev/null
+++ b/tests/conformance/1-source/op_ternary_colon_tokens.zc
@@ -0,0 +1,6 @@
+// expect: 2/
+// spec 1.6.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 1; pn(a ? 2 : 3); return 0; }
+// zc0: skip
diff --git a/tests/conformance/1-source/op_unknown_char.zc b/tests/conformance/1-source/op_unknown_char.zc
new file mode 100644
index 0000000..9de4300
--- /dev/null
+++ b/tests/conformance/1-source/op_unknown_char.zc
@@ -0,0 +1,5 @@
+// expect error: zc: line
+// spec 1.6.1: other punctuation is not an operator
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = 3 \ 4; return 0; }
diff --git a/tests/conformance/1-source/unit_ends_at_backtick.zc b/tests/conformance/1-source/unit_ends_at_backtick.zc
new file mode 100644
index 0000000..7bffa02
--- /dev/null
+++ b/tests/conformance/1-source/unit_ends_at_backtick.zc
@@ -0,0 +1,4 @@
+// expect: 5/
+include rt;
+fn main() { rt.put_n(5); rt.put_c(10); return 0; }
+` this is not compiled @@@ ~~~ ((( int int int
diff --git a/tests/conformance/1-source/unit_ends_at_backtick_first_line.zc b/tests/conformance/1-source/unit_ends_at_backtick_first_line.zc
new file mode 100644
index 0000000..8611df8
--- /dev/null
+++ b/tests/conformance/1-source/unit_ends_at_backtick_first_line.zc
@@ -0,0 +1,6 @@
+// expect: 7/
+// spec 1.1.3 and 1.5.1: the source-ending backtick ends the unit, the rest is stdin
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int c = rt.get_c(); pn(c - 'a' + 7); return 0; }
+`a
diff --git a/tests/conformance/1-source/unit_eof_ends_unit.zc b/tests/conformance/1-source/unit_eof_ends_unit.zc
new file mode 100644
index 0000000..99dff1c
--- /dev/null
+++ b/tests/conformance/1-source/unit_eof_ends_unit.zc
@@ -0,0 +1,6 @@
+// expect: 1/
+// spec 1.1.3: a unit ends at end of input
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(1); return 0; }
+
diff --git a/tests/conformance/1-source/ws_basic.zc b/tests/conformance/1-source/ws_basic.zc
new file mode 100644
index 0000000..34e0461
--- /dev/null
+++ b/tests/conformance/1-source/ws_basic.zc
@@ -0,0 +1,11 @@
+// expect: 3/
+include rt;
+fn main() {
+ int a = 1 ;
+ int
+ b
+ =
+ 2
+ ;
+ rt.put_n(a+b); rt.put_c(10); return 0;
+}
diff --git a/tests/conformance/1-source/ws_carriage_return_tab_ff.zc b/tests/conformance/1-source/ws_carriage_return_tab_ff.zc
new file mode 100644
index 0000000..1c6c5b2
--- /dev/null
+++ b/tests/conformance/1-source/ws_carriage_return_tab_ff.zc
@@ -0,0 +1,5 @@
+// expect: 3/
+// spec 1.1.2: white space is space, tab, line feed, carriage return
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 1; int b = 2; pn(a + b); return 0; }
diff --git a/tests/conformance/1-source/ws_no_space_needed_between_tokens.zc b/tests/conformance/1-source/ws_no_space_needed_between_tokens.zc
new file mode 100644
index 0000000..e19542a
--- /dev/null
+++ b/tests/conformance/1-source/ws_no_space_needed_between_tokens.zc
@@ -0,0 +1,5 @@
+// expect: 5/
+// spec 1.1.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main(){int a=2;int b=3;pn(a+b);return 0;}
diff --git a/tests/conformance/2-types/alias_pointer_to_array.zc b/tests/conformance/2-types/alias_pointer_to_array.zc
new file mode 100644
index 0000000..ef6e532
--- /dev/null
+++ b/tests/conformance/2-types/alias_pointer_to_array.zc
@@ -0,0 +1,15 @@
+// expect: 3/8/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+type row = int[3];
+fn main() {
+ pn(sizeof(row));
+ row* r = rt.new(row, 2);
+ int* q = (int*)r;
+ int i = 0;
+ while (i < 6) { q[i] = 0; i++; }
+ r[1][2] = 8;
+ pn(q[5]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/alias_simple.zc b/tests/conformance/2-types/alias_simple.zc
new file mode 100644
index 0000000..3061ec6
--- /dev/null
+++ b/tests/conformance/2-types/alias_simple.zc
@@ -0,0 +1,6 @@
+// expect: 4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+type myint = int;
+fn main() { myint x = 4; pn(x); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/array_assign_whole.zc b/tests/conformance/2-types/array_assign_whole.zc
new file mode 100644
index 0000000..c51562d
--- /dev/null
+++ b/tests/conformance/2-types/array_assign_whole.zc
@@ -0,0 +1,7 @@
+// expect error: this can't be assigned to
+include rt;
+fn main() {
+ int[3] a; int[3] b;
+ a = b;
+ return 0;
+}
diff --git a/tests/conformance/2-types/array_assign_whole_field.zc b/tests/conformance/2-types/array_assign_whole_field.zc
new file mode 100644
index 0000000..4899e05
--- /dev/null
+++ b/tests/conformance/2-types/array_assign_whole_field.zc
@@ -0,0 +1,8 @@
+// expect error: a whole struct or array can't be assigned; assign its fields
+include rt;
+struct two { int[2] f; }
+fn main() {
+ two* p = rt.new(two); two* q = rt.new(two);
+ p.f = q.f;
+ return 0;
+}
diff --git a/tests/conformance/2-types/array_const_index_negative.zc b/tests/conformance/2-types/array_const_index_negative.zc
new file mode 100644
index 0000000..746a796
--- /dev/null
+++ b/tests/conformance/2-types/array_const_index_negative.zc
@@ -0,0 +1,8 @@
+// expect error: the index is out of range for this array
+include rt;
+fn main() {
+ int[3] a;
+ a[0] = 1;
+ rt.put_n(a[-1]);
+ return 0;
+}
diff --git a/tests/conformance/2-types/array_const_index_out_of_range.zc b/tests/conformance/2-types/array_const_index_out_of_range.zc
new file mode 100644
index 0000000..628849e
--- /dev/null
+++ b/tests/conformance/2-types/array_const_index_out_of_range.zc
@@ -0,0 +1,7 @@
+// expect error: the index is out of range for this array
+include rt;
+fn main() {
+ int[3] a;
+ a[3] = 1;
+ return 0;
+}
diff --git a/tests/conformance/2-types/array_init_bytes_string.zc b/tests/conformance/2-types/array_init_bytes_string.zc
new file mode 100644
index 0000000..af607f0
--- /dev/null
+++ b/tests/conformance/2-types/array_init_bytes_string.zc
@@ -0,0 +1,8 @@
+// expect: 116/101/120/116/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ u8[8] s = b"text";
+ pn(s[0]); pn(s[1]); pn(s[2]); pn(s[3]);
+ return 0;
+}
diff --git a/tests/conformance/2-types/array_init_compound_literal.zc b/tests/conformance/2-types/array_init_compound_literal.zc
new file mode 100644
index 0000000..86825b4
--- /dev/null
+++ b/tests/conformance/2-types/array_init_compound_literal.zc
@@ -0,0 +1,9 @@
+// expect: 8/7/9/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int* p = (int[]){7, 8, 9};
+ pn(p[1]); pn(p[0]); pn(p[2]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/array_init_designator.zc b/tests/conformance/2-types/array_init_designator.zc
new file mode 100644
index 0000000..5d6c926
--- /dev/null
+++ b/tests/conformance/2-types/array_init_designator.zc
@@ -0,0 +1,9 @@
+// expect: 5/0/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[3] d = {[1] = 5};
+ pn(d[1]); pn(d[0]); pn(d[2]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/array_init_negative_designator.zc b/tests/conformance/2-types/array_init_negative_designator.zc
new file mode 100644
index 0000000..bed1dc5
--- /dev/null
+++ b/tests/conformance/2-types/array_init_negative_designator.zc
@@ -0,0 +1,6 @@
+// expect error: zc: line 4:
+include rt;
+fn main() {
+ int[3] a = {[-1] = 5};
+ return 0;
+}
diff --git a/tests/conformance/2-types/array_init_nested.zc b/tests/conformance/2-types/array_init_nested.zc
new file mode 100644
index 0000000..a75474d
--- /dev/null
+++ b/tests/conformance/2-types/array_init_nested.zc
@@ -0,0 +1,9 @@
+// expect: 1/2/3/4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[2][2] m = {{1, 2}, {3, 4}};
+ pn(m[0][0]); pn(m[0][1]); pn(m[1][0]); pn(m[1][1]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/array_init_short.zc b/tests/conformance/2-types/array_init_short.zc
new file mode 100644
index 0000000..638476a
--- /dev/null
+++ b/tests/conformance/2-types/array_init_short.zc
@@ -0,0 +1,9 @@
+// expect: 1/2/0/0/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[5] b = {1, 2};
+ pn(b[0]); pn(b[1]); pn(b[2]); pn(b[3]); pn(b[4]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/array_init_string.zc b/tests/conformance/2-types/array_init_string.zc
new file mode 100644
index 0000000..33037b9
--- /dev/null
+++ b/tests/conformance/2-types/array_init_string.zc
@@ -0,0 +1,8 @@
+// expect: 97/98/99/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ char[4] s = "abc";
+ pn(s[0]); pn(s[1]); pn(s[2]); pn(s[3]);
+ return 0;
+}
diff --git a/tests/conformance/2-types/array_init_too_many.zc b/tests/conformance/2-types/array_init_too_many.zc
new file mode 100644
index 0000000..1409b3c
--- /dev/null
+++ b/tests/conformance/2-types/array_init_too_many.zc
@@ -0,0 +1,6 @@
+// expect error: too many elements in array initializer
+include rt;
+fn main() {
+ int[2] a = {1, 2, 3};
+ return 0;
+}
diff --git a/tests/conformance/2-types/array_of_arrays.zc b/tests/conformance/2-types/array_of_arrays.zc
new file mode 100644
index 0000000..22f4789
--- /dev/null
+++ b/tests/conformance/2-types/array_of_arrays.zc
@@ -0,0 +1,15 @@
+// expect: 6/9/9/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[2][3] a;
+ int* p = (int*)a;
+ int i = 0;
+ while (i < 6) { p[i] = 0; i++; }
+ pn(sizeof(a));
+ a[1][2] = 9;
+ pn(a[1][2]);
+ pn(p[5]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/array_param_decays.zc b/tests/conformance/2-types/array_param_decays.zc
new file mode 100644
index 0000000..5680909
--- /dev/null
+++ b/tests/conformance/2-types/array_param_decays.zc
@@ -0,0 +1,10 @@
+// expect: 6/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int sum3(int[3] a) { return a[0] + a[1] + a[2]; }
+fn main() {
+ int[3] a = {1, 2, 3};
+ pn(sum3(a));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/array_unsized_from_init.zc b/tests/conformance/2-types/array_unsized_from_init.zc
new file mode 100644
index 0000000..7ef7568
--- /dev/null
+++ b/tests/conformance/2-types/array_unsized_from_init.zc
@@ -0,0 +1,9 @@
+// expect: 3/3/20/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[] a = {10, 20, 30};
+ pn(len(a)); pn(sizeof(a)); pn(a[1]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/array_unsized_needs_init.zc b/tests/conformance/2-types/array_unsized_needs_init.zc
new file mode 100644
index 0000000..453eac8
--- /dev/null
+++ b/tests/conformance/2-types/array_unsized_needs_init.zc
@@ -0,0 +1,6 @@
+// expect error: needs an initializer to determine its length
+include rt;
+fn main() {
+ int[] a;
+ return 0;
+}
diff --git a/tests/conformance/2-types/array_value_is_address.zc b/tests/conformance/2-types/array_value_is_address.zc
new file mode 100644
index 0000000..4860048
--- /dev/null
+++ b/tests/conformance/2-types/array_value_is_address.zc
@@ -0,0 +1,11 @@
+// expect: 1/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[3] a;
+ int* p = a;
+ pn(p == (int*)a);
+ pn(&a[0] == p);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/cast_to_sized.zc b/tests/conformance/2-types/cast_to_sized.zc
new file mode 100644
index 0000000..9048cb1
--- /dev/null
+++ b/tests/conformance/2-types/cast_to_sized.zc
@@ -0,0 +1,8 @@
+// expect: 44/-56/44/65535/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn((u8)300); pn((i8)200); pn(300 as u8); pn((u16)-1);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/closure_result_type_coerces.zc b/tests/conformance/2-types/closure_result_type_coerces.zc
new file mode 100644
index 0000000..49b05e5
--- /dev/null
+++ b/tests/conformance/2-types/closure_result_type_coerces.zc
@@ -0,0 +1,9 @@
+// expect: 2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let c = fn:int() { return 2.9; };
+ pn(c());
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/const_array_read_and_copy.zc b/tests/conformance/2-types/const_array_read_and_copy.zc
new file mode 100644
index 0000000..83b6694
--- /dev/null
+++ b/tests/conformance/2-types/const_array_read_and_copy.zc
@@ -0,0 +1,10 @@
+// expect: 2/3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ const int[3] a = {1, 2, 3};
+ int v = a[1];
+ pn(v); v++; pn(v);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/const_array_write.zc b/tests/conformance/2-types/const_array_write.zc
new file mode 100644
index 0000000..08e0998
--- /dev/null
+++ b/tests/conformance/2-types/const_array_write.zc
@@ -0,0 +1,3 @@
+// expect error: const storage cannot be modified
+include rt;
+fn main() { const int[3] a = {1, 2, 3}; a[0] = 5; return 0; }
diff --git a/tests/conformance/2-types/const_compound_assign.zc b/tests/conformance/2-types/const_compound_assign.zc
new file mode 100644
index 0000000..4a2f63e
--- /dev/null
+++ b/tests/conformance/2-types/const_compound_assign.zc
@@ -0,0 +1,3 @@
+// expect error: const storage cannot be modified
+include rt;
+fn main() { const int[3] a = {1, 2, 3}; a[1] += 5; return 0; }
diff --git a/tests/conformance/2-types/const_fixed_order.zc b/tests/conformance/2-types/const_fixed_order.zc
new file mode 100644
index 0000000..2b09784
--- /dev/null
+++ b/tests/conformance/2-types/const_fixed_order.zc
@@ -0,0 +1,3 @@
+// expect error: const storage cannot be modified
+include rt;
+fn main() { fixed const int[3] a = {1, 2, 3}; const fixed int[3] b = {1, 2, 3}; a[0] = 1; return 0; }
diff --git a/tests/conformance/2-types/const_fixed_order_2.zc b/tests/conformance/2-types/const_fixed_order_2.zc
new file mode 100644
index 0000000..01af32d
--- /dev/null
+++ b/tests/conformance/2-types/const_fixed_order_2.zc
@@ -0,0 +1,3 @@
+// expect error: const storage cannot be modified
+include rt;
+fn main() { const fixed int[3] b = {1, 2, 3}; b[0] = 1; return 0; }
diff --git a/tests/conformance/2-types/const_increment.zc b/tests/conformance/2-types/const_increment.zc
new file mode 100644
index 0000000..7d1d434
--- /dev/null
+++ b/tests/conformance/2-types/const_increment.zc
@@ -0,0 +1,3 @@
+// expect error: const storage cannot be modified
+include rt;
+fn main() { const int[3] a = {1, 2, 3}; a[1]++; return 0; }
diff --git a/tests/conformance/2-types/const_local_assign.zc b/tests/conformance/2-types/const_local_assign.zc
new file mode 100644
index 0000000..f32dccf
--- /dev/null
+++ b/tests/conformance/2-types/const_local_assign.zc
@@ -0,0 +1,3 @@
+// expect error: const storage cannot be modified
+include rt;
+fn main() { const k = 5; k = 6; return 0; }
diff --git a/tests/conformance/2-types/const_local_constant.zc b/tests/conformance/2-types/const_local_constant.zc
new file mode 100644
index 0000000..66b98e5
--- /dev/null
+++ b/tests/conformance/2-types/const_local_constant.zc
@@ -0,0 +1,5 @@
+// expect: 6/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { const k = 5; pn(k + 1); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/const_local_needs_init.zc b/tests/conformance/2-types/const_local_needs_init.zc
new file mode 100644
index 0000000..82e5cb9
--- /dev/null
+++ b/tests/conformance/2-types/const_local_needs_init.zc
@@ -0,0 +1,3 @@
+// expect error: a const needs an initializer
+include rt;
+fn main() { const k; return 0; }
diff --git a/tests/conformance/2-types/const_local_typed.zc b/tests/conformance/2-types/const_local_typed.zc
new file mode 100644
index 0000000..b6d56ec
--- /dev/null
+++ b/tests/conformance/2-types/const_local_typed.zc
@@ -0,0 +1,5 @@
+// expect: 7/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { const int k = 7; pn(k); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/const_pointer_element_write.zc b/tests/conformance/2-types/const_pointer_element_write.zc
new file mode 100644
index 0000000..3a0e9cd
--- /dev/null
+++ b/tests/conformance/2-types/const_pointer_element_write.zc
@@ -0,0 +1,3 @@
+// expect error: const storage cannot be modified
+include rt;
+fn main() { int[2] a; const int* p = a; p[1] = 3; return 0; }
diff --git a/tests/conformance/2-types/const_pointer_write.zc b/tests/conformance/2-types/const_pointer_write.zc
new file mode 100644
index 0000000..c2ce78b
--- /dev/null
+++ b/tests/conformance/2-types/const_pointer_write.zc
@@ -0,0 +1,3 @@
+// expect error: const storage cannot be modified
+include rt;
+fn main() { int[2] a; const int* p = a; *p = 3; return 0; }
diff --git a/tests/conformance/2-types/const_to_mutable_no_typecheck.zc b/tests/conformance/2-types/const_to_mutable_no_typecheck.zc
new file mode 100644
index 0000000..962cb71
--- /dev/null
+++ b/tests/conformance/2-types/const_to_mutable_no_typecheck.zc
@@ -0,0 +1,3 @@
+// expect error: const storage cannot be converted to a mutable reference
+include rt;
+fn main() { int[2] a; const int* p = a; int* q = p; return 0; }
diff --git a/tests/conformance/2-types/conv_argument_and_return.zc b/tests/conformance/2-types/conv_argument_and_return.zc
new file mode 100644
index 0000000..42da3b6
--- /dev/null
+++ b/tests/conformance/2-types/conv_argument_and_return.zc
@@ -0,0 +1,8 @@
+// expect: 3.000000/2.000000/2/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void show(float x) { pf(x); }
+float g() { return 2; }
+int h() { return 2.9; }
+fn main() { show(3); pf(g()); pn(h()); return 0; }
diff --git a/tests/conformance/2-types/conv_assignment_to_float.zc b/tests/conformance/2-types/conv_assignment_to_float.zc
new file mode 100644
index 0000000..f48667f
--- /dev/null
+++ b/tests/conformance/2-types/conv_assignment_to_float.zc
@@ -0,0 +1,4 @@
+// expect: 5.000000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() { float f = 0.5; f = 5; pf(f); return 0; }
diff --git a/tests/conformance/2-types/conv_f32_rounds.zc b/tests/conformance/2-types/conv_f32_rounds.zc
new file mode 100644
index 0000000..961525f
--- /dev/null
+++ b/tests/conformance/2-types/conv_f32_rounds.zc
@@ -0,0 +1,4 @@
+// expect: 0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { f32 x = 0; x = 0.1; pn(x == 0.1); return 0; }
diff --git a/tests/conformance/2-types/conv_float_to_int_truncates.zc b/tests/conformance/2-types/conv_float_to_int_truncates.zc
new file mode 100644
index 0000000..19e9e1e
--- /dev/null
+++ b/tests/conformance/2-types/conv_float_to_int_truncates.zc
@@ -0,0 +1,4 @@
+// expect: 2/-2/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int i = 2.5; int j = -2.5; int k = 0.9; pn(i); pn(j); pn(k); return 0; }
diff --git a/tests/conformance/2-types/conv_int_to_float_initializer.zc b/tests/conformance/2-types/conv_int_to_float_initializer.zc
new file mode 100644
index 0000000..32e3b7c
--- /dev/null
+++ b/tests/conformance/2-types/conv_int_to_float_initializer.zc
@@ -0,0 +1,4 @@
+// expect: 1.000000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() { float f = 1; pf(f); return 0; }
diff --git a/tests/conformance/2-types/conv_word_keeps_bits.zc b/tests/conformance/2-types/conv_word_keeps_bits.zc
new file mode 100644
index 0000000..31c28af
--- /dev/null
+++ b/tests/conformance/2-types/conv_word_keeps_bits.zc
@@ -0,0 +1,4 @@
+// expect: 1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { word w = 2.5; pn(w == 4612811918334230528); return 0; }
diff --git a/tests/conformance/2-types/dynarray_handle_layout.zc b/tests/conformance/2-types/dynarray_handle_layout.zc
new file mode 100644
index 0000000..148e4da
--- /dev/null
+++ b/tests/conformance/2-types/dynarray_handle_layout.zc
@@ -0,0 +1,14 @@
+// expect: 1/4/5/1/3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[?] a = rt.new(int[?]);
+ push(a, 5);
+ int* h = (int*)a;
+ int* items = (int*)h[2];
+ pn(h[0]); pn(h[1]); pn(items[0]); pn(h[3]);
+ int[?] b = rt.new(int[?], 3);
+ pn(len(b));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/dynarray_new_n_zero_filled.zc b/tests/conformance/2-types/dynarray_new_n_zero_filled.zc
new file mode 100644
index 0000000..82a1391
--- /dev/null
+++ b/tests/conformance/2-types/dynarray_new_n_zero_filled.zc
@@ -0,0 +1,9 @@
+// expect: 3/0/0/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[?] b = rt.new(int[?], 3);
+ pn(len(b)); pn(b[0]); pn(b[1]); pn(b[2]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/dynarray_packed_elem_size_negated.zc b/tests/conformance/2-types/dynarray_packed_elem_size_negated.zc
new file mode 100644
index 0000000..b7d92e1
--- /dev/null
+++ b/tests/conformance/2-types/dynarray_packed_elem_size_negated.zc
@@ -0,0 +1,16 @@
+// expect: 1/1/1/1/0/
+// spec 2.6.3: word 3 of the handle is the element size, negated for packed element types
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ u8[?] a = rt.new(u8[?]); u16[?] b = rt.new(u16[?]); i32[?] c = rt.new(i32[?]); f32[?] d = rt.new(f32[?]);
+ int[?] e = rt.new(int[?]);
+ int* h;
+ h = (int*)a; pn(h[3] < 0);
+ h = (int*)b; pn(h[3] < 0);
+ h = (int*)c; pn(h[3] < 0);
+ h = (int*)d; pn(h[3] < 0);
+ h = (int*)e; pn(h[3] < 0);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/enum_in_case_labels.zc b/tests/conformance/2-types/enum_in_case_labels.zc
new file mode 100644
index 0000000..caf1f21
--- /dev/null
+++ b/tests/conformance/2-types/enum_in_case_labels.zc
@@ -0,0 +1,14 @@
+// expect: green/
+include rt;
+enum color { RED, GREEN, BLUE };
+fn main() {
+ int c = color.GREEN;
+ switch (c) {
+ case color.RED: rt.put_s("red");
+ case color.GREEN: rt.put_s("green");
+ case color.BLUE: rt.put_s("blue");
+ }
+ rt.put_c(10);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/enum_local.zc b/tests/conformance/2-types/enum_local.zc
new file mode 100644
index 0000000..fb2a3ad
--- /dev/null
+++ b/tests/conformance/2-types/enum_local.zc
@@ -0,0 +1,9 @@
+// expect: 7/8/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ enum { L1 = 7, L2 };
+ pn(L1); pn(L2);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/enum_names_earlier_enum.zc b/tests/conformance/2-types/enum_names_earlier_enum.zc
new file mode 100644
index 0000000..f715d72
--- /dev/null
+++ b/tests/conformance/2-types/enum_names_earlier_enum.zc
@@ -0,0 +1,7 @@
+// expect: 4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum a { X = 3 };
+enum b { Y = X + 1 };
+fn main() { pn(Y); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/enum_names_own_member.zc b/tests/conformance/2-types/enum_names_own_member.zc
new file mode 100644
index 0000000..26d4739
--- /dev/null
+++ b/tests/conformance/2-types/enum_names_own_member.zc
@@ -0,0 +1,4 @@
+// expect error: expected a constant
+include rt;
+enum e { HI = 16, LO = HI + 1 };
+fn main() { return 0; }
diff --git a/tests/conformance/2-types/enum_plain_values.zc b/tests/conformance/2-types/enum_plain_values.zc
new file mode 100644
index 0000000..af9bfa6
--- /dev/null
+++ b/tests/conformance/2-types/enum_plain_values.zc
@@ -0,0 +1,10 @@
+// expect: 0/5/6/0/5/6/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum color { RED, GREEN = 5, BLUE };
+fn main() {
+ pn(RED); pn(GREEN); pn(BLUE);
+ pn(color.RED); pn(color.GREEN); pn(color.BLUE);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/enum_tagged_basic.zc b/tests/conformance/2-types/enum_tagged_basic.zc
new file mode 100644
index 0000000..087e5a4
--- /dev/null
+++ b/tests/conformance/2-types/enum_tagged_basic.zc
@@ -0,0 +1,15 @@
+// expect: 4/1/4/5/2/0/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ pn(sizeof(shape));
+ shape* s = shape.rect(4, 5);
+ pn(s.tag);
+ pn(s.rect_w); pn(s.rect_h);
+ rt.free(s);
+ pn(dot);
+ pn(circle); pn(rect);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/enum_tagged_constructor_fields.zc b/tests/conformance/2-types/enum_tagged_constructor_fields.zc
new file mode 100644
index 0000000..ade0f3a
--- /dev/null
+++ b/tests/conformance/2-types/enum_tagged_constructor_fields.zc
@@ -0,0 +1,12 @@
+// expect: 0/9/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* a = shape.circle(9);
+ shape* d = shape.dot();
+ pn(a.tag); pn(a.circle_r); pn(d.tag);
+ rt.free(a); rt.free(d);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/enum_tagged_float_payload.zc b/tests/conformance/2-types/enum_tagged_float_payload.zc
new file mode 100644
index 0000000..92e4e2a
--- /dev/null
+++ b/tests/conformance/2-types/enum_tagged_float_payload.zc
@@ -0,0 +1,11 @@
+// expect: 2.500000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+enum val { num { float v; }, none };
+fn main() {
+ val* s = val.num(2.5);
+ pf(s.num_v);
+ rt.free(s);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/enum_tagged_wrong_arg_count.zc b/tests/conformance/2-types/enum_tagged_wrong_arg_count.zc
new file mode 100644
index 0000000..bf1c778
--- /dev/null
+++ b/tests/conformance/2-types/enum_tagged_wrong_arg_count.zc
@@ -0,0 +1,8 @@
+// expect error: shape.circle: wrong number of arguments
+include rt;
+enum shape { circle { int r; }, dot };
+fn main() {
+ shape* s = shape.circle(1, 2);
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/2-types/enum_typecheck_enum_to_enum.zc b/tests/conformance/2-types/enum_typecheck_enum_to_enum.zc
new file mode 100644
index 0000000..95c9a29
--- /dev/null
+++ b/tests/conformance/2-types/enum_typecheck_enum_to_enum.zc
@@ -0,0 +1,10 @@
+// expect error: type error: initializer: expected shade, got color
+include rt;
+typecheck on;
+enum color { RED, GREEN };
+enum shade { LIGHT, DARK };
+fn main() {
+ color c = GREEN;
+ shade s = c;
+ return 0;
+}
diff --git a/tests/conformance/2-types/enum_typecheck_enum_to_int.zc b/tests/conformance/2-types/enum_typecheck_enum_to_int.zc
new file mode 100644
index 0000000..5ffcdc3
--- /dev/null
+++ b/tests/conformance/2-types/enum_typecheck_enum_to_int.zc
@@ -0,0 +1,12 @@
+// expect: 1/
+include rt;
+typecheck on;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum color { RED, GREEN };
+fn main() {
+ color c = GREEN;
+ int i = c;
+ pn(i);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/enum_typecheck_int_to_enum.zc b/tests/conformance/2-types/enum_typecheck_int_to_enum.zc
new file mode 100644
index 0000000..9df3057
--- /dev/null
+++ b/tests/conformance/2-types/enum_typecheck_int_to_enum.zc
@@ -0,0 +1,8 @@
+// expect error: initializer: expected color, got int
+include rt;
+typecheck on;
+enum color { RED, GREEN };
+fn main() {
+ color c = 1;
+ return 0;
+}
diff --git a/tests/conformance/2-types/enum_unnamed.zc b/tests/conformance/2-types/enum_unnamed.zc
new file mode 100644
index 0000000..b0785f0
--- /dev/null
+++ b/tests/conformance/2-types/enum_unnamed.zc
@@ -0,0 +1,6 @@
+// expect: 0/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum { A, B };
+fn main() { pn(A); pn(B); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/enum_value_const_expr.zc b/tests/conformance/2-types/enum_value_const_expr.zc
new file mode 100644
index 0000000..2eac9a8
--- /dev/null
+++ b/tests/conformance/2-types/enum_value_const_expr.zc
@@ -0,0 +1,7 @@
+// expect: 16/19/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+const K = 3;
+enum e { P = 1 << 4, Q = K + 16 };
+fn main() { pn(P); pn(Q); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/f32_rounds_on_store.zc b/tests/conformance/2-types/f32_rounds_on_store.zc
new file mode 100644
index 0000000..e137426
--- /dev/null
+++ b/tests/conformance/2-types/f32_rounds_on_store.zc
@@ -0,0 +1,12 @@
+// expect: 0/1/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ f32 x = 0.1;
+ pn(x == 0.1);
+ f32 y = 16777216.0; y = y + 1.0;
+ pn(y == 16777216.0);
+ float z = 16777216.0; z = z + 1.0;
+ pn(z == 16777216.0);
+ return 0;
+}
diff --git a/tests/conformance/2-types/fixed_array_n_is_array_n.zc b/tests/conformance/2-types/fixed_array_n_is_array_n.zc
new file mode 100644
index 0000000..1d26056
--- /dev/null
+++ b/tests/conformance/2-types/fixed_array_n_is_array_n.zc
@@ -0,0 +1,9 @@
+// expect: 3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ fixed int[3] a = {1, 2, 3};
+ pn(sizeof(a));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/fixed_cannot_grow.zc b/tests/conformance/2-types/fixed_cannot_grow.zc
new file mode 100644
index 0000000..fc65c6e
--- /dev/null
+++ b/tests/conformance/2-types/fixed_cannot_grow.zc
@@ -0,0 +1,7 @@
+// expect error: a fixed array can't grow or shrink
+include rt;
+fn main() {
+ fixed int[?] f = rt.new(fixed int[?], 4);
+ push(f, 1);
+ return 0;
+}
diff --git a/tests/conformance/2-types/fixed_cannot_pop.zc b/tests/conformance/2-types/fixed_cannot_pop.zc
new file mode 100644
index 0000000..15384f8
--- /dev/null
+++ b/tests/conformance/2-types/fixed_cannot_pop.zc
@@ -0,0 +1,7 @@
+// expect error: a fixed array can't grow or shrink
+include rt;
+fn main() {
+ fixed int[?] f = rt.new(fixed int[?], 4);
+ pop(f);
+ return 0;
+}
diff --git a/tests/conformance/2-types/fixed_cannot_resize.zc b/tests/conformance/2-types/fixed_cannot_resize.zc
new file mode 100644
index 0000000..4967139
--- /dev/null
+++ b/tests/conformance/2-types/fixed_cannot_resize.zc
@@ -0,0 +1,7 @@
+// expect error: a fixed array can't grow or shrink
+include rt;
+fn main() {
+ fixed int[?] f = rt.new(fixed int[?], 4);
+ resize(f, 2);
+ return 0;
+}
diff --git a/tests/conformance/2-types/fixed_len_and_index.zc b/tests/conformance/2-types/fixed_len_and_index.zc
new file mode 100644
index 0000000..5c1527c
--- /dev/null
+++ b/tests/conformance/2-types/fixed_len_and_index.zc
@@ -0,0 +1,10 @@
+// expect: 4/7/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ fixed int[?] f = rt.new(fixed int[?], 4);
+ f[2] = 7;
+ pn(len(f)); pn(f[2]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/fixed_new_needs_length.zc b/tests/conformance/2-types/fixed_new_needs_length.zc
new file mode 100644
index 0000000..dcaf44d
--- /dev/null
+++ b/tests/conformance/2-types/fixed_new_needs_length.zc
@@ -0,0 +1,6 @@
+// expect error: a fixed array needs its length: new(fixed T[?], n)
+include rt;
+fn main() {
+ fixed int[?] f = rt.new(fixed int[?]);
+ return 0;
+}
diff --git a/tests/conformance/2-types/fixed_to_plain_dyn_param.zc b/tests/conformance/2-types/fixed_to_plain_dyn_param.zc
new file mode 100644
index 0000000..3379b25
--- /dev/null
+++ b/tests/conformance/2-types/fixed_to_plain_dyn_param.zc
@@ -0,0 +1,9 @@
+// expect error: argument: expected int[?], got fixed int[?]
+include rt;
+typecheck on;
+int count(int[?] a) { return len(a); }
+fn main() {
+ fixed int[?] f = rt.new(fixed int[?], 4);
+ int n = count(f);
+ return 0;
+}
diff --git a/tests/conformance/2-types/float_f64_same.zc b/tests/conformance/2-types/float_f64_same.zc
new file mode 100644
index 0000000..df52644
--- /dev/null
+++ b/tests/conformance/2-types/float_f64_same.zc
@@ -0,0 +1,4 @@
+// expect: 1.500000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() { f64 a = 1.5; float b = a; pf(b); return 0; }
diff --git a/tests/conformance/2-types/float_truthy.zc b/tests/conformance/2-types/float_truthy.zc
new file mode 100644
index 0000000..86fe9f8
--- /dev/null
+++ b/tests/conformance/2-types/float_truthy.zc
@@ -0,0 +1,17 @@
+// expect: 0/0/1/1/0/1/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ float z = 0.0;
+ word w = 1 << 63;
+ float nz = w as float;
+ float nan = 0.0 / 0.0;
+ if (z) pn(1); else pn(0);
+ if (nz) pn(1); else pn(0);
+ if (nan) pn(1); else pn(0);
+ pn(nz == 0.0);
+ pn(!nz != 1);
+ pn(nz == z);
+ pn(!nan == 0);
+ return 0;
+}
diff --git a/tests/conformance/2-types/float_truthy_operators.zc b/tests/conformance/2-types/float_truthy_operators.zc
new file mode 100644
index 0000000..98b1e99
--- /dev/null
+++ b/tests/conformance/2-types/float_truthy_operators.zc
@@ -0,0 +1,19 @@
+// expect: 0/0/6/0/0/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ word w = 1 << 63;
+ float nz = w as float;
+ pn(nz && 1);
+ pn(nz || 0);
+ pn(nz ? 5 : 6);
+ int n = 0;
+ while (nz) { n++; break; }
+ pn(n);
+ for (; nz; ) { n++; break; }
+ pn(n);
+ do { } while (nz);
+ pn(n);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/function_type_fn_word.zc b/tests/conformance/2-types/function_type_fn_word.zc
new file mode 100644
index 0000000..7542e4e
--- /dev/null
+++ b/tests/conformance/2-types/function_type_fn_word.zc
@@ -0,0 +1,6 @@
+// expect: 7/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int seven() { return 7; }
+fn main() { fn(int) f = seven; pn(f(1)); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/function_type_param.zc b/tests/conformance/2-types/function_type_param.zc
new file mode 100644
index 0000000..75734e9
--- /dev/null
+++ b/tests/conformance/2-types/function_type_param.zc
@@ -0,0 +1,6 @@
+// expect: 12/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int twice(int x) { return x * 2; }
+int apply(int(int) f, int v) { return f(f(v)) + 4; }
+fn main() { pn(apply(twice, 2)); return 0; }
diff --git a/tests/conformance/2-types/function_type_var.zc b/tests/conformance/2-types/function_type_var.zc
new file mode 100644
index 0000000..f415181
--- /dev/null
+++ b/tests/conformance/2-types/function_type_var.zc
@@ -0,0 +1,12 @@
+// expect: 5/9/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int add(int a, int b) { return a + b; }
+int mul(int a, int b) { return a * b; }
+fn main() {
+ int(int, int) f = add;
+ pn(f(2, 3));
+ f = mul;
+ pn(f(3, 3));
+ return 0;
+}
diff --git a/tests/conformance/2-types/function_value_and_let.zc b/tests/conformance/2-types/function_value_and_let.zc
new file mode 100644
index 0000000..b0f625d
--- /dev/null
+++ b/tests/conformance/2-types/function_value_and_let.zc
@@ -0,0 +1,10 @@
+// expect: 10/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int add(int a, int b) { return a + b; }
+fn main() {
+ int(int, int) f = add;
+ let h = add;
+ pn(f(1, 2) + h(3, 4));
+ return 0;
+}
diff --git a/tests/conformance/2-types/function_value_closure_call.zc b/tests/conformance/2-types/function_value_closure_call.zc
new file mode 100644
index 0000000..34c84b8
--- /dev/null
+++ b/tests/conformance/2-types/function_value_closure_call.zc
@@ -0,0 +1,10 @@
+// expect: 12/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int k = 10;
+ let c = fn(x) { return x + k; };
+ pn(c(2));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/function_value_closure_typed.zc b/tests/conformance/2-types/function_value_closure_typed.zc
new file mode 100644
index 0000000..be0859b
--- /dev/null
+++ b/tests/conformance/2-types/function_value_closure_typed.zc
@@ -0,0 +1,9 @@
+// expect: 9/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let c = fn:int(int a) { return a * 3; };
+ pn(c(3));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/generic_fn_explicit.zc b/tests/conformance/2-types/generic_fn_explicit.zc
new file mode 100644
index 0000000..bcd4734
--- /dev/null
+++ b/tests/conformance/2-types/generic_fn_explicit.zc
@@ -0,0 +1,11 @@
+// expect: 0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+T first<T>(T* p) { return p[0]; }
+fn main() {
+ int[3] ia;
+ ia[0] = 0;
+ pn(first<int>(ia));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/generic_fn_inferred.zc b/tests/conformance/2-types/generic_fn_inferred.zc
new file mode 100644
index 0000000..b2e66c5
--- /dev/null
+++ b/tests/conformance/2-types/generic_fn_inferred.zc
@@ -0,0 +1,12 @@
+// expect: 7/3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+T first<T>(T* p) { return p[0]; }
+fn main() {
+ int[2] ia; ia[0] = 7; ia[1] = 1;
+ char[2] ca; ca[0] = 3; ca[1] = 1;
+ pn(first(ia));
+ pn(first(ca));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/generic_fn_own_copy.zc b/tests/conformance/2-types/generic_fn_own_copy.zc
new file mode 100644
index 0000000..f231421
--- /dev/null
+++ b/tests/conformance/2-types/generic_fn_own_copy.zc
@@ -0,0 +1,8 @@
+// expect: 1/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int size_of<T>() { return sizeof(T); }
+struct two { int a; int b; }
+fn main() { pn(size_of<int>()); pn(size_of<two>()); return 0; }
+
+// zc0: skip
diff --git a/tests/conformance/2-types/generic_fn_return_unconfirmed.zc b/tests/conformance/2-types/generic_fn_return_unconfirmed.zc
new file mode 100644
index 0000000..d7a0f50
--- /dev/null
+++ b/tests/conformance/2-types/generic_fn_return_unconfirmed.zc
@@ -0,0 +1,4 @@
+// expect error: T: isn't a type
+include rt;
+T first(T* p) { return p[0]; }
+fn main() { return 0; }
diff --git a/tests/conformance/2-types/generic_fn_value_explicit.zc b/tests/conformance/2-types/generic_fn_value_explicit.zc
new file mode 100644
index 0000000..2d1d217
--- /dev/null
+++ b/tests/conformance/2-types/generic_fn_value_explicit.zc
@@ -0,0 +1,10 @@
+// expect: 9/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+T ident<T>(T x) { return x; }
+fn main() {
+ let f = ident<int>;
+ pn(f(9));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/generic_struct_basic.zc b/tests/conformance/2-types/generic_struct_basic.zc
new file mode 100644
index 0000000..da9e6fa
--- /dev/null
+++ b/tests/conformance/2-types/generic_struct_basic.zc
@@ -0,0 +1,15 @@
+// expect: 4/8/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct box<T> { T v; int sz() { return sizeof(T); } }
+struct pix { int a; int b; }
+fn main() {
+ box<int>* b = rt.new(box<int>);
+ b.v = 4;
+ pn(b.v);
+ box<pix>* c = rt.new(box<pix>);
+ pn(c.sz() * 4);
+ rt.free(b); rt.free(c);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/generic_struct_nested_close.zc b/tests/conformance/2-types/generic_struct_nested_close.zc
new file mode 100644
index 0000000..8f06406
--- /dev/null
+++ b/tests/conformance/2-types/generic_struct_nested_close.zc
@@ -0,0 +1,13 @@
+// expect: 5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct node<T> { T* p; int n; }
+fn main() {
+ node<node<int>>* a = rt.new(node<node<int>>);
+ a.p = rt.new(node<int>);
+ a.p.n = 5;
+ pn(a.p.n);
+ rt.free(a);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/generic_struct_static_fn.zc b/tests/conformance/2-types/generic_struct_static_fn.zc
new file mode 100644
index 0000000..5910346
--- /dev/null
+++ b/tests/conformance/2-types/generic_struct_static_fn.zc
@@ -0,0 +1,4 @@
+// expect error: a static function can't be in a generic struct
+include rt;
+struct box<T> { T v; static fn mk() { return 0; } }
+fn main() { return 0; }
diff --git a/tests/conformance/2-types/generic_struct_unpacked_fields.zc b/tests/conformance/2-types/generic_struct_unpacked_fields.zc
new file mode 100644
index 0000000..caae5c2
--- /dev/null
+++ b/tests/conformance/2-types/generic_struct_unpacked_fields.zc
@@ -0,0 +1,7 @@
+// expect: 1/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct plain { u8 a; u8 b; }
+struct gen<T> { u8 a; u8 b; }
+fn main() { pn(sizeof(plain)); pn(sizeof(gen<int>)); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/int_sized_cut_more.zc b/tests/conformance/2-types/int_sized_cut_more.zc
new file mode 100644
index 0000000..3fc753c
--- /dev/null
+++ b/tests/conformance/2-types/int_sized_cut_more.zc
@@ -0,0 +1,10 @@
+// expect: -25536/65535/-2147483648/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ i16 v = 40000; pn(v);
+ u16 k = -1; pn(k);
+ i32 w = 0x80000000; pn(w);
+ u8 e = 258; pn(e);
+ return 0;
+}
diff --git a/tests/conformance/2-types/int_sized_cut_store.zc b/tests/conformance/2-types/int_sized_cut_store.zc
new file mode 100644
index 0000000..813f47a
--- /dev/null
+++ b/tests/conformance/2-types/int_sized_cut_store.zc
@@ -0,0 +1,9 @@
+// expect: 4/-56/4294967295/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ u8 a = 250; a = a + 10; pn(a);
+ i8 s = 100; s = s + 100; pn(s);
+ u32 z = 0; z--; pn(z);
+ return 0;
+}
diff --git a/tests/conformance/2-types/int_sized_field.zc b/tests/conformance/2-types/int_sized_field.zc
new file mode 100644
index 0000000..830c57b
--- /dev/null
+++ b/tests/conformance/2-types/int_sized_field.zc
@@ -0,0 +1,12 @@
+// expect: 44/-56/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct szs { u8 a; i8 b; }
+fn main() {
+ szs* p = rt.new(szs);
+ p.a = 300; p.b = 200;
+ pn(p.a); pn(p.b);
+ rt.free(p);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/int_sized_param_return.zc b/tests/conformance/2-types/int_sized_param_return.zc
new file mode 100644
index 0000000..f563be9
--- /dev/null
+++ b/tests/conformance/2-types/int_sized_param_return.zc
@@ -0,0 +1,6 @@
+// expect: 44/44/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f(u8 x) { return x; }
+u8 g() { return 300; }
+fn main() { pn(f(300)); pn(g()); return 0; }
diff --git a/tests/conformance/2-types/no_long.zc b/tests/conformance/2-types/no_long.zc
new file mode 100644
index 0000000..b31e10c
--- /dev/null
+++ b/tests/conformance/2-types/no_long.zc
@@ -0,0 +1,6 @@
+// expect error: zc: line 4:
+include rt;
+fn main() {
+ long x = 1;
+ return 0;
+}
diff --git a/tests/conformance/2-types/no_u64.zc b/tests/conformance/2-types/no_u64.zc
new file mode 100644
index 0000000..26ae40e
--- /dev/null
+++ b/tests/conformance/2-types/no_u64.zc
@@ -0,0 +1,6 @@
+// expect error: zc: line 4:
+include rt;
+fn main() {
+ u64 x = 1;
+ return 0;
+}
diff --git a/tests/conformance/2-types/null_pointer.zc b/tests/conformance/2-types/null_pointer.zc
new file mode 100644
index 0000000..add1803
--- /dev/null
+++ b/tests/conformance/2-types/null_pointer.zc
@@ -0,0 +1,11 @@
+// expect: 1/0/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int* p = 0;
+ pn(p == 0);
+ pn((int)p);
+ pn(!p);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/packed_bytes_in_word.zc b/tests/conformance/2-types/packed_bytes_in_word.zc
new file mode 100644
index 0000000..178eaf3
--- /dev/null
+++ b/tests/conformance/2-types/packed_bytes_in_word.zc
@@ -0,0 +1,14 @@
+// expect: 511/2882338816/-4294967295/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ u8[8] a; u16[4] h; i32[2] q;
+ int* wa = (int*)a; int* wh = (int*)h; int* wq = (int*)q;
+ wa[0] = 0; wh[0] = 0; wq[0] = 0;
+ a[0] = 255; a[1] = 1;
+ h[1] = 0xABCD;
+ q[0] = 1; q[1] = -1;
+ pn(wa[0]); pn(wh[0]); pn(wq[0]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/packed_element_has_no_address.zc b/tests/conformance/2-types/packed_element_has_no_address.zc
new file mode 100644
index 0000000..fae4b5a
--- /dev/null
+++ b/tests/conformance/2-types/packed_element_has_no_address.zc
@@ -0,0 +1,7 @@
+// expect error: an element of a sized-integer array has no address
+include rt;
+fn main() {
+ u8[4] a;
+ u8* p = &a[1];
+ return 0;
+}
diff --git a/tests/conformance/2-types/packed_read_back.zc b/tests/conformance/2-types/packed_read_back.zc
new file mode 100644
index 0000000..17dbe79
--- /dev/null
+++ b/tests/conformance/2-types/packed_read_back.zc
@@ -0,0 +1,11 @@
+// expect: 1/2/3/4/5/6/7/8/9/10/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ u8[10] a;
+ int i = 0;
+ while (i < 10) { a[i] = i + 1; i++; }
+ i = 0;
+ while (i < 10) { pn(a[i]); i++; }
+ return 0;
+}
diff --git a/tests/conformance/2-types/packed_sizeof.zc b/tests/conformance/2-types/packed_sizeof.zc
new file mode 100644
index 0000000..d472926
--- /dev/null
+++ b/tests/conformance/2-types/packed_sizeof.zc
@@ -0,0 +1,10 @@
+// expect: 2/1/2/1/2/1/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(sizeof(u8[10])); pn(sizeof(u8[8])); pn(sizeof(u8[9]));
+ pn(sizeof(u16[4])); pn(sizeof(u16[5]));
+ pn(sizeof(i32[2])); pn(sizeof(i32[3]));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/plain_dyn_to_fixed_param.zc b/tests/conformance/2-types/plain_dyn_to_fixed_param.zc
new file mode 100644
index 0000000..a410fd6
--- /dev/null
+++ b/tests/conformance/2-types/plain_dyn_to_fixed_param.zc
@@ -0,0 +1,11 @@
+// expect: 2/
+include rt;
+typecheck on;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int count(fixed int[?] a) { return len(a); }
+fn main() {
+ int[?] a = rt.new(int[?], 2);
+ pn(count(a));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/prefix_array_is_error.zc b/tests/conformance/2-types/prefix_array_is_error.zc
new file mode 100644
index 0000000..644ad37
--- /dev/null
+++ b/tests/conformance/2-types/prefix_array_is_error.zc
@@ -0,0 +1,6 @@
+// expect error: array types are postfix: T[N], T[] or T[?]
+include rt;
+fn main() {
+ [3]int a;
+ return 0;
+}
diff --git a/tests/conformance/2-types/prefix_pointer_is_error.zc b/tests/conformance/2-types/prefix_pointer_is_error.zc
new file mode 100644
index 0000000..801f35c
--- /dev/null
+++ b/tests/conformance/2-types/prefix_pointer_is_error.zc
@@ -0,0 +1,6 @@
+// expect error: int: is a type, not a value
+include rt;
+fn main() {
+ *int x;
+ return 0;
+}
diff --git a/tests/conformance/2-types/sizeof_bstr.zc b/tests/conformance/2-types/sizeof_bstr.zc
new file mode 100644
index 0000000..5518ef7
--- /dev/null
+++ b/tests/conformance/2-types/sizeof_bstr.zc
@@ -0,0 +1,5 @@
+// expect: 1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(sizeof(bstr)); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/sizeof_builtin.zc b/tests/conformance/2-types/sizeof_builtin.zc
new file mode 100644
index 0000000..a9b7d30
--- /dev/null
+++ b/tests/conformance/2-types/sizeof_builtin.zc
@@ -0,0 +1,10 @@
+// expect: 1/1/1/1/1/1/1/1/1/1/1/1/1/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(sizeof(word)); pn(sizeof(int)); pn(sizeof(char)); pn(sizeof(bool)); pn(sizeof(float));
+ pn(sizeof(f64)); pn(sizeof(f32)); pn(sizeof(i8)); pn(sizeof(u8)); pn(sizeof(byte));
+ pn(sizeof(i16)); pn(sizeof(u16)); pn(sizeof(i32)); pn(sizeof(u32));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/struct_arrow_same_as_dot.zc b/tests/conformance/2-types/struct_arrow_same_as_dot.zc
new file mode 100644
index 0000000..1e940f8
--- /dev/null
+++ b/tests/conformance/2-types/struct_arrow_same_as_dot.zc
@@ -0,0 +1,11 @@
+// expect: 3/4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct pt { int x; int y; }
+fn main() {
+ pt* p = rt.new(pt);
+ p.x = 3; p->y = 4;
+ pn(p->x); pn(p.y);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/struct_contains_itself.zc b/tests/conformance/2-types/struct_contains_itself.zc
new file mode 100644
index 0000000..cc33390
--- /dev/null
+++ b/tests/conformance/2-types/struct_contains_itself.zc
@@ -0,0 +1,4 @@
+// expect error: a struct can't contain itself by value; use a pointer
+include rt;
+struct node { node next; int v; }
+fn main() { return 0; }
diff --git a/tests/conformance/2-types/struct_field_on_int_unique.zc b/tests/conformance/2-types/struct_field_on_int_unique.zc
new file mode 100644
index 0000000..c053ca2
--- /dev/null
+++ b/tests/conformance/2-types/struct_field_on_int_unique.zc
@@ -0,0 +1,6 @@
+// expect: 0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct pt { int zqx; int zqy; }
+fn main() { int i = 0; i = 5; pn(i.zqx * 0); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/struct_field_on_word_ambiguous.zc b/tests/conformance/2-types/struct_field_on_word_ambiguous.zc
new file mode 100644
index 0000000..d71ff17
--- /dev/null
+++ b/tests/conformance/2-types/struct_field_on_word_ambiguous.zc
@@ -0,0 +1,9 @@
+// expect error: .zqv is a field of more than one struct
+include rt;
+struct sa { int zqv; }
+struct sb { int zqv; }
+fn main() {
+ word w = 5;
+ rt.put_n(w.zqv);
+ return 0;
+}
diff --git a/tests/conformance/2-types/struct_field_on_word_unique.zc b/tests/conformance/2-types/struct_field_on_word_unique.zc
new file mode 100644
index 0000000..35d7c16
--- /dev/null
+++ b/tests/conformance/2-types/struct_field_on_word_unique.zc
@@ -0,0 +1,12 @@
+// expect: 5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct uniq { int zqfield; }
+uniq g;
+fn main() {
+ g.zqfield = 5;
+ word w = g;
+ pn(w.zqfield);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/struct_layout_offsets.zc b/tests/conformance/2-types/struct_layout_offsets.zc
new file mode 100644
index 0000000..bac33c0
--- /dev/null
+++ b/tests/conformance/2-types/struct_layout_offsets.zc
@@ -0,0 +1,13 @@
+// expect: 33751041/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct t5 { u8 a; u16 b; }
+fn main() {
+ t5* p = rt.new(t5);
+ int* w = (int*)p;
+ w[0] = 0;
+ p.a = 1; p.b = 0x0203;
+ pn(w[0]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/struct_layout_pack_rules.zc b/tests/conformance/2-types/struct_layout_pack_rules.zc
new file mode 100644
index 0000000..1493373
--- /dev/null
+++ b/tests/conformance/2-types/struct_layout_pack_rules.zc
@@ -0,0 +1,9 @@
+// expect: 3/2/1/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct t1 { u8 a; int b; u8 c; }
+struct t2 { u8 a; u8 b; u16 c; u32 d; u8 e; }
+struct t3 { u8 a; u32 b; }
+struct t4 { u8 a; u32 b; u8 c; }
+fn main() { pn(sizeof(t1)); pn(sizeof(t2)); pn(sizeof(t3)); pn(sizeof(t4)); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/struct_layout_pix.zc b/tests/conformance/2-types/struct_layout_pix.zc
new file mode 100644
index 0000000..463c78d
--- /dev/null
+++ b/tests/conformance/2-types/struct_layout_pix.zc
@@ -0,0 +1,6 @@
+// expect: 2/6/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct pix { u8 r, g, b, a; i16 dx; int w; };
+fn main() { pn(sizeof(pix)); pn(sizeof(pix[3])); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/struct_layout_words.zc b/tests/conformance/2-types/struct_layout_words.zc
new file mode 100644
index 0000000..b0facc4
--- /dev/null
+++ b/tests/conformance/2-types/struct_layout_words.zc
@@ -0,0 +1,6 @@
+// expect: 5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct ws { int a; int[3] b; int c; }
+fn main() { pn(sizeof(ws)); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/struct_param_by_value.zc b/tests/conformance/2-types/struct_param_by_value.zc
new file mode 100644
index 0000000..134fcd4
--- /dev/null
+++ b/tests/conformance/2-types/struct_param_by_value.zc
@@ -0,0 +1,5 @@
+// expect error: structs and arrays are passed by pointer
+include rt;
+struct pt { int x; int y; }
+int getx(pt p) { return p.x; }
+fn main() { return 0; }
diff --git a/tests/conformance/2-types/struct_value_is_address.zc b/tests/conformance/2-types/struct_value_is_address.zc
new file mode 100644
index 0000000..26eb539
--- /dev/null
+++ b/tests/conformance/2-types/struct_value_is_address.zc
@@ -0,0 +1,12 @@
+// expect: 5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct pt { int x; int y; }
+fn main() {
+ pt a;
+ a.x = 5;
+ pt* p = a;
+ pn(p.x);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/tag_names_unreserved.zc b/tests/conformance/2-types/tag_names_unreserved.zc
new file mode 100644
index 0000000..9c780a4
--- /dev/null
+++ b/tests/conformance/2-types/tag_names_unreserved.zc
@@ -0,0 +1,4 @@
+// expect: 6/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int u = 1, m = 2, d = 3; pn(u + m + d); return 0; }
diff --git a/tests/conformance/2-types/tag_on_field.zc b/tests/conformance/2-types/tag_on_field.zc
new file mode 100644
index 0000000..37b814f
--- /dev/null
+++ b/tests/conformance/2-types/tag_on_field.zc
@@ -0,0 +1,4 @@
+// expect error: zc: line 3:
+include rt;
+struct s { int*.u f; }
+fn main() { return 0; }
diff --git a/tests/conformance/2-types/tag_on_global.zc b/tests/conformance/2-types/tag_on_global.zc
new file mode 100644
index 0000000..64c9e7e
--- /dev/null
+++ b/tests/conformance/2-types/tag_on_global.zc
@@ -0,0 +1,4 @@
+// expect error: tags go on locals and parameters, not globals
+include rt;
+int*.u g;
+fn main() { return 0; }
diff --git a/tests/conformance/2-types/type_hash_consed.zc b/tests/conformance/2-types/type_hash_consed.zc
new file mode 100644
index 0000000..e631e3a
--- /dev/null
+++ b/tests/conformance/2-types/type_hash_consed.zc
@@ -0,0 +1,10 @@
+// expect: 1/0/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(typeof(int[3]) == typeof(int[3]));
+ pn(typeof(int*) == typeof(char*));
+ pn(typeof(int(int, char*)) == typeof(int(int, char*)));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/2-types/typecheck_array_to_pointer_decay.zc b/tests/conformance/2-types/typecheck_array_to_pointer_decay.zc
new file mode 100644
index 0000000..1dc1660
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_array_to_pointer_decay.zc
@@ -0,0 +1,6 @@
+// expect: 2/
+include rt;
+typecheck on;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int[3] a = {1, 2, 3}; int* p = a; pn(p[1]); return 0; }
+// zc0: skip
diff --git a/tests/conformance/2-types/typecheck_bstr_to_bstr.zc b/tests/conformance/2-types/typecheck_bstr_to_bstr.zc
new file mode 100644
index 0000000..10f8d3f
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_bstr_to_bstr.zc
@@ -0,0 +1,5 @@
+// expect: 3/
+include rt;
+typecheck on;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { bstr a = b"abc"; bstr b = a; pn(len(b)); return 0; }
diff --git a/tests/conformance/2-types/typecheck_bstr_to_int.zc b/tests/conformance/2-types/typecheck_bstr_to_int.zc
new file mode 100644
index 0000000..6022de8
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_bstr_to_int.zc
@@ -0,0 +1,4 @@
+// expect error: type error: initializer
+include rt;
+typecheck on;
+fn main() { int x = b"abc"; return 0; }
diff --git a/tests/conformance/2-types/typecheck_call_non_function.zc b/tests/conformance/2-types/typecheck_call_non_function.zc
new file mode 100644
index 0000000..d044151
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_call_non_function.zc
@@ -0,0 +1,4 @@
+// expect error: type error
+include rt;
+typecheck on;
+fn main() { int x = 3; int y = x(1); return 0; }
diff --git a/tests/conformance/2-types/typecheck_compare_incompatible.zc b/tests/conformance/2-types/typecheck_compare_incompatible.zc
new file mode 100644
index 0000000..ed9bfa5
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_compare_incompatible.zc
@@ -0,0 +1,4 @@
+// expect error: type error
+include rt;
+typecheck on;
+fn main() { int* p = 0; char* c = 0; int b = (p == c); return 0; }
diff --git a/tests/conformance/2-types/typecheck_const_to_mutable.zc b/tests/conformance/2-types/typecheck_const_to_mutable.zc
new file mode 100644
index 0000000..2574863
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_const_to_mutable.zc
@@ -0,0 +1,4 @@
+// expect error: const storage cannot be converted to a mutable reference
+include rt;
+typecheck on;
+fn main() { const int* p = 0; int* q = p; return 0; }
diff --git a/tests/conformance/2-types/typecheck_default_off.zc b/tests/conformance/2-types/typecheck_default_off.zc
new file mode 100644
index 0000000..00cdde8
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_default_off.zc
@@ -0,0 +1,4 @@
+// expect: 0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { char* s = 5; pn(s == 0); return 0; }
diff --git a/tests/conformance/2-types/typecheck_deref_non_pointer.zc b/tests/conformance/2-types/typecheck_deref_non_pointer.zc
new file mode 100644
index 0000000..c6e1cb2
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_deref_non_pointer.zc
@@ -0,0 +1,4 @@
+// expect error: only pointers can be dereferenced, got int
+include rt;
+typecheck on;
+fn main() { int x = 3; int y = *x; return 0; }
diff --git a/tests/conformance/2-types/typecheck_float_to_int_number.zc b/tests/conformance/2-types/typecheck_float_to_int_number.zc
new file mode 100644
index 0000000..d5488ff
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_float_to_int_number.zc
@@ -0,0 +1,5 @@
+// expect: 2/
+include rt;
+typecheck on;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { float f = 2.5; int i = f; pn(i); return 0; }
diff --git a/tests/conformance/2-types/typecheck_generic_unify.zc b/tests/conformance/2-types/typecheck_generic_unify.zc
new file mode 100644
index 0000000..b0ccc1b
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_generic_unify.zc
@@ -0,0 +1,5 @@
+// expect error: type error: argument: expected int, got char*
+include rt;
+typecheck on;
+T pick<T>(T a, T b) { return a; }
+fn main() { let x = pick(1, "s"); return 0; }
diff --git a/tests/conformance/2-types/typecheck_index_with_pointer.zc b/tests/conformance/2-types/typecheck_index_with_pointer.zc
new file mode 100644
index 0000000..8072626
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_index_with_pointer.zc
@@ -0,0 +1,4 @@
+// expect error: type error
+include rt;
+typecheck on;
+fn main() { int[3] a; int* p = a; int x = a[p]; return 0; }
diff --git a/tests/conformance/2-types/typecheck_number_kinds_convert.zc b/tests/conformance/2-types/typecheck_number_kinds_convert.zc
new file mode 100644
index 0000000..9c3d76e
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_number_kinds_convert.zc
@@ -0,0 +1,5 @@
+// expect: 44/
+include rt;
+typecheck on;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int i = 300; u8 b = i; char c = b; bool t = c; pn(t); return 0; }
diff --git a/tests/conformance/2-types/typecheck_off_argument_count.zc b/tests/conformance/2-types/typecheck_off_argument_count.zc
new file mode 100644
index 0000000..1b392e6
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_off_argument_count.zc
@@ -0,0 +1,4 @@
+// expect error: f: wrong number of arguments
+include rt;
+int f(int a, int b) { return a + b; }
+fn main() { rt.put_n(f(1)); return 0; }
diff --git a/tests/conformance/2-types/typecheck_off_field_on_int.zc b/tests/conformance/2-types/typecheck_off_field_on_int.zc
new file mode 100644
index 0000000..839c0da
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_off_field_on_int.zc
@@ -0,0 +1,4 @@
+// expect error: .zzq: that's a int, not a struct or a pointer to one
+include rt;
+struct pt { int x; int y; }
+fn main() { int i = 3; rt.put_n(i.zzq); return 0; }
diff --git a/tests/conformance/2-types/typecheck_off_missing_field.zc b/tests/conformance/2-types/typecheck_off_missing_field.zc
new file mode 100644
index 0000000..f0998b7
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_off_missing_field.zc
@@ -0,0 +1,4 @@
+// expect error: pt has no field z
+include rt;
+struct pt { int x; int y; }
+fn main() { pt* p = rt.new(pt); p.z = 1; return 0; }
diff --git a/tests/conformance/2-types/typecheck_off_void_return_value_ok.zc b/tests/conformance/2-types/typecheck_off_void_return_value_ok.zc
new file mode 100644
index 0000000..61e51f5
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_off_void_return_value_ok.zc
@@ -0,0 +1,5 @@
+// expect: 0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void f() { return 3; }
+fn main() { pn(f()); return 0; }
diff --git a/tests/conformance/2-types/typecheck_pointer_arithmetic_ok.zc b/tests/conformance/2-types/typecheck_pointer_arithmetic_ok.zc
new file mode 100644
index 0000000..f761ad7
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_pointer_arithmetic_ok.zc
@@ -0,0 +1,13 @@
+// expect: 1/2/
+include rt;
+typecheck on;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[4] a;
+ int* p = a;
+ int* q = p + 1;
+ pn(q - p);
+ int* r = q + 1;
+ pn(r - p);
+ return 0;
+}
diff --git a/tests/conformance/2-types/typecheck_pointer_element_mismatch.zc b/tests/conformance/2-types/typecheck_pointer_element_mismatch.zc
new file mode 100644
index 0000000..d5a617f
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_pointer_element_mismatch.zc
@@ -0,0 +1,4 @@
+// expect error: type error: initializer: expected int*, got char*
+include rt;
+typecheck on;
+fn main() { char* c = 0; int* p = c; return 0; }
diff --git a/tests/conformance/2-types/typecheck_pointer_from_int.zc b/tests/conformance/2-types/typecheck_pointer_from_int.zc
new file mode 100644
index 0000000..fddabb3
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_pointer_from_int.zc
@@ -0,0 +1,4 @@
+// expect error: type error: initializer: expected char*, got int
+include rt;
+typecheck on;
+fn main() { char* s = 5; return 0; }
diff --git a/tests/conformance/2-types/typecheck_pointer_plus_float.zc b/tests/conformance/2-types/typecheck_pointer_plus_float.zc
new file mode 100644
index 0000000..207c4e2
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_pointer_plus_float.zc
@@ -0,0 +1,4 @@
+// expect error: type error
+include rt;
+typecheck on;
+fn main() { float f = 1.5; int* p = 0; int q = p + f; return 0; }
diff --git a/tests/conformance/2-types/typecheck_pointer_times_number.zc b/tests/conformance/2-types/typecheck_pointer_times_number.zc
new file mode 100644
index 0000000..ca0806b
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_pointer_times_number.zc
@@ -0,0 +1,4 @@
+// expect error: type error: arithmetic needs numbers, got int*
+include rt;
+typecheck on;
+fn main() { int[2] a; int* p = a; int q = p * 2; return 0; }
diff --git a/tests/conformance/2-types/typecheck_return_void_value.zc b/tests/conformance/2-types/typecheck_return_void_value.zc
new file mode 100644
index 0000000..44a14f8
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_return_void_value.zc
@@ -0,0 +1,5 @@
+// expect error: type error: return value: expected void, got int
+include rt;
+typecheck on;
+void f() { return 3; }
+fn main() { f(); return 0; }
diff --git a/tests/conformance/2-types/typecheck_string_to_word.zc b/tests/conformance/2-types/typecheck_string_to_word.zc
new file mode 100644
index 0000000..c08426c
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_string_to_word.zc
@@ -0,0 +1,4 @@
+// expect error: type error: initializer
+include rt;
+typecheck on;
+fn main() { word w = "abc"; return 0; }
diff --git a/tests/conformance/2-types/typecheck_toggle_off.zc b/tests/conformance/2-types/typecheck_toggle_off.zc
new file mode 100644
index 0000000..63835dd
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_toggle_off.zc
@@ -0,0 +1,7 @@
+// expect: 1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+typecheck on;
+int fine(int x) { return x + 1; }
+typecheck off;
+fn main() { char* s = 5; pn(fine(0)); return 0; }
diff --git a/tests/conformance/2-types/typecheck_word_compatible.zc b/tests/conformance/2-types/typecheck_word_compatible.zc
new file mode 100644
index 0000000..fff64fc
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_word_compatible.zc
@@ -0,0 +1,5 @@
+// expect: 3/
+include rt;
+typecheck on;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { word w = 3; int i = w; pn(i); return 0; }
diff --git a/tests/conformance/2-types/typecheck_zero_to_pointer_function_dyn.zc b/tests/conformance/2-types/typecheck_zero_to_pointer_function_dyn.zc
new file mode 100644
index 0000000..c454aa5
--- /dev/null
+++ b/tests/conformance/2-types/typecheck_zero_to_pointer_function_dyn.zc
@@ -0,0 +1,9 @@
+// expect: 1/1/1/
+include rt;
+typecheck on;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int* p = 0; int(int) f = 0; int[?] a = 0;
+ pn(p == 0); pn(f == 0); pn(a == 0);
+ return 0;
+}
diff --git a/tests/conformance/2-types/void_pointer_compatible.zc b/tests/conformance/2-types/void_pointer_compatible.zc
new file mode 100644
index 0000000..c41d6e7
--- /dev/null
+++ b/tests/conformance/2-types/void_pointer_compatible.zc
@@ -0,0 +1,12 @@
+// expect: 1/
+include rt;
+typecheck on;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void take(void* p) { pn(p == 0); }
+fn main() {
+ char* s = "abc";
+ void* v = 0;
+ int* p = v;
+ pn(p == 0);
+ return 0;
+}
diff --git a/tests/conformance/2-types/void_variable.zc b/tests/conformance/2-types/void_variable.zc
new file mode 100644
index 0000000..dc63a97
--- /dev/null
+++ b/tests/conformance/2-types/void_variable.zc
@@ -0,0 +1,6 @@
+// expect error: a variable can't be void
+include rt;
+fn main() {
+ void v;
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/assign_target_address_first.zc b/tests/conformance/3-expressions/assign_target_address_first.zc
new file mode 100644
index 0000000..5fe6093
--- /dev/null
+++ b/tests/conformance/3-expressions/assign_target_address_first.zc
@@ -0,0 +1,11 @@
+// expect: 2/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int i = 0;
+ int[3] a = {0, 0, 0};
+ a[i] = i = 2;
+ pn(a[0]); pn(a[2]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/assign_to_deref_and_field.zc b/tests/conformance/3-expressions/assign_to_deref_and_field.zc
new file mode 100644
index 0000000..c6af1ca
--- /dev/null
+++ b/tests/conformance/3-expressions/assign_to_deref_and_field.zc
@@ -0,0 +1,15 @@
+// expect: 5/6/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct pt { int x; int y; }
+fn main() {
+ int[2] a;
+ int* p = a;
+ *p = 5;
+ pt* q = rt.new(pt);
+ q.y = 6;
+ pn(a[0]); pn(q.y);
+ rt.free(q);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/assign_to_literal.zc b/tests/conformance/3-expressions/assign_to_literal.zc
new file mode 100644
index 0000000..d204ff3
--- /dev/null
+++ b/tests/conformance/3-expressions/assign_to_literal.zc
@@ -0,0 +1,6 @@
+// expect error: this can't be assigned to
+include rt;
+fn main() {
+ 3 = 4;
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/assign_to_non_lvalue.zc b/tests/conformance/3-expressions/assign_to_non_lvalue.zc
new file mode 100644
index 0000000..7436a12
--- /dev/null
+++ b/tests/conformance/3-expressions/assign_to_non_lvalue.zc
@@ -0,0 +1,7 @@
+// expect error: this can't be assigned to
+include rt;
+fn main() {
+ int a = 1;
+ (a + 1) = 5;
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/assign_yields_value.zc b/tests/conformance/3-expressions/assign_yields_value.zc
new file mode 100644
index 0000000..9796283
--- /dev/null
+++ b/tests/conformance/3-expressions/assign_yields_value.zc
@@ -0,0 +1,11 @@
+// expect: 9/9/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a, b;
+ b = (a = 4) + 5;
+ pn(b);
+ int[2] arr;
+ pn(arr[1] = 9);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/block_expr_array_literal_vs_block.zc b/tests/conformance/3-expressions/block_expr_array_literal_vs_block.zc
new file mode 100644
index 0000000..7596210
--- /dev/null
+++ b/tests/conformance/3-expressions/block_expr_array_literal_vs_block.zc
@@ -0,0 +1,13 @@
+// expect: 3/5/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[] a = { 1, 2, 3 };
+ pn(len(a));
+ int[] b = { 5 };
+ pn(b[0]);
+ let c = { 5; };
+ pn(c);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/block_expr_break_rejected.zc b/tests/conformance/3-expressions/block_expr_break_rejected.zc
new file mode 100644
index 0000000..1cce727
--- /dev/null
+++ b/tests/conformance/3-expressions/block_expr_break_rejected.zc
@@ -0,0 +1,6 @@
+// expect error: break can't leave
+include rt;
+fn main() {
+ while (1) { let v = { break; 1 }; }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/block_expr_continue_rejected.zc b/tests/conformance/3-expressions/block_expr_continue_rejected.zc
new file mode 100644
index 0000000..6a4c27a
--- /dev/null
+++ b/tests/conformance/3-expressions/block_expr_continue_rejected.zc
@@ -0,0 +1,6 @@
+// expect error: continue can't leave
+include rt;
+fn main() {
+ while (1) { let v = { continue; 1 }; }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/block_expr_m_tail_rejected.zc b/tests/conformance/3-expressions/block_expr_m_tail_rejected.zc
new file mode 100644
index 0000000..9986568
--- /dev/null
+++ b/tests/conformance/3-expressions/block_expr_m_tail_rejected.zc
@@ -0,0 +1,6 @@
+// expect error: t: has to be u to be handed up as the block's value
+include rt;
+fn main() {
+ int* p = { int* t = rt.new(int); t };
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/block_expr_return_rejected.zc b/tests/conformance/3-expressions/block_expr_return_rejected.zc
new file mode 100644
index 0000000..4300368
--- /dev/null
+++ b/tests/conformance/3-expressions/block_expr_return_rejected.zc
@@ -0,0 +1,6 @@
+// expect error: return can't leave a block expression
+include rt;
+fn main() {
+ let v = { return 3; };
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/block_expr_scope.zc b/tests/conformance/3-expressions/block_expr_scope.zc
new file mode 100644
index 0000000..0ac644a
--- /dev/null
+++ b/tests/conformance/3-expressions/block_expr_scope.zc
@@ -0,0 +1,10 @@
+// expect: 8/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int t = 8;
+ let v = { int t = 100; t + 1 };
+ pn(t);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/block_expr_u_tail.zc b/tests/conformance/3-expressions/block_expr_u_tail.zc
new file mode 100644
index 0000000..61c4f03
--- /dev/null
+++ b/tests/conformance/3-expressions/block_expr_u_tail.zc
@@ -0,0 +1,9 @@
+// expect: 4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int* p = { int* t = rt.new(int); *t = 4; u*t };
+ pn(*p);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/block_expr_value.zc b/tests/conformance/3-expressions/block_expr_value.zc
new file mode 100644
index 0000000..b6c973e
--- /dev/null
+++ b/tests/conformance/3-expressions/block_expr_value.zc
@@ -0,0 +1,11 @@
+// expect: 49/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let sq = { let t = 3 + 4; t * t };
+ pn(sq);
+ let z = { let q = 1; q = q + 1; };
+ pn(z);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/bstr_compare.zc b/tests/conformance/3-expressions/bstr_compare.zc
new file mode 100644
index 0000000..de4abd3
--- /dev/null
+++ b/tests/conformance/3-expressions/bstr_compare.zc
@@ -0,0 +1,13 @@
+// expect: 1/1/0/1/1/0/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(b"abc" < b"abd");
+ pn(b"ab" < b"abc");
+ pn(b"abc" < b"abc");
+ pn(b"abc" <= b"abc");
+ pn(b"abc" == b"abc");
+ pn(b"abc" != b"abc");
+ pn(b"b" > b"abc");
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/bstr_compare_unsigned.zc b/tests/conformance/3-expressions/bstr_compare_unsigned.zc
new file mode 100644
index 0000000..df936d6
--- /dev/null
+++ b/tests/conformance/3-expressions/bstr_compare_unsigned.zc
@@ -0,0 +1,8 @@
+// expect: 1/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(b"é" > b"z");
+ pn(b"é" < b"z");
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/bstr_concat_and_len.zc b/tests/conformance/3-expressions/bstr_concat_and_len.zc
new file mode 100644
index 0000000..4bdc8c5
--- /dev/null
+++ b/tests/conformance/3-expressions/bstr_concat_and_len.zc
@@ -0,0 +1,9 @@
+// expect: 5/abcde/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ bstr s = b"abc" + b"de";
+ pn(len(s));
+ rt.put_s(s); rt.put_c(10);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/bstr_index_and_range.zc b/tests/conformance/3-expressions/bstr_index_and_range.zc
new file mode 100644
index 0000000..84b1b83
--- /dev/null
+++ b/tests/conformance/3-expressions/bstr_index_and_range.zc
@@ -0,0 +1,11 @@
+// expect: 98/0/0/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ bstr s = b"abc";
+ pn(s[1]);
+ pn(s[3]);
+ pn(s[5]);
+ pn(s[-1]);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/bstr_index_not_lvalue.zc b/tests/conformance/3-expressions/bstr_index_not_lvalue.zc
new file mode 100644
index 0000000..71762e4
--- /dev/null
+++ b/tests/conformance/3-expressions/bstr_index_not_lvalue.zc
@@ -0,0 +1,7 @@
+// expect error: zc: line 5:
+include rt;
+fn main() {
+ bstr s = b"abc";
+ s[0] = 65;
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/bstr_mix_compare_error.zc b/tests/conformance/3-expressions/bstr_mix_compare_error.zc
new file mode 100644
index 0000000..e8acc38
--- /dev/null
+++ b/tests/conformance/3-expressions/bstr_mix_compare_error.zc
@@ -0,0 +1,6 @@
+// expect error: a byte string needs a byte string on the other side
+include rt;
+fn main() {
+ int x = (b"a" == 5);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/bstr_mix_error.zc b/tests/conformance/3-expressions/bstr_mix_error.zc
new file mode 100644
index 0000000..08daf37
--- /dev/null
+++ b/tests/conformance/3-expressions/bstr_mix_error.zc
@@ -0,0 +1,6 @@
+// expect error: a byte string needs a byte string on the other side
+include rt;
+fn main() {
+ bstr s = b"a" + "b";
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/bstr_put_s_writes_bytes.zc b/tests/conformance/3-expressions/bstr_put_s_writes_bytes.zc
new file mode 100644
index 0000000..bf36611
--- /dev/null
+++ b/tests/conformance/3-expressions/bstr_put_s_writes_bytes.zc
@@ -0,0 +1,7 @@
+// expect: hi there/
+include rt;
+fn main() {
+ rt.put_s(b"hi there");
+ rt.put_c(10);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/bstr_results_shared_not_freed.zc b/tests/conformance/3-expressions/bstr_results_shared_not_freed.zc
new file mode 100644
index 0000000..ef32171
--- /dev/null
+++ b/tests/conformance/3-expressions/bstr_results_shared_not_freed.zc
@@ -0,0 +1,9 @@
+// expect: 4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ bstr s = b"ab" + b"cd";
+ rt.free(s);
+ pn(len(s));
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/bstr_slice.zc b/tests/conformance/3-expressions/bstr_slice.zc
new file mode 100644
index 0000000..5fa20e5
--- /dev/null
+++ b/tests/conformance/3-expressions/bstr_slice.zc
@@ -0,0 +1,14 @@
+// expect: el/he/lo//0//
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ bstr t = b"hello";
+ rt.put_s(t[1:3]); rt.put_c(10);
+ rt.put_s(t[-5:2]); rt.put_c(10);
+ rt.put_s(t[3:100]); rt.put_c(10);
+ bstr e = t[4:2];
+ rt.put_s(e); rt.put_c(10);
+ pn(len(e));
+ rt.put_s(t[2:2]); rt.put_c(10);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/call_23_parameters.zc b/tests/conformance/3-expressions/call_23_parameters.zc
new file mode 100644
index 0000000..d53d037
--- /dev/null
+++ b/tests/conformance/3-expressions/call_23_parameters.zc
@@ -0,0 +1,8 @@
+// expect: 276/
+// spec 3.11.3: at most 24 parameters (23 is under the limit)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int s23(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18, int a19, int a20, int a21, int a22, int a23) {
+ return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20 + a21 + a22 + a23;
+}
+fn main() { pn(s23(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)); return 0; }
diff --git a/tests/conformance/3-expressions/call_24_parameters.zc b/tests/conformance/3-expressions/call_24_parameters.zc
new file mode 100644
index 0000000..4ebe585
--- /dev/null
+++ b/tests/conformance/3-expressions/call_24_parameters.zc
@@ -0,0 +1,7 @@
+// expect: 300/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int s24(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18, int a19, int a20, int a21, int a22, int a23, int a24) {
+ return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20 + a21 + a22 + a23 + a24;
+}
+fn main() { pn(s24(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24)); return 0; }
diff --git a/tests/conformance/3-expressions/call_24_parameters_prototype.zc b/tests/conformance/3-expressions/call_24_parameters_prototype.zc
new file mode 100644
index 0000000..85542aa
--- /dev/null
+++ b/tests/conformance/3-expressions/call_24_parameters_prototype.zc
@@ -0,0 +1,6 @@
+// expect: 0/
+// spec 5.2.2: up to 24 parameters (a prototype)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int s24(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18, int a19, int a20, int a21, int a22, int a23, int a24);
+fn main() { pn(0); return 0; }
diff --git a/tests/conformance/3-expressions/call_25_parameters_rejected.zc b/tests/conformance/3-expressions/call_25_parameters_rejected.zc
new file mode 100644
index 0000000..d8b8896
--- /dev/null
+++ b/tests/conformance/3-expressions/call_25_parameters_rejected.zc
@@ -0,0 +1,8 @@
+// expect error: too many parameters
+// spec 3.11.3 and 5.2.2: at most 24 parameters
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int s25(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18, int a19, int a20, int a21, int a22, int a23, int a24, int a25) {
+ return a1;
+}
+fn main() { return 0; }
diff --git a/tests/conformance/3-expressions/call_before_definition.zc b/tests/conformance/3-expressions/call_before_definition.zc
new file mode 100644
index 0000000..0442130
--- /dev/null
+++ b/tests/conformance/3-expressions/call_before_definition.zc
@@ -0,0 +1,5 @@
+// expect: 5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { pn(later(2, 3)); return 0; }
+int later(int a, int b) { return a + b; }
diff --git a/tests/conformance/3-expressions/call_new_without_rt.zc b/tests/conformance/3-expressions/call_new_without_rt.zc
new file mode 100644
index 0000000..397ba89
--- /dev/null
+++ b/tests/conformance/3-expressions/call_new_without_rt.zc
@@ -0,0 +1,10 @@
+// expect: 5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int* p = new(int);
+ *p = 5;
+ pn(*p);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/call_params_converted_to_float.zc b/tests/conformance/3-expressions/call_params_converted_to_float.zc
new file mode 100644
index 0000000..04219a9
--- /dev/null
+++ b/tests/conformance/3-expressions/call_params_converted_to_float.zc
@@ -0,0 +1,5 @@
+// expect: 4.000000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+float dbl(float x) { return x * 2; }
+fn main() { pf(dbl(2)); return 0; }
diff --git a/tests/conformance/3-expressions/call_params_sized_cut.zc b/tests/conformance/3-expressions/call_params_sized_cut.zc
new file mode 100644
index 0000000..ed71cbe
--- /dev/null
+++ b/tests/conformance/3-expressions/call_params_sized_cut.zc
@@ -0,0 +1,6 @@
+// expect: 44/-56/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int a(u8 x) { return x; }
+int b(i8 x) { return x; }
+fn main() { pn(a(300)); pn(b(200)); return 0; }
diff --git a/tests/conformance/3-expressions/call_static_and_const.zc b/tests/conformance/3-expressions/call_static_and_const.zc
new file mode 100644
index 0000000..d711488
--- /dev/null
+++ b/tests/conformance/3-expressions/call_static_and_const.zc
@@ -0,0 +1,6 @@
+// expect: 7/24/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct S { const MAX = 24; static fn seven() { return 7; } }
+fn main() { pn(S.seven()); pn(S.MAX); return 0; }
+// zc0: skip
diff --git a/tests/conformance/3-expressions/call_tag_limit.zc b/tests/conformance/3-expressions/call_tag_limit.zc
new file mode 100644
index 0000000..2ffd802
--- /dev/null
+++ b/tests/conformance/3-expressions/call_tag_limit.zc
@@ -0,0 +1,4 @@
+// expect error: only the first 12 parameters can be tagged
+include rt;
+void f(int*.m a1, int*.m a2, int*.m a3, int*.m a4, int*.m a5, int*.m a6, int*.m a7, int*.m a8, int*.m a9, int*.m a10, int*.m a11, int*.m a12, int*.m a13) { }
+fn main() { return 0; }
diff --git a/tests/conformance/3-expressions/call_through_value.zc b/tests/conformance/3-expressions/call_through_value.zc
new file mode 100644
index 0000000..98a5c34
--- /dev/null
+++ b/tests/conformance/3-expressions/call_through_value.zc
@@ -0,0 +1,5 @@
+// expect: 9/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int sq(int x) { return x * x; }
+fn main() { int(int) f = sq; pn(f(3)); return 0; }
diff --git a/tests/conformance/3-expressions/call_type_name_as_value.zc b/tests/conformance/3-expressions/call_type_name_as_value.zc
new file mode 100644
index 0000000..75c50d0
--- /dev/null
+++ b/tests/conformance/3-expressions/call_type_name_as_value.zc
@@ -0,0 +1,4 @@
+// expect error: S: is a type, not a value
+include rt;
+struct S { int a; }
+fn main() { rt.put_n(S); return 0; }
diff --git a/tests/conformance/3-expressions/call_void_bare_return_value_zero.zc b/tests/conformance/3-expressions/call_void_bare_return_value_zero.zc
new file mode 100644
index 0000000..3a437c9
--- /dev/null
+++ b/tests/conformance/3-expressions/call_void_bare_return_value_zero.zc
@@ -0,0 +1,5 @@
+// expect: 0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void f() { return; }
+fn main() { pn(f()); return 0; }
diff --git a/tests/conformance/3-expressions/call_void_value_zero.zc b/tests/conformance/3-expressions/call_void_value_zero.zc
new file mode 100644
index 0000000..9fab2d4
--- /dev/null
+++ b/tests/conformance/3-expressions/call_void_value_zero.zc
@@ -0,0 +1,6 @@
+// expect: 0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int sink;
+void f() { sink = 1; }
+fn main() { pn(f()); return 0; }
diff --git a/tests/conformance/3-expressions/call_wrong_arg_count.zc b/tests/conformance/3-expressions/call_wrong_arg_count.zc
new file mode 100644
index 0000000..8c87e43
--- /dev/null
+++ b/tests/conformance/3-expressions/call_wrong_arg_count.zc
@@ -0,0 +1,4 @@
+// expect error: f: wrong number of arguments
+include rt;
+int f(int a, int b) { return a + b; }
+fn main() { rt.put_n(f(1, 2, 3)); return 0; }
diff --git a/tests/conformance/3-expressions/cast_as_char_unchanged.zc b/tests/conformance/3-expressions/cast_as_char_unchanged.zc
new file mode 100644
index 0000000..3b54628
--- /dev/null
+++ b/tests/conformance/3-expressions/cast_as_char_unchanged.zc
@@ -0,0 +1,9 @@
+// expect: 300/44/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int x = 300;
+ pn(x as char);
+ pn(x as u8);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/cast_forms.zc b/tests/conformance/3-expressions/cast_forms.zc
new file mode 100644
index 0000000..d8ef2bf
--- /dev/null
+++ b/tests/conformance/3-expressions/cast_forms.zc
@@ -0,0 +1,14 @@
+// expect: 2/3/44/3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ float f = 2.9;
+ pn((int)f);
+ char* s = "abc";
+ pn(rt.len_w((char*)s));
+ pn((u8)300);
+ int myv = 3;
+ pn((myv));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/cast_name_is_paren_expression.zc b/tests/conformance/3-expressions/cast_name_is_paren_expression.zc
new file mode 100644
index 0000000..de9b281
--- /dev/null
+++ b/tests/conformance/3-expressions/cast_name_is_paren_expression.zc
@@ -0,0 +1,8 @@
+// expect: 6/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int myv = 3;
+ pn((myv) * 2);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/closure_capture_by_reference.zc b/tests/conformance/3-expressions/closure_capture_by_reference.zc
new file mode 100644
index 0000000..3b4163f
--- /dev/null
+++ b/tests/conformance/3-expressions/closure_capture_by_reference.zc
@@ -0,0 +1,11 @@
+// expect: 21/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int k = 10;
+ let cl = fn(x) { return x + k; };
+ k = 20;
+ pn(cl(1));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/closure_in_o3_rejected.zc b/tests/conformance/3-expressions/closure_in_o3_rejected.zc
new file mode 100644
index 0000000..66bb267
--- /dev/null
+++ b/tests/conformance/3-expressions/closure_in_o3_rejected.zc
@@ -0,0 +1,9 @@
+// expect error: closures can't be made inside an o3 region
+include rt;
+fn main() {
+ o3 {
+ int k = 1;
+ int(int) f = fn(int x) { return x + k; };
+ }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/closure_outlives_creator.zc b/tests/conformance/3-expressions/closure_outlives_creator.zc
new file mode 100644
index 0000000..82e88d7
--- /dev/null
+++ b/tests/conformance/3-expressions/closure_outlives_creator.zc
@@ -0,0 +1,15 @@
+// expect: 11/12/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+.u counter() {
+ int c = 10;
+ let f = fn() { c++; return c; };
+ return u*f;
+}
+fn main() {
+ let ctr = counter();
+ pn(ctr());
+ pn(ctr());
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/closure_writes_visible_outside.zc b/tests/conformance/3-expressions/closure_writes_visible_outside.zc
new file mode 100644
index 0000000..aac5390
--- /dev/null
+++ b/tests/conformance/3-expressions/closure_writes_visible_outside.zc
@@ -0,0 +1,11 @@
+// expect: 3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int n = 0;
+ let inc = fn() { n++; return n; };
+ inc(); inc(); inc();
+ pn(n);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/compound_assign_evaluates_once.zc b/tests/conformance/3-expressions/compound_assign_evaluates_once.zc
new file mode 100644
index 0000000..db8ebc5
--- /dev/null
+++ b/tests/conformance/3-expressions/compound_assign_evaluates_once.zc
@@ -0,0 +1,11 @@
+// expect: 1/15/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int i = 0;
+ int[3] a = {10, 20, 30};
+ a[i++] += 5;
+ pn(i); pn(a[0]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/compound_assign_owner_rejected.zc b/tests/conformance/3-expressions/compound_assign_owner_rejected.zc
new file mode 100644
index 0000000..5c080dc
--- /dev/null
+++ b/tests/conformance/3-expressions/compound_assign_owner_rejected.zc
@@ -0,0 +1,7 @@
+// expect error: owns an object; compound assignment would lose it
+include rt;
+fn main() {
+ int* p = rt.new(int);
+ p += 1;
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/compound_assign_yields_value.zc b/tests/conformance/3-expressions/compound_assign_yields_value.zc
new file mode 100644
index 0000000..2bff56f
--- /dev/null
+++ b/tests/conformance/3-expressions/compound_assign_yields_value.zc
@@ -0,0 +1,9 @@
+// expect: 12/12/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 7;
+ pn(a += 5);
+ pn(a);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/const_expr_array_length.zc b/tests/conformance/3-expressions/const_expr_array_length.zc
new file mode 100644
index 0000000..07434a9
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_array_length.zc
@@ -0,0 +1,9 @@
+// expect: 10/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[2 + 3 * 2] a;
+ pn(sizeof(a));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/const_expr_case_label.zc b/tests/conformance/3-expressions/const_expr_case_label.zc
new file mode 100644
index 0000000..3f1e781
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_case_label.zc
@@ -0,0 +1,12 @@
+// expect: nine/
+include rt;
+fn main() {
+ int k = 9;
+ switch (k) {
+ case 1 + 2 * 3: rt.put_s("nine");
+ default: rt.put_s("other");
+ }
+ rt.put_c(10);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/const_expr_compare_rejected.zc b/tests/conformance/3-expressions/const_expr_compare_rejected.zc
new file mode 100644
index 0000000..a37fb78
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_compare_rejected.zc
@@ -0,0 +1,4 @@
+// expect error: zc: line 3:
+include rt;
+const Z = 1 < 2;
+fn main() { return 0; }
diff --git a/tests/conformance/3-expressions/const_expr_division_rejected.zc b/tests/conformance/3-expressions/const_expr_division_rejected.zc
new file mode 100644
index 0000000..f095247
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_division_rejected.zc
@@ -0,0 +1,4 @@
+// expect error: expected ';', found '/'
+include rt;
+const Z = 6 / 2;
+fn main() { return 0; }
diff --git a/tests/conformance/3-expressions/const_expr_function_address.zc b/tests/conformance/3-expressions/const_expr_function_address.zc
new file mode 100644
index 0000000..b444722
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_function_address.zc
@@ -0,0 +1,7 @@
+// expect: 1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f() { return 1; }
+const FA = f;
+fn main() { fn() p = FA; pn(p()); return 0; }
+// zc0: skip
diff --git a/tests/conformance/3-expressions/const_expr_global_const_array_length.zc b/tests/conformance/3-expressions/const_expr_global_const_array_length.zc
new file mode 100644
index 0000000..1b918ed
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_global_const_array_length.zc
@@ -0,0 +1,7 @@
+// expect: 4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+const N = 4;
+int[N] garr;
+fn main() { pn(sizeof(garr)); return 0; }
+// zc0: skip
diff --git a/tests/conformance/3-expressions/const_expr_left_to_right.zc b/tests/conformance/3-expressions/const_expr_left_to_right.zc
new file mode 100644
index 0000000..68e26ab
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_left_to_right.zc
@@ -0,0 +1,8 @@
+// expect: 9/5/7/255/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+const X = 1 + 2 * 3;
+const Y = 10 - 2 - 3;
+const V = 1 | 2 + 4;
+const W = ~0 & 255;
+fn main() { pn(X); pn(Y); pn(V); pn(W); return 0; }
diff --git a/tests/conformance/3-expressions/const_expr_local_const_rejected.zc b/tests/conformance/3-expressions/const_expr_local_const_rejected.zc
new file mode 100644
index 0000000..edab64e
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_local_const_rejected.zc
@@ -0,0 +1,7 @@
+// expect error: expected a constant
+include rt;
+fn main() {
+ const n = 5;
+ int[n] a;
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/const_expr_modulo_rejected.zc b/tests/conformance/3-expressions/const_expr_modulo_rejected.zc
new file mode 100644
index 0000000..4c54ffe
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_modulo_rejected.zc
@@ -0,0 +1,4 @@
+// expect error: zc: line 3:
+include rt;
+const Z = 7 % 2;
+fn main() { return 0; }
diff --git a/tests/conformance/3-expressions/const_expr_names.zc b/tests/conformance/3-expressions/const_expr_names.zc
new file mode 100644
index 0000000..b9fa851
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_names.zc
@@ -0,0 +1,8 @@
+// expect: 5/7/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum { EA = 2, EB };
+const K = EA + EB;
+const L = K + 2;
+fn main() { pn(K); pn(L); return 0; }
+// zc0: skip
diff --git a/tests/conformance/3-expressions/const_expr_neg_not_parens.zc b/tests/conformance/3-expressions/const_expr_neg_not_parens.zc
new file mode 100644
index 0000000..6e96bdc
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_neg_not_parens.zc
@@ -0,0 +1,8 @@
+// expect: -3/-6/-1/24/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+const A = -3;
+const B = -(1 + 2 * 3) + 3;
+const C = ~0;
+const D = (1 + 2) * (3 + 5);
+fn main() { pn(A); pn(B + 0); pn(C); pn(D); return 0; }
diff --git a/tests/conformance/3-expressions/const_expr_shift.zc b/tests/conformance/3-expressions/const_expr_shift.zc
new file mode 100644
index 0000000..6b7e056
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_shift.zc
@@ -0,0 +1,6 @@
+// expect: 16/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+const S = 1 << 4;
+const T = 256 >> 8;
+fn main() { pn(S); pn(T); return 0; }
diff --git a/tests/conformance/3-expressions/const_expr_ternary_rejected.zc b/tests/conformance/3-expressions/const_expr_ternary_rejected.zc
new file mode 100644
index 0000000..81af58b
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_ternary_rejected.zc
@@ -0,0 +1,4 @@
+// expect error: zc: line 3:
+include rt;
+const Z = 1 ? 2 : 3;
+fn main() { return 0; }
diff --git a/tests/conformance/3-expressions/const_expr_xor_rejected.zc b/tests/conformance/3-expressions/const_expr_xor_rejected.zc
new file mode 100644
index 0000000..eb1ad25
--- /dev/null
+++ b/tests/conformance/3-expressions/const_expr_xor_rejected.zc
@@ -0,0 +1,4 @@
+// expect error: zc: line 3:
+include rt;
+const Z = 7 ^ 2;
+fn main() { return 0; }
diff --git a/tests/conformance/3-expressions/decr_prefix_postfix.zc b/tests/conformance/3-expressions/decr_prefix_postfix.zc
new file mode 100644
index 0000000..ba38935
--- /dev/null
+++ b/tests/conformance/3-expressions/decr_prefix_postfix.zc
@@ -0,0 +1,11 @@
+// expect: 4/3/2/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 4;
+ pn(a--);
+ pn(a);
+ pn(--a);
+ pn(a);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/dyn_array_array_len_cap_const.zc b/tests/conformance/3-expressions/dyn_array_array_len_cap_const.zc
new file mode 100644
index 0000000..d1bf61d
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_array_len_cap_const.zc
@@ -0,0 +1,9 @@
+// expect: 5/5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[5] a;
+ pn(len(a)); pn(cap(a));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/dyn_array_cap_at_least_doubles.zc b/tests/conformance/3-expressions/dyn_array_cap_at_least_doubles.zc
new file mode 100644
index 0000000..5a55545
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_cap_at_least_doubles.zc
@@ -0,0 +1,17 @@
+// expect: 1/1/10/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[?] a = rt.new(int[?]);
+ int c0 = cap(a);
+ int i = 0;
+ while (i < c0) { push(a, i); i++; }
+ pn(cap(a) == c0);
+ push(a, 99);
+ pn(cap(a) >= 2 * c0);
+ int j = 0;
+ while (j < 9) { push(a, j); j++; }
+ pn(len(a) - c0);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/dyn_array_const_index_warning.zc b/tests/conformance/3-expressions/dyn_array_const_index_warning.zc
new file mode 100644
index 0000000..36890d7
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_const_index_warning.zc
@@ -0,0 +1,8 @@
+// expect: zc: line 5: warning: out-of-bounds access: index 2 is outside length 2 (storage declared or allocated on line 4)/zy: index 2 out of range (length 2)/
+include rt;
+fn main() {
+ int[?] a = {1, 2};
+ rt.put_n(a[2]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/dyn_array_index_negative.zc b/tests/conformance/3-expressions/dyn_array_index_negative.zc
new file mode 100644
index 0000000..c87e786
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_index_negative.zc
@@ -0,0 +1,11 @@
+// expect: zy: index -1 out of range (length 2)/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[?] a = {1, 2};
+ int i = 0 - 1;
+ pn(a[i]);
+ pn(99);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/dyn_array_index_out_of_range.zc b/tests/conformance/3-expressions/dyn_array_index_out_of_range.zc
new file mode 100644
index 0000000..eff8061
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_index_out_of_range.zc
@@ -0,0 +1,12 @@
+// expect: 2/zy: index 2 out of range (length 2)/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[?] a = {1, 2};
+ int i = 2;
+ pn(len(a));
+ pn(a[i]);
+ pn(99);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/dyn_array_intrinsics.zc b/tests/conformance/3-expressions/dyn_array_intrinsics.zc
new file mode 100644
index 0000000..6056423
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_intrinsics.zc
@@ -0,0 +1,11 @@
+// expect: 4/4/4/4/3/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[?] a = {1, 2};
+ push(a, 3); a.push(4);
+ pn(len(a)); pn(cap(a)); pn(a[3]);
+ pn(pop(a)); pn(a.pop()); pn(a.len());
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/dyn_array_len_of_pointer_typecheck.zc b/tests/conformance/3-expressions/dyn_array_len_of_pointer_typecheck.zc
new file mode 100644
index 0000000..4153ee4
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_len_of_pointer_typecheck.zc
@@ -0,0 +1,7 @@
+// expect error: len needs an array
+include rt;
+typecheck on;
+fn main() {
+ rt.put_n(len("text"));
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/dyn_array_new_len_cap.zc b/tests/conformance/3-expressions/dyn_array_new_len_cap.zc
new file mode 100644
index 0000000..b491d62
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_new_len_cap.zc
@@ -0,0 +1,13 @@
+// expect: 0/1/1/5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[?] a = rt.new(int[?]);
+ pn(len(a)); pn(cap(a) >= 4);
+ int i = 0;
+ while (i < 5) { push(a, i); i++; }
+ pn(cap(a) >= 8);
+ pn(len(a));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/dyn_array_pop_empty.zc b/tests/conformance/3-expressions/dyn_array_pop_empty.zc
new file mode 100644
index 0000000..6f5fdd0
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_pop_empty.zc
@@ -0,0 +1,10 @@
+// expect: zy: index -1 out of range (length 0)/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[?] a = rt.new(int[?]);
+ pn(pop(a));
+ pn(99);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/dyn_array_pop_returns_last.zc b/tests/conformance/3-expressions/dyn_array_pop_returns_last.zc
new file mode 100644
index 0000000..f3773bb
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_pop_returns_last.zc
@@ -0,0 +1,10 @@
+// expect: 3/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[?] a = {1, 2, 3};
+ pn(pop(a));
+ pn(a.pop());
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/dyn_array_push_aggregate.zc b/tests/conformance/3-expressions/dyn_array_push_aggregate.zc
new file mode 100644
index 0000000..5dce054
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_push_aggregate.zc
@@ -0,0 +1,9 @@
+// expect error: push takes scalar or reference elements
+include rt;
+struct pt { int x; int y; }
+fn main() {
+ pt[?] a = rt.new(pt[?]);
+ pt* p = rt.new(pt);
+ push(a, p);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/dyn_array_receiver_calls.zc b/tests/conformance/3-expressions/dyn_array_receiver_calls.zc
new file mode 100644
index 0000000..6290f13
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_receiver_calls.zc
@@ -0,0 +1,11 @@
+// expect: 3/4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[?] a = {1, 2};
+ a.push(3);
+ pn(a.len());
+ pn(a.cap());
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/dyn_array_resize.zc b/tests/conformance/3-expressions/dyn_array_resize.zc
new file mode 100644
index 0000000..c0ae4f5
--- /dev/null
+++ b/tests/conformance/3-expressions/dyn_array_resize.zc
@@ -0,0 +1,16 @@
+// expect: 5/0/0/3/7/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[?] a = {7, 8, 9};
+ resize(a, 5);
+ pn(len(a)); pn(a[3]); pn(a[4]);
+ resize(a, 1);
+ a.resize(3);
+ pn(len(a));
+ pn(a[0]);
+ resize(a, 2);
+ pn(len(a));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/eval_order_arguments.zc b/tests/conformance/3-expressions/eval_order_arguments.zc
new file mode 100644
index 0000000..d7bbb76
--- /dev/null
+++ b/tests/conformance/3-expressions/eval_order_arguments.zc
@@ -0,0 +1,9 @@
+// expect: 1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void two(int a, int b) { pn(a * 10 + b); }
+fn main() {
+ int i = 0;
+ two(i++, i++);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/eval_order_binary_calls.zc b/tests/conformance/3-expressions/eval_order_binary_calls.zc
new file mode 100644
index 0000000..36b4c8a
--- /dev/null
+++ b/tests/conformance/3-expressions/eval_order_binary_calls.zc
@@ -0,0 +1,10 @@
+// expect: 12/
+include rt;
+int trace;
+int step(int v) { trace = trace * 10 + v; return v; }
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int r = step(1) - step(2) * 1;
+ pn(trace);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/eval_order_calls_left_to_right.zc b/tests/conformance/3-expressions/eval_order_calls_left_to_right.zc
new file mode 100644
index 0000000..9c7fed3
--- /dev/null
+++ b/tests/conformance/3-expressions/eval_order_calls_left_to_right.zc
@@ -0,0 +1,11 @@
+// expect: 123/
+include rt;
+int trace;
+int step(int v) { trace = trace * 10 + v; return v; }
+int add3(int a, int b, int c) { return a + b + c; }
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int r = add3(step(1), step(2), step(3));
+ pn(trace);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/eval_order_operands.zc b/tests/conformance/3-expressions/eval_order_operands.zc
new file mode 100644
index 0000000..a8f289c
--- /dev/null
+++ b/tests/conformance/3-expressions/eval_order_operands.zc
@@ -0,0 +1,10 @@
+// expect: 38/11/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 18;
+ pn(a++ + ++a);
+ int j = 1;
+ pn(j + (j = 5) * 2);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/float_as_keeps_bits.zc b/tests/conformance/3-expressions/float_as_keeps_bits.zc
new file mode 100644
index 0000000..69bf4c3
--- /dev/null
+++ b/tests/conformance/3-expressions/float_as_keeps_bits.zc
@@ -0,0 +1,10 @@
+// expect: 0.000000/4607182418800017408/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ pf(3 as float);
+ float one = 1.0;
+ pn(one as int);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/float_basic_arith.zc b/tests/conformance/3-expressions/float_basic_arith.zc
new file mode 100644
index 0000000..caed2b2
--- /dev/null
+++ b/tests/conformance/3-expressions/float_basic_arith.zc
@@ -0,0 +1,12 @@
+// expect: 3.500000/inf/-inf/nan/3.000000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ pf(7 / 2.0);
+ pf(1.0 / 0.0);
+ pf(-1.0 / 0.0);
+ pf(0.0 / 0.0);
+ float r = 7 / 2;
+ pf(r);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/float_cast_value_and_bits.zc b/tests/conformance/3-expressions/float_cast_value_and_bits.zc
new file mode 100644
index 0000000..290263f
--- /dev/null
+++ b/tests/conformance/3-expressions/float_cast_value_and_bits.zc
@@ -0,0 +1,15 @@
+// expect: -2/3.000000/1/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ float f = -2.9;
+ int i = 3;
+ pn((int)f);
+ pf((float)i);
+ word w = 4607182418800017408;
+ pn(w as float == 1.0);
+ pn((3 as float) == 3.0);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/float_division_int_stored.zc b/tests/conformance/3-expressions/float_division_int_stored.zc
new file mode 100644
index 0000000..c105e0b
--- /dev/null
+++ b/tests/conformance/3-expressions/float_division_int_stored.zc
@@ -0,0 +1,10 @@
+// expect: 3.000000/0.500000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ float r = 7 / 2;
+ pf(r);
+ float s = 1 / 2.0;
+ pf(s);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/float_int_ops_on_bits.zc b/tests/conformance/3-expressions/float_int_ops_on_bits.zc
new file mode 100644
index 0000000..38a45a8
--- /dev/null
+++ b/tests/conformance/3-expressions/float_int_ops_on_bits.zc
@@ -0,0 +1,12 @@
+// expect: 1/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ float f = 1.0;
+ int bits = f as int;
+ word r = f & 4607182418800017408;
+ word r2 = f | 0;
+ pn(r == bits);
+ pn(r2 == bits);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/float_lit_exponent_arith.zc b/tests/conformance/3-expressions/float_lit_exponent_arith.zc
new file mode 100644
index 0000000..5b718c8
--- /dev/null
+++ b/tests/conformance/3-expressions/float_lit_exponent_arith.zc
@@ -0,0 +1,8 @@
+// expect: 1000.000000/0.001000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ pf(1e3);
+ pf(1e-3);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/float_mixed_comparisons.zc b/tests/conformance/3-expressions/float_mixed_comparisons.zc
new file mode 100644
index 0000000..b03394a
--- /dev/null
+++ b/tests/conformance/3-expressions/float_mixed_comparisons.zc
@@ -0,0 +1,8 @@
+// expect: 1/1/1/0/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ float f = 2.5;
+ pn(1 < f); pn(f > 2); pn(2.0 == 2); pn(f == 2); pn(3 >= 2.5);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/float_negate_is_zero_minus.zc b/tests/conformance/3-expressions/float_negate_is_zero_minus.zc
new file mode 100644
index 0000000..5c673db
--- /dev/null
+++ b/tests/conformance/3-expressions/float_negate_is_zero_minus.zc
@@ -0,0 +1,14 @@
+// expect: -1.500000/0/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ float f = 1.5;
+ pf(-f);
+ float z = -0.0;
+ pn(z as int);
+ float y = 0.0;
+ float ny = -y;
+ pn(ny as int);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/float_operand_conversion.zc b/tests/conformance/3-expressions/float_operand_conversion.zc
new file mode 100644
index 0000000..018a7c6
--- /dev/null
+++ b/tests/conformance/3-expressions/float_operand_conversion.zc
@@ -0,0 +1,12 @@
+// expect: 3.500000/0.500000/3.000000/2.000000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ float f = 1.5;
+ int i = 2;
+ pf(f + i);
+ pf(f - 1);
+ pf(f * i);
+ pf(i * 1.0);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/float_tracked_through_locals_fields_params.zc b/tests/conformance/3-expressions/float_tracked_through_locals_fields_params.zc
new file mode 100644
index 0000000..87f2c72
--- /dev/null
+++ b/tests/conformance/3-expressions/float_tracked_through_locals_fields_params.zc
@@ -0,0 +1,20 @@
+// expect: 2.500000/2.500000/2.500000/2.500000/
+include rt;
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+struct box { float v; }
+float g;
+float half(float x) { return x / 2; }
+float getg() { return g; }
+fn main() {
+ float a = 5;
+ pf(a / 2);
+ box* b = rt.new(box);
+ b.v = 5;
+ pf(b.v / 2);
+ pf(half(5));
+ g = 5;
+ pf(getg() / 2);
+ rt.free(b);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/incr_needs_lvalue.zc b/tests/conformance/3-expressions/incr_needs_lvalue.zc
new file mode 100644
index 0000000..69f84f8
--- /dev/null
+++ b/tests/conformance/3-expressions/incr_needs_lvalue.zc
@@ -0,0 +1,7 @@
+// expect error: ++ and -- need something to assign to
+include rt;
+fn main() {
+ int a = 1;
+ (a + 1)++;
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/incr_needs_lvalue_prefix.zc b/tests/conformance/3-expressions/incr_needs_lvalue_prefix.zc
new file mode 100644
index 0000000..c4f617f
--- /dev/null
+++ b/tests/conformance/3-expressions/incr_needs_lvalue_prefix.zc
@@ -0,0 +1,6 @@
+// expect error: ++ and -- need something to assign to
+include rt;
+fn main() {
+ ++5;
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/incr_on_float_changes_bits.zc b/tests/conformance/3-expressions/incr_on_float_changes_bits.zc
new file mode 100644
index 0000000..7062daf
--- /dev/null
+++ b/tests/conformance/3-expressions/incr_on_float_changes_bits.zc
@@ -0,0 +1,10 @@
+// expect: 0/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ float f = 1.5;
+ f++;
+ pn(f == 1.5);
+ pn(f as int == 4609434218613702657);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_add_wrap.zc b/tests/conformance/3-expressions/int_add_wrap.zc
new file mode 100644
index 0000000..8c4e0d2
--- /dev/null
+++ b/tests/conformance/3-expressions/int_add_wrap.zc
@@ -0,0 +1,15 @@
+// expect: -9223372036854775808/-9223372036854775808/9223372036854775807/9223372036854775807/-2/-2/3/3/
+// spec 3.4.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(9223372036854775807 + 1);
+ { int a = 9223372036854775807, b = 1; pn(a + b); }
+ pn((-9223372036854775807 - 1) + -1);
+ { int a = (-9223372036854775807 - 1), b = -1; pn(a + b); }
+ pn(9223372036854775807 + 9223372036854775807);
+ { int a = 9223372036854775807, b = 9223372036854775807; pn(a + b); }
+ pn(1 + 2);
+ { int a = 1, b = 2; pn(a + b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_bitwise_and.zc b/tests/conformance/3-expressions/int_bitwise_and.zc
new file mode 100644
index 0000000..5ce4641
--- /dev/null
+++ b/tests/conformance/3-expressions/int_bitwise_and.zc
@@ -0,0 +1,15 @@
+// expect: 255/255/2/2/-9223372036854775808/-9223372036854775808/0/0/
+// spec 3.4.5: bitwise on all 64 bits
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(-1 & 255);
+ { int a = -1, b = 255; pn(a & b); }
+ pn(6 & 3);
+ { int a = 6, b = 3; pn(a & b); }
+ pn((-9223372036854775807 - 1) & -1);
+ { int a = (-9223372036854775807 - 1), b = -1; pn(a & b); }
+ pn(0 & -1);
+ { int a = 0, b = -1; pn(a & b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_bitwise_or.zc b/tests/conformance/3-expressions/int_bitwise_or.zc
new file mode 100644
index 0000000..fc5cdc2
--- /dev/null
+++ b/tests/conformance/3-expressions/int_bitwise_or.zc
@@ -0,0 +1,13 @@
+// expect: -1/-1/7/7/-9223372036854775807/-9223372036854775807/
+// spec 3.4.5
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(-256 | 255);
+ { int a = -256, b = 255; pn(a | b); }
+ pn(6 | 3);
+ { int a = 6, b = 3; pn(a | b); }
+ pn((-9223372036854775807 - 1) | 1);
+ { int a = (-9223372036854775807 - 1), b = 1; pn(a | b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_bitwise_xor.zc b/tests/conformance/3-expressions/int_bitwise_xor.zc
new file mode 100644
index 0000000..3aea716
--- /dev/null
+++ b/tests/conformance/3-expressions/int_bitwise_xor.zc
@@ -0,0 +1,15 @@
+// expect: -2/-2/5/5/0/0/-6/-6/
+// spec 3.4.5
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(-1 ^ 1);
+ { int a = -1, b = 1; pn(a ^ b); }
+ pn(6 ^ 3);
+ { int a = 6, b = 3; pn(a ^ b); }
+ pn((-9223372036854775807 - 1) ^ (-9223372036854775807 - 1));
+ { int a = (-9223372036854775807 - 1), b = (-9223372036854775807 - 1); pn(a ^ b); }
+ pn(5 ^ -1);
+ { int a = 5, b = -1; pn(a ^ b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_compare_ge.zc b/tests/conformance/3-expressions/int_compare_ge.zc
new file mode 100644
index 0000000..c8b886b
--- /dev/null
+++ b/tests/conformance/3-expressions/int_compare_ge.zc
@@ -0,0 +1,17 @@
+// expect: 0/0/0/0/1/1/1/1/1/1/
+// spec 3.4.5
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(-1 >= 0);
+ { int a = -1, b = 0; pn(a >= b); }
+ pn((-9223372036854775807 - 1) >= 9223372036854775807);
+ { int a = (-9223372036854775807 - 1), b = 9223372036854775807; pn(a >= b); }
+ pn(9223372036854775807 >= (-9223372036854775807 - 1));
+ { int a = 9223372036854775807, b = (-9223372036854775807 - 1); pn(a >= b); }
+ pn(0 >= 0);
+ { int a = 0, b = 0; pn(a >= b); }
+ pn(4 >= 3);
+ { int a = 4, b = 3; pn(a >= b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_compare_signed.zc b/tests/conformance/3-expressions/int_compare_signed.zc
new file mode 100644
index 0000000..c09bedd
--- /dev/null
+++ b/tests/conformance/3-expressions/int_compare_signed.zc
@@ -0,0 +1,19 @@
+// expect: 1/1/1/1/1/1/0/0/0/0/1/1/
+// spec 3.4.5
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(-1 < 0);
+ { int a = -1, b = 0; pn(a < b); }
+ pn(-1 < 1);
+ { int a = -1, b = 1; pn(a < b); }
+ pn((-9223372036854775807 - 1) < 9223372036854775807);
+ { int a = (-9223372036854775807 - 1), b = 9223372036854775807; pn(a < b); }
+ pn(9223372036854775807 < (-9223372036854775807 - 1));
+ { int a = 9223372036854775807, b = (-9223372036854775807 - 1); pn(a < b); }
+ pn(0 < 0);
+ { int a = 0, b = 0; pn(a < b); }
+ pn(3 < 4);
+ { int a = 3, b = 4; pn(a < b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_div_signs.zc b/tests/conformance/3-expressions/int_div_signs.zc
new file mode 100644
index 0000000..c6bcdca
--- /dev/null
+++ b/tests/conformance/3-expressions/int_div_signs.zc
@@ -0,0 +1,19 @@
+// expect: 3/3/-3/-3/-3/-3/3/3/0/0/14/14/
+// spec 3.4.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(7 / 2);
+ { int a = 7, b = 2; pn(a / b); }
+ pn(7 / -2);
+ { int a = 7, b = -2; pn(a / b); }
+ pn(-7 / 2);
+ { int a = -7, b = 2; pn(a / b); }
+ pn(-7 / -2);
+ { int a = -7, b = -2; pn(a / b); }
+ pn(0 / 5);
+ { int a = 0, b = 5; pn(a / b); }
+ pn(100 / 7);
+ { int a = 100, b = 7; pn(a / b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_div_zero.zc b/tests/conformance/3-expressions/int_div_zero.zc
new file mode 100644
index 0000000..ee1eec5
--- /dev/null
+++ b/tests/conformance/3-expressions/int_div_zero.zc
@@ -0,0 +1,13 @@
+// expect: 0/0/0/0/0/0/
+// spec 3.4.3: division by zero gives 0
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(5 / 0);
+ { int a = 5, b = 0; pn(a / b); }
+ pn(-5 / 0);
+ { int a = -5, b = 0; pn(a / b); }
+ pn(0 / 0);
+ { int a = 0, b = 0; pn(a / b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_logical_or_values.zc b/tests/conformance/3-expressions/int_logical_or_values.zc
new file mode 100644
index 0000000..ec84c41
--- /dev/null
+++ b/tests/conformance/3-expressions/int_logical_or_values.zc
@@ -0,0 +1,17 @@
+// expect: 1/1/1/1/0/0/1/1/1/1/
+// spec 3.4.6: || gives 0 or 1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(0 || 9);
+ { int a = 0, b = 9; pn(a || b); }
+ pn(5 || 0);
+ { int a = 5, b = 0; pn(a || b); }
+ pn(0 || 0);
+ { int a = 0, b = 0; pn(a || b); }
+ pn(-3 || -3);
+ { int a = -3, b = -3; pn(a || b); }
+ pn((-9223372036854775807 - 1) || 0);
+ { int a = (-9223372036854775807 - 1), b = 0; pn(a || b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_logical_values.zc b/tests/conformance/3-expressions/int_logical_values.zc
new file mode 100644
index 0000000..3382025
--- /dev/null
+++ b/tests/conformance/3-expressions/int_logical_values.zc
@@ -0,0 +1,17 @@
+// expect: 1/1/0/0/0/0/0/0/1/1/
+// spec 3.4.6: && gives 0 or 1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(5 && 7);
+ { int a = 5, b = 7; pn(a && b); }
+ pn(5 && 0);
+ { int a = 5, b = 0; pn(a && b); }
+ pn(0 && 7);
+ { int a = 0, b = 7; pn(a && b); }
+ pn(0 && 0);
+ { int a = 0, b = 0; pn(a && b); }
+ pn(-1 && (-9223372036854775807 - 1));
+ { int a = -1, b = (-9223372036854775807 - 1); pn(a && b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_min_div_minus1.zc b/tests/conformance/3-expressions/int_min_div_minus1.zc
new file mode 100644
index 0000000..8f13ef1
--- /dev/null
+++ b/tests/conformance/3-expressions/int_min_div_minus1.zc
@@ -0,0 +1,9 @@
+// expect: -9223372036854775808/-9223372036854775808/
+// spec 3.4.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn((-9223372036854775807 - 1) / -1);
+ { int a = (-9223372036854775807 - 1), b = -1; pn(a / b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_min_mod_minus1.zc b/tests/conformance/3-expressions/int_min_mod_minus1.zc
new file mode 100644
index 0000000..bd8b36e
--- /dev/null
+++ b/tests/conformance/3-expressions/int_min_mod_minus1.zc
@@ -0,0 +1,9 @@
+// expect: 0/0/
+// spec 3.4.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn((-9223372036854775807 - 1) % -1);
+ { int a = (-9223372036854775807 - 1), b = -1; pn(a % b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_mod_signs.zc b/tests/conformance/3-expressions/int_mod_signs.zc
new file mode 100644
index 0000000..4ed0c6f
--- /dev/null
+++ b/tests/conformance/3-expressions/int_mod_signs.zc
@@ -0,0 +1,19 @@
+// expect: 1/1/1/1/-1/-1/-1/-1/0/0/2/2/
+// spec 3.4.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(7 % 2);
+ { int a = 7, b = 2; pn(a % b); }
+ pn(7 % -2);
+ { int a = 7, b = -2; pn(a % b); }
+ pn(-7 % 2);
+ { int a = -7, b = 2; pn(a % b); }
+ pn(-7 % -2);
+ { int a = -7, b = -2; pn(a % b); }
+ pn(0 % 5);
+ { int a = 0, b = 5; pn(a % b); }
+ pn(100 % 7);
+ { int a = 100, b = 7; pn(a % b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_mod_zero.zc b/tests/conformance/3-expressions/int_mod_zero.zc
new file mode 100644
index 0000000..4a77a7b
--- /dev/null
+++ b/tests/conformance/3-expressions/int_mod_zero.zc
@@ -0,0 +1,13 @@
+// expect: 5/5/-5/-5/0/0/
+// spec 3.4.3: n % 0 is n
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(5 % 0);
+ { int a = 5, b = 0; pn(a % b); }
+ pn(-5 % 0);
+ { int a = -5, b = 0; pn(a % b); }
+ pn(0 % 0);
+ { int a = 0, b = 0; pn(a % b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_mul_wrap.zc b/tests/conformance/3-expressions/int_mul_wrap.zc
new file mode 100644
index 0000000..66d9e3b
--- /dev/null
+++ b/tests/conformance/3-expressions/int_mul_wrap.zc
@@ -0,0 +1,15 @@
+// expect: -2/-2/-9223372036709301616/-9223372036709301616/-9223372036854775808/-9223372036854775808/-20/-20/
+// spec 3.4.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(9223372036854775807 * 2);
+ { int a = 9223372036854775807, b = 2; pn(a * b); }
+ pn(3037000500 * 3037000500);
+ { int a = 3037000500, b = 3037000500; pn(a * b); }
+ pn((-9223372036854775807 - 1) * -1);
+ { int a = (-9223372036854775807 - 1), b = -1; pn(a * b); }
+ pn(-4 * 5);
+ { int a = -4, b = 5; pn(a * b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_shl_count_mod64.zc b/tests/conformance/3-expressions/int_shl_count_mod64.zc
new file mode 100644
index 0000000..ed90516
--- /dev/null
+++ b/tests/conformance/3-expressions/int_shl_count_mod64.zc
@@ -0,0 +1,23 @@
+// expect: -9223372036854775808/-9223372036854775808/1/1/2/2/-9223372036854775808/-9223372036854775808/-4611686018427387904/-4611686018427387904/-2/-2/1/1/5/5/
+// spec 3.4.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(1 << 63);
+ { int a = 1, b = 63; pn(a << b); }
+ pn(1 << 64);
+ { int a = 1, b = 64; pn(a << b); }
+ pn(1 << 65);
+ { int a = 1, b = 65; pn(a << b); }
+ pn(1 << -1);
+ { int a = 1, b = -1; pn(a << b); }
+ pn(3 << 62);
+ { int a = 3, b = 62; pn(a << b); }
+ pn(-1 << 1);
+ { int a = -1, b = 1; pn(a << b); }
+ pn(1 << 128);
+ { int a = 1, b = 128; pn(a << b); }
+ pn(5 << 0);
+ { int a = 5, b = 0; pn(a << b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_shr_arith.zc b/tests/conformance/3-expressions/int_shr_arith.zc
new file mode 100644
index 0000000..8bd8de5
--- /dev/null
+++ b/tests/conformance/3-expressions/int_shr_arith.zc
@@ -0,0 +1,23 @@
+// expect: -4/-4/-1/-1/-1/-1/2/2/-1/-1/128/128/-1/-1/5/5/
+// spec 3.4.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(-8 >> 1);
+ { int a = -8, b = 1; pn(a >> b); }
+ pn(-1 >> 63);
+ { int a = -1, b = 63; pn(a >> b); }
+ pn(-1 >> 64);
+ { int a = -1, b = 64; pn(a >> b); }
+ pn(5 >> -63);
+ { int a = 5, b = -63; pn(a >> b); }
+ pn((-9223372036854775807 - 1) >> 63);
+ { int a = (-9223372036854775807 - 1), b = 63; pn(a >> b); }
+ pn(1024 >> 3);
+ { int a = 1024, b = 3; pn(a >> b); }
+ pn(-1 >> 1);
+ { int a = -1, b = 1; pn(a >> b); }
+ pn(5 >> 64);
+ { int a = 5, b = 64; pn(a >> b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/int_sub_wrap.zc b/tests/conformance/3-expressions/int_sub_wrap.zc
new file mode 100644
index 0000000..f906dd0
--- /dev/null
+++ b/tests/conformance/3-expressions/int_sub_wrap.zc
@@ -0,0 +1,13 @@
+// expect: 9223372036854775807/9223372036854775807/-9223372036854775808/-9223372036854775808/-2/-2/
+// spec 3.4.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn((-9223372036854775807 - 1) - 1);
+ { int a = (-9223372036854775807 - 1), b = 1; pn(a - b); }
+ pn(0 - (-9223372036854775807 - 1));
+ { int a = 0, b = (-9223372036854775807 - 1); pn(a - b); }
+ pn(5 - 7);
+ { int a = 5, b = 7; pn(a - b); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/member_dot_arrow_same.zc b/tests/conformance/3-expressions/member_dot_arrow_same.zc
new file mode 100644
index 0000000..f900a1d
--- /dev/null
+++ b/tests/conformance/3-expressions/member_dot_arrow_same.zc
@@ -0,0 +1,14 @@
+// expect: 3/4/5/6/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct pt { int x; int y; }
+fn main() {
+ pt a;
+ a.x = 3; a->y = 4;
+ pt* p = &a;
+ pn(a.x); pn(a->y);
+ p.x = 5; p->y = 6;
+ pn(p.x); pn(p->y);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/member_field_wins_over_method.zc b/tests/conformance/3-expressions/member_field_wins_over_method.zc
new file mode 100644
index 0000000..34680a9
--- /dev/null
+++ b/tests/conformance/3-expressions/member_field_wins_over_method.zc
@@ -0,0 +1,12 @@
+// expect: 5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct fw { int get; int get() { return 99; } }
+fn main() {
+ fw* a = rt.new(fw);
+ a.get = 5;
+ pn(a.get);
+ rt.free(a);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/member_method_call.zc b/tests/conformance/3-expressions/member_method_call.zc
new file mode 100644
index 0000000..cc44c62
--- /dev/null
+++ b/tests/conformance/3-expressions/member_method_call.zc
@@ -0,0 +1,12 @@
+// expect: 7/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct acc { int total; fn add(n) { this.total = this.total + n; return this.total; } }
+fn main() {
+ acc* a = rt.new(acc);
+ a.add(3);
+ pn(a.add(4));
+ rt.free(a);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/member_missing_field_suggestion.zc b/tests/conformance/3-expressions/member_missing_field_suggestion.zc
new file mode 100644
index 0000000..8713561
--- /dev/null
+++ b/tests/conformance/3-expressions/member_missing_field_suggestion.zc
@@ -0,0 +1,8 @@
+// expect error: pt has no field nmae; did you mean 'name'?
+include rt;
+struct pt { int name; int y; }
+fn main() {
+ pt* p = rt.new(pt);
+ rt.put_n(p.nmae);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/member_two_pointer_levels.zc b/tests/conformance/3-expressions/member_two_pointer_levels.zc
new file mode 100644
index 0000000..d1870f4
--- /dev/null
+++ b/tests/conformance/3-expressions/member_two_pointer_levels.zc
@@ -0,0 +1,9 @@
+// expect error: zc: line 7:
+include rt;
+struct pt { int x; int y; }
+fn main() {
+ pt* p = rt.new(pt);
+ pt** pp = &p;
+ rt.put_n(pp.x);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_as_binds_tight.zc b/tests/conformance/3-expressions/prec_as_binds_tight.zc
new file mode 100644
index 0000000..baf41e0
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_as_binds_tight.zc
@@ -0,0 +1,10 @@
+// expect: -1/260/45/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(-2 as int + 1);
+ pn(250 + 10 as u8);
+ int k = 1;
+ pn(k + 300 as u8);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_as_then_star.zc b/tests/conformance/3-expressions/prec_as_then_star.zc
new file mode 100644
index 0000000..046f069
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_as_then_star.zc
@@ -0,0 +1,7 @@
+// expect error: zc: line 5:
+include rt;
+fn main() {
+ int x = 3, y = 4;
+ rt.put_n(x as int * y);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_assign_lower_than_ternary.zc b/tests/conformance/3-expressions/prec_assign_lower_than_ternary.zc
new file mode 100644
index 0000000..9ca1541
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_assign_lower_than_ternary.zc
@@ -0,0 +1,12 @@
+// expect: 5/5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a, c = 0;
+ a = 1 ? 5 : 6;
+ pn(a);
+ a = 0 ? 7 : 1 ? 5 : 9;
+ pn(a);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/prec_assign_right_assoc.zc b/tests/conformance/3-expressions/prec_assign_right_assoc.zc
new file mode 100644
index 0000000..4cb885e
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_assign_right_assoc.zc
@@ -0,0 +1,9 @@
+// expect: 7/7/7/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a, b;
+ pn(a = b = 7);
+ pn(a); pn(b);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_chains.zc b/tests/conformance/3-expressions/prec_chains.zc
new file mode 100644
index 0000000..c8cd31f
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_chains.zc
@@ -0,0 +1,55 @@
+// expect: 0/0/1/1/1/1/1/1/-1/-1/1/1/1/1/13/13/1/1/1/1/3/3/1/1/1/1/1/1/1/1/7/7/1/1/7/7/-1/-1/1/1/0/0/1/1/0/0/1/1/
+// random chains of binary operators of several levels (spec 3.2.1)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(12 != 7 <= 1 & 9 + 7 && 2 << 0 & 7 | 4 > 3);
+ { int v0 = 12, v1 = 7, v2 = 1, v3 = 9, v4 = 7, v5 = 2, v6 = 0, v7 = 7, v8 = 4, v9 = 3; pn(v0 != v1 <= v2 & v3 + v4 && v5 << v6 & v7 | v8 > v9); }
+ pn(3 >> 1 | 2 >> 1 == 9 * -1 | 0 >> 0 >= 7 <= -1);
+ { int v0 = 3, v1 = 1, v2 = 2, v3 = 1, v4 = 9, v5 = -1, v6 = 0, v7 = 0, v8 = 7, v9 = -1; pn(v0 >> v1 | v2 >> v3 == v4 * v5 | v6 >> v7 >= v8 <= v9); }
+ pn(1 > -2 || -2 == 7 ^ 6 * 6 >> 6);
+ { int v0 = 1, v1 = -2, v2 = -2, v3 = 7, v4 = 6, v5 = 6, v6 = 6; pn(v0 > v1 || v2 == v3 ^ v4 * v5 >> v6); }
+ pn(2 >= -2 << 4 && 12 && -2 << 7 <= -2 + 6);
+ { int v0 = 2, v1 = -2, v2 = 4, v3 = 12, v4 = -2, v5 = 7, v6 = -2, v7 = 6; pn(v0 >= v1 << v2 && v3 && v4 << v5 <= v6 + v7); }
+ pn(5 + 0 * -2 > 4 | -2);
+ { int v0 = 5, v1 = 0, v2 = -2, v3 = 4, v4 = -2; pn(v0 + v1 * v2 > v3 | v4); }
+ pn(7 && 6 <= 2 * 4 == -2 ^ 0 == 6 <= -1);
+ { int v0 = 7, v1 = 6, v2 = 2, v3 = 4, v4 = -2, v5 = 0, v6 = 6, v7 = -1; pn(v0 && v1 <= v2 * v3 == v4 ^ v5 == v6 <= v7); }
+ pn(9 - -2 & 1 == -1 & 2 & -2 || 2 || 6 + 7 * -2);
+ { int v0 = 9, v1 = -2, v2 = 1, v3 = -1, v4 = 2, v5 = -2, v6 = 2, v7 = 6, v8 = 7, v9 = -2; pn(v0 - v1 & v2 == v3 & v4 & v5 || v6 || v7 + v8 * v9); }
+ pn(12 >= -2 | 2 + 3 & 5 | 12);
+ { int v0 = 12, v1 = -2, v2 = 2, v3 = 3, v4 = 5, v5 = 12; pn(v0 >= v1 | v2 + v3 & v4 | v5); }
+ pn(12 != -1 | 5 ^ 6 && 9 && 9 + 2);
+ { int v0 = 12, v1 = -1, v2 = 5, v3 = 6, v4 = 9, v5 = 9, v6 = 2; pn(v0 != v1 | v2 ^ v3 && v4 && v5 + v6); }
+ pn(3 <= 7 || -1 - -2 != 12 < 4 & 6 >= 12 ^ 12);
+ { int v0 = 3, v1 = 7, v2 = -1, v3 = -2, v4 = 12, v5 = 4, v6 = 6, v7 = 12, v8 = 12; pn(v0 <= v1 || v2 - v3 != v4 < v5 & v6 >= v7 ^ v8); }
+ pn(-1 == 3 * 2 | 3 | 2 << 2 <= 6);
+ { int v0 = -1, v1 = 3, v2 = 2, v3 = 3, v4 = 2, v5 = 2, v6 = 6; pn(v0 == v1 * v2 | v3 | v4 << v5 <= v6); }
+ pn(5 < 1 << 7 | 6 * 1 == 0 << 2 + -1 + -1);
+ { int v0 = 5, v1 = 1, v2 = 7, v3 = 6, v4 = 1, v5 = 0, v6 = 2, v7 = -1, v8 = -1; pn(v0 < v1 << v2 | v3 * v4 == v5 << v6 + v7 + v8); }
+ pn(-1 > 1 < 1 >> 3 - 7 << 7 == 6 | 3 < 5 + 7);
+ { int v0 = -1, v1 = 1, v2 = 1, v3 = 3, v4 = 7, v5 = 7, v6 = 6, v7 = 3, v8 = 5, v9 = 7; pn(v0 > v1 < v2 >> v3 - v4 << v5 == v6 | v7 < v8 + v9); }
+ pn(7 * 1 < 3 ^ 3 != 9 < 4 >= 9);
+ { int v0 = 7, v1 = 1, v2 = 3, v3 = 3, v4 = 9, v5 = 4, v6 = 9; pn(v0 * v1 < v2 ^ v3 != v4 < v5 >= v6); }
+ pn(2 <= 4 ^ 0 * 6 < 5 + 5 > 12);
+ { int v0 = 2, v1 = 4, v2 = 0, v3 = 6, v4 = 5, v5 = 5, v6 = 12; pn(v0 <= v1 ^ v2 * v3 < v4 + v5 > v6); }
+ pn(-2 + 2 | 5 > -2 < 12 * 6 ^ 6);
+ { int v0 = -2, v1 = 2, v2 = 5, v3 = -2, v4 = 12, v5 = 6, v6 = 6; pn(v0 + v1 | v2 > v3 < v4 * v5 ^ v6); }
+ pn(4 == 12 == 12 < 2 != -1 - 9);
+ { int v0 = 4, v1 = 12, v2 = 12, v3 = 2, v4 = -1, v5 = 9; pn(v0 == v1 == v2 < v3 != v4 - v5); }
+ pn(5 | 3 - 12 & 6 | 1);
+ { int v0 = 5, v1 = 3, v2 = 12, v3 = 6, v4 = 1; pn(v0 | v1 - v2 & v3 | v4); }
+ pn(-2 >> 3 | 9 & 12 < 6 < -1 ^ -1 + 2 << 4 < 7);
+ { int v0 = -2, v1 = 3, v2 = 9, v3 = 12, v4 = 6, v5 = -1, v6 = -1, v7 = 2, v8 = 4, v9 = 7; pn(v0 >> v1 | v2 & v3 < v4 < v5 ^ v6 + v7 << v8 < v9); }
+ pn(6 && 2 + 9 < -1 > 12 | 3 <= 9 != 2 <= -1);
+ { int v0 = 6, v1 = 2, v2 = 9, v3 = -1, v4 = 12, v5 = 3, v6 = 9, v7 = 2, v8 = -1; pn(v0 && v1 + v2 < v3 > v4 | v5 <= v6 != v7 <= v8); }
+ pn(2 & 1 * 2 - 1 | 0);
+ { int v0 = 2, v1 = 1, v2 = 2, v3 = 1, v4 = 0; pn(v0 & v1 * v2 - v3 | v4); }
+ pn(3 ^ 2 - -2 || 2 != 9 && 12 + -1 > 5);
+ { int v0 = 3, v1 = 2, v2 = -2, v3 = 2, v4 = 9, v5 = 12, v6 = -1, v7 = 5; pn(v0 ^ v1 - v2 || v3 != v4 && v5 + v6 > v7); }
+ pn(1 + 9 && 0 + 9 + 1 >= -2 << 6 == 5 - 2);
+ { int v0 = 1, v1 = 9, v2 = 0, v3 = 9, v4 = 1, v5 = -2, v6 = 6, v7 = 5, v8 = 2; pn(v0 + v1 && v2 + v3 + v4 >= v5 << v6 == v7 - v8); }
+ pn(9 != 3 || 7 + 12 < 1 > 2);
+ { int v0 = 9, v1 = 3, v2 = 7, v3 = 12, v4 = 1, v5 = 2; pn(v0 != v1 || v2 + v3 < v4 > v5); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_compound_assign_right.zc b/tests/conformance/3-expressions/prec_compound_assign_right.zc
new file mode 100644
index 0000000..3dee965
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_compound_assign_right.zc
@@ -0,0 +1,9 @@
+// expect: 12/3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 2, b = 3;
+ a *= b += 3;
+ pn(a); pn(b - 3);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_deref_postfix.zc b/tests/conformance/3-expressions/prec_deref_postfix.zc
new file mode 100644
index 0000000..2a3355f
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_deref_postfix.zc
@@ -0,0 +1,12 @@
+// expect: 5/6/8/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[3] a = {5, 6, 7};
+ int* p = a;
+ pn(*p);
+ pn(*p + 1);
+ pn(*p++ + 3);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/prec_left_add.zc b/tests/conformance/3-expressions/prec_left_add.zc
new file mode 100644
index 0000000..f3c7da6
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_add.zc
@@ -0,0 +1,39 @@
+// expect: 1/1/1/1/101/101/3/3/4/4/0/0/1/1/0/0/1/1/1/1/1/1/872/872/-1/-1/76/76/-2/-2/-8/-8/
+// first operator + followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(2 + -8 || 100);
+ { int a = 2, b = -8, c = 100; pn(a + b || c); }
+ pn(9 + 0 && -8);
+ { int a = 9, b = 0, c = -8; pn(a + b && c); }
+ pn(100 + -3 | 5);
+ { int a = 100, b = -3, c = 5; pn(a + b | c); }
+ pn(5 + -8 ^ -2);
+ { int a = 5, b = -8, c = -2; pn(a + b ^ c); }
+ pn(5 + 0 & 6);
+ { int a = 5, b = 0, c = 6; pn(a + b & c); }
+ pn(8 + 4 == -2);
+ { int a = 8, b = 4, c = -2; pn(a + b == c); }
+ pn(5 + 6 != 100);
+ { int a = 5, b = 6, c = 100; pn(a + b != c); }
+ pn(3 + 100 < 12);
+ { int a = 3, b = 100, c = 12; pn(a + b < c); }
+ pn(6 + 4 > -8);
+ { int a = 6, b = 4, c = -8; pn(a + b > c); }
+ pn(5 + -2 <= 100);
+ { int a = 5, b = -2, c = 100; pn(a + b <= c); }
+ pn(6 + 7 >= 2);
+ { int a = 6, b = 7, c = 2; pn(a + b >= c); }
+ pn(100 + 9 << 3);
+ { int a = 100, b = 9, c = 3; pn(a + b << c); }
+ pn(4 + -8 >> 3);
+ { int a = 4, b = -8, c = 3; pn(a + b >> c); }
+ pn(100 + 12 * -2);
+ { int a = 100, b = 12, c = -2; pn(a + b * c); }
+ pn(-2 + 3 / 12);
+ { int a = -2, b = 3, c = 12; pn(a + b / c); }
+ pn(-8 + 3 % 1);
+ { int a = -8, b = 3, c = 1; pn(a + b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_and.zc b/tests/conformance/3-expressions/prec_left_and.zc
new file mode 100644
index 0000000..32a00cc
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_and.zc
@@ -0,0 +1,41 @@
+// expect: 1/1/1/1/7/7/-6/-6/1/1/0/0/0/0/1/1/0/0/0/0/12/12/5/5/0/0/4/4/0/0/0/0/0/0/
+// first operator & followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(-2 & 3 || 4);
+ { int a = -2, b = 3, c = 4; pn(a & b || c); }
+ pn(4 & -1 && 12);
+ { int a = 4, b = -1, c = 12; pn(a & b && c); }
+ pn(4 & 2 | 7);
+ { int a = 4, b = 2, c = 7; pn(a & b | c); }
+ pn(4 & 100 ^ -2);
+ { int a = 4, b = 100, c = -2; pn(a & b ^ c); }
+ pn(9 & 12 == 12);
+ { int a = 9, b = 12, c = 12; pn(a & b == c); }
+ pn(100 & 8 != -2);
+ { int a = 100, b = 8, c = -2; pn(a & b != c); }
+ pn(0 & 8 < 1);
+ { int a = 0, b = 8, c = 1; pn(a & b < c); }
+ pn(5 & 8 > 4);
+ { int a = 5, b = 8, c = 4; pn(a & b > c); }
+ pn(4 & 8 <= 2);
+ { int a = 4, b = 8, c = 2; pn(a & b <= c); }
+ pn(4 & -2 >= -1);
+ { int a = 4, b = -2, c = -1; pn(a & b >= c); }
+ pn(-3 & 3 << 2);
+ { int a = -3, b = 3, c = 2; pn(a & b << c); }
+ pn(5 & -1 >> 2);
+ { int a = 5, b = -1, c = 2; pn(a & b >> c); }
+ pn(0 & 9 + 2);
+ { int a = 0, b = 9, c = 2; pn(a & b + c); }
+ pn(5 & 4 - 6);
+ { int a = 5, b = 4, c = 6; pn(a & b - c); }
+ pn(1 & 5 * 2);
+ { int a = 1, b = 5, c = 2; pn(a & b * c); }
+ pn(12 & 9 / 3);
+ { int a = 12, b = 9, c = 3; pn(a & b / c); }
+ pn(12 & 5 % 5);
+ { int a = 12, b = 5, c = 5; pn(a & b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_andand.zc b/tests/conformance/3-expressions/prec_left_andand.zc
new file mode 100644
index 0000000..3e7a456
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_andand.zc
@@ -0,0 +1,41 @@
+// expect: 1/1/1/1/0/0/1/1/0/0/0/0/0/0/0/0/0/0/1/1/1/1/1/1/1/1/1/1/1/1/1/1/0/0/
+// first operator && followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(0 && 6 || 8);
+ { int a = 0, b = 6, c = 8; pn(a && b || c); }
+ pn(5 && 4 | 4);
+ { int a = 5, b = 4, c = 4; pn(a && b | c); }
+ pn(3 && 7 ^ 7);
+ { int a = 3, b = 7, c = 7; pn(a && b ^ c); }
+ pn(-2 && 12 & 6);
+ { int a = -2, b = 12, c = 6; pn(a && b & c); }
+ pn(-2 && 6 == 1);
+ { int a = -2, b = 6, c = 1; pn(a && b == c); }
+ pn(0 && 8 != 8);
+ { int a = 0, b = 8, c = 8; pn(a && b != c); }
+ pn(7 && 9 < 5);
+ { int a = 7, b = 9, c = 5; pn(a && b < c); }
+ pn(3 && -3 > -2);
+ { int a = 3, b = -3, c = -2; pn(a && b > c); }
+ pn(1 && 12 <= 4);
+ { int a = 1, b = 12, c = 4; pn(a && b <= c); }
+ pn(7 && 4 >= 2);
+ { int a = 7, b = 4, c = 2; pn(a && b >= c); }
+ pn(-2 && 2 << 4);
+ { int a = -2, b = 2, c = 4; pn(a && b << c); }
+ pn(-3 && 9 >> 3);
+ { int a = -3, b = 9, c = 3; pn(a && b >> c); }
+ pn(5 && -3 + 4);
+ { int a = 5, b = -3, c = 4; pn(a && b + c); }
+ pn(8 && -1 - 6);
+ { int a = 8, b = -1, c = 6; pn(a && b - c); }
+ pn(-2 && 3 * 7);
+ { int a = -2, b = 3, c = 7; pn(a && b * c); }
+ pn(-2 && 3 / -1);
+ { int a = -2, b = 3, c = -1; pn(a && b / c); }
+ pn(9 && 100 % 5);
+ { int a = 9, b = 100, c = 5; pn(a && b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_div.zc b/tests/conformance/3-expressions/prec_left_div.zc
new file mode 100644
index 0000000..d2c30b1
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_div.zc
@@ -0,0 +1,43 @@
+// expect: 1/1/1/1/7/7/8/8/12/12/1/1/1/1/0/0/0/0/1/1/1/1/48/48/0/0/-8/-8/-7/-7/3/3/0/0/1/1/
+// first operator / followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(-2 / -8 || 5);
+ { int a = -2, b = -8, c = 5; pn(a / b || c); }
+ pn(-2 / -1 && 1);
+ { int a = -2, b = -1, c = 1; pn(a / b && c); }
+ pn(3 / 6 | 7);
+ { int a = 3, b = 6, c = 7; pn(a / b | c); }
+ pn(-1 / -1 ^ 9);
+ { int a = -1, b = -1, c = 9; pn(a / b ^ c); }
+ pn(12 / 1 & -2);
+ { int a = 12, b = 1, c = -2; pn(a / b & c); }
+ pn(-1 / 9 == 0);
+ { int a = -1, b = 9, c = 0; pn(a / b == c); }
+ pn(100 / 0 != 6);
+ { int a = 100, b = 0, c = 6; pn(a / b != c); }
+ pn(7 / -3 < -2);
+ { int a = 7, b = -3, c = -2; pn(a / b < c); }
+ pn(4 / 7 > 6);
+ { int a = 4, b = 7, c = 6; pn(a / b > c); }
+ pn(-8 / 5 <= -1);
+ { int a = -8, b = 5, c = -1; pn(a / b <= c); }
+ pn(100 / 0 >= -3);
+ { int a = 100, b = 0, c = -3; pn(a / b >= c); }
+ pn(100 / 8 << 2);
+ { int a = 100, b = 8, c = 2; pn(a / b << c); }
+ pn(7 / 12 >> 2);
+ { int a = 7, b = 12, c = 2; pn(a / b >> c); }
+ pn(8 / 12 + -8);
+ { int a = 8, b = 12, c = -8; pn(a / b + c); }
+ pn(4 / 7 - 7);
+ { int a = 4, b = 7, c = 7; pn(a / b - c); }
+ pn(12 / 12 * 3);
+ { int a = 12, b = 12, c = 3; pn(a / b * c); }
+ pn(1 / 8 / -8);
+ { int a = 1, b = 8, c = -8; pn(a / b / c); }
+ pn(9 / 1 % -2);
+ { int a = 9, b = 1, c = -2; pn(a / b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_eq.zc b/tests/conformance/3-expressions/prec_left_eq.zc
new file mode 100644
index 0000000..2a436e6
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_eq.zc
@@ -0,0 +1,43 @@
+// expect: 1/1/0/0/-7/-7/6/6/0/0/1/1/1/1/0/0/0/0/0/0/0/0/0/0/1/1/0/0/0/0/0/0/0/0/1/1/
+// first operator == followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(6 == 100 || 7);
+ { int a = 6, b = 100, c = 7; pn(a == b || c); }
+ pn(1 == 8 && 7);
+ { int a = 1, b = 8, c = 7; pn(a == b && c); }
+ pn(-2 == -2 | -8);
+ { int a = -2, b = -2, c = -8; pn(a == b | c); }
+ pn(5 == 5 ^ 7);
+ { int a = 5, b = 5, c = 7; pn(a == b ^ c); }
+ pn(4 == 4 & 100);
+ { int a = 4, b = 4, c = 100; pn(a == b & c); }
+ pn(4 == 4 == 1);
+ { int a = 4, b = 4, c = 1; pn(a == b == c); }
+ pn(7 == -1 != -1);
+ { int a = 7, b = -1, c = -1; pn(a == b != c); }
+ pn(100 == 0 < 8);
+ { int a = 100, b = 0, c = 8; pn(a == b < c); }
+ pn(5 == -8 > -2);
+ { int a = 5, b = -8, c = -2; pn(a == b > c); }
+ pn(6 == 1 <= 3);
+ { int a = 6, b = 1, c = 3; pn(a == b <= c); }
+ pn(100 == 2 >= -8);
+ { int a = 100, b = 2, c = -8; pn(a == b >= c); }
+ pn(9 == 9 << 5);
+ { int a = 9, b = 9, c = 5; pn(a == b << c); }
+ pn(2 == 8 >> 2);
+ { int a = 2, b = 8, c = 2; pn(a == b >> c); }
+ pn(2 == 6 + -2);
+ { int a = 2, b = 6, c = -2; pn(a == b + c); }
+ pn(9 == 12 - -8);
+ { int a = 9, b = 12, c = -8; pn(a == b - c); }
+ pn(1 == 1 * -2);
+ { int a = 1, b = 1, c = -2; pn(a == b * c); }
+ pn(-8 == -8 / -1);
+ { int a = -8, b = -8, c = -1; pn(a == b / c); }
+ pn(0 == 9 % 9);
+ { int a = 0, b = 9, c = 9; pn(a == b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_ge.zc b/tests/conformance/3-expressions/prec_left_ge.zc
new file mode 100644
index 0000000..c5b2d73
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_ge.zc
@@ -0,0 +1,43 @@
+// expect: 1/1/0/0/5/5/-3/-3/0/0/0/0/1/1/0/0/0/0/0/0/0/0/1/1/1/1/0/0/0/0/0/0/1/1/1/1/
+// first operator >= followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(-8 >= 8 || 7);
+ { int a = -8, b = 8, c = 7; pn(a >= b || c); }
+ pn(5 >= 12 && 2);
+ { int a = 5, b = 12, c = 2; pn(a >= b && c); }
+ pn(6 >= 7 | 5);
+ { int a = 6, b = 7, c = 5; pn(a >= b | c); }
+ pn(-1 >= 5 ^ -3);
+ { int a = -1, b = 5, c = -3; pn(a >= b ^ c); }
+ pn(9 >= 12 & 8);
+ { int a = 9, b = 12, c = 8; pn(a >= b & c); }
+ pn(1 >= 12 == 12);
+ { int a = 1, b = 12, c = 12; pn(a >= b == c); }
+ pn(-3 >= -2 != 5);
+ { int a = -3, b = -2, c = 5; pn(a >= b != c); }
+ pn(0 >= 1 < 0);
+ { int a = 0, b = 1, c = 0; pn(a >= b < c); }
+ pn(5 >= 100 > 5);
+ { int a = 5, b = 100, c = 5; pn(a >= b > c); }
+ pn(12 >= 12 <= -1);
+ { int a = 12, b = 12, c = -1; pn(a >= b <= c); }
+ pn(1 >= 9 >= 7);
+ { int a = 1, b = 9, c = 7; pn(a >= b >= c); }
+ pn(6 >= -1 << 7);
+ { int a = 6, b = -1, c = 7; pn(a >= b << c); }
+ pn(6 >= 100 >> 5);
+ { int a = 6, b = 100, c = 5; pn(a >= b >> c); }
+ pn(4 >= 1 + 8);
+ { int a = 4, b = 1, c = 8; pn(a >= b + c); }
+ pn(-1 >= 9 - -8);
+ { int a = -1, b = 9, c = -8; pn(a >= b - c); }
+ pn(7 >= 4 * 5);
+ { int a = 7, b = 4, c = 5; pn(a >= b * c); }
+ pn(2 >= 8 / 0);
+ { int a = 2, b = 8, c = 0; pn(a >= b / c); }
+ pn(7 >= 9 % 5);
+ { int a = 7, b = 9, c = 5; pn(a >= b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_gt.zc b/tests/conformance/3-expressions/prec_left_gt.zc
new file mode 100644
index 0000000..138989c
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_gt.zc
@@ -0,0 +1,43 @@
+// expect: 1/1/0/0/-1/-1/-8/-8/0/0/0/0/1/1/1/1/0/0/0/0/1/1/0/0/1/1/0/0/0/0/0/0/1/1/1/1/
+// first operator > followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(0 > 2 || 2);
+ { int a = 0, b = 2, c = 2; pn(a > b || c); }
+ pn(5 > 7 && 3);
+ { int a = 5, b = 7, c = 3; pn(a > b && c); }
+ pn(-1 > 5 | -1);
+ { int a = -1, b = 5, c = -1; pn(a > b | c); }
+ pn(7 > 8 ^ -8);
+ { int a = 7, b = 8, c = -8; pn(a > b ^ c); }
+ pn(12 > 1 & 12);
+ { int a = 12, b = 1, c = 12; pn(a > b & c); }
+ pn(3 > 8 == 4);
+ { int a = 3, b = 8, c = 4; pn(a > b == c); }
+ pn(-8 > 1 != 8);
+ { int a = -8, b = 1, c = 8; pn(a > b != c); }
+ pn(-3 > 7 < 1);
+ { int a = -3, b = 7, c = 1; pn(a > b < c); }
+ pn(100 > 9 > 3);
+ { int a = 100, b = 9, c = 3; pn(a > b > c); }
+ pn(3 > -3 <= -8);
+ { int a = 3, b = -3, c = -8; pn(a > b <= c); }
+ pn(-1 > 100 >= -8);
+ { int a = -1, b = 100, c = -8; pn(a > b >= c); }
+ pn(9 > 4 << 2);
+ { int a = 9, b = 4, c = 2; pn(a > b << c); }
+ pn(3 > -1 >> 5);
+ { int a = 3, b = -1, c = 5; pn(a > b >> c); }
+ pn(-3 > 7 + 9);
+ { int a = -3, b = 7, c = 9; pn(a > b + c); }
+ pn(-2 > 2 - -2);
+ { int a = -2, b = 2, c = -2; pn(a > b - c); }
+ pn(0 > -3 * -8);
+ { int a = 0, b = -3, c = -8; pn(a > b * c); }
+ pn(1 > 8 / -1);
+ { int a = 1, b = 8, c = -1; pn(a > b / c); }
+ pn(4 > 4 % 1);
+ { int a = 4, b = 4, c = 1; pn(a > b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_le.zc b/tests/conformance/3-expressions/prec_left_le.zc
new file mode 100644
index 0000000..e204439
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_le.zc
@@ -0,0 +1,43 @@
+// expect: 1/1/1/1/-7/-7/7/7/0/0/0/0/1/1/1/1/0/0/0/0/0/0/1/1/1/1/0/0/0/0/0/0/1/1/0/0/
+// first operator <= followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(12 <= 0 || 4);
+ { int a = 12, b = 0, c = 4; pn(a <= b || c); }
+ pn(3 <= 7 && -1);
+ { int a = 3, b = 7, c = -1; pn(a <= b && c); }
+ pn(4 <= 6 | -8);
+ { int a = 4, b = 6, c = -8; pn(a <= b | c); }
+ pn(0 <= 8 ^ 6);
+ { int a = 0, b = 8, c = 6; pn(a <= b ^ c); }
+ pn(-8 <= 12 & 4);
+ { int a = -8, b = 12, c = 4; pn(a <= b & c); }
+ pn(-3 <= -2 == 6);
+ { int a = -3, b = -2, c = 6; pn(a <= b == c); }
+ pn(6 <= 3 != -2);
+ { int a = 6, b = 3, c = -2; pn(a <= b != c); }
+ pn(9 <= -8 < 1);
+ { int a = 9, b = -8, c = 1; pn(a <= b < c); }
+ pn(-3 <= -1 > 9);
+ { int a = -3, b = -1, c = 9; pn(a <= b > c); }
+ pn(-8 <= 9 <= 0);
+ { int a = -8, b = 9, c = 0; pn(a <= b <= c); }
+ pn(-8 <= 9 >= 6);
+ { int a = -8, b = 9, c = 6; pn(a <= b >= c); }
+ pn(-3 <= 3 << 2);
+ { int a = -3, b = 3, c = 2; pn(a <= b << c); }
+ pn(-2 <= 3 >> 1);
+ { int a = -2, b = 3, c = 1; pn(a <= b >> c); }
+ pn(4 <= -2 + -3);
+ { int a = 4, b = -2, c = -3; pn(a <= b + c); }
+ pn(6 <= -3 - 3);
+ { int a = 6, b = -3, c = 3; pn(a <= b - c); }
+ pn(-3 <= -2 * 3);
+ { int a = -3, b = -2, c = 3; pn(a <= b * c); }
+ pn(0 <= 9 / 2);
+ { int a = 0, b = 9, c = 2; pn(a <= b / c); }
+ pn(3 <= 8 % 7);
+ { int a = 3, b = 8, c = 7; pn(a <= b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_lt.zc b/tests/conformance/3-expressions/prec_left_lt.zc
new file mode 100644
index 0000000..36a0c5f
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_lt.zc
@@ -0,0 +1,43 @@
+// expect: 1/1/1/1/-7/-7/6/6/0/0/1/1/1/1/1/1/0/0/1/1/0/0/1/1/1/1/0/0/1/1/1/1/1/1/1/1/
+// first operator < followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(6 < 9 || 7);
+ { int a = 6, b = 9, c = 7; pn(a < b || c); }
+ pn(1 < 7 && -2);
+ { int a = 1, b = 7, c = -2; pn(a < b && c); }
+ pn(3 < 12 | -8);
+ { int a = 3, b = 12, c = -8; pn(a < b | c); }
+ pn(7 < 12 ^ 7);
+ { int a = 7, b = 12, c = 7; pn(a < b ^ c); }
+ pn(7 < -3 & 9);
+ { int a = 7, b = -3, c = 9; pn(a < b & c); }
+ pn(7 < 7 == 0);
+ { int a = 7, b = 7, c = 0; pn(a < b == c); }
+ pn(3 < 2 != 1);
+ { int a = 3, b = 2, c = 1; pn(a < b != c); }
+ pn(4 < 100 < 4);
+ { int a = 4, b = 100, c = 4; pn(a < b < c); }
+ pn(-1 < 8 > 6);
+ { int a = -1, b = 8, c = 6; pn(a < b > c); }
+ pn(6 < 7 <= 9);
+ { int a = 6, b = 7, c = 9; pn(a < b <= c); }
+ pn(-1 < 0 >= 8);
+ { int a = -1, b = 0, c = 8; pn(a < b >= c); }
+ pn(9 < 12 << 6);
+ { int a = 9, b = 12, c = 6; pn(a < b << c); }
+ pn(-3 < 0 >> 4);
+ { int a = -3, b = 0, c = 4; pn(a < b >> c); }
+ pn(4 < -2 + 1);
+ { int a = 4, b = -2, c = 1; pn(a < b + c); }
+ pn(-8 < 4 - 2);
+ { int a = -8, b = 4, c = 2; pn(a < b - c); }
+ pn(6 < 3 * 3);
+ { int a = 6, b = 3, c = 3; pn(a < b * c); }
+ pn(-1 < 100 / 6);
+ { int a = -1, b = 100, c = 6; pn(a < b / c); }
+ pn(-2 < -8 % -2);
+ { int a = -2, b = -8, c = -2; pn(a < b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_mod.zc b/tests/conformance/3-expressions/prec_left_mod.zc
new file mode 100644
index 0000000..a69cf77
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_mod.zc
@@ -0,0 +1,43 @@
+// expect: 1/1/1/1/-7/-7/1/1/-4/-4/0/0/1/1/1/1/0/0/1/1/0/0/0/0/-2/-2/-2/-2/-9/-9/4/4/0/0/1/1/
+// first operator % followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(2 % 5 || 2);
+ { int a = 2, b = 5, c = 2; pn(a % b || c); }
+ pn(-1 % 100 && 100);
+ { int a = -1, b = 100, c = 100; pn(a % b && c); }
+ pn(7 % 6 | -8);
+ { int a = 7, b = 6, c = -8; pn(a % b | c); }
+ pn(3 % 100 ^ 2);
+ { int a = 3, b = 100, c = 2; pn(a % b ^ c); }
+ pn(-2 % -8 & -3);
+ { int a = -2, b = -8, c = -3; pn(a % b & c); }
+ pn(9 % 6 == 2);
+ { int a = 9, b = 6, c = 2; pn(a % b == c); }
+ pn(7 % 8 != -8);
+ { int a = 7, b = 8, c = -8; pn(a % b != c); }
+ pn(9 % 9 < 3);
+ { int a = 9, b = 9, c = 3; pn(a % b < c); }
+ pn(5 % -8 > 100);
+ { int a = 5, b = -8, c = 100; pn(a % b > c); }
+ pn(8 % -8 <= 0);
+ { int a = 8, b = -8, c = 0; pn(a % b <= c); }
+ pn(-1 % -2 >= 5);
+ { int a = -1, b = -2, c = 5; pn(a % b >= c); }
+ pn(100 % 5 << 6);
+ { int a = 100, b = 5, c = 6; pn(a % b << c); }
+ pn(-8 % 0 >> 2);
+ { int a = -8, b = 0, c = 2; pn(a % b >> c); }
+ pn(-1 % 0 + -1);
+ { int a = -1, b = 0, c = -1; pn(a % b + c); }
+ pn(-3 % 3 - 9);
+ { int a = -3, b = 3, c = 9; pn(a % b - c); }
+ pn(5 % 2 * 4);
+ { int a = 5, b = 2, c = 4; pn(a % b * c); }
+ pn(-8 % 5 / 100);
+ { int a = -8, b = 5, c = 100; pn(a % b / c); }
+ pn(5 % 4 % 2);
+ { int a = 5, b = 4, c = 2; pn(a % b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_mul.zc b/tests/conformance/3-expressions/prec_left_mul.zc
new file mode 100644
index 0000000..4e2dacc
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_mul.zc
@@ -0,0 +1,39 @@
+// expect: 1/1/1/1/-2/-2/27/27/0/0/0/0/1/1/1/1/1/1/1/1/1/1/4/4/106/106/7/7/-36/-36/0/0/
+// first operator * followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(4 * -2 || -8);
+ { int a = 4, b = -2, c = -8; pn(a * b || c); }
+ pn(4 * 12 && 100);
+ { int a = 4, b = 12, c = 100; pn(a * b && c); }
+ pn(-2 * 5 | -2);
+ { int a = -2, b = 5, c = -2; pn(a * b | c); }
+ pn(4 * 7 ^ 7);
+ { int a = 4, b = 7, c = 7; pn(a * b ^ c); }
+ pn(6 * 8 & 9);
+ { int a = 6, b = 8, c = 9; pn(a * b & c); }
+ pn(-3 * 8 == 8);
+ { int a = -3, b = 8, c = 8; pn(a * b == c); }
+ pn(6 * 5 != -2);
+ { int a = 6, b = 5, c = -2; pn(a * b != c); }
+ pn(8 * -2 < -3);
+ { int a = 8, b = -2, c = -3; pn(a * b < c); }
+ pn(-2 * -3 > 3);
+ { int a = -2, b = -3, c = 3; pn(a * b > c); }
+ pn(-3 * 9 <= 2);
+ { int a = -3, b = 9, c = 2; pn(a * b <= c); }
+ pn(2 * 12 >= 9);
+ { int a = 2, b = 12, c = 9; pn(a * b >= c); }
+ pn(3 * 100 >> 6);
+ { int a = 3, b = 100, c = 6; pn(a * b >> c); }
+ pn(-3 * -2 + 100);
+ { int a = -3, b = -2, c = 100; pn(a * b + c); }
+ pn(-2 * -2 - -3);
+ { int a = -2, b = -2, c = -3; pn(a * b - c); }
+ pn(-8 * 9 / 2);
+ { int a = -8, b = 9, c = 2; pn(a * b / c); }
+ pn(6 * 9 % 6);
+ { int a = 6, b = 9, c = 6; pn(a * b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_ne.zc b/tests/conformance/3-expressions/prec_left_ne.zc
new file mode 100644
index 0000000..e14991f
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_ne.zc
@@ -0,0 +1,43 @@
+// expect: 1/1/1/1/5/5/8/8/0/0/0/0/0/0/1/1/0/0/1/1/1/1/1/1/1/1/1/1/0/0/1/1/1/1/1/1/
+// first operator != followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(1 != 12 || -1);
+ { int a = 1, b = 12, c = -1; pn(a != b || c); }
+ pn(1 != 5 && -8);
+ { int a = 1, b = 5, c = -8; pn(a != b && c); }
+ pn(1 != -3 | 5);
+ { int a = 1, b = -3, c = 5; pn(a != b | c); }
+ pn(2 != 6 ^ 9);
+ { int a = 2, b = 6, c = 9; pn(a != b ^ c); }
+ pn(6 != -3 & -8);
+ { int a = 6, b = -3, c = -8; pn(a != b & c); }
+ pn(2 != -8 == -1);
+ { int a = 2, b = -8, c = -1; pn(a != b == c); }
+ pn(7 != 0 != 1);
+ { int a = 7, b = 0, c = 1; pn(a != b != c); }
+ pn(4 != -1 < -3);
+ { int a = 4, b = -1, c = -3; pn(a != b < c); }
+ pn(1 != 2 > -2);
+ { int a = 1, b = 2, c = -2; pn(a != b > c); }
+ pn(8 != -8 <= -3);
+ { int a = 8, b = -8, c = -3; pn(a != b <= c); }
+ pn(3 != 6 >= 100);
+ { int a = 3, b = 6, c = 100; pn(a != b >= c); }
+ pn(2 != 4 << 7);
+ { int a = 2, b = 4, c = 7; pn(a != b << c); }
+ pn(4 != 12 >> 1);
+ { int a = 4, b = 12, c = 1; pn(a != b >> c); }
+ pn(1 != 4 + -2);
+ { int a = 1, b = 4, c = -2; pn(a != b + c); }
+ pn(-2 != 1 - 3);
+ { int a = -2, b = 1, c = 3; pn(a != b - c); }
+ pn(3 != 8 * -2);
+ { int a = 3, b = 8, c = -2; pn(a != b * c); }
+ pn(4 != 2 / 4);
+ { int a = 4, b = 2, c = 4; pn(a != b / c); }
+ pn(12 != 7 % 1);
+ { int a = 12, b = 7, c = 1; pn(a != b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_or.zc b/tests/conformance/3-expressions/prec_left_or.zc
new file mode 100644
index 0000000..85b7181
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_or.zc
@@ -0,0 +1,41 @@
+// expect: 1/1/1/1/-2/-2/13/13/1/1/5/5/-1/-1/9/9/101/101/-3/-3/-186/-186/101/101/-7/-7/-3/-3/-1/-1/-1/-1/11/11/
+// first operator | followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(-1 | 0 || 1);
+ { int a = -1, b = 0, c = 1; pn(a | b || c); }
+ pn(3 | 0 && 7);
+ { int a = 3, b = 0, c = 7; pn(a | b && c); }
+ pn(-2 | 0 ^ -2);
+ { int a = -2, b = 0, c = -2; pn(a | b ^ c); }
+ pn(12 | 7 & 1);
+ { int a = 12, b = 7, c = 1; pn(a | b & c); }
+ pn(1 | -3 == 2);
+ { int a = 1, b = -3, c = 2; pn(a | b == c); }
+ pn(5 | 5 != -8);
+ { int a = 5, b = 5, c = -8; pn(a | b != c); }
+ pn(-1 | 100 < 12);
+ { int a = -1, b = 100, c = 12; pn(a | b < c); }
+ pn(9 | -1 > 1);
+ { int a = 9, b = -1, c = 1; pn(a | b > c); }
+ pn(100 | 0 <= 4);
+ { int a = 100, b = 0, c = 4; pn(a | b <= c); }
+ pn(-3 | 6 >= 6);
+ { int a = -3, b = 6, c = 6; pn(a | b >= c); }
+ pn(6 | -3 << 6);
+ { int a = 6, b = -3, c = 6; pn(a | b << c); }
+ pn(100 | 7 >> 2);
+ { int a = 100, b = 7, c = 2; pn(a | b >> c); }
+ pn(-8 | 8 + 9);
+ { int a = -8, b = 8, c = 9; pn(a | b + c); }
+ pn(-3 | 1 - -3);
+ { int a = -3, b = 1, c = -3; pn(a | b - c); }
+ pn(-2 | -3 * 7);
+ { int a = -2, b = -3, c = 7; pn(a | b * c); }
+ pn(-3 | -2 / 2);
+ { int a = -3, b = -2, c = 2; pn(a | b / c); }
+ pn(9 | 2 % -8);
+ { int a = 9, b = 2, c = -8; pn(a | b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_oror.zc b/tests/conformance/3-expressions/prec_left_oror.zc
new file mode 100644
index 0000000..5a70617
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_oror.zc
@@ -0,0 +1,41 @@
+// expect: 1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/1/
+// first operator || followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(12 || 9 && 0);
+ { int a = 12, b = 9, c = 0; pn(a || b && c); }
+ pn(7 || 0 | 4);
+ { int a = 7, b = 0, c = 4; pn(a || b | c); }
+ pn(4 || -1 ^ 7);
+ { int a = 4, b = -1, c = 7; pn(a || b ^ c); }
+ pn(3 || -8 & 100);
+ { int a = 3, b = -8, c = 100; pn(a || b & c); }
+ pn(4 || 100 == -8);
+ { int a = 4, b = 100, c = -8; pn(a || b == c); }
+ pn(100 || -3 != 1);
+ { int a = 100, b = -3, c = 1; pn(a || b != c); }
+ pn(7 || 2 < -2);
+ { int a = 7, b = 2, c = -2; pn(a || b < c); }
+ pn(-1 || 0 > 4);
+ { int a = -1, b = 0, c = 4; pn(a || b > c); }
+ pn(100 || -3 <= -1);
+ { int a = 100, b = -3, c = -1; pn(a || b <= c); }
+ pn(1 || 8 >= 12);
+ { int a = 1, b = 8, c = 12; pn(a || b >= c); }
+ pn(-8 || 100 << 3);
+ { int a = -8, b = 100, c = 3; pn(a || b << c); }
+ pn(9 || 12 >> 2);
+ { int a = 9, b = 12, c = 2; pn(a || b >> c); }
+ pn(1 || -1 + 8);
+ { int a = 1, b = -1, c = 8; pn(a || b + c); }
+ pn(-3 || 100 - 100);
+ { int a = -3, b = 100, c = 100; pn(a || b - c); }
+ pn(12 || -2 * -3);
+ { int a = 12, b = -2, c = -3; pn(a || b * c); }
+ pn(-8 || 0 / -2);
+ { int a = -8, b = 0, c = -2; pn(a || b / c); }
+ pn(-1 || 4 % -1);
+ { int a = -1, b = 4, c = -1; pn(a || b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_shl.zc b/tests/conformance/3-expressions/prec_left_shl.zc
new file mode 100644
index 0000000..78eef19
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_shl.zc
@@ -0,0 +1,43 @@
+// expect: 1/1/0/0/72/72/36/36/0/0/0/0/1/1/0/0/1/1/1/1/1/1/-64/-64/32/32/2594073385365405696/2594073385365405696/900719925474099200/900719925474099200/-144115188075855872/-144115188075855872/2/2/-1/-1/
+// first operator << followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(3 << 3 || 2);
+ { int a = 3, b = 3, c = 2; pn(a << b || c); }
+ pn(-8 << 7 && 0);
+ { int a = -8, b = 7, c = 0; pn(a << b && c); }
+ pn(4 << 4 | 8);
+ { int a = 4, b = 4, c = 8; pn(a << b | c); }
+ pn(1 << 6 ^ 100);
+ { int a = 1, b = 6, c = 100; pn(a << b ^ c); }
+ pn(3 << 5 & 1);
+ { int a = 3, b = 5, c = 1; pn(a << b & c); }
+ pn(2 << 3 == 6);
+ { int a = 2, b = 3, c = 6; pn(a << b == c); }
+ pn(-3 << 6 != 100);
+ { int a = -3, b = 6, c = 100; pn(a << b != c); }
+ pn(5 << 6 < 9);
+ { int a = 5, b = 6, c = 9; pn(a << b < c); }
+ pn(7 << 0 > 3);
+ { int a = 7, b = 0, c = 3; pn(a << b > c); }
+ pn(0 << 1 <= 3);
+ { int a = 0, b = 1, c = 3; pn(a << b <= c); }
+ pn(8 << 0 >= 3);
+ { int a = 8, b = 0, c = 3; pn(a << b >= c); }
+ pn(-1 << 1 << 5);
+ { int a = -1, b = 1, c = 5; pn(a << b << c); }
+ pn(4 << 5 >> 2);
+ { int a = 4, b = 5, c = 2; pn(a << b >> c); }
+ pn(9 << 2 + -8);
+ { int a = 9, b = 2, c = -8; pn(a << b + c); }
+ pn(100 << 1 - 12);
+ { int a = 100, b = 1, c = 12; pn(a << b - c); }
+ pn(-8 << 6 * 9);
+ { int a = -8, b = 6, c = 9; pn(a << b * c); }
+ pn(2 << 0 / 7);
+ { int a = 2, b = 0, c = 7; pn(a << b / c); }
+ pn(-1 << 5 % 5);
+ { int a = -1, b = 5, c = 5; pn(a << b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_shr.zc b/tests/conformance/3-expressions/prec_left_shr.zc
new file mode 100644
index 0000000..e3de1cd
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_shr.zc
@@ -0,0 +1,43 @@
+// expect: 1/1/1/1/-4/-4/-6/-6/0/0/0/0/1/1/1/1/1/1/1/1/0/0/-128/-128/0/0/0/0/-1/-1/0/0/4/4/7/7/
+// first operator >> followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(9 >> 5 || 9);
+ { int a = 9, b = 5, c = 9; pn(a >> b || c); }
+ pn(100 >> 6 && -1);
+ { int a = 100, b = 6, c = -1; pn(a >> b && c); }
+ pn(4 >> 0 | -8);
+ { int a = 4, b = 0, c = -8; pn(a >> b | c); }
+ pn(-3 >> 1 ^ 4);
+ { int a = -3, b = 1, c = 4; pn(a >> b ^ c); }
+ pn(8 >> 3 & 0);
+ { int a = 8, b = 3, c = 0; pn(a >> b & c); }
+ pn(5 >> 2 == 9);
+ { int a = 5, b = 2, c = 9; pn(a >> b == c); }
+ pn(5 >> 7 != 1);
+ { int a = 5, b = 7, c = 1; pn(a >> b != c); }
+ pn(-3 >> 0 < -2);
+ { int a = -3, b = 0, c = -2; pn(a >> b < c); }
+ pn(100 >> 6 > -2);
+ { int a = 100, b = 6, c = -2; pn(a >> b > c); }
+ pn(-8 >> 0 <= -3);
+ { int a = -8, b = 0, c = -3; pn(a >> b <= c); }
+ pn(8 >> 7 >= 100);
+ { int a = 8, b = 7, c = 100; pn(a >> b >= c); }
+ pn(-3 >> 3 << 7);
+ { int a = -3, b = 3, c = 7; pn(a >> b << c); }
+ pn(6 >> 6 >> 5);
+ { int a = 6, b = 6, c = 5; pn(a >> b >> c); }
+ pn(0 >> 2 + 8);
+ { int a = 0, b = 2, c = 8; pn(a >> b + c); }
+ pn(-2 >> 0 - 4);
+ { int a = -2, b = 0, c = 4; pn(a >> b - c); }
+ pn(9 >> 3 * 8);
+ { int a = 9, b = 3, c = 8; pn(a >> b * c); }
+ pn(4 >> 0 / 4);
+ { int a = 4, b = 0, c = 4; pn(a >> b / c); }
+ pn(7 >> 7 % 1);
+ { int a = 7, b = 7, c = 1; pn(a >> b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_sub.zc b/tests/conformance/3-expressions/prec_left_sub.zc
new file mode 100644
index 0000000..6cdb21d
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_sub.zc
@@ -0,0 +1,43 @@
+// expect: 1/1/1/1/-1/-1/-13/-13/0/0/0/0/1/1/1/1/0/0/1/1/0/0/768/768/-3/-3/6/6/-16/-16/-28/-28/7/7/8/8/
+// first operator - followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(5 - 6 || -1);
+ { int a = 5, b = 6, c = -1; pn(a - b || c); }
+ pn(-1 - 12 && -2);
+ { int a = -1, b = 12, c = -2; pn(a - b && c); }
+ pn(4 - 7 | -1);
+ { int a = 4, b = 7, c = -1; pn(a - b | c); }
+ pn(12 - -2 ^ -3);
+ { int a = 12, b = -2, c = -3; pn(a - b ^ c); }
+ pn(4 - 1 & 4);
+ { int a = 4, b = 1, c = 4; pn(a - b & c); }
+ pn(12 - 1 == 12);
+ { int a = 12, b = 1, c = 12; pn(a - b == c); }
+ pn(100 - 1 != 7);
+ { int a = 100, b = 1, c = 7; pn(a - b != c); }
+ pn(8 - -3 < 100);
+ { int a = 8, b = -3, c = 100; pn(a - b < c); }
+ pn(-1 - -3 > 2);
+ { int a = -1, b = -3, c = 2; pn(a - b > c); }
+ pn(1 - -2 <= 9);
+ { int a = 1, b = -2, c = 9; pn(a - b <= c); }
+ pn(8 - 9 >= 7);
+ { int a = 8, b = 9, c = 7; pn(a - b >= c); }
+ pn(7 - 1 << 7);
+ { int a = 7, b = 1, c = 7; pn(a - b << c); }
+ pn(0 - 9 >> 2);
+ { int a = 0, b = 9, c = 2; pn(a - b >> c); }
+ pn(5 - 7 + 8);
+ { int a = 5, b = 7, c = 8; pn(a - b + c); }
+ pn(-2 - 8 - 6);
+ { int a = -2, b = 8, c = 6; pn(a - b - c); }
+ pn(-8 - 5 * 4);
+ { int a = -8, b = 5, c = 4; pn(a - b * c); }
+ pn(7 - 5 / 6);
+ { int a = 7, b = 5, c = 6; pn(a - b / c); }
+ pn(6 - -2 % 6);
+ { int a = 6, b = -2, c = 6; pn(a - b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_left_xor.zc b/tests/conformance/3-expressions/prec_left_xor.zc
new file mode 100644
index 0000000..a977688
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_left_xor.zc
@@ -0,0 +1,41 @@
+// expect: 1/1/1/1/7/7/2/2/4/4/7/7/8/8/4/4/-3/-3/-2/-2/3/3/-3/-3/12/12/-8/-8/87/87/-2/-2/3/3/
+// first operator ^ followed by each other binary operator; operands chosen so that the two groupings differ
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(5 ^ -8 || 9);
+ { int a = 5, b = -8, c = 9; pn(a ^ b || c); }
+ pn(-2 ^ 5 && -3);
+ { int a = -2, b = 5, c = -3; pn(a ^ b && c); }
+ pn(7 ^ 4 | 4);
+ { int a = 7, b = 4, c = 4; pn(a ^ b | c); }
+ pn(7 ^ -1 & 5);
+ { int a = 7, b = -1, c = 5; pn(a ^ b & c); }
+ pn(4 ^ 4 == 6);
+ { int a = 4, b = 4, c = 6; pn(a ^ b == c); }
+ pn(6 ^ -8 != 12);
+ { int a = 6, b = -8, c = 12; pn(a ^ b != c); }
+ pn(8 ^ -1 < -1);
+ { int a = 8, b = -1, c = -1; pn(a ^ b < c); }
+ pn(4 ^ 2 > 5);
+ { int a = 4, b = 2, c = 5; pn(a ^ b > c); }
+ pn(-3 ^ 8 <= 6);
+ { int a = -3, b = 8, c = 6; pn(a ^ b <= c); }
+ pn(-2 ^ -8 >= 1);
+ { int a = -2, b = -8, c = 1; pn(a ^ b >= c); }
+ pn(3 ^ 0 << 2);
+ { int a = 3, b = 0, c = 2; pn(a ^ b << c); }
+ pn(2 ^ -2 >> 2);
+ { int a = 2, b = -2, c = 2; pn(a ^ b >> c); }
+ pn(9 ^ -2 + 7);
+ { int a = 9, b = -2, c = 7; pn(a ^ b + c); }
+ pn(3 ^ -8 - -3);
+ { int a = 3, b = -8, c = -3; pn(a ^ b - c); }
+ pn(6 ^ 9 * 9);
+ { int a = 6, b = 9, c = 9; pn(a ^ b * c); }
+ pn(-2 ^ -2 / -8);
+ { int a = -2, b = -2, c = -8; pn(a ^ b / c); }
+ pn(3 ^ 12 % -3);
+ { int a = 3, b = 12, c = -3; pn(a ^ b % c); }
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_postfix_incr_value.zc b/tests/conformance/3-expressions/prec_postfix_incr_value.zc
new file mode 100644
index 0000000..b5ad819
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_postfix_incr_value.zc
@@ -0,0 +1,11 @@
+// expect: 5/6/7/7/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 5;
+ pn(a++);
+ pn(a);
+ pn(++a);
+ pn(a);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/prec_postfix_tighter_than_prefix.zc b/tests/conformance/3-expressions/prec_postfix_tighter_than_prefix.zc
new file mode 100644
index 0000000..36cccf5
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_postfix_tighter_than_prefix.zc
@@ -0,0 +1,12 @@
+// expect: -6/6/-5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[3] a = {5, 6, 7};
+ int i = 1;
+ pn(-a[i]);
+ pn(- -a[i]);
+ pn(-a[i - 1]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/prec_table_examples.zc b/tests/conformance/3-expressions/prec_table_examples.zc
new file mode 100644
index 0000000..f78562d
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_table_examples.zc
@@ -0,0 +1,24 @@
+// expect: 1/1/0/3/0/6/8/1/1/3/10/5/2/1/0/3/-1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(1 || 0 && 0);
+ pn(0 && 0 || 1);
+ pn(1 | 2 && 0);
+ pn(0 == 0 | 2);
+ pn(6 & 3 == 3);
+ pn(1 + 2 << 1);
+ pn(1 << 2 + 1);
+ pn(2 < 3 == 1);
+ pn(1 < 2 < 3 ? 1 : 0);
+ pn(1 ^ 3 & 2);
+ pn(7 & 3 ^ 1 | 8);
+ pn(10 - 3 - 2);
+ pn(100 / 10 / 5);
+ pn(1 < 2 < 3);
+ pn(3 > 2 > 1);
+ pn(0 ? 1 : 0 ? 2 : 3);
+ pn(-2 as int + 1);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/prec_ternary_cond_is_binary.zc b/tests/conformance/3-expressions/prec_ternary_cond_is_binary.zc
new file mode 100644
index 0000000..2890f6e
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_ternary_cond_is_binary.zc
@@ -0,0 +1,12 @@
+// expect: 3/8/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a, b = 3;
+ a = b == 3 ? 3 : 4;
+ pn(a);
+ a = b + 1 > 3 && b ? 8 : 9;
+ pn(a);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/prec_ternary_else_assign.zc b/tests/conformance/3-expressions/prec_ternary_else_assign.zc
new file mode 100644
index 0000000..400e780
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_ternary_else_assign.zc
@@ -0,0 +1,13 @@
+// expect: 0/5/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 1, c = 0;
+ a ? 1 : c = 5;
+ pn(c);
+ a = 0;
+ a ? 1 : c = 5;
+ pn(c);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/prec_ternary_middle_full_expr.zc b/tests/conformance/3-expressions/prec_ternary_middle_full_expr.zc
new file mode 100644
index 0000000..21ac07c
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_ternary_middle_full_expr.zc
@@ -0,0 +1,10 @@
+// expect: 4/4/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 1, b = 0;
+ int r = a ? b = 4 : 7;
+ pn(r); pn(b);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/prec_unary_vs_binary.zc b/tests/conformance/3-expressions/prec_unary_vs_binary.zc
new file mode 100644
index 0000000..a7b7e48
--- /dev/null
+++ b/tests/conformance/3-expressions/prec_unary_vs_binary.zc
@@ -0,0 +1,12 @@
+// expect: -6/-6/6/-9/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 2, b = 3;
+ pn(-a * b);
+ pn(- a * b);
+ pn(-(-a) * b);
+ pn(~a * 3 + 0);
+ pn(!a + 1 == 1);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/ptr_add_words.zc b/tests/conformance/3-expressions/ptr_add_words.zc
new file mode 100644
index 0000000..6b869f6
--- /dev/null
+++ b/tests/conformance/3-expressions/ptr_add_words.zc
@@ -0,0 +1,14 @@
+// expect: 5/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct point { int x; int y; }
+fn main() {
+ point* p = rt.new(point, 3);
+ p[1].x = 5;
+ int* q = (int*)p;
+ pn(q[2]);
+ pn((int)(p + 1) - (int)p);
+ rt.free(p);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/ptr_addr_of_forms.zc b/tests/conformance/3-expressions/ptr_addr_of_forms.zc
new file mode 100644
index 0000000..4bcf8cf
--- /dev/null
+++ b/tests/conformance/3-expressions/ptr_addr_of_forms.zc
@@ -0,0 +1,24 @@
+// expect: 1/1/1/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct pt { int x; int y; }
+int gv;
+fn main() {
+ int a = 3;
+ int* pa = &a;
+ *pa = 4;
+ pn(a == 4);
+ *(&gv) = 8;
+ pn(gv == 8);
+ pt* q = rt.new(pt);
+ int* py = &q.y;
+ *py = 6;
+ pn(q.y == 6);
+ int[3] arr;
+ int* pe = &arr[2];
+ *pe = 1;
+ pn(arr[2]);
+ rt.free(q);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/ptr_deref_struct_is_address.zc b/tests/conformance/3-expressions/ptr_deref_struct_is_address.zc
new file mode 100644
index 0000000..f495fc5
--- /dev/null
+++ b/tests/conformance/3-expressions/ptr_deref_struct_is_address.zc
@@ -0,0 +1,11 @@
+// expect: 1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct point { int x; int y; }
+fn main() {
+ point* p = rt.new(point, 4);
+ pn((int)(*(p + 2)) == (int)(p + 2));
+ rt.free(p);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/ptr_difference.zc b/tests/conformance/3-expressions/ptr_difference.zc
new file mode 100644
index 0000000..ea5eb15
--- /dev/null
+++ b/tests/conformance/3-expressions/ptr_difference.zc
@@ -0,0 +1,12 @@
+// expect: 3/-3/2/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int[8] a;
+ int* p = a;
+ int* q = p + 3;
+ pn(q - p);
+ pn(p - q);
+ pn((q - 1) - p);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/ptr_field_of_new_object.zc b/tests/conformance/3-expressions/ptr_field_of_new_object.zc
new file mode 100644
index 0000000..3d01581
--- /dev/null
+++ b/tests/conformance/3-expressions/ptr_field_of_new_object.zc
@@ -0,0 +1,7 @@
+// expect error: use a field of a new object only after binding it to a name
+include rt;
+struct pt { int x; int y; }
+fn main() {
+ rt.put_n(rt.new(pt).x);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/ptr_index_must_be_number.zc b/tests/conformance/3-expressions/ptr_index_must_be_number.zc
new file mode 100644
index 0000000..766e348
--- /dev/null
+++ b/tests/conformance/3-expressions/ptr_index_must_be_number.zc
@@ -0,0 +1,8 @@
+// expect error: type error
+include rt;
+typecheck on;
+fn main() {
+ int[2] a; int* p = a;
+ rt.put_n(a[p]);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/ptr_index_new_object.zc b/tests/conformance/3-expressions/ptr_index_new_object.zc
new file mode 100644
index 0000000..7f729fa
--- /dev/null
+++ b/tests/conformance/3-expressions/ptr_index_new_object.zc
@@ -0,0 +1,6 @@
+// expect error: index a new object only after binding it to a name
+include rt;
+fn main() {
+ rt.put_n(rt.new(int)[0]);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/ptr_index_scaled.zc b/tests/conformance/3-expressions/ptr_index_scaled.zc
new file mode 100644
index 0000000..fd61dd9
--- /dev/null
+++ b/tests/conformance/3-expressions/ptr_index_scaled.zc
@@ -0,0 +1,13 @@
+// expect: 7/9/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct trip { int a; int b; int c; }
+fn main() {
+ trip* t = rt.new(trip, 2);
+ int* w = (int*)t;
+ w[3] = 7; w[5] = 9;
+ pn(t[1].a); pn(t[1].c);
+ rt.free(t);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/short_circuit.zc b/tests/conformance/3-expressions/short_circuit.zc
new file mode 100644
index 0000000..ac23ade
--- /dev/null
+++ b/tests/conformance/3-expressions/short_circuit.zc
@@ -0,0 +1,15 @@
+// expect: 1/1/0/1/
+include rt;
+int calls;
+int seen(int v) { calls++; return v; }
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ calls = 0;
+ int r = seen(1) || seen(0) && seen(1);
+ pn(r); pn(calls);
+ calls = 0;
+ r = seen(0) && seen(1);
+ pn(r);
+ pn(calls);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/short_circuit_and_evaluates_right.zc b/tests/conformance/3-expressions/short_circuit_and_evaluates_right.zc
new file mode 100644
index 0000000..ae3e774
--- /dev/null
+++ b/tests/conformance/3-expressions/short_circuit_and_evaluates_right.zc
@@ -0,0 +1,10 @@
+// expect: 1/2/
+include rt;
+int calls;
+int seen(int v) { calls++; return v; }
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int r = seen(7) && seen(9);
+ pn(r); pn(calls);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/short_circuit_or_evaluates_right_when_zero.zc b/tests/conformance/3-expressions/short_circuit_or_evaluates_right_when_zero.zc
new file mode 100644
index 0000000..056159a
--- /dev/null
+++ b/tests/conformance/3-expressions/short_circuit_or_evaluates_right_when_zero.zc
@@ -0,0 +1,10 @@
+// expect: 1/2/
+include rt;
+int calls;
+int seen(int v) { calls++; return v; }
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int r = seen(0) || seen(3);
+ pn(r); pn(calls);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/short_circuit_or_skips_right.zc b/tests/conformance/3-expressions/short_circuit_or_skips_right.zc
new file mode 100644
index 0000000..1e573ee
--- /dev/null
+++ b/tests/conformance/3-expressions/short_circuit_or_skips_right.zc
@@ -0,0 +1,10 @@
+// expect: 1/1/
+include rt;
+int calls;
+int seen(int v) { calls++; return v; }
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int r = seen(7) || seen(0);
+ pn(r); pn(calls);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/sizeof_expr_not_run.zc b/tests/conformance/3-expressions/sizeof_expr_not_run.zc
new file mode 100644
index 0000000..1714a38
--- /dev/null
+++ b/tests/conformance/3-expressions/sizeof_expr_not_run.zc
@@ -0,0 +1,10 @@
+// expect: 0/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int i = 0;
+ int n = sizeof(i++);
+ pn(i); pn(n);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/sizeof_packed.zc b/tests/conformance/3-expressions/sizeof_packed.zc
new file mode 100644
index 0000000..86df5b1
--- /dev/null
+++ b/tests/conformance/3-expressions/sizeof_packed.zc
@@ -0,0 +1,6 @@
+// expect: 13/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+struct four { u8 a, b, c, d; }
+fn main() { pn(sizeof(u8[100])); pn(sizeof(four)); return 0; }
+// zc0: skip
diff --git a/tests/conformance/3-expressions/ternary_nests_right.zc b/tests/conformance/3-expressions/ternary_nests_right.zc
new file mode 100644
index 0000000..1b61fef
--- /dev/null
+++ b/tests/conformance/3-expressions/ternary_nests_right.zc
@@ -0,0 +1,10 @@
+// expect: 3/2/1/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(0 ? 1 : 0 ? 2 : 3);
+ pn(0 ? 1 : 1 ? 2 : 3);
+ pn(1 ? 1 : 1 ? 2 : 3);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/ternary_one_branch_only.zc b/tests/conformance/3-expressions/ternary_one_branch_only.zc
new file mode 100644
index 0000000..b0a423f
--- /dev/null
+++ b/tests/conformance/3-expressions/ternary_one_branch_only.zc
@@ -0,0 +1,14 @@
+// expect: 1/1/0/
+include rt;
+int calls;
+int seen(int v) { calls++; return v; }
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int r = 1 ? seen(1) : seen(2);
+ pn(r);
+ pn(calls);
+ r = 0 ? seen(5) : 0;
+ pn(calls - 1);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/typeof_print.zc b/tests/conformance/3-expressions/typeof_print.zc
new file mode 100644
index 0000000..b003572
--- /dev/null
+++ b/tests/conformance/3-expressions/typeof_print.zc
@@ -0,0 +1,9 @@
+// expect: int(int, char*)/fixed u8[?]/
+include rt;
+include run;
+fn main() {
+ run.tprint(typeof(int(int, char*))); rt.put_c(10);
+ run.tprint(typeof(fixed u8[?])); rt.put_c(10);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/3-expressions/unary_minus_wraps.zc b/tests/conformance/3-expressions/unary_minus_wraps.zc
new file mode 100644
index 0000000..aba1c47
--- /dev/null
+++ b/tests/conformance/3-expressions/unary_minus_wraps.zc
@@ -0,0 +1,9 @@
+// expect: -9223372036854775808/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 0x7fffffffffffffff;
+ a = a + 1;
+ pn(-a);
+ return 0;
+}
diff --git a/tests/conformance/3-expressions/unary_ops_values.zc b/tests/conformance/3-expressions/unary_ops_values.zc
new file mode 100644
index 0000000..c477efe
--- /dev/null
+++ b/tests/conformance/3-expressions/unary_ops_values.zc
@@ -0,0 +1,8 @@
+// expect: 0/1/-1/-6/5/-5/1/0/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 5, z = 0;
+ pn(!a); pn(!z); pn(~z); pn(~a); pn(-(-a)); pn(-a); pn(!!a); pn(!!z);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/asm_arith_mnemonics.zc b/tests/conformance/4-statements/asm_arith_mnemonics.zc
new file mode 100644
index 0000000..79e06da
--- /dev/null
+++ b/tests/conformance/4-statements/asm_arith_mnemonics.zc
@@ -0,0 +1,11 @@
+// expect: 42/8/14/6/
+// spec 4.13.1: mnemonics * & | ^
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ pn(asm { 6 7 * });
+ pn(asm { 12 10 & });
+ pn(asm { 12 10 | });
+ pn(asm { 12 10 ^ });
+ return 0;
+}
diff --git a/tests/conformance/4-statements/asm_constant_name.zc b/tests/conformance/4-statements/asm_constant_name.zc
new file mode 100644
index 0000000..b27f133
--- /dev/null
+++ b/tests/conformance/4-statements/asm_constant_name.zc
@@ -0,0 +1,6 @@
+// expect: 9/
+// spec 4.13.1: the name of a constant pushes its value
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+const K = 9;
+fn main() { pn(asm { K }); return 0; }
diff --git a/tests/conformance/4-statements/asm_expression_value.zc b/tests/conformance/4-statements/asm_expression_value.zc
new file mode 100644
index 0000000..68e483c
--- /dev/null
+++ b/tests/conformance/4-statements/asm_expression_value.zc
@@ -0,0 +1,5 @@
+// expect: 5/
+// spec 4.13.1 example
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = asm { 2 3 + }; pn(x); return 0; }
diff --git a/tests/conformance/4-statements/asm_float_literal.zc b/tests/conformance/4-statements/asm_float_literal.zc
new file mode 100644
index 0000000..dfb1e23
--- /dev/null
+++ b/tests/conformance/4-statements/asm_float_literal.zc
@@ -0,0 +1,7 @@
+// expect: 1.500000/
+// spec 4.13.1: a float literal emits flit and its bits
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() { float f = asm { 1.5 }; pf(f); return 0; }
+
diff --git a/tests/conformance/4-statements/asm_function_name.zc b/tests/conformance/4-statements/asm_function_name.zc
new file mode 100644
index 0000000..56d8bad
--- /dev/null
+++ b/tests/conformance/4-statements/asm_function_name.zc
@@ -0,0 +1,6 @@
+// expect: 3/
+// spec 4.13.1: a function name pushes its address
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int three() { return 3; }
+fn main() { fn() g = asm { three }; pn(g()); return 0; }
diff --git a/tests/conformance/4-statements/asm_negative_literal.zc b/tests/conformance/4-statements/asm_negative_literal.zc
new file mode 100644
index 0000000..ebd8432
--- /dev/null
+++ b/tests/conformance/4-statements/asm_negative_literal.zc
@@ -0,0 +1,5 @@
+// expect: -2/
+// spec 4.13.1: -n pushes a negative
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = asm { -5 3 + }; pn(x); return 0; }
diff --git a/tests/conformance/4-statements/asm_statement_local.zc b/tests/conformance/4-statements/asm_statement_local.zc
new file mode 100644
index 0000000..9b7e985
--- /dev/null
+++ b/tests/conformance/4-statements/asm_statement_local.zc
@@ -0,0 +1,5 @@
+// expect: 8/
+// spec 4.13.1 example: the name of a local pushes its address
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int y = 7; asm { y @ 1 + y ! } pn(y); return 0; }
diff --git a/tests/conformance/4-statements/asm_string_pushes_address.zc b/tests/conformance/4-statements/asm_string_pushes_address.zc
new file mode 100644
index 0000000..7041996
--- /dev/null
+++ b/tests/conformance/4-statements/asm_string_pushes_address.zc
@@ -0,0 +1,5 @@
+// expect: 104/
+// spec 4.13.1: a string pushes its address
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { char* s = asm { "hi" }; pn(s[0]); return 0; }
diff --git a/tests/conformance/4-statements/asm_unknown_name.zc b/tests/conformance/4-statements/asm_unknown_name.zc
new file mode 100644
index 0000000..f6436a8
--- /dev/null
+++ b/tests/conformance/4-statements/asm_unknown_name.zc
@@ -0,0 +1,5 @@
+// expect error: unknown name in asm
+// spec 4.13.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int x = asm { nosuchthing }; return 0; }
diff --git a/tests/conformance/4-statements/break_inner_loop_only.zc b/tests/conformance/4-statements/break_inner_loop_only.zc
new file mode 100644
index 0000000..47db8ef
--- /dev/null
+++ b/tests/conformance/4-statements/break_inner_loop_only.zc
@@ -0,0 +1,12 @@
+// expect: 6/
+// spec 4.8.1: break leaves the innermost loop
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int n = 0;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 5; j++) { if (j == 2) break; n++; }
+ }
+ pn(n);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/break_outside.zc b/tests/conformance/4-statements/break_outside.zc
new file mode 100644
index 0000000..6662c16
--- /dev/null
+++ b/tests/conformance/4-statements/break_outside.zc
@@ -0,0 +1,5 @@
+// expect error: break outside a loop or a switch
+// spec 4.8.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { break; return 0; }
diff --git a/tests/conformance/4-statements/checked_owned_never_used.zc b/tests/conformance/4-statements/checked_owned_never_used.zc
new file mode 100644
index 0000000..6c89dee
--- /dev/null
+++ b/tests/conformance/4-statements/checked_owned_never_used.zc
@@ -0,0 +1,9 @@
+// expect error: p: owned object is never used
+// spec 6.5.2 (the checked counterpart of unchecked_toplevel_rest_of_unit)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int* p = rt.new(int);
+ pn(1);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/continue_in_switch_outside_loop.zc b/tests/conformance/4-statements/continue_in_switch_outside_loop.zc
new file mode 100644
index 0000000..eaca865
--- /dev/null
+++ b/tests/conformance/4-statements/continue_in_switch_outside_loop.zc
@@ -0,0 +1,5 @@
+// expect error: continue outside a loop
+// spec 4.8.1 and 4.7.1: continue inside a switch continues the enclosing loop, there is none here
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int k = 1; switch (k) { case 1: continue; } return 0; }
diff --git a/tests/conformance/4-statements/continue_outside.zc b/tests/conformance/4-statements/continue_outside.zc
new file mode 100644
index 0000000..7d8e808
--- /dev/null
+++ b/tests/conformance/4-statements/continue_outside.zc
@@ -0,0 +1,5 @@
+// expect error: continue outside a loop
+// spec 4.8.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { continue; return 0; }
diff --git a/tests/conformance/4-statements/decl_const_assign.zc b/tests/conformance/4-statements/decl_const_assign.zc
new file mode 100644
index 0000000..63728dc
--- /dev/null
+++ b/tests/conformance/4-statements/decl_const_assign.zc
@@ -0,0 +1,5 @@
+// expect error: const storage cannot be modified
+// spec 4.1.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { const k = 1; k += 2; return 0; }
diff --git a/tests/conformance/4-statements/decl_const_increment.zc b/tests/conformance/4-statements/decl_const_increment.zc
new file mode 100644
index 0000000..28d7065
--- /dev/null
+++ b/tests/conformance/4-statements/decl_const_increment.zc
@@ -0,0 +1,5 @@
+// expect error: const storage cannot be modified
+// spec 4.1.4 and 2.10.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { const k = 1; k++; return 0; }
diff --git a/tests/conformance/4-statements/decl_const_local_typed_float.zc b/tests/conformance/4-statements/decl_const_local_typed_float.zc
new file mode 100644
index 0000000..d8470ae
--- /dev/null
+++ b/tests/conformance/4-statements/decl_const_local_typed_float.zc
@@ -0,0 +1,6 @@
+// expect: 3.000000/
+// spec 4.1.4: const T k = e is a typed const
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() { const float k = 3; pf(k); return 0; }
diff --git a/tests/conformance/4-statements/decl_const_takes_initializer_type.zc b/tests/conformance/4-statements/decl_const_takes_initializer_type.zc
new file mode 100644
index 0000000..cfe2aec
--- /dev/null
+++ b/tests/conformance/4-statements/decl_const_takes_initializer_type.zc
@@ -0,0 +1,6 @@
+// expect: 0.500000/
+// spec 4.1.4 and 2.10.2: a local const takes the type of its initializer (float here)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() { const k = 1.5; pf(k - 1); return 0; }
diff --git a/tests/conformance/4-statements/decl_for_init_scope.zc b/tests/conformance/4-statements/decl_for_init_scope.zc
new file mode 100644
index 0000000..7d4cae3
--- /dev/null
+++ b/tests/conformance/4-statements/decl_for_init_scope.zc
@@ -0,0 +1,5 @@
+// expect error: i is used but never defined
+// spec 4.1.8: a for initializer declaration is scoped to the loop
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { for (int i = 0; i < 2; i++) { } pn(i); return 0; }
diff --git a/tests/conformance/4-statements/decl_for_let_init_scope.zc b/tests/conformance/4-statements/decl_for_let_init_scope.zc
new file mode 100644
index 0000000..1f94e3b
--- /dev/null
+++ b/tests/conformance/4-statements/decl_for_let_init_scope.zc
@@ -0,0 +1,5 @@
+// expect error: i is used but never defined
+// spec 4.6 and 4.1.8
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { for (let i = 0; i < 2; i++) { } pn(i); return 0; }
diff --git a/tests/conformance/4-statements/decl_let_array.zc b/tests/conformance/4-statements/decl_let_array.zc
new file mode 100644
index 0000000..9d8d701
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_array.zc
@@ -0,0 +1,10 @@
+// expect: 10/3/
+// spec 4.1.2: let a[10]; is an untyped array of 10 words (word[10])
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let a[10];
+ a[9] = 3;
+ pn(sizeof(a)); pn(a[9]);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_let_bstr.zc b/tests/conformance/4-statements/decl_let_bstr.zc
new file mode 100644
index 0000000..c54d0d8
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_bstr.zc
@@ -0,0 +1,9 @@
+// expect: 3/98/
+// spec 4.1.2: bstr from a byte-string literal
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let t = b"abc";
+ pn(len(t)); pn(t[1]);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_let_char_ptr.zc b/tests/conformance/4-statements/decl_let_char_ptr.zc
new file mode 100644
index 0000000..4bc7a57
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_char_ptr.zc
@@ -0,0 +1,9 @@
+// expect: 2/105/
+// spec 4.1.2: char* from a word-string literal
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let s = "hi";
+ pn(rt.len_w(s)); pn(s[1]);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_let_float_local.zc b/tests/conformance/4-statements/decl_let_float_local.zc
new file mode 100644
index 0000000..118e6a9
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_float_local.zc
@@ -0,0 +1,10 @@
+// expect: 0.750000/
+// spec 4.1.2: a float local from a float initializer, so / is float division
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+fn main() {
+ let f = 1.5;
+ pf(f / 2);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_let_function_type.zc b/tests/conformance/4-statements/decl_let_function_type.zc
new file mode 100644
index 0000000..9f9d76d
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_function_type.zc
@@ -0,0 +1,6 @@
+// expect: 7/
+// spec 4.1.2: the function type of the initializer
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int add(int a, int b) { return a + b; }
+fn main() { let h = add; pn(h(3, 4)); return 0; }
diff --git a/tests/conformance/4-statements/decl_let_integer_is_word.zc b/tests/conformance/4-statements/decl_let_integer_is_word.zc
new file mode 100644
index 0000000..8159089
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_integer_is_word.zc
@@ -0,0 +1,5 @@
+// expect: 3/
+// spec 4.1.2: a plain word for integers
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { let n = 3; pn(n); return 0; }
diff --git a/tests/conformance/4-statements/decl_let_multiple.zc b/tests/conformance/4-statements/decl_let_multiple.zc
new file mode 100644
index 0000000..e6ec7d4
--- /dev/null
+++ b/tests/conformance/4-statements/decl_let_multiple.zc
@@ -0,0 +1,10 @@
+// expect: 1/2/
+// spec 4.1.2: let a = e, b[10]
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ let a = 1, b[4];
+ b[3] = 2;
+ pn(a); pn(b[3]);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_redeclare_same_block.zc b/tests/conformance/4-statements/decl_redeclare_same_block.zc
new file mode 100644
index 0000000..e593fb7
--- /dev/null
+++ b/tests/conformance/4-statements/decl_redeclare_same_block.zc
@@ -0,0 +1,5 @@
+// expect: 2/
+// spec 4.1.6: redeclaring a name in the same block is accepted and the new one hides the old one
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 1; int a = 2; pn(a); return 0; }
diff --git a/tests/conformance/4-statements/decl_scope_ends_with_block.zc b/tests/conformance/4-statements/decl_scope_ends_with_block.zc
new file mode 100644
index 0000000..4d868d7
--- /dev/null
+++ b/tests/conformance/4-statements/decl_scope_ends_with_block.zc
@@ -0,0 +1,5 @@
+// expect error: x is used but never defined
+// spec 4.1.8: a local is scoped to its block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { { int x = 1; } pn(x); return 0; }
diff --git a/tests/conformance/4-statements/decl_shadow_function_name.zc b/tests/conformance/4-statements/decl_shadow_function_name.zc
new file mode 100644
index 0000000..b7dcdd4
--- /dev/null
+++ b/tests/conformance/4-statements/decl_shadow_function_name.zc
@@ -0,0 +1,6 @@
+// expect: 5/
+// spec 4.1.6: a local may shadow a function name
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int twice(int x) { return x * 2; }
+fn main() { int twice = 5; pn(twice); return 0; }
diff --git a/tests/conformance/4-statements/decl_shadow_global.zc b/tests/conformance/4-statements/decl_shadow_global.zc
new file mode 100644
index 0000000..279c063
--- /dev/null
+++ b/tests/conformance/4-statements/decl_shadow_global.zc
@@ -0,0 +1,6 @@
+// expect: 2/1/
+// spec 4.1.6: a local may shadow a global
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int g = 1;
+fn main() { int g = 2; pn(g); pn(1); return 0; }
diff --git a/tests/conformance/4-statements/decl_shadow_outer_block.zc b/tests/conformance/4-statements/decl_shadow_outer_block.zc
new file mode 100644
index 0000000..eaf1fca
--- /dev/null
+++ b/tests/conformance/4-statements/decl_shadow_outer_block.zc
@@ -0,0 +1,10 @@
+// expect: 2/1/
+// spec 4.1.6: a local may shadow a local of an outer block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 1;
+ { int a = 2; pn(a); }
+ pn(a);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_shadow_param.zc b/tests/conformance/4-statements/decl_shadow_param.zc
new file mode 100644
index 0000000..9a91f1c
--- /dev/null
+++ b/tests/conformance/4-statements/decl_shadow_param.zc
@@ -0,0 +1,6 @@
+// expect: 9/5/
+// spec 4.1.6: a local may shadow a parameter
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f(int x) { { int x = 9; pn(x); } return x; }
+fn main() { pn(f(5)); return 0; }
diff --git a/tests/conformance/4-statements/decl_tag_only.zc b/tests/conformance/4-statements/decl_tag_only.zc
new file mode 100644
index 0000000..6bd731e
--- /dev/null
+++ b/tests/conformance/4-statements/decl_tag_only.zc
@@ -0,0 +1,10 @@
+// expect: 4/
+// spec 4.1.3: a declaration with only a tag declares an untyped local with that ownership tag
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ .m r = rt.new(2);
+ r[0] = 4;
+ pn(r[0]);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_typed_array_declarator.zc b/tests/conformance/4-statements/decl_typed_array_declarator.zc
new file mode 100644
index 0000000..1b144aa
--- /dev/null
+++ b/tests/conformance/4-statements/decl_typed_array_declarator.zc
@@ -0,0 +1,10 @@
+// expect: 10/
+// spec 4.1.1: a declarator followed by [n] makes an array of n
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a[10];
+ pn(sizeof(a));
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/decl_typed_multi.zc b/tests/conformance/4-statements/decl_typed_multi.zc
new file mode 100644
index 0000000..4dc4d1c
--- /dev/null
+++ b/tests/conformance/4-statements/decl_typed_multi.zc
@@ -0,0 +1,11 @@
+// expect: 8/
+// spec 4.1.1: T a = e, b, c[10];
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 1, b = 2, c[3];
+ c[2] = 5;
+ pn(a + b + c[2]);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/decl_typed_tag_u_hand_up.zc b/tests/conformance/4-statements/decl_typed_tag_u_hand_up.zc
new file mode 100644
index 0000000..7bbf280
--- /dev/null
+++ b/tests/conformance/4-statements/decl_typed_tag_u_hand_up.zc
@@ -0,0 +1,14 @@
+// expect: 3/
+// spec 4.1.1: T*.u declaration; spec 6.3.1 the tag is the initial state
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+.u make() {
+ int*.u p = rt.new(int);
+ *p = 3;
+ return u*p;
+}
+fn main() {
+ int* q = make();
+ pn(*q);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/decl_uninit_global_is_zero.zc b/tests/conformance/4-statements/decl_uninit_global_is_zero.zc
new file mode 100644
index 0000000..6596d18
--- /dev/null
+++ b/tests/conformance/4-statements/decl_uninit_global_is_zero.zc
@@ -0,0 +1,8 @@
+// expect: 0/0/0/
+// spec 4.1.5 and 5.3.1: a global with no initializer is 0
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int g;
+int[4] ga;
+fn main() { pn(g); pn(ga[0]); pn(ga[3]); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/decl_void_variable.zc b/tests/conformance/4-statements/decl_void_variable.zc
new file mode 100644
index 0000000..c9a8d85
--- /dev/null
+++ b/tests/conformance/4-statements/decl_void_variable.zc
@@ -0,0 +1,5 @@
+// expect error: a variable can't be void
+// spec 4.1.7
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { void v = 0; return 0; }
diff --git a/tests/conformance/4-statements/do_basic.zc b/tests/conformance/4-statements/do_basic.zc
new file mode 100644
index 0000000..0194f93
--- /dev/null
+++ b/tests/conformance/4-statements/do_basic.zc
@@ -0,0 +1,11 @@
+// expect: 13/
+// spec 4.5
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int n = 0, i = 0;
+ do { i++; if (i == 2) continue; n = n + i; } while (i < 5);
+ pn(n);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/do_break.zc b/tests/conformance/4-statements/do_break.zc
new file mode 100644
index 0000000..6f27c2e
--- /dev/null
+++ b/tests/conformance/4-statements/do_break.zc
@@ -0,0 +1,6 @@
+// expect: 3/
+// spec 4.8.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int n = 0; do { n++; if (n == 3) break; } while (1); pn(n); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/do_continue_jumps_to_test.zc b/tests/conformance/4-statements/do_continue_jumps_to_test.zc
new file mode 100644
index 0000000..0e5a7d1
--- /dev/null
+++ b/tests/conformance/4-statements/do_continue_jumps_to_test.zc
@@ -0,0 +1,6 @@
+// expect: 1/
+// spec 4.5: continue jumps to the test (the test is false, so the loop ends)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int n = 0; do { n++; continue; n = 99; } while (0); pn(n); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/do_runs_once.zc b/tests/conformance/4-statements/do_runs_once.zc
new file mode 100644
index 0000000..f320337
--- /dev/null
+++ b/tests/conformance/4-statements/do_runs_once.zc
@@ -0,0 +1,6 @@
+// expect: 1/
+// spec 4.5: runs the body, then tests
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int n = 0; do { n++; } while (0); pn(n); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/for_basic.zc b/tests/conformance/4-statements/for_basic.zc
new file mode 100644
index 0000000..97b9d1c
--- /dev/null
+++ b/tests/conformance/4-statements/for_basic.zc
@@ -0,0 +1,5 @@
+// expect: 10/
+// spec 4.6
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int s = 0; for (int i = 1; i <= 4; i++) s += i; pn(s); return 0; }
diff --git a/tests/conformance/4-statements/for_cond_tests_first.zc b/tests/conformance/4-statements/for_cond_tests_first.zc
new file mode 100644
index 0000000..6df4a4f
--- /dev/null
+++ b/tests/conformance/4-statements/for_cond_tests_first.zc
@@ -0,0 +1,5 @@
+// expect: 0/
+// spec 4.6
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int n = 0; for (int i = 5; i < 3; i++) n++; pn(n); return 0; }
diff --git a/tests/conformance/4-statements/for_continue_runs_step.zc b/tests/conformance/4-statements/for_continue_runs_step.zc
new file mode 100644
index 0000000..371dc21
--- /dev/null
+++ b/tests/conformance/4-statements/for_continue_runs_step.zc
@@ -0,0 +1,10 @@
+// expect: 4/
+// spec 4.6 and 4.8.1: continue runs step then tests
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int c = 0;
+ for (int i = 0; i < 4; i++) { c++; continue; c = 99; }
+ pn(c);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/for_empty_parts.zc b/tests/conformance/4-statements/for_empty_parts.zc
new file mode 100644
index 0000000..7212ec6
--- /dev/null
+++ b/tests/conformance/4-statements/for_empty_parts.zc
@@ -0,0 +1,10 @@
+// expect: 3/
+// spec 4.6: init, cond and step may be empty; empty cond means true
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int i = 0;
+ for (;;) { i++; if (i == 3) break; }
+ pn(i);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/for_expression_init.zc b/tests/conformance/4-statements/for_expression_init.zc
new file mode 100644
index 0000000..3cf1093
--- /dev/null
+++ b/tests/conformance/4-statements/for_expression_init.zc
@@ -0,0 +1,5 @@
+// expect: 3/
+// spec 4.6: init may be an expression
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int i; int n = 0; for (i = 0; i < 3; i++) n++; pn(n); return 0; }
diff --git a/tests/conformance/4-statements/for_let_init.zc b/tests/conformance/4-statements/for_let_init.zc
new file mode 100644
index 0000000..6041db1
--- /dev/null
+++ b/tests/conformance/4-statements/for_let_init.zc
@@ -0,0 +1,5 @@
+// expect: 6/
+// spec 4.6: init is a declaration (typed or let)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int s = 0; for (let i = 0; i < 4; i++) s += i; pn(s); return 0; }
diff --git a/tests/conformance/4-statements/for_variable_is_scoped.zc b/tests/conformance/4-statements/for_variable_is_scoped.zc
new file mode 100644
index 0000000..f154684
--- /dev/null
+++ b/tests/conformance/4-statements/for_variable_is_scoped.zc
@@ -0,0 +1,11 @@
+// expect: 100/5/
+// spec 4.6: the loop variable's scope is the loop (an outer i is untouched)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int i = 100;
+ int last = 0;
+ for (int i = 0; i < 6; i++) last = i;
+ pn(i); pn(last);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/hints_forms_accepted.zc b/tests/conformance/4-statements/hints_forms_accepted.zc
new file mode 100644
index 0000000..a07ffd4
--- /dev/null
+++ b/tests/conformance/4-statements/hints_forms_accepted.zc
@@ -0,0 +1,9 @@
+// expect: 1/
+// spec 4.12: hints on, small, off have no effect on a normal run
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+hints on;
+hints small;
+hints off;
+fn main() { hints on; pn(1); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/if_basic.zc b/tests/conformance/4-statements/if_basic.zc
new file mode 100644
index 0000000..31cd9e1
--- /dev/null
+++ b/tests/conformance/4-statements/if_basic.zc
@@ -0,0 +1,10 @@
+// expect: 1/0/2/
+// spec 4.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ if (5) pn(1); else pn(9);
+ if (0) pn(9); else pn(0);
+ if (-3) pn(2);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/if_branch_is_own_scope.zc b/tests/conformance/4-statements/if_branch_is_own_scope.zc
new file mode 100644
index 0000000..d4f82ea
--- /dev/null
+++ b/tests/conformance/4-statements/if_branch_is_own_scope.zc
@@ -0,0 +1,5 @@
+// expect error: q is used but never defined
+// spec 4.3: each branch is its own block even without braces
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { if (1) int q = 5; pn(q); return 0; }
diff --git a/tests/conformance/4-statements/if_else_binds_nearest.zc b/tests/conformance/4-statements/if_else_binds_nearest.zc
new file mode 100644
index 0000000..0c9f235
--- /dev/null
+++ b/tests/conformance/4-statements/if_else_binds_nearest.zc
@@ -0,0 +1,8 @@
+// expect: 2/
+// spec 4.3: else binds to the nearest if
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ if (1) if (0) pn(1); else pn(2);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/if_else_binds_nearest_outer_not_taken.zc b/tests/conformance/4-statements/if_else_binds_nearest_outer_not_taken.zc
new file mode 100644
index 0000000..8549864
--- /dev/null
+++ b/tests/conformance/4-statements/if_else_binds_nearest_outer_not_taken.zc
@@ -0,0 +1,8 @@
+// expect:
+// spec 4.3: else binds to the nearest if, so nothing prints when the outer condition is false
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ if (0) if (0) pn(1); else pn(2);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/if_else_chain.zc b/tests/conformance/4-statements/if_else_chain.zc
new file mode 100644
index 0000000..292a3b0
--- /dev/null
+++ b/tests/conformance/4-statements/if_else_chain.zc
@@ -0,0 +1,9 @@
+// expect: 3/
+// spec 4.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int n = 7;
+ if (n < 3) pn(1); else if (n < 6) pn(2); else if (n < 9) pn(3); else pn(4);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/if_float_condition.zc b/tests/conformance/4-statements/if_float_condition.zc
new file mode 100644
index 0000000..02a988c
--- /dev/null
+++ b/tests/conformance/4-statements/if_float_condition.zc
@@ -0,0 +1,11 @@
+// expect: 0/1/1/
+// spec 4.3: a float is false when +0.0 or -0.0
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ float z = 0.0, h = 0.5, n = 0.0 - 3.0;
+ if (z) pn(9); else pn(0);
+ if (h) pn(1); else pn(9);
+ if (n) pn(1); else pn(9);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/memdebug_double_free.zc b/tests/conformance/4-statements/memdebug_double_free.zc
new file mode 100644
index 0000000..ff91511
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_double_free.zc
@@ -0,0 +1,10 @@
+// expect error: zy: double free from line
+// spec 4.11
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug on;
+fn main() {
+ unchecked { int* p = rt.new(int); rt.free(p); rt.free(p); }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_off.zc b/tests/conformance/4-statements/memdebug_off.zc
new file mode 100644
index 0000000..27de549
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_off.zc
@@ -0,0 +1,8 @@
+// expect: 1/
+// spec 4.11: memdebug off; stops the checks
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug on;
+memdebug off;
+fn main() { unchecked { int* p = rt.new(int); rt.free(p); rt.free(p); } pn(1); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_report.zc b/tests/conformance/4-statements/memdebug_report.zc
new file mode 100644
index 0000000..db81c6d
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_report.zc
@@ -0,0 +1,15 @@
+// expect: 1/
+// spec 4.11: rt.memreport() returns the count of live recorded objects
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug on;
+fn main() {
+ unchecked {
+ int* q = rt.new(3);
+ int* r = rt.new(2);
+ rt.free(r);
+ pn(rt.memreport());
+ }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_report_line.zc b/tests/conformance/4-statements/memdebug_report_line.zc
new file mode 100644
index 0000000..8ab4273
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_report_line.zc
@@ -0,0 +1,15 @@
+// expect error: leak: line 8
+// spec 4.11: leak: line N W words per live recorded object (N is the allocation line)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug on;
+fn main() {
+ unchecked {
+ int* q = rt.new(3);
+ int* r = rt.new(2);
+ rt.free(q);
+ rt.memreport();
+ }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_scrub_accepted.zc b/tests/conformance/4-statements/memdebug_scrub_accepted.zc
new file mode 100644
index 0000000..5253918
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_scrub_accepted.zc
@@ -0,0 +1,7 @@
+// expect: 1/
+// spec 4.11: memdebug scrub; is a form of the statement
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug scrub;
+fn main() { pn(1); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_scrub_fills.zc b/tests/conformance/4-statements/memdebug_scrub_fills.zc
new file mode 100644
index 0000000..ad15e3d
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_scrub_fills.zc
@@ -0,0 +1,10 @@
+// expect: 57005/
+// spec 4.11: memdebug scrub; fills freed payloads with 57005
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug scrub;
+fn main() {
+ unchecked { int* p = rt.new(int); *p = 5; rt.free(p); pn(*p); }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_statement_form.zc b/tests/conformance/4-statements/memdebug_statement_form.zc
new file mode 100644
index 0000000..e9273b1
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_statement_form.zc
@@ -0,0 +1,6 @@
+// expect: 1/
+// spec 4.11: memdebug is also a statement in a function
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { memdebug on; int* p = rt.new(int); rt.free(p); pn(1); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/memdebug_use_after_free.zc b/tests/conformance/4-statements/memdebug_use_after_free.zc
new file mode 100644
index 0000000..434aa5a
--- /dev/null
+++ b/tests/conformance/4-statements/memdebug_use_after_free.zc
@@ -0,0 +1,10 @@
+// expect error: zy: use after free from line
+// spec 4.11
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+memdebug on;
+fn main() {
+ unchecked { int* p = rt.new(int); *p = 5; rt.free(p); pn(*p); }
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/nested_return_in_loop.zc b/tests/conformance/4-statements/nested_return_in_loop.zc
new file mode 100644
index 0000000..ba246fb
--- /dev/null
+++ b/tests/conformance/4-statements/nested_return_in_loop.zc
@@ -0,0 +1,9 @@
+// expect: 3/
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int find(int want) {
+ for (int i = 0; i < 10; i++) { if (i == want) return i; }
+ return -1;
+}
+fn main() { pn(find(3)); return 0; }
+
diff --git a/tests/conformance/4-statements/o3_asm_cannot_reach.zc b/tests/conformance/4-statements/o3_asm_cannot_reach.zc
new file mode 100644
index 0000000..4150742
--- /dev/null
+++ b/tests/conformance/4-statements/o3_asm_cannot_reach.zc
@@ -0,0 +1,6 @@
+// expect error: asm can't reach an o3 variable
+// spec 4.10.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { o3 { int x = 1; asm { x @ } } return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_block.zc b/tests/conformance/4-statements/o3_block.zc
new file mode 100644
index 0000000..3291152
--- /dev/null
+++ b/tests/conformance/4-statements/o3_block.zc
@@ -0,0 +1,11 @@
+// expect: 45/
+// spec 4.10.1: o3 { } marks a block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int t = 0;
+ o3 { int s = 0; for (int i = 0; i < 10; i++) s += i; t = s; }
+ pn(t);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_fn_form.zc b/tests/conformance/4-statements/o3_fn_form.zc
new file mode 100644
index 0000000..30cfc6b
--- /dev/null
+++ b/tests/conformance/4-statements/o3_fn_form.zc
@@ -0,0 +1,7 @@
+// expect: 6/
+// spec 4.10.1: o3 fn f(...)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+o3 fn triple(int a) { return a * 3; }
+fn main() { pn(triple(2)); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_function_sum.zc b/tests/conformance/4-statements/o3_function_sum.zc
new file mode 100644
index 0000000..37b3ef4
--- /dev/null
+++ b/tests/conformance/4-statements/o3_function_sum.zc
@@ -0,0 +1,13 @@
+// expect: 10/
+// spec 4.10.1 example: o3 changes speed, not meaning
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+o3 int sum(fixed int[?] a) { int s = 0; for (int i = 0; i < len(a); i++) s += a[i]; return s; }
+fn main() {
+ fixed int[?] a = rt.new(fixed int[?], 4);
+ for (int i = 0; i < 4; i++) a[i] = i + 1;
+ pn(sum(a));
+ rt.free(a);
+ return 0;
+}
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_nested_is_ordinary_block.zc b/tests/conformance/4-statements/o3_nested_is_ordinary_block.zc
new file mode 100644
index 0000000..4d2306d
--- /dev/null
+++ b/tests/conformance/4-statements/o3_nested_is_ordinary_block.zc
@@ -0,0 +1,6 @@
+// expect: 2/
+// spec 4.10.2: a nested o3 is an ordinary block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { o3 { int a = 1; o3 { int b = a + 1; pn(b); } } return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_no_address_of.zc b/tests/conformance/4-statements/o3_no_address_of.zc
new file mode 100644
index 0000000..47cad16
--- /dev/null
+++ b/tests/conformance/4-statements/o3_no_address_of.zc
@@ -0,0 +1,6 @@
+// expect error: an o3 variable has no address
+// spec 4.10.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { o3 { int x = 1; int* p = &x; } return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_outside_function_ordinary_block.zc b/tests/conformance/4-statements/o3_outside_function_ordinary_block.zc
new file mode 100644
index 0000000..7fe3f09
--- /dev/null
+++ b/tests/conformance/4-statements/o3_outside_function_ordinary_block.zc
@@ -0,0 +1,7 @@
+// expect: 1/
+// spec 4.10.2: an o3 { } outside a function is an ordinary block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+o3 { }
+fn main() { pn(1); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_parameter_needs_type.zc b/tests/conformance/4-statements/o3_parameter_needs_type.zc
new file mode 100644
index 0000000..37384be
--- /dev/null
+++ b/tests/conformance/4-statements/o3_parameter_needs_type.zc
@@ -0,0 +1,7 @@
+// expect error: o3 parameters need a type
+// spec 4.10.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+o3 fn f(a) { return a; }
+fn main() { return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_single_variable.zc b/tests/conformance/4-statements/o3_single_variable.zc
new file mode 100644
index 0000000..3deca8d
--- /dev/null
+++ b/tests/conformance/4-statements/o3_single_variable.zc
@@ -0,0 +1,6 @@
+// expect: 7/
+// spec 4.10.1: o3 T x = e; marks one variable
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { o3 int x = 7; pn(x); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/o3_variable_needs_type.zc b/tests/conformance/4-statements/o3_variable_needs_type.zc
new file mode 100644
index 0000000..0741302
--- /dev/null
+++ b/tests/conformance/4-statements/o3_variable_needs_type.zc
@@ -0,0 +1,6 @@
+// expect error: o3 variables need a type
+// spec 4.10.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { o3 { let x = 1; pn(x); } return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/return_bare_is_zero.zc b/tests/conformance/4-statements/return_bare_is_zero.zc
new file mode 100644
index 0000000..deb9235
--- /dev/null
+++ b/tests/conformance/4-statements/return_bare_is_zero.zc
@@ -0,0 +1,6 @@
+// expect: 0/
+// spec 4.8.2: return; returns 0
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int g() { return; }
+fn main() { pn(g()); return 0; }
diff --git a/tests/conformance/4-statements/return_fall_off_is_zero.zc b/tests/conformance/4-statements/return_fall_off_is_zero.zc
new file mode 100644
index 0000000..e0d1229
--- /dev/null
+++ b/tests/conformance/4-statements/return_fall_off_is_zero.zc
@@ -0,0 +1,6 @@
+// expect: 0/
+// spec 4.8.2: falling off the end returns 0
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int g() { int a = 1; a++; }
+fn main() { pn(g()); return 0; }
diff --git a/tests/conformance/4-statements/return_frees_owned_locals.zc b/tests/conformance/4-statements/return_frees_owned_locals.zc
new file mode 100644
index 0000000..ccff11c
--- /dev/null
+++ b/tests/conformance/4-statements/return_frees_owned_locals.zc
@@ -0,0 +1,11 @@
+// expect: 5/
+// spec 4.8.2 and 6.5.1: return frees every owned local of the scopes it leaves
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f(int n) {
+ int* p = rt.new(int);
+ *p = n;
+ if (n > 1) return *p;
+ return 0;
+}
+fn main() { pn(f(5)); return 0; }
diff --git a/tests/conformance/4-statements/return_outside_function.zc b/tests/conformance/4-statements/return_outside_function.zc
new file mode 100644
index 0000000..82e8f35
--- /dev/null
+++ b/tests/conformance/4-statements/return_outside_function.zc
@@ -0,0 +1,6 @@
+// expect error: zc: line 5:
+// spec 4.8.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+return 1;
+fn main() { return 0; }
diff --git a/tests/conformance/4-statements/return_value_converted_float.zc b/tests/conformance/4-statements/return_value_converted_float.zc
new file mode 100644
index 0000000..43248e1
--- /dev/null
+++ b/tests/conformance/4-statements/return_value_converted_float.zc
@@ -0,0 +1,7 @@
+// expect: 2.000000/
+// spec 4.8.2: converted to the result type
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn pf(x) { asm { x @ #1220 } rt.put_c(10); return 0; }
+float g() { return 2; }
+fn main() { pf(g()); return 0; }
diff --git a/tests/conformance/4-statements/return_value_converted_int.zc b/tests/conformance/4-statements/return_value_converted_int.zc
new file mode 100644
index 0000000..346c67b
--- /dev/null
+++ b/tests/conformance/4-statements/return_value_converted_int.zc
@@ -0,0 +1,6 @@
+// expect: -2/
+// spec 4.8.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int g() { return -2.7; }
+fn main() { pn(g()); return 0; }
diff --git a/tests/conformance/4-statements/return_void_value_typecheck_on.zc b/tests/conformance/4-statements/return_void_value_typecheck_on.zc
new file mode 100644
index 0000000..a1d35ef
--- /dev/null
+++ b/tests/conformance/4-statements/return_void_value_typecheck_on.zc
@@ -0,0 +1,7 @@
+// expect error: type error: return value: expected void, got int
+// spec 4.8.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+typecheck on;
+void f() { return 4; }
+fn main() { f(); return 0; }
diff --git a/tests/conformance/4-statements/stmt_block_scope.zc b/tests/conformance/4-statements/stmt_block_scope.zc
new file mode 100644
index 0000000..3b6fd6e
--- /dev/null
+++ b/tests/conformance/4-statements/stmt_block_scope.zc
@@ -0,0 +1,5 @@
+// expect: 3/1/
+// spec 4.2: { ... } is a block with its own scope
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 1; { int a = 3; pn(a); } pn(a); return 0; }
diff --git a/tests/conformance/4-statements/stmt_empty_statement.zc b/tests/conformance/4-statements/stmt_empty_statement.zc
new file mode 100644
index 0000000..520a451
--- /dev/null
+++ b/tests/conformance/4-statements/stmt_empty_statement.zc
@@ -0,0 +1,5 @@
+// expect: 1/
+// spec 4.2: ; alone is empty
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { ;;; pn(1); ; return 0; }
diff --git a/tests/conformance/4-statements/stmt_expression_value_dropped.zc b/tests/conformance/4-statements/stmt_expression_value_dropped.zc
new file mode 100644
index 0000000..b69ccaf
--- /dev/null
+++ b/tests/conformance/4-statements/stmt_expression_value_dropped.zc
@@ -0,0 +1,5 @@
+// expect: 2/
+// spec 4.2: the value of an expression statement is dropped
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int a = 1; a + 5; a = a + 1; 7; pn(a); return 0; }
diff --git a/tests/conformance/4-statements/stmt_fresh_value_thrown_away.zc b/tests/conformance/4-statements/stmt_fresh_value_thrown_away.zc
new file mode 100644
index 0000000..999f8c0
--- /dev/null
+++ b/tests/conformance/4-statements/stmt_fresh_value_thrown_away.zc
@@ -0,0 +1,5 @@
+// expect error: a new object (or a u result) can't be thrown away
+// spec 4.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { rt.new(int); return 0; }
diff --git a/tests/conformance/4-statements/stmt_u_result_thrown_away.zc b/tests/conformance/4-statements/stmt_u_result_thrown_away.zc
new file mode 100644
index 0000000..834dd96
--- /dev/null
+++ b/tests/conformance/4-statements/stmt_u_result_thrown_away.zc
@@ -0,0 +1,6 @@
+// expect error: a new object (or a u result) can't be thrown away
+// spec 4.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int*.u mk() { int*.u p = rt.new(int); return u*p; }
+fn main() { mk(); return 0; }
diff --git a/tests/conformance/4-statements/switch_break_in_loop_leaves_switch_only.zc b/tests/conformance/4-statements/switch_break_in_loop_leaves_switch_only.zc
new file mode 100644
index 0000000..d69b64a
--- /dev/null
+++ b/tests/conformance/4-statements/switch_break_in_loop_leaves_switch_only.zc
@@ -0,0 +1,13 @@
+// expect: 3/
+// spec 4.7.1: break in a switch inside a loop leaves the switch, not the loop
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int n = 0;
+ for (int i = 0; i < 3; i++) {
+ switch (i) { case 1: break; default: n++; }
+ n++;
+ }
+ pn(n);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_break_leaves_early.zc b/tests/conformance/4-statements/switch_break_leaves_early.zc
new file mode 100644
index 0000000..8adbe64
--- /dev/null
+++ b/tests/conformance/4-statements/switch_break_leaves_early.zc
@@ -0,0 +1,10 @@
+// expect: 1/9/
+// spec 4.7.1: break inside a switch leaves it early
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int k = 1;
+ switch (k) { case 1: pn(1); break; pn(2); }
+ pn(9);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_case_own_block.zc b/tests/conformance/4-statements/switch_case_own_block.zc
new file mode 100644
index 0000000..16bc31f
--- /dev/null
+++ b/tests/conformance/4-statements/switch_case_own_block.zc
@@ -0,0 +1,11 @@
+// expect: 5/6/
+// spec 4.7.2: the statements of a case form their own block
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void t(int k) {
+ switch (k) {
+ case 1: int x = 5; pn(x);
+ case 2: int x = 6; pn(x);
+ }
+}
+fn main() { t(1); t(2); return 0; }
diff --git a/tests/conformance/4-statements/switch_case_three.zc b/tests/conformance/4-statements/switch_case_three.zc
new file mode 100644
index 0000000..eefaced
--- /dev/null
+++ b/tests/conformance/4-statements/switch_case_three.zc
@@ -0,0 +1,10 @@
+// expect: three/
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 3;
+ switch (k) { case 1, 2: ps("one-two"); case 3: ps("three"); break; default: ps("d"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_case_underscore.zc b/tests/conformance/4-statements/switch_case_underscore.zc
new file mode 100644
index 0000000..4d05f8e
--- /dev/null
+++ b/tests/conformance/4-statements/switch_case_underscore.zc
@@ -0,0 +1,7 @@
+// expect: d/one/
+// spec 4.7.1: case _ is a catch-all with the same meaning as default
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+void t(int k) { switch (k) { case 1: ps("one"); case _: ps("d"); } }
+fn main() { t(8); t(1); return 0; }
diff --git a/tests/conformance/4-statements/switch_continue_continues_loop.zc b/tests/conformance/4-statements/switch_continue_continues_loop.zc
new file mode 100644
index 0000000..d408253
--- /dev/null
+++ b/tests/conformance/4-statements/switch_continue_continues_loop.zc
@@ -0,0 +1,10 @@
+// expect: 1/3/4/
+// spec 4.7.1: continue inside a switch continues the enclosing loop
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ for (int i = 1; i <= 4; i++) {
+ switch (i) { case 2: continue; default: pn(i); }
+ }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_default_and_underscore.zc b/tests/conformance/4-statements/switch_default_and_underscore.zc
new file mode 100644
index 0000000..92c9025
--- /dev/null
+++ b/tests/conformance/4-statements/switch_default_and_underscore.zc
@@ -0,0 +1,5 @@
+// expect error: a switch has one
+// spec 4.7.1: default and _ are the same thing, so a switch can have only one of them
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int k = 1; switch (k) { default: pn(1); case _: pn(2); } return 0; }
diff --git a/tests/conformance/4-statements/switch_default_first_position_not_matched.zc b/tests/conformance/4-statements/switch_default_first_position_not_matched.zc
new file mode 100644
index 0000000..4d63ae3
--- /dev/null
+++ b/tests/conformance/4-statements/switch_default_first_position_not_matched.zc
@@ -0,0 +1,10 @@
+// expect: one/
+// spec 4.7.1: default runs when no label matches, wherever it is written
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 1;
+ switch (k) { default: ps("d"); case 1: ps("one"); case 2: ps("two"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_default_first_position_taken.zc b/tests/conformance/4-statements/switch_default_first_position_taken.zc
new file mode 100644
index 0000000..113795f
--- /dev/null
+++ b/tests/conformance/4-statements/switch_default_first_position_taken.zc
@@ -0,0 +1,10 @@
+// expect: d/
+// spec 4.7.1: default runs when no label matches, wherever it is written
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 7;
+ switch (k) { default: ps("d"); case 1: ps("one"); case 2: ps("two"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_default_middle.zc b/tests/conformance/4-statements/switch_default_middle.zc
new file mode 100644
index 0000000..a390efe
--- /dev/null
+++ b/tests/conformance/4-statements/switch_default_middle.zc
@@ -0,0 +1,7 @@
+// expect: d/two/
+// spec 4.7.1: default in the middle
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+void t(int k) { switch (k) { case 1: ps("one"); default: ps("d"); case 2: ps("two"); } }
+fn main() { t(5); t(2); return 0; }
diff --git a/tests/conformance/4-statements/switch_default_runs.zc b/tests/conformance/4-statements/switch_default_runs.zc
new file mode 100644
index 0000000..bc42976
--- /dev/null
+++ b/tests/conformance/4-statements/switch_default_runs.zc
@@ -0,0 +1,10 @@
+// expect: d/
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 9;
+ switch (k) { case 1, 2: ps("one-two"); case 3: ps("three"); break; default: ps("d"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_duplicate_labels_first_wins.zc b/tests/conformance/4-statements/switch_duplicate_labels_first_wins.zc
new file mode 100644
index 0000000..e2a2e3b
--- /dev/null
+++ b/tests/conformance/4-statements/switch_duplicate_labels_first_wins.zc
@@ -0,0 +1,10 @@
+// expect: first/
+// spec 4.7.2: duplicate labels are not an error, the first matching case in source order runs
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 4;
+ switch (k) { case 4: ps("first"); case 4: ps("second"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_expression_evaluated_once.zc b/tests/conformance/4-statements/switch_expression_evaluated_once.zc
new file mode 100644
index 0000000..bf82b99
--- /dev/null
+++ b/tests/conformance/4-statements/switch_expression_evaluated_once.zc
@@ -0,0 +1,10 @@
+// expect: 1/hit/
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int i = 0;
+ switch (i++) { case 5: pn(5); case 6: pn(6); case 0: rt.put_s("hit"); }
+ pn(i);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_label_forms.zc b/tests/conformance/4-statements/switch_label_forms.zc
new file mode 100644
index 0000000..ae131aa
--- /dev/null
+++ b/tests/conformance/4-statements/switch_label_forms.zc
@@ -0,0 +1,16 @@
+// expect: neg/chr/sum/enum/
+// spec 4.7.1 and 3.14: labels are constant expressions
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum color { RED, GREEN };
+void t(int k) {
+ switch (k) {
+ case -1: rt.put_s("neg");
+ case 'a': rt.put_s("chr");
+ case 1 + 1 * 3: rt.put_s("sum");
+ case color.GREEN: rt.put_s("enum");
+ }
+ rt.put_c(10);
+}
+fn main() { t(-1); pn(0); return 0; }
+// zc0: skip
diff --git a/tests/conformance/4-statements/switch_nested.zc b/tests/conformance/4-statements/switch_nested.zc
new file mode 100644
index 0000000..7fd9a34
--- /dev/null
+++ b/tests/conformance/4-statements/switch_nested.zc
@@ -0,0 +1,14 @@
+// expect: in2/
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int a = 1, b = 2;
+ switch (a) {
+ case 1:
+ switch (b) { case 1: ps("in1"); break; case 2: ps("in2"); break; }
+ case 2: ps("outer2");
+ }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_no_fallthrough_k2.zc b/tests/conformance/4-statements/switch_no_fallthrough_k2.zc
new file mode 100644
index 0000000..276ca30
--- /dev/null
+++ b/tests/conformance/4-statements/switch_no_fallthrough_k2.zc
@@ -0,0 +1,10 @@
+// expect: one-two/
+// spec 4.7.1: cases do not fall through
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 2;
+ switch (k) { case 1, 2: ps("one-two"); case 3: ps("three"); break; default: ps("d"); }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_no_match_no_default.zc b/tests/conformance/4-statements/switch_no_match_no_default.zc
new file mode 100644
index 0000000..3021388
--- /dev/null
+++ b/tests/conformance/4-statements/switch_no_match_no_default.zc
@@ -0,0 +1,11 @@
+// expect: after/
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+void ps(char* s) { rt.put_s(s); rt.put_c(10); }
+fn main() {
+ int k = 5;
+ switch (k) { case 1: ps("one"); case 2: ps("two"); }
+ ps("after");
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_non_constant_label.zc b/tests/conformance/4-statements/switch_non_constant_label.zc
new file mode 100644
index 0000000..dc42b5b
--- /dev/null
+++ b/tests/conformance/4-statements/switch_non_constant_label.zc
@@ -0,0 +1,5 @@
+// expect error: expected a constant
+// spec 4.7.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int k = 1, j = 2; switch (k) { case j: pn(1); } return 0; }
diff --git a/tests/conformance/4-statements/switch_return_inside_case.zc b/tests/conformance/4-statements/switch_return_inside_case.zc
new file mode 100644
index 0000000..7375e79
--- /dev/null
+++ b/tests/conformance/4-statements/switch_return_inside_case.zc
@@ -0,0 +1,6 @@
+// expect: 20/10/
+// spec 4.7.1 and 4.8.2
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f(int k) { switch (k) { case 1: return 10; case 2: return 20; } return 0; }
+fn main() { pn(f(2)); pn(f(1)); return 0; }
diff --git a/tests/conformance/4-statements/switch_tagged_all_covered_no_warning.zc b/tests/conformance/4-statements/switch_tagged_all_covered_no_warning.zc
new file mode 100644
index 0000000..45a9846
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_all_covered_no_warning.zc
@@ -0,0 +1,11 @@
+// expect: 2/
+// spec 4.7.3: no warning when every member is covered
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum e { a { int v; }, b };
+fn main() {
+ e* s = e.a(2);
+ switch (s) { case a(v): pn(v); case b: pn(0); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_binding_count.zc b/tests/conformance/4-statements/switch_tagged_binding_count.zc
new file mode 100644
index 0000000..08006a6
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_binding_count.zc
@@ -0,0 +1,11 @@
+// expect error: a case binds every field of its member
+// spec 4.7.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.rect(1, 2);
+ switch (s) { case rect(w): pn(w); default: pn(0); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_binding_scoped_to_case.zc b/tests/conformance/4-statements/switch_tagged_binding_scoped_to_case.zc
new file mode 100644
index 0000000..ed8ee03
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_binding_scoped_to_case.zc
@@ -0,0 +1,12 @@
+// expect error: w is used but never defined
+// spec 4.7.3: each payload field is bound to a new local scoped to that case
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.rect(1, 2);
+ switch (s) { case rect(w, h): pn(w); default: pn(0); }
+ pn(w);
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_circle.zc b/tests/conformance/4-statements/switch_tagged_circle.zc
new file mode 100644
index 0000000..b1b1c55
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_circle.zc
@@ -0,0 +1,11 @@
+// expect: 7/
+// spec 4.7.3
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.circle(7);
+ switch (s) { case circle(r): pn(r); case rect(w, h): pn(w * h); case dot: rt.put_s("dot"); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_default_no_warning.zc b/tests/conformance/4-statements/switch_tagged_default_no_warning.zc
new file mode 100644
index 0000000..0a22a7a
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_default_no_warning.zc
@@ -0,0 +1,11 @@
+// expect: 1/
+// spec 4.7.3: no warning when there is a default
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.circle(1);
+ switch (s) { case circle(r): pn(r); default: pn(0); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_example.zc b/tests/conformance/4-statements/switch_tagged_example.zc
new file mode 100644
index 0000000..932aefc
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_example.zc
@@ -0,0 +1,11 @@
+// expect: 20/
+// spec 4.7.3 example: prints 20
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.rect(4, 5);
+ switch (s) { case circle(r): pn(r); case rect(w, h): pn(w * h); case dot: rt.put_s("dot"); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_match_by_tag.zc b/tests/conformance/4-statements/switch_tagged_match_by_tag.zc
new file mode 100644
index 0000000..9d2f7a1
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_match_by_tag.zc
@@ -0,0 +1,19 @@
+// expect: dot/dot2/
+// spec 4.7.3: case member: or case member(): matches by tag
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+void t(shape* s) {
+ switch (s) { case circle: rt.put_s("circle"); case rect(): rt.put_s("rect"); case dot: rt.put_s("dot"); }
+ rt.put_c(10);
+}
+void u(shape* s) {
+ switch (s) { case circle: rt.put_s("circle"); case rect: rt.put_s("rect"); case dot(): rt.put_s("dot2"); }
+ rt.put_c(10);
+}
+fn main() {
+ shape* a = shape.dot();
+ t(a); u(a);
+ rt.free(a);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_uncovered_warning.zc b/tests/conformance/4-statements/switch_tagged_uncovered_warning.zc
new file mode 100644
index 0000000..d567da5
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_uncovered_warning.zc
@@ -0,0 +1,11 @@
+// expect error: warning: this switch doesn't cover rect, dot
+// spec 4.7.3: a switch on a tagged enum with no default that omits a member prints a warning
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.circle(1);
+ switch (s) { case circle(r): pn(r); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_tagged_uncovered_warning_not_error.zc b/tests/conformance/4-statements/switch_tagged_uncovered_warning_not_error.zc
new file mode 100644
index 0000000..dfacc9c
--- /dev/null
+++ b/tests/conformance/4-statements/switch_tagged_uncovered_warning_not_error.zc
@@ -0,0 +1,11 @@
+// expect: zc: line 8: warning: this switch doesn't cover rect, dot/1/
+// spec 4.7.3 and 6.14: the warning is not an error, the program runs
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+fn main() {
+ shape* s = shape.circle(1);
+ switch (s) { case circle(r): pn(r); }
+ rt.free(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/switch_two_defaults.zc b/tests/conformance/4-statements/switch_two_defaults.zc
new file mode 100644
index 0000000..e1f4f90
--- /dev/null
+++ b/tests/conformance/4-statements/switch_two_defaults.zc
@@ -0,0 +1,5 @@
+// expect error: a switch has one default
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int k = 1; switch (k) { default: pn(1); default: pn(2); } return 0; }
diff --git a/tests/conformance/4-statements/switch_two_underscores.zc b/tests/conformance/4-statements/switch_two_underscores.zc
new file mode 100644
index 0000000..afc5f2b
--- /dev/null
+++ b/tests/conformance/4-statements/switch_two_underscores.zc
@@ -0,0 +1,5 @@
+// expect error: a switch has one catch-all case
+// spec 4.7.1
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int k = 1; switch (k) { case _: pn(1); case _: pn(2); } return 0; }
diff --git a/tests/conformance/4-statements/unchecked_fn.zc b/tests/conformance/4-statements/unchecked_fn.zc
new file mode 100644
index 0000000..fa2055e
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_fn.zc
@@ -0,0 +1,6 @@
+// expect: 1/
+// spec 4.9: unchecked fn makes one function unchecked
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+unchecked fn leaky() { int* p = rt.new(int); return 0; }
+fn main() { leaky(); pn(1); return 0; }
diff --git a/tests/conformance/4-statements/unchecked_fn_does_not_extend.zc b/tests/conformance/4-statements/unchecked_fn_does_not_extend.zc
new file mode 100644
index 0000000..e93a582
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_fn_does_not_extend.zc
@@ -0,0 +1,6 @@
+// expect error: q: owned object is never used
+// spec 4.9: only that function is unchecked
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+unchecked fn leaky() { int* p = rt.new(int); return 0; }
+fn main() { int* q = rt.new(int); leaky(); return 0; }
diff --git a/tests/conformance/4-statements/unchecked_stmt_block.zc b/tests/conformance/4-statements/unchecked_stmt_block.zc
new file mode 100644
index 0000000..eca1a38
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_stmt_block.zc
@@ -0,0 +1,9 @@
+// expect: ok/
+// spec 4.9 and 8.3: in unchecked code a second free of an object is ignored
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ unchecked { int* p = rt.new(int); rt.free(p); rt.free(p); }
+ rt.put_s("ok"); rt.put_c(10);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/unchecked_stmt_single.zc b/tests/conformance/4-statements/unchecked_stmt_single.zc
new file mode 100644
index 0000000..2bdccb1
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_stmt_single.zc
@@ -0,0 +1,10 @@
+// expect: 3/
+// spec 4.9: unchecked stmt
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int a = 1;
+ unchecked a = a + 2;
+ pn(a);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/unchecked_toplevel_rest_of_unit.zc b/tests/conformance/4-statements/unchecked_toplevel_rest_of_unit.zc
new file mode 100644
index 0000000..439eca7
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_toplevel_rest_of_unit.zc
@@ -0,0 +1,10 @@
+// expect: 1/
+// spec 4.9: unchecked; at top level switches the analyzer off for the rest of the unit
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+unchecked;
+fn main() {
+ int* p = rt.new(int);
+ pn(1);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/unchecked_tracked_local_rejected.zc b/tests/conformance/4-statements/unchecked_tracked_local_rejected.zc
new file mode 100644
index 0000000..a5f0d6d
--- /dev/null
+++ b/tests/conformance/4-statements/unchecked_tracked_local_rejected.zc
@@ -0,0 +1,9 @@
+// expect error: p: is tracked by the analyzer and can't be used in unchecked code
+// spec 4.9
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int* p = rt.new(int);
+ unchecked { *p = 2; }
+ return 0;
+}
diff --git a/tests/conformance/4-statements/while_basic.zc b/tests/conformance/4-statements/while_basic.zc
new file mode 100644
index 0000000..05fa171
--- /dev/null
+++ b/tests/conformance/4-statements/while_basic.zc
@@ -0,0 +1,5 @@
+// expect: 10/
+// spec 4.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int i = 0, s = 0; while (i < 5) { i++; s += i; } pn(s - 5); return 0; }
diff --git a/tests/conformance/4-statements/while_continue.zc b/tests/conformance/4-statements/while_continue.zc
new file mode 100644
index 0000000..28c32b0
--- /dev/null
+++ b/tests/conformance/4-statements/while_continue.zc
@@ -0,0 +1,10 @@
+// expect: 25/
+// spec 4.8.1: continue goes to the next iteration of a while (the test)
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() {
+ int i = 0, s = 0;
+ while (i < 10) { i++; if (i % 2 == 0) continue; s += i; }
+ pn(s);
+ return 0;
+}
diff --git a/tests/conformance/4-statements/while_one_exit_by_return.zc b/tests/conformance/4-statements/while_one_exit_by_return.zc
new file mode 100644
index 0000000..6e71d2f
--- /dev/null
+++ b/tests/conformance/4-statements/while_one_exit_by_return.zc
@@ -0,0 +1,6 @@
+// expect: 4/
+// spec 4.4
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+int f() { int i = 0; while (1) { i++; if (i == 4) return i; } }
+fn main() { pn(f()); return 0; }
diff --git a/tests/conformance/4-statements/while_one_exits_by_break.zc b/tests/conformance/4-statements/while_one_exits_by_break.zc
new file mode 100644
index 0000000..e105204
--- /dev/null
+++ b/tests/conformance/4-statements/while_one_exits_by_break.zc
@@ -0,0 +1,5 @@
+// expect: 3/
+// spec 4.4: while (1) exits by break or return
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int i = 0; while (1) { i++; if (i == 3) break; } pn(i); return 0; }
diff --git a/tests/conformance/4-statements/while_tests_before.zc b/tests/conformance/4-statements/while_tests_before.zc
new file mode 100644
index 0000000..069afbf
--- /dev/null
+++ b/tests/conformance/4-statements/while_tests_before.zc
@@ -0,0 +1,5 @@
+// expect: 0/
+// spec 4.4: tests before each pass
+include rt;
+void pn(int x) { rt.put_n(x); rt.put_c(10); }
+fn main() { int n = 0; while (0) n++; pn(n); return 0; }
diff --git a/tests/conformance/run.sh b/tests/conformance/run.sh
new file mode 100755
index 0000000..433b37d
--- /dev/null
+++ b/tests/conformance/run.sh
@@ -0,0 +1,180 @@
+#!/bin/bash
+# runs the language conformance programs (tests/conformance/<section>/<name>.zc) against docs/SPEC.md.
+# the first line of each program is its expectation, derived from the spec text alone:
+# // expect: TEXT the program must compile and print exactly TEXT, newlines written as /
+# // expect error: TEXT the compiler must reject it, with TEXT as a substring of its output
+# directive lines (a line `// zc0: ...` anywhere in the file, by convention the last one):
+# // zc0: skip outside zc0's subset (appendix a): not run on zc0. a program without
+# this line that zc0 rejects is a failure of zc0
+# // zc0: error zc0 must reject the program too (error programs are otherwise
+# not run on zc0, which has no checks)
+# a program may read stdin after a source-ending backtick line, as everywhere else.
+# every program runs on build/bin/zy; --zym adds build/bin/zym, --zc0 adds zc0 (through the
+# run-only images of src/tools/parity.sh). tests/conformance/known.txt lists failures that are
+# understood: one line per failure, `PATH IMPL CLASS reason` with PATH relative to
+# tests/conformance and IMPL one of zy, zym, zc0. they print as `known` and do not fail the run.
+set -u
+usage() {
+ printf '%s\n' 'usage: tests/conformance/run.sh [--zym] [--zc0] [-q] [-t SECONDS] [FILE.zc | DIR ...]' \
+ 'runs the conformance programs under tests/conformance (or the given files and folders) on build/bin/zy.' \
+ 'each program starts with `// expect: TEXT` (output, newlines as /) or `// expect error: TEXT`.' \
+ 'prints ok, FAIL, known or skip per program and implementation, then a summary per section and a total;' \
+ 'exit status 1 when anything fails that is not listed in tests/conformance/known.txt.' \
+ 'options:' \
+ ' --zym also run every program on build/bin/zym' \
+ ' --zc0 also run the programs zc0 accepts through zc0 (build/bin/zc0 and a microcore per program)' \
+ ' -q print only FAIL lines and the summary' \
+ ' -t SECONDS time limit for each run (default 20)' \
+ ' --help, -h show this help and exit' \
+ 'work files are under build/conformance/ and build/parity/.'
+}
+zym=0; zc0=0; quiet=0; limit=20; args=()
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --help|-h) usage; exit 0 ;;
+ --zym) zym=1; shift ;;
+ --zc0) zc0=1; shift ;;
+ -q) quiet=1; shift ;;
+ -t) [ $# -ge 2 ] || { echo "run.sh: -t needs a number of seconds" >&2; exit 2; }
+ case "$2" in ''|*[!0-9]*|0) echo "run.sh: -t needs a positive number of seconds" >&2; exit 2 ;; esac
+ limit=$2; shift 2 ;;
+ --) shift; args+=("$@"); break ;;
+ -*) echo "run.sh: unknown option $1; use --help for usage" >&2; exit 2 ;;
+ *) args+=("$1"); shift ;;
+ esac
+done
+cd "$(dirname "$0")/../.." || exit 2
+root=$PWD
+conf=tests/conformance
+[ ${#args[@]} -gt 0 ] || args=("$conf")
+files=()
+for a in "${args[@]}"; do
+ if [ -d "$a" ]; then
+ while IFS= read -r f; do files+=("$f"); done < <(find "$a" -name '*.zc' | sort)
+ elif [ -f "$a" ]; then files+=("$a")
+ else echo "run.sh: no such file or folder: $a" >&2; exit 2; fi
+done
+[ -x build/bin/zy ] || { echo "run.sh: build/bin/zy is missing; run make first" >&2; exit 2; }
+[ $zym = 0 ] || [ -x build/bin/zym ] || { echo "run.sh: build/bin/zym is missing; run make first" >&2; exit 2; }
+W=build/conformance; mkdir -p "$W"
+known=$conf/known.txt
+
+declare -A cnt
+secs=()
+fails=0
+bump() { cnt["$1"]=$(( ${cnt["$1"]:-0} + 1 )); }
+
+# status: ok FAIL skip. a FAIL listed in known.txt is shown as known and does not fail the run
+emit() { # name impl status detail
+ local name=$1 impl=$2 st=$3 detail=$4 sec=${1%%/*} why
+ if [ "$st" = FAIL ] && [ -f "$known" ] && why=$(grep -m1 "^$name $impl " "$known"); then
+ st=known; detail="$detail [$(echo "$why" | cut -d' ' -f3-)]"
+ fi
+ bump "$sec:$impl:$st"
+ case $st in
+ FAIL) fails=$((fails+1)); echo "FAIL $impl $name: $detail" ;;
+ known) [ $quiet = 1 ] || echo "known $impl $name: $detail" ;;
+ ok) [ $quiet = 1 ] || echo "ok $impl $name" ;;
+ skip) [ $quiet = 1 ] || echo "skip $impl $name: $detail" ;;
+ esac
+}
+
+kind_of() { if head -n1 "$1" | grep -q '^// expect error: '; then echo err; else echo out; fi; }
+text_of() { head -n1 "$1" | sed -e 's#^// expect error: ##' -e 's#^// expect: ##'; }
+
+# check FILE OUTPUTFILE: sets detail and returns 1 on a mismatch
+detail=""
+check() {
+ local f=$1 out=$2 kind text got
+ kind=$(kind_of "$f"); text=$(text_of "$f")
+ if [ "$kind" = out ]; then
+ got=$(tr '\n' '/' < "$out" | tr -c '[:print:]' '?')
+ [ "$got" = "$text" ] && return 0
+ detail="expected [$text] got [${got:0:300}]"; return 1
+ fi
+ grep -qF -- "$text" "$out" && return 0
+ detail="expected an error containing [$text] got [$(head -c 300 "$out" | tr '\n' '/')]"; return 1
+}
+
+for f in "${files[@]}"; do
+ case $f in "$conf"/*) name=${f#"$conf"/} ;; *) name=$f ;; esac
+ sec=${name%%/*}
+ case " ${secs[*]:-} " in *" $sec "*) ;; *) secs+=("$sec") ;; esac
+ if ! head -n1 "$f" | grep -q '^// expect\( error\)\?: '; then
+ emit "$name" zy FAIL "no expectation on the first line"; continue
+ fi
+done
+
+# zy and zym
+run_one() { # file name impl binary
+ local f=$1 name=$2 impl=$3 bin=$4 d out rc
+ d=$W/$(echo "${name%.zc}" | tr '/' '_'); mkdir -p "$d"; out=$d/out.$impl
+ ( cd "$d" && timeout -k 1 "$limit" "$root/$bin" < "$root/$f" > "$root/$out" 2>&1 ); rc=$?
+ if [ $rc = 124 ]; then emit "$name" "$impl" FAIL "timed out after ${limit}s"; return; fi
+ if check "$f" "$out"; then emit "$name" "$impl" ok ""; else emit "$name" "$impl" FAIL "$detail"; fi
+}
+for f in "${files[@]}"; do
+ case $f in "$conf"/*) name=${f#"$conf"/} ;; *) name=$f ;; esac
+ head -n1 "$f" | grep -q '^// expect\( error\)\?: ' || continue
+ run_one "$f" "$name" zy build/bin/zy
+ [ $zym = 0 ] || run_one "$f" "$name" zym build/bin/zym
+done
+
+# zc0 through parity.sh: one call for every program that is meant for it
+if [ $zc0 = 1 ]; then
+ elig=(); errs=()
+ for f in "${files[@]}"; do
+ case $f in "$conf"/*) name=${f#"$conf"/} ;; *) name=$f ;; esac
+ head -n1 "$f" | grep -q '^// expect\( error\)\?: ' || continue
+ if grep -q '^// zc0: skip' "$f"; then emit "$name" zc0 skip "marked // zc0: skip"; continue; fi
+ if [ "$(kind_of "$f")" = err ]; then
+ if grep -q '^// zc0: error' "$f"; then errs+=("$f"); else emit "$name" zc0 skip "error program, zc0 has no checks"; fi
+ continue
+ fi
+ elig+=("$f")
+ done
+ if [ ${#elig[@]} -gt 0 ] || [ ${#errs[@]} -gt 0 ]; then
+ bash src/tools/parity.sh -t "$limit" "${elig[@]}" > "$W/parity.log" 2>&1
+ pre=build/parity/prefix.zc
+ for f in "${elig[@]}"; do
+ name=${f#"$conf"/}; d=build/parity/$(echo "${f%.zc}" | tr '/' '_')
+ if ! cat "$pre" "$f" | build/bin/zc0 > /dev/null 2> "$W/zc0.err"; then
+ emit "$name" zc0 FAIL "zc0 rejects a program inside its subset: $(head -n1 "$W/zc0.err" | cut -c1-120)"; continue
+ fi
+ if grep -q "^broken: $f" "$W/parity.log"; then emit "$name" zc0 FAIL "$(grep "^broken: $f" "$W/parity.log")"; continue; fi
+ if [ ! -f "$d/out0" ]; then emit "$name" zc0 FAIL "no output (see $W/parity.log)"; continue; fi
+ if check "$f" "$d/out0"; then emit "$name" zc0 ok ""; else emit "$name" zc0 FAIL "$detail"; fi
+ done
+ for f in "${errs[@]}"; do
+ name=${f#"$conf"/}
+ if cat "$pre" "$f" | build/bin/zc0 > /dev/null 2> "$W/zc0.err"; then
+ emit "$name" zc0 FAIL "zc0 accepted a program the spec says is an error"
+ else emit "$name" zc0 ok ""; fi
+ done
+ fi
+fi
+
+echo "summary (programs, ok, FAIL, known, skip per implementation):"
+impls="zy"; [ $zym = 1 ] && impls="$impls zym"; [ $zc0 = 1 ] && impls="$impls zc0"
+tot=0
+declare -A itot
+for s in "${secs[@]}"; do
+ n=0; line=""
+ for f in "${files[@]}"; do
+ case $f in "$conf"/*) name=${f#"$conf"/} ;; *) name=$f ;; esac
+ [ "${name%%/*}" = "$s" ] && n=$((n+1))
+ done
+ tot=$((tot+n))
+ for i in $impls; do
+ o=${cnt["$s:$i:ok"]:-0}; b=${cnt["$s:$i:FAIL"]:-0}; k=${cnt["$s:$i:known"]:-0}; sk=${cnt["$s:$i:skip"]:-0}
+ line="$line $i $o/$b/$k/$sk"
+ itot["$i:ok"]=$(( ${itot["$i:ok"]:-0} + o )); itot["$i:FAIL"]=$(( ${itot["$i:FAIL"]:-0} + b ))
+ itot["$i:known"]=$(( ${itot["$i:known"]:-0} + k )); itot["$i:skip"]=$(( ${itot["$i:skip"]:-0} + sk ))
+ done
+ printf ' %-24s %3d programs%s\n' "$s" "$n" "$line"
+done
+line=""
+for i in $impls; do line="$line $i ${itot["$i:ok"]:-0}/${itot["$i:FAIL"]:-0}/${itot["$i:known"]:-0}/${itot["$i:skip"]:-0}"; done
+printf ' %-24s %3d programs%s\n' total "$tot" "$line"
+echo "(per implementation: ok/FAIL/known/skip)"
+[ $fails -eq 0 ]